Skip to content

Commit

Permalink
Expand scopes when minting tokens and add checks for shares and lw sc…
Browse files Browse the repository at this point in the history
…opes
  • Loading branch information
ishank011 committed Jun 4, 2021
1 parent 2cc1fec commit edf08c1
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 130 deletions.
91 changes: 60 additions & 31 deletions internal/grpc/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
Expand Down Expand Up @@ -243,46 +244,74 @@ func dismantleToken(ctx context.Context, tkn string, req interface{}, mgr token.
// Currently, we only check for public shares, but this will be extended
// for OCM shares, guest accounts, etc.
log.Info().Msgf("resolving path reference to ID to check token scope %+v", ref.GetPath())
var share link.PublicShare
var publicShareScope []byte
for k := range tokenScope {
if strings.HasPrefix(k, "publicshare") {
publicShareScope = tokenScope[k].Resource.Value
break
switch {
case strings.HasPrefix(k, "publicshare"):
var share link.PublicShare
err = utils.UnmarshalJSONToProtoV1(tokenScope[k].Resource.Value, &share)
if err != nil {
continue
}
if ok, err := checkResourcePath(ctx, ref, share.ResourceId, gatewayAddr); err == nil && ok {
return u, nil
}

case strings.HasPrefix(k, "share"):
var share collaboration.Share
err = utils.UnmarshalJSONToProtoV1(tokenScope[k].Resource.Value, &share)
if err != nil {
continue
}
if ok, err := checkResourcePath(ctx, ref, share.ResourceId, gatewayAddr); err == nil && ok {
return u, nil
}
case strings.HasPrefix(k, "lightweight"):
client, err := pool.GetGatewayServiceClient(gatewayAddr)
if err != nil {
continue
}
shares, err := client.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{})
if err != nil {
continue
}
for _, share := range shares.Shares {
if ok, err := checkResourcePath(ctx, ref, share.Share.ResourceId, gatewayAddr); err == nil && ok {
return u, nil
}
}
}
}
err = utils.UnmarshalJSONToProtoV1(publicShareScope, &share)
if err != nil {
return nil, err
}
}
}

client, err := pool.GetGatewayServiceClient(gatewayAddr)
if err != nil {
return nil, err
}
return nil, err
}

// Since the public share is obtained from the scope, the current token
// has access to it.
statReq := &provider.StatRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Id{Id: share.ResourceId},
},
}
func checkResourcePath(ctx context.Context, ref *provider.Reference, r *provider.ResourceId, gatewayAddr string) (bool, error) {
client, err := pool.GetGatewayServiceClient(gatewayAddr)
if err != nil {
return false, err
}

statResponse, err := client.Stat(ctx, statReq)
if err != nil || statResponse.Status.Code != rpc.Code_CODE_OK {
return nil, err
}
// Since the public share is obtained from the scope, the current token
// has access to it.
statReq := &provider.StatRequest{
Ref: &provider.Reference{
Spec: &provider.Reference_Id{Id: r},
},
}

if strings.HasPrefix(ref.GetPath(), statResponse.Info.Path) {
// The path corresponds to the resource to which the token has access.
// We allow access to it.
return u, nil
}
}
statResponse, err := client.Stat(ctx, statReq)
if err != nil || statResponse.Status.Code != rpc.Code_CODE_OK {
return false, err
}

return nil, err
if strings.HasPrefix(ref.GetPath(), statResponse.Info.Path) {
// The path corresponds to the resource to which the token has access.
// We allow access to it.
return true, nil
}
return false, nil
}

func extractRef(req interface{}) (*provider.Reference, bool) {
Expand Down
75 changes: 74 additions & 1 deletion internal/grpc/services/gateway/authprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,24 @@ package gateway
import (
"context"
"fmt"
"strings"

authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/auth/scope"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
tokenpkg "github.com/cs3org/reva/pkg/token"
userpkg "github.com/cs3org/reva/pkg/user"
"github.com/cs3org/reva/pkg/utils"
"github.com/pkg/errors"
"google.golang.org/grpc/metadata"
)
Expand Down Expand Up @@ -93,7 +98,15 @@ func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest
}, nil
}

token, err := s.tokenmgr.MintToken(ctx, res.User, res.TokenScope)
scope, err := s.expandScopes(ctx, res.TokenScope)
if err != nil {
err = errors.Wrap(err, "authsvc: error expanding token scope")
return &gateway.AuthenticateResponse{
Status: status.NewUnauthenticated(ctx, err, "error expanding access token scope"),
}, nil
}

token, err := s.tokenmgr.MintToken(ctx, res.User, scope)
if err != nil {
err = errors.Wrap(err, "authsvc: error in MintToken")
res := &gateway.AuthenticateResponse{
Expand Down Expand Up @@ -191,3 +204,63 @@ func (s *svc) findAuthProvider(ctx context.Context, authType string) (provider.P

return nil, errtypes.InternalError("gateway: error finding an auth provider for type: " + authType)
}

func (s *svc) expandScopes(ctx context.Context, scopeMap map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
newMap := make(map[string]*authpb.Scope)
for k, v := range scopeMap {
newMap[k] = v
switch {
case strings.HasPrefix(k, "publicshare"):
var share link.PublicShare
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, &share)
if err != nil {
return nil, err
}
newMap, err = s.statAndAddResource(ctx, share.ResourceId, v.Role, newMap)
if err != nil {
return nil, err
}

case strings.HasPrefix(k, "share"):
var share collaboration.Share
err := utils.UnmarshalJSONToProtoV1(v.Resource.Value, &share)
if err != nil {
return nil, err
}
newMap, err = s.statAndAddResource(ctx, share.ResourceId, v.Role, newMap)
if err != nil {
return nil, err
}

case strings.HasPrefix(k, "lightweight"):
shares, err := s.ListReceivedShares(ctx, &collaboration.ListReceivedSharesRequest{})
if err != nil {
return nil, err
}
for _, share := range shares.Shares {
newMap, err = scope.AddShareScope(share.Share, v.Role, newMap)
if err != nil {
return nil, err
}
newMap, err = s.statAndAddResource(ctx, share.Share.ResourceId, v.Role, newMap)
if err != nil {
return nil, err
}
}
}
}
return newMap, nil
}

func (s *svc) statAndAddResource(ctx context.Context, r *storageprovider.ResourceId, role authpb.Role, scopeMap map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
statReq := &storageprovider.StatRequest{
Ref: &storageprovider.Reference{
Spec: &storageprovider.Reference_Id{Id: r},
},
}
statResponse, err := s.Stat(ctx, statReq)
if err != nil || statResponse.Status.Code != rpc.Code_CODE_OK {
return nil, err
}
return scope.AddResourceInfoScope(statResponse.Info, role, scopeMap)
}
134 changes: 37 additions & 97 deletions pkg/auth/scope/lightweight.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,100 +18,40 @@

package scope

// import (
// "fmt"
// "strings"
//
// authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
// provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
// registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
// types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
// "github.com/cs3org/reva/pkg/errtypes"
// "github.com/cs3org/reva/pkg/utils"
// )
//
// func lightweightAccountScope(scope *authpb.Scope, resource interface{}) (bool, error) {
// var r provider.ResourceInfo
// err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &r)
// if err != nil {
// return false, err
// }
//
// switch v := resource.(type) {
// // Viewer role
// case *registry.GetStorageProvidersRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
// case *provider.StatRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
// case *provider.ListContainerRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
// case *provider.InitiateFileDownloadRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
//
// // Editor role
// // TODO(ishank011): Add role checks,
// // need to return appropriate status codes in the ocs/ocdav layers.
// case *provider.CreateContainerRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
// case *provider.DeleteRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
// case *provider.MoveRequest:
// return checkResourceInfo(&r, v.GetSource()) && checkResourceInfo(&r, v.GetDestination()), nil
// case *provider.InitiateFileUploadRequest:
// return checkResourceInfo(&r, v.GetRef()), nil
//
// case string:
// return checkPath(v), nil
// }
//
// return false, errtypes.InternalError(fmt.Sprintf("resource type assertion failed: %+v", resource))
// }
//
// func checkResourceInfo(inf *provider.ResourceInfo, ref *provider.Reference) bool {
// // ref: <id:<storage_id:$storageID opaque_id:$opaqueID > >
// if ref.GetId() != nil {
// return inf.Id.StorageId == ref.GetId().StorageId && inf.Id.OpaqueId == ref.GetId().OpaqueId
// }
// // ref: <path:$path >
// if strings.HasPrefix(ref.GetPath(), inf.Path) {
// return true
// }
// return false
// }
//
// func checkPath(path string) bool {
// paths := []string{
// "/dataprovider",
// "/data",
// }
// for _, p := range paths {
// if strings.HasPrefix(path, p) {
// return true
// }
// }
// return false
// }
//
// // AddLightweightAccountScope adds the scope to allow access to lightweight user.
// func AddLightweightAccountScope(scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
// ref := &provider.Reference{
// Spec: &provider.Reference_Path{
// Path: "/",
// },
// }
// val, err := utils.MarshalProtoV1ToJSON(ref)
// if err != nil {
// return nil, err
// }
// if scopes == nil {
// scopes = make(map[string]*authpb.Scope)
// }
// scopes["resourceinfo:"+r.Id.String()] = &authpb.Scope{
// Resource: &types.OpaqueEntry{
// Decoder: "json",
// Value: val,
// },
// Role: role,
// }
// return scopes, nil
// }
import (
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/pkg/utils"
)

func lightweightAccountScope(scope *authpb.Scope, resource interface{}) (bool, error) {
// Lightweight accounts have access to resources shared with them.
// These cannot be resolved from here, but need to be added to the scope from
// where the call to mint tokens is made.
return false, nil
}

// AddLightweightAccountScope adds the scope to allow access to lightweight user.
func AddLightweightAccountScope(role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
ref := &provider.Reference{
Spec: &provider.Reference_Path{
Path: "/",
},
}
val, err := utils.MarshalProtoV1ToJSON(ref)
if err != nil {
return nil, err
}
if scopes == nil {
scopes = make(map[string]*authpb.Scope)
}
scopes["lightweight"] = &authpb.Scope{
Resource: &types.OpaqueEntry{
Decoder: "json",
Value: val,
},
Role: role,
}
return scopes, nil
}
1 change: 1 addition & 0 deletions pkg/auth/scope/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var supportedScopes = map[string]Verifier{
"publicshare": publicshareScope,
"resourceinfo": resourceinfoScope,
"share": shareScope,
"lightweight": lightweightAccountScope,
}

// VerifyScope is the function to be called when dismantling tokens to check if
Expand Down
2 changes: 1 addition & 1 deletion pkg/auth/scope/share.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func checkSharePath(path string) bool {
return false
}

// AddPShareScope adds the scope to allow access to a user/group share and
// AddShareScope adds the scope to allow access to a user/group share and
// the shared resource.
func AddShareScope(share *collaboration.Share, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
val, err := utils.MarshalProtoV1ToJSON(share)
Expand Down

0 comments on commit edf08c1

Please sign in to comment.