github.com/cs3org/reva/v2@v2.27.7/internal/http/services/ocmd/invites.go (about) 1 // Copyright 2018-2023 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 ocmd 20 21 import ( 22 "encoding/json" 23 "errors" 24 "fmt" 25 "mime" 26 "net/http" 27 28 gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" 29 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 30 invitepb "github.com/cs3org/go-cs3apis/cs3/ocm/invite/v1beta1" 31 ocmprovider "github.com/cs3org/go-cs3apis/cs3/ocm/provider/v1beta1" 32 rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1" 33 "github.com/cs3org/reva/v2/internal/http/services/reqres" 34 "github.com/cs3org/reva/v2/pkg/appctx" 35 ocmuser "github.com/cs3org/reva/v2/pkg/ocm/user" 36 "github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool" 37 "github.com/cs3org/reva/v2/pkg/utils" 38 ) 39 40 type invitesHandler struct { 41 gatewaySelector *pool.Selector[gateway.GatewayAPIClient] 42 } 43 44 func (h *invitesHandler) init(c *config) error { 45 var err error 46 47 gatewaySelector, err := pool.GatewaySelector(c.GatewaySvc) 48 if err != nil { 49 return err 50 } 51 h.gatewaySelector = gatewaySelector 52 return nil 53 } 54 55 type acceptInviteRequest struct { 56 Token string `json:"token"` 57 UserID string `json:"userID"` 58 RecipientProvider string `json:"recipientProvider"` 59 Name string `json:"name"` 60 Email string `json:"email"` 61 } 62 63 // AcceptInvite informs avout an accepted invitation so that the users 64 // can initiate the OCM share creation. 65 func (h *invitesHandler) AcceptInvite(w http.ResponseWriter, r *http.Request) { 66 ctx := r.Context() 67 log := appctx.GetLogger(ctx) 68 69 req, err := getAcceptInviteRequest(r) 70 if err != nil { 71 reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "missing parameters in request", err) 72 return 73 } 74 75 if req.Token == "" || req.UserID == "" || req.RecipientProvider == "" { 76 reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token, userID and recipiendProvider must not be null", nil) 77 return 78 } 79 80 clientIP, err := utils.GetClientIP(r) 81 if err != nil { 82 reqres.WriteError(w, r, reqres.APIErrorServerError, fmt.Sprintf("error retrieving client IP from request: %s", r.RemoteAddr), err) 83 return 84 } 85 86 providerInfo := ocmprovider.ProviderInfo{ 87 Domain: req.RecipientProvider, 88 Services: []*ocmprovider.Service{ 89 { 90 Host: clientIP, 91 }, 92 }, 93 } 94 gatewayClient, err := h.gatewaySelector.Next() 95 if err != nil { 96 reqres.WriteError(w, r, reqres.APIErrorServerError, "error getting gateway client", err) 97 return 98 } 99 providerAllowedResp, err := gatewayClient.IsProviderAllowed(ctx, &ocmprovider.IsProviderAllowedRequest{ 100 Provider: &providerInfo, 101 }) 102 if err != nil { 103 reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc is provider allowed request", err) 104 return 105 } 106 if providerAllowedResp.Status.Code != rpc.Code_CODE_OK { 107 reqres.WriteError(w, r, reqres.APIErrorUntrustedService, "provider not trusted", errors.New(providerAllowedResp.Status.Message)) 108 return 109 } 110 111 userObj := &userpb.User{ 112 Id: &userpb.UserId{ 113 OpaqueId: req.UserID, 114 Idp: req.RecipientProvider, 115 Type: userpb.UserType_USER_TYPE_FEDERATED, 116 }, 117 Mail: req.Email, 118 DisplayName: req.Name, 119 } 120 acceptInviteRequest := &invitepb.AcceptInviteRequest{ 121 InviteToken: &invitepb.InviteToken{ 122 Token: req.Token, 123 }, 124 RemoteUser: userObj, 125 } 126 acceptInviteResponse, err := gatewayClient.AcceptInvite(ctx, acceptInviteRequest) 127 if err != nil { 128 reqres.WriteError(w, r, reqres.APIErrorServerError, "error sending a grpc accept invite request", err) 129 return 130 } 131 if acceptInviteResponse.Status.Code != rpc.Code_CODE_OK { 132 switch acceptInviteResponse.Status.Code { 133 case rpc.Code_CODE_NOT_FOUND: 134 reqres.WriteError(w, r, reqres.APIErrorNotFound, "token not found", nil) 135 return 136 case rpc.Code_CODE_INVALID_ARGUMENT: 137 reqres.WriteError(w, r, reqres.APIErrorInvalidParameter, "token has expired", nil) 138 return 139 case rpc.Code_CODE_ALREADY_EXISTS: 140 reqres.WriteError(w, r, reqres.APIErrorAlreadyExist, "user already known", nil) 141 return 142 default: 143 reqres.WriteError(w, r, reqres.APIErrorServerError, "unexpected error: "+acceptInviteResponse.Status.Message, errors.New(acceptInviteResponse.Status.Message)) 144 return 145 } 146 } 147 148 if err := json.NewEncoder(w).Encode(&user{ 149 UserID: ocmuser.FederatedID(acceptInviteResponse.UserId, "").GetOpaqueId(), 150 Email: acceptInviteResponse.Email, 151 Name: acceptInviteResponse.DisplayName, 152 }); err != nil { 153 reqres.WriteError(w, r, reqres.APIErrorServerError, "error encoding response", err) 154 return 155 } 156 w.WriteHeader(http.StatusOK) 157 w.Header().Set("Content-Type", "application/json") 158 159 log.Info().Str("user", fmt.Sprintf("%s@%s", userObj.Id.OpaqueId, userObj.Id.Idp)).Str("token", req.Token).Msg("added to accepted users") 160 } 161 162 type user struct { 163 UserID string `json:"userID"` 164 Email string `json:"email"` 165 Name string `json:"name"` 166 } 167 168 func getAcceptInviteRequest(r *http.Request) (*acceptInviteRequest, error) { 169 var req acceptInviteRequest 170 contentType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) 171 if err == nil && contentType == "application/json" { 172 if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 173 return nil, err 174 } 175 } else { 176 req.Token, req.UserID, req.RecipientProvider = r.FormValue("token"), r.FormValue("userID"), r.FormValue("recipientProvider") 177 req.Name, req.Email = r.FormValue("name"), r.FormValue("email") 178 } 179 return &req, nil 180 }