Merge branch 'master' into no-additional-init

This commit is contained in:
A.Unger
2021-07-02 13:25:30 +02:00
662 changed files with 43301 additions and 29594 deletions
+34 -4
View File
@@ -1,21 +1,24 @@
package command
import (
"context"
"os"
"strings"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/micro/cli/v2"
ociscfg "github.com/owncloud/ocis/ocis-pkg/config"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/proxy/pkg/config"
"github.com/owncloud/ocis/proxy/pkg/flagset"
"github.com/owncloud/ocis/proxy/pkg/version"
"github.com/spf13/viper"
"github.com/thejerf/suture/v4"
)
// Execute is the entry point for the ocis-proxy command.
func Execute() error {
cfg := config.New()
func Execute(cfg *config.Config) error {
app := &cli.App{
Name: "ocis-proxy",
Version: version.String,
@@ -34,7 +37,6 @@ func Execute() error {
Before: func(c *cli.Context) error {
cfg.Service.Version = version.String
return nil
//return ParseConfig(c, cfg)
},
Commands: []*cli.Command{
@@ -64,11 +66,14 @@ func NewLogger(cfg *config.Config) log.Logger {
log.Level(cfg.Log.Level),
log.Pretty(cfg.Log.Pretty),
log.Color(cfg.Log.Color),
log.File(cfg.Log.File),
)
}
// ParseConfig loads proxy configuration from Viper known paths.
func ParseConfig(c *cli.Context, cfg *config.Config) error {
sync.ParsingViperConfig.Lock()
defer sync.ParsingViperConfig.Unlock()
logger := NewLogger(cfg)
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
@@ -109,3 +114,28 @@ func ParseConfig(c *cli.Context, cfg *config.Config) error {
return nil
}
// SutureService allows for the proxy command to be embedded and supervised by a suture supervisor tree.
type SutureService struct {
cfg *config.Config
}
// NewSutureService creates a new proxy.SutureService
func NewSutureService(cfg *ociscfg.Config) suture.Service {
if cfg.Mode == 0 {
cfg.Proxy.Supervised = true
}
cfg.Proxy.Log.File = cfg.Log.File
return SutureService{
cfg: cfg.Proxy,
}
}
func (s SutureService) Serve(ctx context.Context) error {
s.cfg.Context = ctx
if err := Execute(s.cfg); err != nil {
return err
}
return nil
}
+28 -146
View File
@@ -5,26 +5,18 @@ import (
"crypto/tls"
"fmt"
"net/http"
"os"
"os/signal"
"strings"
"time"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
"contrib.go.opencensus.io/exporter/jaeger"
"contrib.go.opencensus.io/exporter/ocagent"
"contrib.go.opencensus.io/exporter/zipkin"
"github.com/coreos/go-oidc"
"github.com/justinas/alice"
"github.com/micro/cli/v2"
"github.com/oklog/run"
openzipkin "github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
acc "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/conversions"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/service/grpc"
"github.com/owncloud/ocis/ocis-pkg/sync"
"github.com/owncloud/ocis/proxy/pkg/config"
"github.com/owncloud/ocis/proxy/pkg/cs3"
"github.com/owncloud/ocis/proxy/pkg/flagset"
@@ -33,10 +25,10 @@ import (
"github.com/owncloud/ocis/proxy/pkg/proxy"
"github.com/owncloud/ocis/proxy/pkg/server/debug"
proxyHTTP "github.com/owncloud/ocis/proxy/pkg/server/http"
"github.com/owncloud/ocis/proxy/pkg/tracing"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
storepb "github.com/owncloud/ocis/store/pkg/proto/v0"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
"golang.org/x/oauth2"
)
@@ -45,8 +37,9 @@ func Server(cfg *config.Config) *cli.Command {
return &cli.Command{
Name: "server",
Usage: "Start integrated server",
Flags: flagset.ServerWithConfig(cfg),
Flags: append(flagset.ServerWithConfig(cfg), flagset.RootWithConfig(cfg)...),
Before: func(ctx *cli.Context) error {
logger := NewLogger(cfg)
if cfg.HTTP.Root != "/" {
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
}
@@ -56,113 +49,34 @@ func Server(cfg *config.Config) *cli.Command {
return err
}
if err := ParseConfig(ctx, cfg); err != nil {
return err
if !cfg.Supervised {
return ParseConfig(ctx, cfg)
}
// TODO we could parse OCIS_URL and set the PROXY_HTTP_ADDR port but that would make it harder to deploy with a
// reverse proxy ... wouldn't it?
logger.Debug().Str("service", "ocs").Msg("ignoring config file parsing when running supervised")
return nil
},
Action: func(c *cli.Context) error {
logger := NewLogger(cfg)
if cfg.Tracing.Enabled {
switch t := cfg.Tracing.Type; t {
case "agent":
exporter, err := ocagent.NewExporter(
ocagent.WithReconnectionPeriod(5*time.Second),
ocagent.WithAddress(cfg.Tracing.Endpoint),
ocagent.WithServiceName(cfg.Tracing.Service),
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create agent tracing")
return err
}
trace.RegisterExporter(exporter)
view.RegisterExporter(exporter)
case "jaeger":
exporter, err := jaeger.NewExporter(
jaeger.Options{
AgentEndpoint: cfg.Tracing.Endpoint,
CollectorEndpoint: cfg.Tracing.Collector,
Process: jaeger.Process{
ServiceName: cfg.Tracing.Service,
},
},
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create jaeger tracing")
return err
}
trace.RegisterExporter(exporter)
case "zipkin":
endpoint, err := openzipkin.NewEndpoint(
cfg.Tracing.Service,
cfg.Tracing.Endpoint,
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create zipkin tracing")
return err
}
exporter := zipkin.NewExporter(
zipkinhttp.NewReporter(
cfg.Tracing.Collector,
),
endpoint,
)
trace.RegisterExporter(exporter)
default:
logger.Warn().
Str("type", t).
Msg("Unknown tracing backend")
}
trace.ApplyConfig(
trace.Config{
DefaultSampler: trace.AlwaysSample(),
},
)
} else {
logger.Debug().
Msg("Tracing is not enabled")
if err := tracing.Configure(cfg, logger); err != nil {
return err
}
var (
gr = run.Group{}
ctx, cancel = context.WithCancel(context.Background())
metrics = metrics.New()
m = metrics.New()
)
gr := run.Group{}
ctx, cancel := func() (context.Context, context.CancelFunc) {
if cfg.Context == nil {
return context.WithCancel(context.Background())
}
return context.WithCancel(cfg.Context)
}()
defer cancel()
metrics.BuildInfo.WithLabelValues(cfg.Service.Version).Set(1)
m.BuildInfo.WithLabelValues(cfg.Service.Version).Set(1)
rp := proxy.NewMultiHostReverseProxy(
proxy.Logger(logger),
@@ -175,9 +89,7 @@ func Server(cfg *config.Config) *cli.Command {
proxyHTTP.Logger(logger),
proxyHTTP.Context(ctx),
proxyHTTP.Config(cfg),
proxyHTTP.Metrics(metrics),
proxyHTTP.Flags(flagset.RootWithConfig(config.New())),
proxyHTTP.Flags(flagset.ServerWithConfig(config.New())),
proxyHTTP.Metrics(metrics.New()),
proxyHTTP.Middlewares(loadMiddlewares(ctx, logger, cfg)),
)
@@ -209,48 +121,18 @@ func Server(cfg *config.Config) *cli.Command {
)
if err != nil {
logger.Error().
Err(err).
Str("server", "debug").
Msg("Failed to initialize server")
logger.Error().Err(err).Str("server", "debug").Msg("Failed to initialize server")
return err
}
gr.Add(func() error {
return server.ListenAndServe()
}, func(_ error) {
ctx, timeout := context.WithTimeout(ctx, 5*time.Second)
defer timeout()
defer cancel()
if err := server.Shutdown(ctx); err != nil {
logger.Error().
Err(err).
Str("server", "debug").
Msg("Failed to shutdown server")
} else {
logger.Info().
Str("server", "debug").
Msg("Shutting down server")
}
gr.Add(server.ListenAndServe, func(_ error) {
_ = server.Shutdown(ctx)
cancel()
})
}
{
stop := make(chan os.Signal, 1)
gr.Add(func() error {
signal.Notify(stop, os.Interrupt)
<-stop
return nil
}, func(err error) {
close(stop)
cancel()
})
if !cfg.Supervised {
sync.Trap(&gr, cancel)
}
return gr.Run()
@@ -286,7 +168,7 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic
var oidcHTTPClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: cfg.OIDC.Insecure,
InsecureSkipVerify: cfg.OIDC.Insecure, //nolint:gosec
},
DisableKeepAlives: true,
},
+9 -1
View File
@@ -1,10 +1,13 @@
package config
import "context"
// Log defines the available logging configuration.
type Log struct {
Level string
Pretty bool
Color bool
File string
}
// Debug defines the available debug configuration.
@@ -119,6 +122,9 @@ type Config struct {
AutoprovisionAccounts bool
EnableBasicAuth bool
InsecureBackends bool
Context context.Context
Supervised bool
}
// OIDC is the config for the OpenID-Connect middleware. If set the proxy will try to authenticate every request
@@ -160,5 +166,7 @@ type MigrationSelectorConf struct {
// New initializes a new configuration
func New() *Config {
return &Config{}
return &Config{
HTTP: HTTP{},
}
}
-123
View File
@@ -1,123 +0,0 @@
package crypto
import (
"crypto/ecdsa"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"net"
"os"
"time"
"github.com/owncloud/ocis/ocis-pkg/log"
)
func publicKey(priv interface{}) interface{} {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
default:
return nil
}
}
func pemBlockForKey(priv interface{}, l log.Logger) *pem.Block {
switch k := priv.(type) {
case *rsa.PrivateKey:
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}
case *ecdsa.PrivateKey:
b, err := x509.MarshalECPrivateKey(k)
if err != nil {
l.Fatal().Err(err).Msg("Unable to marshal ECDSA private key")
}
return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
default:
return nil
}
}
// GenCert generates TLS-Certificates
func GenCert(l log.Logger) error {
var priv interface{}
var err error
priv, err = rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
l.Fatal().Err(err).Msg("Failed to generate private key")
}
notBefore := time.Now()
notAfter := notBefore.Add(24 * time.Hour * 365)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
l.Fatal().Err(err).Msg("Failed to generate serial number")
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Corp"},
CommonName: "OCIS",
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
hosts := []string{"127.0.0.1", "localhost"}
for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, h)
}
}
//template.IsCA = true
//template.KeyUsage |= x509.KeyUsageCertSign
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
if err != nil {
l.Fatal().Err(err).Msg("Failed to create certificate")
}
certOut, err := os.Create("server.crt")
if err != nil {
l.Fatal().Err(err).Msg("Failed to open server.crt for writing")
}
err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
if err != nil {
l.Fatal().Err(err).Msg("Failed to encode certificate")
}
err = certOut.Close()
if err != nil {
l.Fatal().Err(err).Msg("Failed to write cert")
}
l.Info().Msg("Written server.crt")
keyOut, err := os.OpenFile("server.key", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
l.Fatal().Err(err).Msg("Failed to open server.key for writing")
}
err = pem.Encode(keyOut, pemBlockForKey(priv, l))
if err != nil {
l.Fatal().Err(err).Msg("Failed to encode key")
}
err = keyOut.Close()
if err != nil {
l.Fatal().Err(err).Msg("Failed to write key")
}
l.Info().Msg("Written server.key")
return nil
}
+42 -31
View File
@@ -1,7 +1,11 @@
package flagset
import (
"path"
"github.com/micro/cli/v2"
"github.com/owncloud/ocis/ocis-pkg/flags"
pkgos "github.com/owncloud/ocis/ocis-pkg/os"
"github.com/owncloud/ocis/proxy/pkg/config"
)
@@ -10,25 +14,26 @@ func RootWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "log-level",
Value: "info",
Usage: "Set logging level",
EnvVars: []string{"PROXY_LOG_LEVEL"},
EnvVars: []string{"PROXY_LOG_LEVEL", "OCIS_LOG_LEVEL"},
Destination: &cfg.Log.Level,
},
&cli.BoolFlag{
Name: "log-pretty",
Value: true,
Usage: "Enable pretty logging",
EnvVars: []string{"PROXY_LOG_PRETTY"},
EnvVars: []string{"PROXY_LOG_PRETTY", "OCIS_LOG_PRETTY"},
Destination: &cfg.Log.Pretty,
},
&cli.BoolFlag{
Name: "log-color",
Value: true,
Usage: "Enable colored logging",
EnvVars: []string{"PROXY_LOG_COLOR"},
EnvVars: []string{"PROXY_LOG_COLOR", "OCIS_LOG_COLOR"},
Destination: &cfg.Log.Color,
},
&cli.StringFlag{
Name: "extensions",
Usage: "Run specific extensions during supervised mode",
},
}
}
@@ -37,7 +42,7 @@ func HealthWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "debug-addr",
Value: "0.0.0.0:9109",
Value: flags.OverrideDefaultString(cfg.Debug.Addr, "0.0.0.0:9109"),
Usage: "Address to debug endpoint",
EnvVars: []string{"PROXY_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
@@ -48,6 +53,12 @@ func HealthWithConfig(cfg *config.Config) []cli.Flag {
// ServerWithConfig applies cfg to the root flagset
func ServerWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "log-file",
Usage: "Enable log to file",
EnvVars: []string{"PROXY_LOG_FILE", "OCIS_LOG_FILE"},
Destination: &cfg.Log.File,
},
&cli.StringFlag{
Name: "config-file",
Value: "",
@@ -63,7 +74,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "tracing-type",
Value: "jaeger",
Value: flags.OverrideDefaultString(cfg.Tracing.Type, "jaeger"),
Usage: "Tracing backend type",
EnvVars: []string{"PROXY_TRACING_TYPE"},
Destination: &cfg.Tracing.Type,
@@ -84,14 +95,14 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "tracing-service",
Value: "proxy",
Value: flags.OverrideDefaultString(cfg.Tracing.Service, "proxy"),
Usage: "Service name for tracing",
EnvVars: []string{"PROXY_TRACING_SERVICE"},
Destination: &cfg.Tracing.Service,
},
&cli.StringFlag{
Name: "debug-addr",
Value: "0.0.0.0:9205",
Value: flags.OverrideDefaultString(cfg.Debug.Addr, "0.0.0.0:9205"),
Usage: "Address to bind debug server",
EnvVars: []string{"PROXY_DEBUG_ADDR"},
Destination: &cfg.Debug.Addr,
@@ -117,77 +128,77 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.StringFlag{
Name: "http-addr",
Value: "0.0.0.0:9200",
Value: flags.OverrideDefaultString(cfg.HTTP.Addr, "0.0.0.0:9200"),
Usage: "Address to bind http server",
EnvVars: []string{"PROXY_HTTP_ADDR"},
Destination: &cfg.HTTP.Addr,
},
&cli.StringFlag{
Name: "http-root",
Value: "/",
Value: flags.OverrideDefaultString(cfg.HTTP.Root, "/"),
Usage: "Root path of http server",
EnvVars: []string{"PROXY_HTTP_ROOT"},
Destination: &cfg.HTTP.Root,
},
&cli.StringFlag{
Name: "asset-path",
Value: "",
Value: flags.OverrideDefaultString(cfg.Asset.Path, ""),
Usage: "Path to custom assets",
EnvVars: []string{"PROXY_ASSET_PATH"},
Destination: &cfg.Asset.Path,
},
&cli.StringFlag{
Name: "service-namespace",
Value: "com.owncloud.web",
Value: flags.OverrideDefaultString(cfg.Service.Namespace, "com.owncloud.web"),
Usage: "Set the base namespace for the service namespace",
EnvVars: []string{"PROXY_SERVICE_NAMESPACE"},
Destination: &cfg.Service.Namespace,
},
&cli.StringFlag{
Name: "service-name",
Value: "proxy",
Value: flags.OverrideDefaultString(cfg.Service.Name, "proxy"),
Usage: "Service name",
EnvVars: []string{"PROXY_SERVICE_NAME"},
Destination: &cfg.Service.Name,
},
&cli.StringFlag{
Name: "transport-tls-cert",
Value: "",
Value: flags.OverrideDefaultString(cfg.HTTP.TLSCert, path.Join(pkgos.MustUserConfigDir("ocis", "proxy"), "server.crt")),
Usage: "Certificate file for transport encryption",
EnvVars: []string{"PROXY_TRANSPORT_TLS_CERT"},
Destination: &cfg.HTTP.TLSCert,
},
&cli.StringFlag{
Name: "transport-tls-key",
Value: "",
Value: flags.OverrideDefaultString(cfg.HTTP.TLSKey, path.Join(pkgos.MustUserConfigDir("ocis", "proxy"), "server.key")),
Usage: "Secret file for transport encryption",
EnvVars: []string{"PROXY_TRANSPORT_TLS_KEY"},
Destination: &cfg.HTTP.TLSKey,
},
&cli.BoolFlag{
Name: "tls",
Value: flags.OverrideDefaultBool(cfg.HTTP.TLS, true),
Usage: "Use TLS (disable only if proxy is behind a TLS-terminating reverse-proxy).",
EnvVars: []string{"PROXY_TLS"},
Value: true,
Destination: &cfg.HTTP.TLS,
},
&cli.StringFlag{
Name: "jwt-secret",
Value: "Pive-Fumkiu4",
Value: flags.OverrideDefaultString(cfg.TokenManager.JWTSecret, "Pive-Fumkiu4"),
Usage: "Used to create JWT to talk to reva, should equal reva's jwt-secret",
EnvVars: []string{"PROXY_JWT_SECRET", "OCIS_JWT_SECRET"},
Destination: &cfg.TokenManager.JWTSecret,
},
&cli.StringFlag{
Name: "reva-gateway-addr",
Value: "127.0.0.1:9142",
Value: flags.OverrideDefaultString(cfg.Reva.Address, "127.0.0.1:9142"),
Usage: "REVA Gateway Endpoint",
EnvVars: []string{"PROXY_REVA_GATEWAY_ADDR"},
Destination: &cfg.Reva.Address,
},
&cli.BoolFlag{
Name: "insecure",
Value: false,
Value: flags.OverrideDefaultBool(cfg.InsecureBackends, false),
Usage: "allow insecure communication to upstream servers",
EnvVars: []string{"PROXY_INSECURE_BACKENDS"},
Destination: &cfg.InsecureBackends,
@@ -197,28 +208,28 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
&cli.StringFlag{
Name: "oidc-issuer",
Value: "https://localhost:9200",
Value: flags.OverrideDefaultString(cfg.OIDC.Issuer, "https://localhost:9200"),
Usage: "OIDC issuer",
EnvVars: []string{"PROXY_OIDC_ISSUER", "OCIS_URL"}, // PROXY_OIDC_ISSUER takes precedence over OCIS_URL
Destination: &cfg.OIDC.Issuer,
},
&cli.BoolFlag{
Name: "oidc-insecure",
Value: true,
Value: flags.OverrideDefaultBool(cfg.OIDC.Insecure, true),
Usage: "OIDC allow insecure communication",
EnvVars: []string{"PROXY_OIDC_INSECURE"},
Destination: &cfg.OIDC.Insecure,
},
&cli.IntFlag{
Name: "oidc-userinfo-cache-tll",
Value: 10,
Value: flags.OverrideDefaultInt(cfg.OIDC.UserinfoCache.TTL, 10),
Usage: "Fallback TTL in seconds for caching userinfo, when no token lifetime can be identified",
EnvVars: []string{"PROXY_OIDC_USERINFO_CACHE_TTL"},
Destination: &cfg.OIDC.UserinfoCache.TTL,
},
&cli.IntFlag{
Name: "oidc-userinfo-cache-size",
Value: 1024,
Value: flags.OverrideDefaultInt(cfg.OIDC.UserinfoCache.Size, 1024),
Usage: "Max entries for caching userinfo",
EnvVars: []string{"PROXY_OIDC_USERINFO_CACHE_SIZE"},
Destination: &cfg.OIDC.UserinfoCache.Size,
@@ -226,7 +237,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
&cli.BoolFlag{
Name: "autoprovision-accounts",
Value: false,
Value: flags.OverrideDefaultBool(cfg.AutoprovisionAccounts, false),
Usage: "create accounts from OIDC access tokens to learn new users",
EnvVars: []string{"PROXY_AUTOPROVISION_ACCOUNTS"},
Destination: &cfg.AutoprovisionAccounts,
@@ -241,7 +252,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
},
&cli.BoolFlag{
Name: "enable-presignedurls",
Value: true,
Value: flags.OverrideDefaultBool(cfg.PreSignedURL.Enabled, true),
Usage: "Enable or disable handling the presigned urls in the proxy",
EnvVars: []string{"PROXY_ENABLE_PRESIGNEDURLS"},
Destination: &cfg.PreSignedURL.Enabled,
@@ -250,7 +261,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
// Basic auth
&cli.BoolFlag{
Name: "enable-basic-auth",
Value: false,
Value: flags.OverrideDefaultBool(cfg.EnableBasicAuth, false),
Usage: "enable basic authentication",
EnvVars: []string{"PROXY_ENABLE_BASIC_AUTH"},
Destination: &cfg.EnableBasicAuth,
@@ -258,7 +269,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
&cli.StringFlag{
Name: "account-backend-type",
Value: "accounts",
Value: flags.OverrideDefaultString(cfg.AccountBackend, "accounts"),
Usage: "account-backend-type",
EnvVars: []string{"PROXY_ACCOUNT_BACKEND_TYPE"},
Destination: &cfg.AccountBackend,
@@ -278,14 +289,14 @@ func ListProxyWithConfig(cfg *config.Config) []cli.Flag {
return []cli.Flag{
&cli.StringFlag{
Name: "service-namespace",
Value: "com.owncloud.web",
Value: flags.OverrideDefaultString(cfg.OIDC.Issuer, "com.owncloud.web"),
Usage: "Set the base namespace for the service namespace",
EnvVars: []string{"PROXY_SERVICE_NAMESPACE"},
Destination: &cfg.Service.Namespace,
},
&cli.StringFlag{
Name: "service-name",
Value: "proxy",
Value: flags.OverrideDefaultString(cfg.Service.Name, "proxy"),
Usage: "Service name",
EnvVars: []string{"PROXY_SERVICE_NAME"},
Destination: &cfg.Service.Name,
+4 -16
View File
@@ -49,21 +49,9 @@ func New() *Metrics {
}, []string{"versions"}),
}
prometheus.Register(
m.Counter,
)
prometheus.Register(
m.Latency,
)
prometheus.Register(
m.Duration,
)
prometheus.Register(
m.BuildInfo,
)
_ = prometheus.Register(m.Counter)
_ = prometheus.Register(m.Latency)
_ = prometheus.Register(m.Duration)
_ = prometheus.Register(m.BuildInfo)
return m
}
+9 -4
View File
@@ -1,6 +1,7 @@
package middleware
import (
"github.com/cs3org/reva/pkg/auth/scope"
"github.com/owncloud/ocis/proxy/pkg/user/backend"
"net/http"
@@ -56,10 +57,10 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if u == nil && claims != nil {
var claim, value string
switch {
case claims.Email != "":
claim, value = "mail", claims.Email
case claims.PreferredUsername != "":
claim, value = "username", claims.PreferredUsername
case claims.Email != "":
claim, value = "mail", claims.Email
case claims.OcisID != "":
//claim, value = "id", claims.OcisID
default:
@@ -91,8 +92,12 @@ func (m accountResolver) ServeHTTP(w http.ResponseWriter, req *http.Request) {
m.logger.Debug().Interface("claims", claims).Interface("user", u).Msgf("associated claims with uuid")
}
token, err := m.tokenManager.MintToken(req.Context(), u)
s, err := scope.GetOwnerScope()
if err != nil {
m.logger.Error().Err(err).Msgf("could not get owner scope")
return
}
token, err := m.tokenManager.MintToken(req.Context(), u, s)
if err != nil {
m.logger.Error().Err(err).Msgf("could not mint token")
w.WriteHeader(http.StatusInternalServerError)
+3 -3
View File
@@ -91,7 +91,7 @@ func (m oidcAuth) getClaims(token string, req *http.Request) (claims oidc.Standa
oauth2.StaticTokenSource(oauth2Token),
)
if err != nil {
m.logger.Error().Err(err).Str("token", token).Msg("Failed to get userinfo")
m.logger.Error().Err(err).Msg("Failed to get userinfo")
status = http.StatusUnauthorized
return
}
@@ -112,7 +112,7 @@ func (m oidcAuth) getClaims(token string, req *http.Request) (claims oidc.Standa
return
}
var ok = false
var ok bool
if claims, ok = hit.V.(oidc.StandardClaims); !ok {
status = http.StatusInternalServerError
return
@@ -155,7 +155,7 @@ func (m oidcAuth) shouldServe(req *http.Request) bool {
// todo: looks dirty, check later
// TODO: make a PR to coreos/go-oidc for exposing userinfo endpoint on provider, see https://github.com/coreos/go-oidc/issues/248
for _, ignoringPath := range []string{"/konnect/v1/userinfo"} {
for _, ignoringPath := range []string{"/konnect/v1/userinfo", "/status.php"} {
if req.URL.Path == ignoringPath {
return false
}
+15 -15
View File
@@ -54,7 +54,7 @@ func NewMultiHostReverseProxy(opts ...Option) *MultiHostReverseProxy {
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: options.Config.InsecureBackends,
InsecureSkipVerify: options.Config.InsecureBackends, //nolint:gosec
},
}
@@ -146,12 +146,12 @@ func (p *MultiHostReverseProxy) directorSelectionDirector(r *http.Request) {
Str("routeType", string(rt)).
Msg("director found")
p.logger.
Info().Fields(map[string]interface{}{
"method": r.Method,
"path": r.URL.Path,
"from": r.RemoteAddr,
}).Msg("access-log")
p.logger.Info().
Str("method", r.Method).
Str("path", r.Method).
Str("from", r.RemoteAddr).
Msg("access-log")
p.Directors[pol][rt][endpoint](r)
return
}
@@ -322,6 +322,14 @@ func defaultPolicies() []config.Policy {
Endpoint: "/data",
Backend: "http://localhost:9140",
},
{
Endpoint: "/graph/",
Backend: "http://localhost:9120",
},
{
Endpoint: "/graph-explorer/",
Backend: "http://localhost:9135",
},
// if we were using the go micro api gateway we could look up the endpoint in the registry dynamically
{
Endpoint: "/api/v0/accounts",
@@ -340,14 +348,6 @@ func defaultPolicies() []config.Policy {
Endpoint: "/settings.js",
Backend: "http://localhost:9190",
},
{
Endpoint: "/api/v0/greet",
Backend: "http://localhost:9105",
},
{
Endpoint: "/hello.js",
Backend: "http://localhost:9105",
},
{
Endpoint: "/onlyoffice.js",
Backend: "http://localhost:9220",
+5 -4
View File
@@ -136,16 +136,17 @@ func TestProxyIntegration(t *testing.T) {
rr := httptest.NewRecorder()
rp.ServeHTTP(rr, tc.input)
rsp := rr.Result()
if rr.Result().StatusCode != 200 {
t.Errorf("Expected status 200 from proxy-response got %v", rr.Result().StatusCode)
if rsp.StatusCode != 200 {
t.Errorf("Expected status 200 from proxy-response got %v", rsp.StatusCode)
}
resultBody, err := ioutil.ReadAll(rr.Result().Body)
resultBody, err := ioutil.ReadAll(rsp.Body)
if err != nil {
t.Fatal("Error reading result body")
}
if err = rr.Result().Body.Close(); err != nil {
if err = rsp.Body.Close(); err != nil {
t.Fatal("Error closing result body")
}
+6 -2
View File
@@ -33,7 +33,9 @@ func health(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
// TODO(tboerger): check if services are up and running
io.WriteString(w, http.StatusText(http.StatusOK))
if _, err := io.WriteString(w, http.StatusText(http.StatusOK)); err != nil {
panic(err)
}
}
}
@@ -45,6 +47,8 @@ func ready(cfg *config.Config) func(http.ResponseWriter, *http.Request) {
// TODO(tboerger): check if services are up and running
io.WriteString(w, http.StatusText(http.StatusOK))
if _, err := io.WriteString(w, http.StatusText(http.StatusOK)); err != nil {
panic(err)
}
}
}
+13 -18
View File
@@ -5,9 +5,8 @@ import (
"os"
"github.com/asim/go-micro/v3"
pkgcrypto "github.com/owncloud/ocis/ocis-pkg/crypto"
svc "github.com/owncloud/ocis/ocis-pkg/service/http"
"github.com/owncloud/ocis/proxy/pkg/crypto"
)
// Server initializes the http service and server.
@@ -17,25 +16,19 @@ func Server(opts ...Option) (svc.Service, error) {
httpCfg := options.Config.HTTP
var cer tls.Certificate
var certErr error
var tlsConfig *tls.Config
if options.Config.HTTP.TLS {
if httpCfg.TLSCert == "" || httpCfg.TLSKey == "" {
l.Warn().Msgf("No tls certificate provided, using a generated one")
_, certErr := os.Stat("./server.crt")
_, keyErr := os.Stat("./server.key")
l.Warn().Msgf("No tls certificate provided, using a generated one")
_, certErr := os.Stat(httpCfg.TLSCert)
_, keyErr := os.Stat(httpCfg.TLSKey)
if os.IsNotExist(certErr) || os.IsNotExist(keyErr) {
// GenCert has side effects as it writes 2 files to the binary running location
if err := crypto.GenCert(l); err != nil {
l.Fatal().Err(err).Msgf("Could not generate test-certificate")
os.Exit(1)
}
if os.IsNotExist(certErr) || os.IsNotExist(keyErr) {
// GenCert has side effects as it writes 2 files to the binary running location
if err := pkgcrypto.GenCert(httpCfg.TLSCert, httpCfg.TLSKey, l); err != nil {
l.Fatal().Err(err).Msgf("Could not generate test-certificate")
os.Exit(1)
}
httpCfg.TLSCert = "server.crt"
httpCfg.TLSKey = "server.key"
}
cer, certErr = tls.LoadX509KeyPair(httpCfg.TLSCert, httpCfg.TLSKey)
@@ -44,7 +37,7 @@ func Server(opts ...Option) (svc.Service, error) {
os.Exit(1)
}
tlsConfig = &tls.Config{Certificates: []tls.Certificate{cer}}
tlsConfig = &tls.Config{MinVersion: tls.VersionTLS12, Certificates: []tls.Certificate{cer}}
}
chain := options.Middlewares.Then(options.Handler)
@@ -59,7 +52,9 @@ func Server(opts ...Option) (svc.Service, error) {
svc.Flags(options.Flags...),
)
micro.RegisterHandler(service.Server(), chain)
if err := micro.RegisterHandler(service.Server(), chain); err != nil {
return svc.Service{}, err
}
return service, nil
}
+90
View File
@@ -0,0 +1,90 @@
package tracing
import (
"time"
"contrib.go.opencensus.io/exporter/jaeger"
"contrib.go.opencensus.io/exporter/ocagent"
"contrib.go.opencensus.io/exporter/zipkin"
openzipkin "github.com/openzipkin/zipkin-go"
zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/proxy/pkg/config"
"go.opencensus.io/stats/view"
"go.opencensus.io/trace"
)
func Configure(cfg *config.Config, logger log.Logger) error {
if cfg.Tracing.Enabled {
switch t := cfg.Tracing.Type; t {
case "agent":
exporter, err := ocagent.NewExporter(
ocagent.WithReconnectionPeriod(5*time.Second),
ocagent.WithAddress(cfg.Tracing.Endpoint),
ocagent.WithServiceName(cfg.Tracing.Service),
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create agent tracing")
return err
}
trace.RegisterExporter(exporter)
view.RegisterExporter(exporter)
case "jaeger":
exporter, err := jaeger.NewExporter(
jaeger.Options{
AgentEndpoint: cfg.Tracing.Endpoint,
CollectorEndpoint: cfg.Tracing.Collector,
Process: jaeger.Process{
ServiceName: cfg.Tracing.Service,
},
},
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create jaeger tracing")
return err
}
trace.RegisterExporter(exporter)
case "zipkin":
endpoint, err := openzipkin.NewEndpoint(
cfg.Tracing.Service,
cfg.Tracing.Endpoint,
)
if err != nil {
logger.Error().
Err(err).
Str("endpoint", cfg.Tracing.Endpoint).
Str("collector", cfg.Tracing.Collector).
Msg("Failed to create zipkin tracing")
return err
}
exporter := zipkin.NewExporter(
zipkinhttp.NewReporter(
cfg.Tracing.Collector,
),
endpoint,
)
trace.RegisterExporter(exporter)
default:
logger.Warn().
Str("type", t).
Msg("Unknown tracing backend")
}
trace.ApplyConfig(
trace.Config{
DefaultSampler: trace.AlwaysSample(),
},
)
} else {
logger.Debug().
Msg("Tracing is not enabled")
}
return nil
}
+14 -16
View File
@@ -3,15 +3,15 @@ package backend
import (
"context"
"fmt"
"net/http"
"strings"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
accounts "github.com/owncloud/ocis/accounts/pkg/proto/v0"
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/oidc"
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
"net/http"
"strconv"
"strings"
)
// NewAccountsServiceUserBackend creates a user-provider which fetches users from the ocis accounts-service
@@ -139,18 +139,8 @@ func (a *accountsServiceBackend) accountToUser(account *accounts.Account) *cs3.U
Mail: account.Mail,
MailVerified: account.ExternalUserState == "" || account.ExternalUserState == "Accepted",
Groups: expandGroups(account),
Opaque: &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"uid": {
Decoder: "plain",
Value: []byte(strconv.FormatInt(account.UidNumber, 10)),
},
"gid": {
Decoder: "plain",
Value: []byte(strconv.FormatInt(account.GidNumber, 10)),
},
},
},
UidNumber: account.UidNumber,
GidNumber: account.GidNumber,
}
return user
}
@@ -208,7 +198,15 @@ func injectRoles(ctx context.Context, u *cs3.User, ss settings.RoleService) erro
return err
}
u.Opaque.Map["roles"] = enc
if u.Opaque == nil {
u.Opaque = &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"roles": enc,
},
}
} else {
u.Opaque.Map["roles"] = enc
}
return nil
}
+2 -5
View File
@@ -145,11 +145,8 @@ func assertUserMatchesAccount(t *testing.T, exp *accounts.Account, act *userv1be
assert.Equal(t, `["a","b"]`, string(act.Opaque.Map["roles"].GetValue()))
// UID/GID
assert.NotNil(t, act.Opaque.Map["uid"])
assert.Equal(t, "1", string(act.Opaque.Map["uid"].GetValue()))
assert.NotNil(t, act.Opaque.Map["gid"])
assert.Equal(t, "2", string(act.Opaque.Map["gid"].GetValue()))
assert.Equal(t, int64(1), act.UidNumber)
assert.Equal(t, int64(2), act.GidNumber)
}
func newAccountsBackend(mockAccounts []*accounts.Account, mockRoles []*settings.UserRoleAssignment) UserBackend {
+15 -5
View File
@@ -3,6 +3,7 @@ package backend
import (
"context"
"fmt"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
@@ -10,6 +11,7 @@ import (
"github.com/owncloud/ocis/ocis-pkg/log"
"github.com/owncloud/ocis/ocis-pkg/oidc"
settings "github.com/owncloud/ocis/settings/pkg/proto/v0"
settingsSvc "github.com/owncloud/ocis/settings/pkg/service/v0"
)
type cs3backend struct {
@@ -57,7 +59,10 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, w
}
if len(roleIDs) == 0 {
return user, nil
roleIDs = append(roleIDs, settingsSvc.BundleUUIDRoleUser, settingsSvc.SelfManagementPermissionID)
// if roles are empty, assume we haven't seen the user before and assign a default user role. At least until
// proper roles are provided. See https://github.com/owncloud/ocis/issues/1825 for more context.
//return user, nil
}
enc, err := encodeRoleIDs(roleIDs)
@@ -65,10 +70,14 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, w
c.logger.Error().Err(err).Msg("Could not encode loaded roles")
}
user.Opaque = &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"roles": enc,
},
if user.Opaque == nil {
user.Opaque = &types.Opaque{
Map: map[string]*types.OpaqueEntry{
"roles": enc,
},
}
} else {
user.Opaque.Map["roles"] = enc
}
return res.User, nil
@@ -76,6 +85,7 @@ func (c *cs3backend) GetUserByClaims(ctx context.Context, claim, value string, w
func (c *cs3backend) Authenticate(ctx context.Context, username string, password string) (*cs3.User, error) {
res, err := c.authProvider.Authenticate(ctx, &gateway.AuthenticateRequest{
Type: "basic",
ClientId: username,
ClientSecret: password,
})