Skip to content

Commit

Permalink
add public share auth middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Oct 1, 2021
1 parent 990abd6 commit 50cdb03
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 12 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/public-share-auth-middleware.md
Original file line number Diff line number Diff line change
@@ -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
28 changes: 16 additions & 12 deletions proxy/pkg/command/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -158,25 +158,25 @@ 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(
acc.NewAccountsService("com.owncloud.api.accounts", grpc.DefaultClient),
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")
}
Expand All @@ -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
Expand All @@ -216,20 +216,24 @@ 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.PublicShareAuth(
middleware.Logger(logger),
middleware.RevaGatewayClient(revaClient),
),
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),
Expand All @@ -238,14 +242,14 @@ 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),
),
Expand Down
58 changes: 58 additions & 0 deletions proxy/pkg/middleware/public_share_auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package middleware

import (
"net/http"
"strings"

gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
)

const (
headerRevaAccessToken = "x-access-token"
headerShareToken = "public-token"
appProviderPathPrefix = "/app/open"
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 == "" || !strings.HasPrefix(appProviderPathPrefix, r.URL.Path) {
// 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)
})
}
}

0 comments on commit 50cdb03

Please sign in to comment.