diff --git a/changelog/unreleased/public-share-auth-middleware.md b/changelog/unreleased/public-share-auth-middleware.md new file mode 100644 index 00000000000..566bcb845a0 --- /dev/null +++ b/changelog/unreleased/public-share-auth-middleware.md @@ -0,0 +1,6 @@ +Enhancement: Add a middleware to authenticate public share requests + +Added a new middleware to authenticate public share requests. This makes it possible to use APIs which require an authenticated context with public shares. + +https://github.com/owncloud/ocis/pull/2536 +https://github.com/owncloud/ocis/issues/2479 diff --git a/changelog/unreleased/update-reva.md b/changelog/unreleased/update-reva.md new file mode 100644 index 00000000000..1448f51493d --- /dev/null +++ b/changelog/unreleased/update-reva.md @@ -0,0 +1,10 @@ +Enhancement: Update reva to v1.14.1-0.20211015144112-cddbdd4c560f + +Updated reva to v1.14.1-0.20211015144112-cddbdd4c560f +This update includes: + * Enhancement [cs3org/reva#2170](https://github.com/cs3org/reva/pull/2170): Handle propfind requests for existing files + * Enhancement [cs3org/reva#2166](https://github.com/cs3org/reva/pull/2166): Allow nil quota in decomposedfs + * Enhancement [cs3org/reva#2152](https://github.com/cs3org/reva/pull/2152): Report quota per storage space + * Enhancement [cs3org/reva#2143](https://github.com/cs3org/reva/pull/2143): Enabling apps to work in public shares + +https://github.com/owncloud/ocis/pull/2536 diff --git a/go.mod b/go.mod index 351db26ae50..c1eaae965cf 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/blevesearch/bleve/v2 v2.1.0 github.com/coreos/go-oidc/v3 v3.0.0 github.com/cs3org/go-cs3apis v0.0.0-20211007101428-6d142794ec11 - github.com/cs3org/reva v1.14.1-0.20211015081146-2e9bc0c7714a + github.com/cs3org/reva v1.14.1-0.20211015144112-cddbdd4c560f github.com/disintegration/imaging v1.6.2 github.com/glauth/glauth v1.1.3-0.20210729125545-b9aecdfcac31 github.com/go-chi/chi/v5 v5.0.4 diff --git a/go.sum b/go.sum index 787356f79ed..abeede699b2 100644 --- a/go.sum +++ b/go.sum @@ -293,6 +293,8 @@ github.com/cs3org/go-cs3apis v0.0.0-20211007101428-6d142794ec11 h1:cc/8fdzWdr/wA github.com/cs3org/go-cs3apis v0.0.0-20211007101428-6d142794ec11/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY= github.com/cs3org/reva v1.14.1-0.20211015081146-2e9bc0c7714a h1:xauop9DkHYtOA3qLGmohOi0rt6WqN8+1BCWu5i/4cL4= github.com/cs3org/reva v1.14.1-0.20211015081146-2e9bc0c7714a/go.mod h1:uENdZEtDFmTRt6+d4+Ro4P5XnNL+9I6gwftHEBJzHQw= +github.com/cs3org/reva v1.14.1-0.20211015144112-cddbdd4c560f h1:DVy9daUTEgnAP35Q5Vn5rt0FXiHwTr4vp0pecHFHA4Q= +github.com/cs3org/reva v1.14.1-0.20211015144112-cddbdd4c560f/go.mod h1:uENdZEtDFmTRt6+d4+Ro4P5XnNL+9I6gwftHEBJzHQw= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8 h1:Z9lwXumT5ACSmJ7WGnFl+OMLLjpz5uR2fyz7dC255FI= github.com/cubewise-code/go-mime v0.0.0-20200519001935-8c5762b177d8/go.mod h1:4abs/jPXcmJzYoYGF91JF9Uq9s/KL5n1jvFDix8KcqY= github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4= diff --git a/graph/pkg/middleware/auth.go b/graph/pkg/middleware/auth.go index dca9fafa9e7..ed4a2ecf63d 100644 --- a/graph/pkg/middleware/auth.go +++ b/graph/pkg/middleware/auth.go @@ -61,7 +61,7 @@ func Auth(opts ...account.Option) func(http.Handler) http.Handler { errorcode.InvalidAuthenticationToken.Render(w, r, http.StatusUnauthorized, "invalid token") return } - if ok, err := scope.VerifyScope(tokenScope, r); err != nil || !ok { + if ok, err := scope.VerifyScope(ctx, tokenScope, r); err != nil || !ok { opt.Logger.Error().Err(err).Msg("verifying scope failed") errorcode.InvalidAuthenticationToken.Render(w, r, http.StatusUnauthorized, "verifying scope failed") return diff --git a/ocis-pkg/middleware/account.go b/ocis-pkg/middleware/account.go index 9d7c26d4ead..562a9ce45e4 100644 --- a/ocis-pkg/middleware/account.go +++ b/ocis-pkg/middleware/account.go @@ -60,7 +60,7 @@ func ExtractAccountUUID(opts ...account.Option) func(http.Handler) http.Handler opt.Logger.Error().Err(err) return } - if ok, err := scope.VerifyScope(tokenScope, r); err != nil || !ok { + if ok, err := scope.VerifyScope(r.Context(), tokenScope, r); err != nil || !ok { opt.Logger.Error().Err(err).Msg("verifying scope failed") return } diff --git a/proxy/pkg/command/server.go b/proxy/pkg/command/server.go index 01cdb6bbfa0..8b434110349 100644 --- a/proxy/pkg/command/server.go +++ b/proxy/pkg/command/server.go @@ -147,7 +147,7 @@ func Server(cfg *config.Config) *cli.Command { } } -func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alice.Chain { +func loadMiddlewares(ctx context.Context, logger log.Logger, cfg *config.Config) alice.Chain { rolesClient := settings.NewRoleService("com.owncloud.api.settings", grpc.DefaultClient) revaClient, err := cs3.GetGatewayServiceClient(cfg.Reva.Address) var userProvider backend.UserBackend @@ -158,7 +158,7 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic "expires": int64(24 * 60 * 60), }) if err != nil { - l.Error().Err(err). + logger.Error().Err(err). Msg("Failed to create token manager") } userProvider = backend.NewAccountsServiceUserBackend( @@ -166,17 +166,17 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic rolesClient, cfg.OIDC.Issuer, tokenManager, - l, + logger, ) case "cs3": - userProvider = backend.NewCS3UserBackend(rolesClient, revaClient, cfg.MachineAuthAPIKey, l) + userProvider = backend.NewCS3UserBackend(rolesClient, revaClient, cfg.MachineAuthAPIKey, logger) default: - l.Fatal().Msgf("Invalid accounts backend type '%s'", cfg.AccountBackend) + logger.Fatal().Msgf("Invalid accounts backend type '%s'", cfg.AccountBackend) } storeClient := storepb.NewStoreService("com.owncloud.api.store", grpc.DefaultClient) if err != nil { - l.Error().Err(err). + logger.Error().Err(err). Str("gateway", cfg.Reva.Address). Msg("Failed to create reva gateway service client") } @@ -196,7 +196,7 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic pkgmiddleware.TraceContext, chimiddleware.RealIP, chimiddleware.RequestID, - middleware.AccessLog(l), + middleware.AccessLog(logger), middleware.HTTPSRedirect, // now that we established the basics, on with authentication middleware @@ -216,20 +216,20 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic middleware.TokenCacheTTL(time.Second*time.Duration(cfg.OIDC.UserinfoCache.TTL)), // basic Options - middleware.Logger(l), + middleware.Logger(logger), middleware.EnableBasicAuth(cfg.EnableBasicAuth), middleware.UserProvider(userProvider), middleware.OIDCIss(cfg.OIDC.Issuer), middleware.CredentialsByUserAgent(cfg.Reva.Middleware.Auth.CredentialsByUserAgent), ), middleware.SignedURLAuth( - middleware.Logger(l), + middleware.Logger(logger), middleware.PreSignedURLConfig(cfg.PreSignedURL), middleware.UserProvider(userProvider), middleware.Store(storeClient), ), middleware.AccountResolver( - middleware.Logger(l), + middleware.Logger(logger), middleware.UserProvider(userProvider), middleware.TokenManagerConfig(cfg.TokenManager), middleware.UserOIDCClaim(cfg.UserOIDCClaim), @@ -238,17 +238,21 @@ func loadMiddlewares(ctx context.Context, l log.Logger, cfg *config.Config) alic ), middleware.SelectorCookie( - middleware.Logger(l), + middleware.Logger(logger), middleware.UserProvider(userProvider), middleware.PolicySelectorConfig(*cfg.PolicySelector), ), // finally, trigger home creation when a user logs in middleware.CreateHome( - middleware.Logger(l), + middleware.Logger(logger), middleware.TokenManagerConfig(cfg.TokenManager), middleware.RevaGatewayClient(revaClient), ), + middleware.PublicShareAuth( + middleware.Logger(logger), + middleware.RevaGatewayClient(revaClient), + ), ) } diff --git a/proxy/pkg/middleware/public_share_auth.go b/proxy/pkg/middleware/public_share_auth.go new file mode 100644 index 00000000000..32e0fc00419 --- /dev/null +++ b/proxy/pkg/middleware/public_share_auth.go @@ -0,0 +1,56 @@ +package middleware + +import ( + "net/http" + + gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" +) + +const ( + headerRevaAccessToken = "x-access-token" + headerShareToken = "public-token" + basicAuthPasswordPrefix = "basic|" + authenticationType = "publicshares" +) + +// PublicShareAuth ... +func PublicShareAuth(opts ...Option) func(next http.Handler) http.Handler { + options := newOptions(opts...) + logger := options.Logger + + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Currently we only want to authenticate app open request coming from public shares. + shareToken := r.Header.Get(headerShareToken) + if shareToken == "" { + // Don't authenticate + next.ServeHTTP(w, r) + return + } + + // We can ignore the username since it is always set to "public" in public shares. + _, password, ok := r.BasicAuth() + + sharePassword := basicAuthPasswordPrefix + if ok { + sharePassword += password + } + + authResp, err := options.RevaGatewayClient.Authenticate(r.Context(), &gateway.AuthenticateRequest{ + Type: authenticationType, + ClientId: shareToken, + ClientSecret: sharePassword, + }) + + if err != nil { + logger.Debug().Err(err).Str("public_share_token", shareToken).Msg("could not authenticate public share") + // try another middleware + next.ServeHTTP(w, r) + return + } + + r.Header.Add(headerRevaAccessToken, authResp.Token) + next.ServeHTTP(w, r) + }) + } +}