github.com/cs3org/reva/v2@v2.27.7/pkg/auth/scope/publicshare.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package scope
    20  
    21  import (
    22  	"context"
    23  	"strings"
    24  
    25  	appprovider "github.com/cs3org/go-cs3apis/cs3/app/provider/v1beta1"
    26  	appregistry "github.com/cs3org/go-cs3apis/cs3/app/registry/v1beta1"
    27  	authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
    28  	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
    29  	userv1beta1 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    30  	permissionsv1beta1 "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
    31  	collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
    32  	link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1"
    33  	provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    34  	registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
    35  	types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
    36  	"github.com/cs3org/reva/v2/pkg/errtypes"
    37  	"github.com/cs3org/reva/v2/pkg/utils"
    38  	"github.com/rs/zerolog"
    39  )
    40  
    41  // PublicStorageProviderID is the space id used for the public links storage space
    42  const PublicStorageProviderID = "7993447f-687f-490d-875c-ac95e89a62a4"
    43  
    44  func publicshareScope(ctx context.Context, scope *authpb.Scope, resource interface{}, logger *zerolog.Logger) (bool, error) {
    45  	var share link.PublicShare
    46  	err := utils.UnmarshalJSONToProtoV1(scope.Resource.Value, &share)
    47  	if err != nil {
    48  		return false, err
    49  	}
    50  
    51  	switch v := resource.(type) {
    52  	// Viewer role
    53  	case *registry.GetStorageProvidersRequest:
    54  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    55  	case *registry.ListStorageProvidersRequest:
    56  		ref := &provider.Reference{}
    57  		if v.Opaque != nil && v.Opaque.Map != nil {
    58  			if e, ok := v.Opaque.Map["storage_id"]; ok {
    59  				if ref.ResourceId == nil {
    60  					ref.ResourceId = &provider.ResourceId{}
    61  				}
    62  				ref.ResourceId.StorageId = string(e.Value)
    63  			}
    64  			if e, ok := v.Opaque.Map["space_id"]; ok {
    65  				if ref.ResourceId == nil {
    66  					ref.ResourceId = &provider.ResourceId{}
    67  				}
    68  				ref.ResourceId.SpaceId = string(e.Value)
    69  			}
    70  			if e, ok := v.Opaque.Map["opaque_id"]; ok {
    71  				if ref.ResourceId == nil {
    72  					ref.ResourceId = &provider.ResourceId{}
    73  				}
    74  				ref.ResourceId.OpaqueId = string(e.Value)
    75  			}
    76  			if e, ok := v.Opaque.Map["path"]; ok {
    77  				ref.Path = string(e.Value)
    78  			}
    79  		}
    80  		return checkStorageRef(ctx, &share, ref), nil
    81  	case *provider.CreateHomeRequest:
    82  		return false, nil
    83  	case *provider.GetPathRequest:
    84  		return checkStorageRef(ctx, &share, &provider.Reference{ResourceId: v.GetResourceId()}), nil
    85  	case *provider.StatRequest:
    86  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    87  	case *provider.GetLockRequest:
    88  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    89  	case *provider.UnlockRequest:
    90  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    91  	case *provider.RefreshLockRequest:
    92  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    93  	case *provider.SetLockRequest:
    94  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    95  	case *provider.ListContainerRequest:
    96  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    97  	case *provider.InitiateFileDownloadRequest:
    98  		return checkStorageRef(ctx, &share, v.GetRef()), nil
    99  	case *appprovider.OpenInAppRequest:
   100  		return checkStorageRef(ctx, &share, &provider.Reference{ResourceId: v.ResourceInfo.Id}), nil
   101  	case *gateway.OpenInAppRequest:
   102  		return checkStorageRef(ctx, &share, v.GetRef()), nil
   103  	case *permissionsv1beta1.CheckPermissionRequest:
   104  		return true, nil
   105  
   106  	// Editor role
   107  	// need to return appropriate status codes in the ocs/ocdav layers.
   108  	case *provider.CreateContainerRequest:
   109  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetRef()), nil
   110  	case *provider.TouchFileRequest:
   111  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetRef()), nil
   112  	case *provider.DeleteRequest:
   113  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetRef()), nil
   114  	case *provider.MoveRequest:
   115  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetSource()) && checkStorageRef(ctx, &share, v.GetDestination()), nil
   116  	case *provider.InitiateFileUploadRequest:
   117  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetRef()), nil
   118  	case *provider.SetArbitraryMetadataRequest:
   119  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetRef()), nil
   120  	case *provider.UnsetArbitraryMetadataRequest:
   121  		return hasRoleEditor(scope) && checkStorageRef(ctx, &share, v.GetRef()), nil
   122  
   123  	// App provider requests
   124  	case *appregistry.GetDefaultAppProviderForMimeTypeRequest:
   125  		return true, nil
   126  
   127  	case *appregistry.GetAppProvidersRequest:
   128  		return true, nil
   129  	case *userv1beta1.GetUserByClaimRequest:
   130  		return true, nil
   131  	case *userv1beta1.GetUserRequest:
   132  		return true, nil
   133  
   134  	case *provider.ListStorageSpacesRequest:
   135  		return true, nil
   136  	case *link.GetPublicShareRequest:
   137  		return checkPublicShareRef(&share, v.GetRef()), nil
   138  	case *link.ListPublicSharesRequest:
   139  		// public links must not leak info about other links
   140  		return false, nil
   141  
   142  	case *collaboration.ListReceivedSharesRequest:
   143  		// public links must not leak info about collaborative shares
   144  		return false, nil
   145  	case string:
   146  		return checkResourcePath(v), nil
   147  	}
   148  
   149  	msg := "public resource type assertion failed"
   150  	logger.Debug().Str("scope", "publicshareScope").Interface("resource", resource).Msg(msg)
   151  	return false, errtypes.InternalError(msg)
   152  }
   153  
   154  func checkStorageRef(ctx context.Context, s *link.PublicShare, r *provider.Reference) bool {
   155  	// r: <resource_id:<storage_id:$storageID space_id:$spaceID opaque_id:$opaqueID> path:$path > >
   156  	if utils.ResourceIDEqual(s.ResourceId, r.GetResourceId()) {
   157  		return true
   158  	}
   159  
   160  	// r: <path:"/public/$token" >
   161  	if strings.HasPrefix(r.GetPath(), "/public/"+s.Token) || strings.HasPrefix(r.GetPath(), "./"+s.Token) {
   162  		return true
   163  	}
   164  
   165  	// r: <resource_id:<storage_id: space_id: opaque_id:$token> path:$path>
   166  	if id := r.GetResourceId(); id.GetStorageId() == PublicStorageProviderID {
   167  		// access to /public
   168  		if id.GetOpaqueId() == PublicStorageProviderID {
   169  			return true
   170  		}
   171  		// access relative to /public/$token
   172  		if id.GetOpaqueId() == s.Token {
   173  			return true
   174  		}
   175  	}
   176  	return false
   177  }
   178  
   179  func checkPublicShareRef(s *link.PublicShare, ref *link.PublicShareReference) bool {
   180  	// ref: <token:$token >
   181  	return ref.GetToken() == s.Token
   182  }
   183  
   184  // AddPublicShareScope adds the scope to allow access to a public share and
   185  // the shared resource.
   186  func AddPublicShareScope(share *link.PublicShare, role authpb.Role, scopes map[string]*authpb.Scope) (map[string]*authpb.Scope, error) {
   187  	// Create a new "scope share" to only expose the required fields `ResourceId` and `Token` to the scope.
   188  	scopeShare := &link.PublicShare{ResourceId: share.ResourceId, Token: share.Token}
   189  	val, err := utils.MarshalProtoV1ToJSON(scopeShare)
   190  	if err != nil {
   191  		return nil, err
   192  	}
   193  	if scopes == nil {
   194  		scopes = make(map[string]*authpb.Scope)
   195  	}
   196  	scopes["publicshare:"+share.Id.OpaqueId] = &authpb.Scope{
   197  		Resource: &types.OpaqueEntry{
   198  			Decoder: "json",
   199  			Value:   val,
   200  		},
   201  		Role: role,
   202  	}
   203  	return scopes, nil
   204  }