Merge pull request #2536 from owncloud/public-share-auth-middleware

add public share auth middleware
This commit is contained in:
Willy Kloucek
2021-10-18 07:54:11 +02:00
committed by GitHub
8 changed files with 93 additions and 15 deletions

View File

@@ -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

View File

@@ -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

2
go.mod
View File

@@ -19,7 +19,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

2
go.sum
View File

@@ -292,6 +292,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=

View File

@@ -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

View File

@@ -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
}

View File

@@ -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),
),
)
}

View File

@@ -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)
})
}
}