diff --git a/services/auth-app/pkg/command/server.go b/services/auth-app/pkg/command/server.go index 323e203c73..a8a76f73ad 100644 --- a/services/auth-app/pkg/command/server.go +++ b/services/auth-app/pkg/command/server.go @@ -7,6 +7,7 @@ import ( "path" "github.com/cs3org/reva/v2/cmd/revad/runtime" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" "github.com/gofrs/uuid" "github.com/oklog/run" "github.com/owncloud/ocis/v2/ocis-pkg/config/configlog" @@ -19,6 +20,7 @@ import ( "github.com/owncloud/ocis/v2/services/auth-app/pkg/logging" "github.com/owncloud/ocis/v2/services/auth-app/pkg/revaconfig" "github.com/owncloud/ocis/v2/services/auth-app/pkg/server/debug" + "github.com/owncloud/ocis/v2/services/auth-app/pkg/server/http" "github.com/urfave/cli/v2" ) @@ -86,6 +88,32 @@ func Server(cfg *config.Config) *cli.Command { logger.Fatal().Err(err).Msg("failed to register the grpc service") } + gatewaySelector, err := pool.GatewaySelector( + cfg.Reva.Address, + append( + cfg.Reva.GetRevaOptions(), + pool.WithRegistry(registry.GetRegistry()), + pool.WithTracerProvider(traceProvider), + )...) + if err != nil { + return err + } + + server, err := http.Server( + http.Logger(logger), + http.Context(ctx), + http.Config(cfg), + http.GatewaySelector(gatewaySelector), + http.TracerProvider(traceProvider), + ) + if err != nil { + logger.Fatal().Err(err).Msg("failed to initialize http server") + } + + gr.Add(server.Run, func(err error) { + logger.Error().Err(err).Str("server", "http").Msg("shutting down server") + }) + return gr.Run() }, } diff --git a/services/auth-app/pkg/config/config.go b/services/auth-app/pkg/config/config.go index 01d58b81eb..1fab75b7a2 100644 --- a/services/auth-app/pkg/config/config.go +++ b/services/auth-app/pkg/config/config.go @@ -15,6 +15,7 @@ type Config struct { Debug Debug `yaml:"debug"` GRPC GRPCConfig `yaml:"grpc"` + HTTP HTTP `yaml:"http"` TokenManager *TokenManager `yaml:"token_manager"` Reva *shared.Reva `yaml:"reva"` @@ -55,3 +56,20 @@ type GRPCConfig struct { Namespace string `yaml:"-"` Protocol string `yaml:"protocol" env:"AUTH_APP_GRPC_PROTOCOL" desc:"The transport protocol of the GRPC service." introductionVersion:"%%NEXT%%"` } + +// HTTP defines the available http configuration. +type HTTP struct { + Addr string `yaml:"addr" env:"AUTH_APP_HTTP_ADDR" desc:"The bind address of the HTTP service." introductionVersion:"pre5.0"` + Namespace string `yaml:"-"` + Root string `yaml:"root" env:"AUTH_APP_HTTP_ROOT" desc:"Subdirectory that serves as the root for this HTTP service." introductionVersion:"pre5.0"` + CORS CORS `yaml:"cors"` + TLS shared.HTTPServiceTLS `yaml:"tls"` +} + +// CORS defines the available cors configuration. +type CORS struct { + AllowedOrigins []string `yaml:"allow_origins" env:"OCIS_CORS_ALLOW_ORIGINS;AUTH_APP_CORS_ALLOW_ORIGINS" desc:"A list of allowed CORS origins. See following chapter for more details: *Access-Control-Allow-Origin* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin. See the Environment Variable Types description for more details." introductionVersion:"pre5.0"` + AllowedMethods []string `yaml:"allow_methods" env:"OCIS_CORS_ALLOW_METHODS;AUTH_APP_CORS_ALLOW_METHODS" desc:"A list of allowed CORS methods. See following chapter for more details: *Access-Control-Request-Method* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Method. See the Environment Variable Types description for more details." introductionVersion:"pre5.0"` + AllowedHeaders []string `yaml:"allow_headers" env:"OCIS_CORS_ALLOW_HEADERS;AUTH_APP_CORS_ALLOW_HEADERS" desc:"A list of allowed CORS headers. See following chapter for more details: *Access-Control-Request-Headers* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Request-Headers. See the Environment Variable Types description for more details." introductionVersion:"pre5.0"` + AllowCredentials bool `yaml:"allow_credentials" env:"OCIS_CORS_ALLOW_CREDENTIALS;AUTH_APP_CORS_ALLOW_CREDENTIALS" desc:"Allow credentials for CORS.See following chapter for more details: *Access-Control-Allow-Credentials* at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials." introductionVersion:"pre5.0"` +} diff --git a/services/auth-app/pkg/config/defaults/defaultconfig.go b/services/auth-app/pkg/config/defaults/defaultconfig.go index 19953bcef2..cd845f7f4d 100644 --- a/services/auth-app/pkg/config/defaults/defaultconfig.go +++ b/services/auth-app/pkg/config/defaults/defaultconfig.go @@ -28,6 +28,17 @@ func DefaultConfig() *config.Config { Namespace: "com.owncloud.api", Protocol: "tcp", }, + HTTP: config.HTTP{ + Addr: "127.0.0.1:0", + Namespace: "com.owncloud.api", + Root: "/", + CORS: config.CORS{ + AllowedOrigins: []string{"*"}, + AllowedMethods: []string{"POST"}, + AllowedHeaders: []string{"Authorization", "Origin", "Content-Type", "Accept", "X-Requested-With", "X-Request-Id", "Ocs-Apirequest"}, + AllowCredentials: true, + }, + }, Service: config.Service{ Name: "auth-app", }, diff --git a/services/auth-app/pkg/server/http/option.go b/services/auth-app/pkg/server/http/option.go new file mode 100644 index 0000000000..3f7a4779d3 --- /dev/null +++ b/services/auth-app/pkg/server/http/option.go @@ -0,0 +1,86 @@ +package http + +import ( + "context" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/owncloud/ocis/v2/ocis-pkg/log" + "github.com/owncloud/ocis/v2/services/auth-app/pkg/config" + "github.com/urfave/cli/v2" + "go.opentelemetry.io/otel/trace" +) + +// Option defines a single option function. +type Option func(o *Options) + +// Options defines the available options for this package. +type Options struct { + Logger log.Logger + Context context.Context + Config *config.Config + Flags []cli.Flag + Namespace string + GatewaySelector pool.Selectable[gateway.GatewayAPIClient] + TracerProvider trace.TracerProvider +} + +// newOptions initializes the available default options. +func newOptions(opts ...Option) Options { + opt := Options{} + + for _, o := range opts { + o(&opt) + } + + return opt +} + +// Logger provides a function to set the logger option. +func Logger(val log.Logger) Option { + return func(o *Options) { + o.Logger = val + } +} + +// Context provides a function to set the context option. +func Context(val context.Context) Option { + return func(o *Options) { + o.Context = val + } +} + +// Config provides a function to set the config option. +func Config(val *config.Config) Option { + return func(o *Options) { + o.Config = val + } +} + +// Flags provides a function to set the flags option. +func Flags(val []cli.Flag) Option { + return func(o *Options) { + o.Flags = append(o.Flags, val...) + } +} + +// Namespace provides a function to set the Namespace option. +func Namespace(val string) Option { + return func(o *Options) { + o.Namespace = val + } +} + +// GatewaySelector provides a function to configure the gateway client selector +func GatewaySelector(gatewaySelector pool.Selectable[gateway.GatewayAPIClient]) Option { + return func(o *Options) { + o.GatewaySelector = gatewaySelector + } +} + +// TracerProvider provides a function to set the TracerProvider option +func TracerProvider(val trace.TracerProvider) Option { + return func(o *Options) { + o.TracerProvider = val + } +} diff --git a/services/auth-app/pkg/server/http/server.go b/services/auth-app/pkg/server/http/server.go new file mode 100644 index 0000000000..8ba4cec9a4 --- /dev/null +++ b/services/auth-app/pkg/server/http/server.go @@ -0,0 +1,96 @@ +package http + +import ( + "fmt" + + stdhttp "net/http" + + "github.com/go-chi/chi/v5" + chimiddleware "github.com/go-chi/chi/v5/middleware" + "github.com/owncloud/ocis/v2/ocis-pkg/account" + "github.com/owncloud/ocis/v2/ocis-pkg/cors" + "github.com/owncloud/ocis/v2/ocis-pkg/middleware" + "github.com/owncloud/ocis/v2/ocis-pkg/service/http" + "github.com/owncloud/ocis/v2/ocis-pkg/tracing" + "github.com/owncloud/ocis/v2/ocis-pkg/version" + svc "github.com/owncloud/ocis/v2/services/auth-app/pkg/service" + "github.com/riandyrn/otelchi" + "go-micro.dev/v4" +) + +// Service is the service interface +type Service interface{} + +// Server initializes the http service and server. +func Server(opts ...Option) (http.Service, error) { + options := newOptions(opts...) + + service, err := http.NewService( + http.TLSConfig(options.Config.HTTP.TLS), + http.Logger(options.Logger), + http.Namespace(options.Config.HTTP.Namespace), + http.Name(options.Config.Service.Name), + http.Version(version.GetString()), + http.Address(options.Config.HTTP.Addr), + http.Context(options.Context), + http.Flags(options.Flags...), + http.TraceProvider(options.TracerProvider), + ) + if err != nil { + options.Logger.Error(). + Err(err). + Msg("Error initializing http service") + return http.Service{}, fmt.Errorf("could not initialize http service: %w", err) + } + + middlewares := []func(stdhttp.Handler) stdhttp.Handler{ + chimiddleware.RequestID, + middleware.Version( + options.Config.Service.Name, + version.GetString(), + ), + middleware.Logger( + options.Logger, + ), + middleware.ExtractAccountUUID( + account.Logger(options.Logger), + account.JWTSecret(options.Config.TokenManager.JWTSecret), + ), + middleware.Cors( + cors.Logger(options.Logger), + cors.AllowedOrigins(options.Config.HTTP.CORS.AllowedOrigins), + cors.AllowedMethods(options.Config.HTTP.CORS.AllowedMethods), + cors.AllowedHeaders(options.Config.HTTP.CORS.AllowedHeaders), + cors.AllowCredentials(options.Config.HTTP.CORS.AllowCredentials), + ), + } + + mux := chi.NewMux() + mux.Use(middlewares...) + + mux.Use( + otelchi.Middleware( + "auth-app", + otelchi.WithChiRoutes(mux), + otelchi.WithTracerProvider(options.TracerProvider), + otelchi.WithPropagators(tracing.GetPropagator()), + ), + ) + + handle, err := svc.NewAuthAppService( + svc.Logger(options.Logger), + svc.Mux(mux), + svc.Config(options.Config), + svc.GatewaySelector(options.GatewaySelector), + svc.TraceProvider(options.TracerProvider), + ) + if err != nil { + return http.Service{}, err + } + + if err := micro.RegisterHandler(service.Server(), handle); err != nil { + return http.Service{}, err + } + + return service, nil +} diff --git a/services/auth-app/pkg/service/option.go b/services/auth-app/pkg/service/option.go new file mode 100644 index 0000000000..3fc046192d --- /dev/null +++ b/services/auth-app/pkg/service/option.go @@ -0,0 +1,67 @@ +package service + +import ( + "context" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/go-chi/chi/v5" + "github.com/owncloud/ocis/v2/ocis-pkg/log" + "github.com/owncloud/ocis/v2/services/auth-app/pkg/config" + "go.opentelemetry.io/otel/trace" +) + +// Option defines a single option function. +type Option func(o *Options) + +// Options defines the available options for this package. +type Options struct { + Logger log.Logger + Context context.Context + Config *config.Config + GatewaySelector pool.Selectable[gateway.GatewayAPIClient] + Mux *chi.Mux + TracerProvider trace.TracerProvider +} + +// Logger provides a function to set the logger option. +func Logger(val log.Logger) Option { + return func(o *Options) { + o.Logger = val + } +} + +// Context provides a function to set the context option. +func Context(val context.Context) Option { + return func(o *Options) { + o.Context = val + } +} + +// Config provides a function to set the config option. +func Config(val *config.Config) Option { + return func(o *Options) { + o.Config = val + } +} + +// GatewaySelector provides a function to configure the gateway client selector +func GatewaySelector(gatewaySelector pool.Selectable[gateway.GatewayAPIClient]) Option { + return func(o *Options) { + o.GatewaySelector = gatewaySelector + } +} + +// TraceProvider provides a function to set the TracerProvider option +func TraceProvider(val trace.TracerProvider) Option { + return func(o *Options) { + o.TracerProvider = val + } +} + +// Mux defines the muxer for the userlog service +func Mux(m *chi.Mux) Option { + return func(o *Options) { + o.Mux = m + } +} diff --git a/services/auth-app/pkg/service/service.go b/services/auth-app/pkg/service/service.go new file mode 100644 index 0000000000..37e67974b8 --- /dev/null +++ b/services/auth-app/pkg/service/service.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + "net/http" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" + "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" + "github.com/go-chi/chi/v5" +) + +// AuthAppService defines the service interface. +type AuthAppService struct { + gws pool.Selectable[gateway.GatewayAPIClient] + m *chi.Mux +} + +// NewAuthAppService initializes a new AuthAppService. +func NewAuthAppService(opts ...Option) (*AuthAppService, error) { + o := &Options{} + for _, opt := range opts { + opt(o) + } + a := &AuthAppService{ + gws: o.GatewaySelector, + m: o.Mux, + } + + a.m.Route("/auth-app/tokens", func(r chi.Router) { + r.Post("/", a.HandleCreate) + }) + + return a, nil +} + +// ServeHTTP implements the http.Handler interface. +func (a *AuthAppService) ServeHTTP(w http.ResponseWriter, r *http.Request) { + a.m.ServeHTTP(w, r) +} + +// HandleCreate handles the creation of a new auth-token +func (a *AuthAppService) HandleCreate(w http.ResponseWriter, r *http.Request) { + fmt.Println("ALIVE") +} diff --git a/services/proxy/pkg/config/defaults/defaultconfig.go b/services/proxy/pkg/config/defaults/defaultconfig.go index d37c83ac9e..f59255b396 100644 --- a/services/proxy/pkg/config/defaults/defaultconfig.go +++ b/services/proxy/pkg/config/defaults/defaultconfig.go @@ -258,6 +258,10 @@ func DefaultPolicies() []config.Policy { Endpoint: "/api/v0/settings", Service: "com.owncloud.web.settings", }, + { + Endpoint: "/auth-app/tokens", + Service: "com.owncloud.api.auth-app", + }, }, }, }