Skip to content

Commit

Permalink
Merge pull request cs3org#4653 from 2403905/issue-8858
Browse files Browse the repository at this point in the history
Replacement for TokenInfo endpoint
  • Loading branch information
2403905 committed May 14, 2024
2 parents 297b9ba + a09426b commit 7099ed4
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 0 deletions.
12 changes: 12 additions & 0 deletions changelog/unreleased/tokenInfo-endpoint-replacement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Enhancement: Allow to resolve public shares without the ocs tokeninfo endpoint

Instead of querying the /v1.php/apps/files_sharing/api/v1/tokeninfo/ endpoint, a client can now resolve public and internal links by sending a PROPFIND request to /dav/public-files/{sharetoken}

* authenticated clients accessing an internal link are redirected to the "real" resource (`/dav/spaces/{target-resource-id}
* authenticated clients are able to resolve public links like before. For password protected links they need to supply the password even if they have access to the underlying resource by other means.
* unauthenticated clients accessing an internal link get a 401 returned with WWW-Authenticate set to Bearer (so that the client knows that it need to get a token via the IDP login page.
* unauthenticated clients accessing a password protected link get a 401 returned with an error message to indicate the requirement for needing the link's password.

https://github.com/cs3org/reva/pull/4653
https://github.com/owncloud/ocis/issues/8858
62 changes: 62 additions & 0 deletions internal/http/services/owncloud/ocdav/dav.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package ocdav

import (
"context"
"fmt"
"net/http"
"path"
"path/filepath"
Expand All @@ -28,6 +29,7 @@ import (
gatewayv1beta1 "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/config"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav/errors"
Expand All @@ -36,12 +38,18 @@ import (
ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/v2/pkg/rhttp/router"
"github.com/cs3org/reva/v2/pkg/storage/utils/grants"
"github.com/cs3org/reva/v2/pkg/storagespace"
"github.com/cs3org/reva/v2/pkg/utils"
"go.opentelemetry.io/otel/trace"
"google.golang.org/grpc/metadata"
)

const (
_trashbinPath = "trash-bin"

// WwwAuthenticate captures the Www-Authenticate header string.
WwwAuthenticate = "Www-Authenticate"
)

// DavHandler routes to the different sub handlers
Expand Down Expand Up @@ -248,6 +256,39 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
var hasValidBasicAuthHeader bool
var pass string
var err error
// If user is authenticated
_, userExists := ctxpkg.ContextGetUser(ctx)
if userExists {
client, err := s.gatewaySelector.Next()
if err != nil {
log.Error().Err(err).Msg("error sending grpc stat request")
w.WriteHeader(http.StatusInternalServerError)
return
}
psRes, err := client.GetPublicShare(ctx, &link.GetPublicShareRequest{
Ref: &link.PublicShareReference{
Spec: &link.PublicShareReference_Token{
Token: token,
},
}})
if err != nil && !strings.Contains(err.Error(), "core access token not found") {
log.Error().Err(err).Msg("error sending grpc stat request")
w.WriteHeader(http.StatusInternalServerError)
return
}
// If the link is internal then 307 redirect
if psRes.Status.Code == rpc.Code_CODE_OK && grants.PermissionsEqual(psRes.Share.Permissions.GetPermissions(), &provider.ResourcePermissions{}) {
if psRes.GetShare().GetResourceId() != nil {
rUrl := path.Join("/dav/spaces", storagespace.FormatResourceID(*psRes.GetShare().GetResourceId()))
http.Redirect(w, r, rUrl, http.StatusTemporaryRedirect)
return
}
log.Debug().Str("token", token).Interface("status", res.Status).Msg("resource id not found")
w.WriteHeader(http.StatusNotFound)
return
}
}

if _, pass, hasValidBasicAuthHeader = r.BasicAuth(); hasValidBasicAuthHeader {
res, err = handleBasicAuth(r.Context(), s.gatewaySelector, token, pass)
} else {
Expand Down Expand Up @@ -286,6 +327,17 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
return
}

if userExists {
// Build new context without an authenticated user.
// the public link should be resolved by the 'publicshares' authenticated user
baseURI := ctx.Value(net.CtxKeyBaseURI).(string)
logger := appctx.GetLogger(ctx)
span := trace.SpanFromContext(ctx)
span.End()
ctx = trace.ContextWithSpan(context.Background(), span)
ctx = appctx.WithLogger(ctx, logger)
ctx = context.WithValue(ctx, net.CtxKeyBaseURI, baseURI)
}
ctx = ctxpkg.ContextSetToken(ctx, res.Token)
ctx = ctxpkg.ContextSetUser(ctx, res.User)
ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, res.Token)
Expand All @@ -301,6 +353,16 @@ func (h *DavHandler) Handler(s *svc) http.Handler {
return
case sRes.Status.Code == rpc.Code_CODE_PERMISSION_DENIED:
fallthrough
case sRes.Status.Code == rpc.Code_CODE_OK && grants.PermissionsEqual(sRes.GetInfo().GetPermissionSet(), &provider.ResourcePermissions{}):
// If the link is internal
if !userExists {
w.Header().Add(WwwAuthenticate, fmt.Sprintf("Bearer realm=\"%s\", charset=\"UTF-8\"", r.Host))
w.WriteHeader(http.StatusUnauthorized)
b, err := errors.Marshal(http.StatusUnauthorized, "No 'Authorization: Bearer' header found", "")
errors.HandleWebdavError(log, w, b, err)
return
}
fallthrough
case sRes.Status.Code == rpc.Code_CODE_NOT_FOUND:
log.Debug().Str("token", token).Interface("status", res.Status).Msg("resource not found")
w.WriteHeader(http.StatusNotFound) // log the difference
Expand Down
4 changes: 4 additions & 0 deletions internal/http/services/owncloud/ocdav/ocdav_blackbox_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
cs3user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
cs3storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
cs3types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/v2/internal/http/services/owncloud/ocdav"
Expand Down Expand Up @@ -180,6 +181,9 @@ var _ = Describe("ocdav", func() {
},
}

client.On("GetPublicShare", mock.Anything, mock.Anything).Return(&link.GetPublicShareResponse{
Status: status.NewNotFound(ctx, "not found")},
nil)
client.On("GetUser", mock.Anything, mock.Anything).Return(&cs3user.GetUserResponse{
Status: status.NewNotFound(ctx, "not found"),
}, nil)
Expand Down

0 comments on commit 7099ed4

Please sign in to comment.