github.com/cs3org/reva/v2@v2.27.7/pkg/auth/manager/publicshares/publicshares.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 publicshares 20 21 import ( 22 "context" 23 "strings" 24 "time" 25 26 authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" 27 user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 28 rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 29 link "github.com/cs3org/go-cs3apis/cs3/sharing/link/v1beta1" 30 types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" 31 "github.com/cs3org/reva/v2/pkg/auth" 32 "github.com/cs3org/reva/v2/pkg/auth/manager/registry" 33 "github.com/cs3org/reva/v2/pkg/auth/scope" 34 "github.com/cs3org/reva/v2/pkg/errtypes" 35 "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" 36 "github.com/cs3org/reva/v2/pkg/utils" 37 "github.com/mitchellh/mapstructure" 38 "github.com/pkg/errors" 39 ) 40 41 func init() { 42 registry.Register("publicshares", New) 43 } 44 45 type manager struct { 46 c *config 47 } 48 49 type config struct { 50 GatewayAddr string `mapstructure:"gateway_addr"` 51 } 52 53 func parseConfig(m map[string]interface{}) (*config, error) { 54 c := &config{} 55 if err := mapstructure.Decode(m, c); err != nil { 56 err = errors.Wrap(err, "error decoding conf") 57 return nil, err 58 } 59 return c, nil 60 } 61 62 // New returns a new auth Manager. 63 func New(m map[string]interface{}) (auth.Manager, error) { 64 mgr := &manager{} 65 err := mgr.Configure(m) 66 if err != nil { 67 return nil, err 68 } 69 return mgr, nil 70 } 71 72 func (m *manager) Configure(ml map[string]interface{}) error { 73 conf, err := parseConfig(ml) 74 if err != nil { 75 return err 76 } 77 m.c = conf 78 return nil 79 } 80 81 func (m *manager) Authenticate(ctx context.Context, token, secret string) (*user.User, map[string]*authpb.Scope, error) { 82 gwConn, err := pool.GetGatewayServiceClient(m.c.GatewayAddr) 83 if err != nil { 84 return nil, nil, err 85 } 86 87 var auth *link.PublicShareAuthentication 88 if strings.HasPrefix(secret, "password|") { 89 secret = strings.TrimPrefix(secret, "password|") 90 auth = &link.PublicShareAuthentication{ 91 Spec: &link.PublicShareAuthentication_Password{ 92 Password: secret, 93 }, 94 } 95 } else if strings.HasPrefix(secret, "signature|") { 96 secret = strings.TrimPrefix(secret, "signature|") 97 parts := strings.Split(secret, "|") 98 sig, expiration := parts[0], parts[1] 99 exp, _ := time.Parse(time.RFC3339, expiration) 100 101 auth = &link.PublicShareAuthentication{ 102 Spec: &link.PublicShareAuthentication_Signature{ 103 Signature: &link.ShareSignature{ 104 Signature: sig, 105 SignatureExpiration: &types.Timestamp{ 106 Seconds: uint64(exp.UnixNano() / 1000000000), 107 Nanos: uint32(exp.UnixNano() % 1000000000), 108 }, 109 }, 110 }, 111 } 112 } 113 114 publicShareResponse, err := gwConn.GetPublicShareByToken(ctx, &link.GetPublicShareByTokenRequest{ 115 Token: token, 116 Authentication: auth, 117 Sign: true, 118 }) 119 switch { 120 case err != nil: 121 return nil, nil, err 122 case publicShareResponse.Status.Code == rpcv1beta1.Code_CODE_NOT_FOUND: 123 return nil, nil, errtypes.NotFound(publicShareResponse.Status.Message) 124 case publicShareResponse.Status.Code == rpcv1beta1.Code_CODE_PERMISSION_DENIED: 125 return nil, nil, errtypes.InvalidCredentials(publicShareResponse.Status.Message) 126 case publicShareResponse.Status.Code != rpcv1beta1.Code_CODE_OK: 127 return nil, nil, errtypes.InternalError(publicShareResponse.Status.Message) 128 } 129 130 var owner *user.User 131 // FIXME use new user type SPACE_OWNER 132 if publicShareResponse.GetShare().GetOwner().GetType() == 8 { 133 owner = &user.User{Id: publicShareResponse.GetShare().GetOwner(), DisplayName: "Public", Username: "public"} 134 } else { 135 getUserResponse, err := gwConn.GetUser(ctx, &user.GetUserRequest{ 136 UserId: publicShareResponse.GetShare().GetCreator(), 137 }) 138 switch { 139 case err != nil: 140 return nil, nil, err 141 case getUserResponse.GetStatus().GetCode() == rpcv1beta1.Code_CODE_NOT_FOUND: 142 return nil, nil, errtypes.NotFound(getUserResponse.GetStatus().GetMessage()) 143 case getUserResponse.GetStatus().GetCode() == rpcv1beta1.Code_CODE_PERMISSION_DENIED: 144 return nil, nil, errtypes.InvalidCredentials(getUserResponse.GetStatus().GetMessage()) 145 case getUserResponse.GetStatus().GetCode() != rpcv1beta1.Code_CODE_OK: 146 return nil, nil, errtypes.InternalError(getUserResponse.GetStatus().GetMessage()) 147 } 148 owner = getUserResponse.GetUser() 149 } 150 151 share := publicShareResponse.GetShare() 152 role := authpb.Role_ROLE_VIEWER 153 roleStr := "viewer" 154 if share.Permissions.Permissions.InitiateFileUpload && !share.Permissions.Permissions.InitiateFileDownload { 155 role = authpb.Role_ROLE_UPLOADER 156 roleStr = "uploader" 157 } else if share.Permissions.Permissions.InitiateFileUpload { 158 role = authpb.Role_ROLE_EDITOR 159 roleStr = "editor" 160 } 161 162 scope, err := scope.AddPublicShareScope(share, role, nil) 163 if err != nil { 164 return nil, nil, err 165 } 166 167 owner.Opaque = &types.Opaque{ 168 Map: map[string]*types.OpaqueEntry{ 169 "public-share-role": { 170 Decoder: "plain", 171 Value: []byte(roleStr), 172 }, 173 }, 174 } 175 176 u := &user.User{Id: &user.UserId{OpaqueId: token, Idp: "public", Type: user.UserType_USER_TYPE_GUEST}, DisplayName: "Public", Username: "public"} 177 owner.Opaque = utils.AppendJSONToOpaque(owner.Opaque, "impersonating-user", u) 178 179 return owner, scope, nil 180 } 181 182 // ErrPasswordNotProvided is returned when the public share is password protected, but there was no password on the request 183 var ErrPasswordNotProvided = errors.New("public share is password protected, but password was not provided")