github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/identity.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package lib 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net/http" 23 "strconv" 24 25 "github.com/pkg/errors" 26 27 "github.com/cloudflare/cfssl/log" 28 "github.com/hyperledger/fabric-ca/api" 29 "github.com/hyperledger/fabric-ca/util" 30 "github.com/hyperledger/fabric/bccsp" 31 ) 32 33 func newIdentity(client *Client, name string, key bccsp.Key, cert []byte) *Identity { 34 id := new(Identity) 35 id.name = name 36 id.ecert = newSigner(key, cert, id) 37 id.client = client 38 if client != nil { 39 id.CSP = client.csp 40 } else { 41 id.CSP = util.GetDefaultBCCSP() 42 } 43 return id 44 } 45 46 // Identity is fabric-ca's implementation of an identity 47 type Identity struct { 48 name string 49 ecert *Signer 50 client *Client 51 CSP bccsp.BCCSP 52 } 53 54 // GetName returns the identity name 55 func (i *Identity) GetName() string { 56 return i.name 57 } 58 59 // GetClient returns the client associated with this identity 60 func (i *Identity) GetClient() *Client { 61 return i.client 62 } 63 64 // GetECert returns the enrollment certificate signer for this identity 65 func (i *Identity) GetECert() *Signer { 66 return i.ecert 67 } 68 69 // GetTCertBatch returns a batch of TCerts for this identity 70 func (i *Identity) GetTCertBatch(req *api.GetTCertBatchRequest) ([]*Signer, error) { 71 reqBody, err := util.Marshal(req, "GetTCertBatchRequest") 72 if err != nil { 73 return nil, err 74 } 75 err = i.Post("tcert", reqBody, nil, nil) 76 if err != nil { 77 return nil, err 78 } 79 // Ignore the contents of the response for now. They will be processed in the future when we need to 80 // support the Go SDK. We currently have Node and Java SDKs which process this and they are the 81 // priority. 82 return nil, nil 83 } 84 85 // Register registers a new identity 86 // @param req The registration request 87 func (i *Identity) Register(req *api.RegistrationRequest) (rr *api.RegistrationResponse, err error) { 88 log.Debugf("Register %+v", req) 89 if req.Name == "" { 90 return nil, errors.New("Register was called without a Name set") 91 } 92 93 reqBody, err := util.Marshal(req, "RegistrationRequest") 94 if err != nil { 95 return nil, err 96 } 97 98 // Send a post to the "register" endpoint with req as body 99 resp := &api.RegistrationResponse{} 100 err = i.Post("register", reqBody, resp, nil) 101 if err != nil { 102 return nil, err 103 } 104 105 log.Debug("The register request completed successfully") 106 return resp, nil 107 } 108 109 // RegisterAndEnroll registers and enrolls an identity and returns the identity 110 func (i *Identity) RegisterAndEnroll(req *api.RegistrationRequest) (*Identity, error) { 111 if i.client == nil { 112 return nil, errors.New("No client is associated with this identity") 113 } 114 rresp, err := i.Register(req) 115 if err != nil { 116 return nil, errors.WithMessage(err, fmt.Sprintf("Failed to register %s", req.Name)) 117 } 118 eresp, err := i.client.Enroll(&api.EnrollmentRequest{ 119 Name: req.Name, 120 Secret: rresp.Secret, 121 }) 122 if err != nil { 123 return nil, errors.WithMessage(err, fmt.Sprintf("Failed to enroll %s", req.Name)) 124 } 125 return eresp.Identity, nil 126 } 127 128 // Reenroll reenrolls an existing Identity and returns a new Identity 129 // @param req The reenrollment request 130 func (i *Identity) Reenroll(req *api.ReenrollmentRequest) (*EnrollmentResponse, error) { 131 log.Debugf("Reenrolling %s", util.StructToString(req)) 132 133 csrPEM, key, err := i.client.GenCSR(req.CSR, i.GetName()) 134 if err != nil { 135 return nil, err 136 } 137 138 reqNet := &api.ReenrollmentRequestNet{ 139 CAName: req.CAName, 140 AttrReqs: req.AttrReqs, 141 } 142 143 // Get the body of the request 144 if req.CSR != nil { 145 reqNet.SignRequest.Hosts = req.CSR.Hosts 146 } 147 reqNet.SignRequest.Request = string(csrPEM) 148 reqNet.SignRequest.Profile = req.Profile 149 reqNet.SignRequest.Label = req.Label 150 151 body, err := util.Marshal(reqNet, "SignRequest") 152 if err != nil { 153 return nil, err 154 } 155 var result enrollmentResponseNet 156 err = i.Post("reenroll", body, &result, nil) 157 if err != nil { 158 return nil, err 159 } 160 return i.client.newEnrollmentResponse(&result, i.GetName(), key) 161 } 162 163 // Revoke the identity associated with 'id' 164 func (i *Identity) Revoke(req *api.RevocationRequest) (*api.RevocationResponse, error) { 165 log.Debugf("Entering identity.Revoke %+v", req) 166 reqBody, err := util.Marshal(req, "RevocationRequest") 167 if err != nil { 168 return nil, err 169 } 170 var result revocationResponseNet 171 err = i.Post("revoke", reqBody, &result, nil) 172 if err != nil { 173 return nil, err 174 } 175 log.Debugf("Successfully revoked certificates: %+v", req) 176 crl, err := util.B64Decode(result.CRL) 177 if err != nil { 178 return nil, err 179 } 180 return &api.RevocationResponse{RevokedCerts: result.RevokedCerts, CRL: crl}, nil 181 } 182 183 // RevokeSelf revokes the current identity and all certificates 184 func (i *Identity) RevokeSelf() (*api.RevocationResponse, error) { 185 name := i.GetName() 186 log.Debugf("RevokeSelf %s", name) 187 req := &api.RevocationRequest{ 188 Name: name, 189 } 190 return i.Revoke(req) 191 } 192 193 // GenCRL generates CRL 194 func (i *Identity) GenCRL(req *api.GenCRLRequest) (*api.GenCRLResponse, error) { 195 log.Debugf("Entering identity.GenCRL %+v", req) 196 reqBody, err := util.Marshal(req, "GenCRLRequest") 197 if err != nil { 198 return nil, err 199 } 200 var result genCRLResponseNet 201 err = i.Post("gencrl", reqBody, &result, nil) 202 if err != nil { 203 return nil, err 204 } 205 log.Debugf("Successfully generated CRL: %+v", req) 206 crl, err := util.B64Decode(result.CRL) 207 if err != nil { 208 return nil, err 209 } 210 return &api.GenCRLResponse{CRL: crl}, nil 211 } 212 213 // GetIdentity returns information about the requested identity 214 func (i *Identity) GetIdentity(id, caname string) (*api.GetIDResponse, error) { 215 log.Debugf("Entering identity.GetIdentity %s", id) 216 result := &api.GetIDResponse{} 217 err := i.Get(fmt.Sprintf("identities/%s", id), caname, result) 218 if err != nil { 219 return nil, err 220 } 221 222 log.Debugf("Successfully retrieved identity: %+v", result) 223 return result, nil 224 } 225 226 // GetAllIdentities returns all identities that the caller is authorized to see 227 func (i *Identity) GetAllIdentities(caname string, cb func(*json.Decoder) error) error { 228 log.Debugf("Entering identity.GetAllIdentities") 229 err := i.GetStreamResponse("identities", caname, "result.identities", cb) 230 if err != nil { 231 return err 232 } 233 log.Debugf("Successfully retrieved identities") 234 return nil 235 } 236 237 // AddIdentity adds a new identity to the server 238 func (i *Identity) AddIdentity(req *api.AddIdentityRequest) (*api.IdentityResponse, error) { 239 log.Debugf("Entering identity.AddIdentity with request: %+v", req) 240 if req.ID == "" { 241 return nil, errors.New("Adding identity with no 'ID' set") 242 } 243 244 reqBody, err := util.Marshal(req, "addIdentity") 245 if err != nil { 246 return nil, err 247 } 248 249 // Send a post to the "identities" endpoint with req as body 250 result := &api.IdentityResponse{} 251 err = i.Post("identities", reqBody, result, nil) 252 if err != nil { 253 return nil, err 254 } 255 256 log.Debugf("Successfully added new identity '%s'", result.ID) 257 return result, nil 258 } 259 260 // ModifyIdentity modifies an existing identity on the server 261 func (i *Identity) ModifyIdentity(req *api.ModifyIdentityRequest) (*api.IdentityResponse, error) { 262 log.Debugf("Entering identity.ModifyIdentity with request: %+v", req) 263 if req.ID == "" { 264 return nil, errors.New("Name of identity to be modified not specified") 265 } 266 267 reqBody, err := util.Marshal(req, "modifyIdentity") 268 if err != nil { 269 return nil, err 270 } 271 272 // Send a put to the "identities" endpoint with req as body 273 result := &api.IdentityResponse{} 274 err = i.Put(fmt.Sprintf("identities/%s", req.ID), reqBody, nil, result) 275 if err != nil { 276 return nil, err 277 } 278 279 log.Debugf("Successfully modified identity '%s'", result.ID) 280 return result, nil 281 } 282 283 // RemoveIdentity removes a new identity from the server 284 func (i *Identity) RemoveIdentity(req *api.RemoveIdentityRequest) (*api.IdentityResponse, error) { 285 log.Debugf("Entering identity.RemoveIdentity with request: %+v", req) 286 id := req.ID 287 if id == "" { 288 return nil, errors.New("Name of the identity to removed is required") 289 } 290 291 // Send a delete to the "identities" endpoint id as a path parameter 292 result := &api.IdentityResponse{} 293 queryParam := make(map[string]string) 294 queryParam["force"] = strconv.FormatBool(req.Force) 295 queryParam["ca"] = req.CAName 296 err := i.Delete(fmt.Sprintf("identities/%s", id), result, queryParam) 297 if err != nil { 298 return nil, err 299 } 300 301 log.Debugf("Successfully removed identity: %s", id) 302 return result, nil 303 } 304 305 // GetAffiliation returns information about the requested affiliation 306 func (i *Identity) GetAffiliation(affiliation, caname string) (*api.AffiliationResponse, error) { 307 log.Debugf("Entering identity.GetAffiliation %+v", affiliation) 308 result := &api.AffiliationResponse{} 309 err := i.Get(fmt.Sprintf("affiliations/%s", affiliation), caname, result) 310 if err != nil { 311 return nil, err 312 } 313 log.Debugf("Successfully retrieved affiliation: %+v", result) 314 return result, nil 315 } 316 317 // GetAllAffiliations returns all affiliations that the caller is authorized to see 318 func (i *Identity) GetAllAffiliations(caname string) (*api.AffiliationResponse, error) { 319 log.Debugf("Entering identity.GetAllAffiliations") 320 result := &api.AffiliationResponse{} 321 err := i.Get("affiliations", caname, result) 322 if err != nil { 323 return nil, err 324 } 325 log.Debug("Successfully retrieved affiliations") 326 return result, nil 327 } 328 329 // AddAffiliation adds a new affiliation to the server 330 func (i *Identity) AddAffiliation(req *api.AddAffiliationRequest) (*api.AffiliationResponse, error) { 331 log.Debugf("Entering identity.AddAffiliation with request: %+v", req) 332 if req.Name == "" { 333 return nil, errors.New("Affiliation to add was not specified") 334 } 335 336 reqBody, err := util.Marshal(req, "addAffiliation") 337 if err != nil { 338 return nil, err 339 } 340 341 // Send a post to the "affiliations" endpoint with req as body 342 result := &api.AffiliationResponse{} 343 queryParam := make(map[string]string) 344 queryParam["force"] = strconv.FormatBool(req.Force) 345 err = i.Post("affiliations", reqBody, result, queryParam) 346 if err != nil { 347 return nil, err 348 } 349 350 log.Debugf("Successfully added new affiliation") 351 return result, nil 352 } 353 354 // ModifyAffiliation renames an existing affiliation on the server 355 func (i *Identity) ModifyAffiliation(req *api.ModifyAffiliationRequest) (*api.AffiliationResponse, error) { 356 log.Debugf("Entering identity.ModifyAffiliation with request: %+v", req) 357 modifyAff := req.Name 358 if modifyAff == "" { 359 return nil, errors.New("Affiliation to modify was not specified") 360 } 361 362 if req.NewName == "" { 363 return nil, errors.New("New affiliation not specified") 364 } 365 366 reqBody, err := util.Marshal(req, "modifyIdentity") 367 if err != nil { 368 return nil, err 369 } 370 371 // Send a put to the "affiliations" endpoint with req as body 372 result := &api.AffiliationResponse{} 373 queryParam := make(map[string]string) 374 queryParam["force"] = strconv.FormatBool(req.Force) 375 err = i.Put(fmt.Sprintf("affiliations/%s", modifyAff), reqBody, queryParam, result) 376 if err != nil { 377 return nil, err 378 } 379 380 log.Debugf("Successfully modified affiliation") 381 return result, nil 382 } 383 384 // RemoveAffiliation removes an existing affiliation from the server 385 func (i *Identity) RemoveAffiliation(req *api.RemoveAffiliationRequest) (*api.AffiliationResponse, error) { 386 log.Debugf("Entering identity.RemoveAffiliation with request: %+v", req) 387 removeAff := req.Name 388 if removeAff == "" { 389 return nil, errors.New("Affiliation to remove was not specified") 390 } 391 392 // Send a delete to the "affiliations" endpoint with the affiliation as a path parameter 393 result := &api.AffiliationResponse{} 394 queryParam := make(map[string]string) 395 queryParam["force"] = strconv.FormatBool(req.Force) 396 queryParam["ca"] = req.CAName 397 err := i.Delete(fmt.Sprintf("affiliations/%s", removeAff), result, queryParam) 398 if err != nil { 399 return nil, err 400 } 401 402 log.Debugf("Successfully removed affiliation") 403 return result, nil 404 } 405 406 // Store writes my identity info to disk 407 func (i *Identity) Store() error { 408 if i.client == nil { 409 return errors.New("An identity with no client may not be stored") 410 } 411 return i.client.StoreMyIdentity(i.ecert.cert) 412 } 413 414 // Get sends a get request to an endpoint 415 func (i *Identity) Get(endpoint, caname string, result interface{}) error { 416 req, err := i.client.newGet(endpoint) 417 if err != nil { 418 return err 419 } 420 if caname != "" { 421 addQueryParm(req, "ca", caname) 422 } 423 err = i.addTokenAuthHdr(req, nil) 424 if err != nil { 425 return err 426 } 427 return i.client.SendReq(req, result) 428 } 429 430 // GetStreamResponse sends a request to an endpoint and streams the response 431 func (i *Identity) GetStreamResponse(endpoint, caname, stream string, cb func(*json.Decoder) error) error { 432 req, err := i.client.newGet(endpoint) 433 if err != nil { 434 return err 435 } 436 if caname != "" { 437 addQueryParm(req, "ca", caname) 438 } 439 err = i.addTokenAuthHdr(req, nil) 440 if err != nil { 441 return err 442 } 443 return i.client.StreamResponse(req, stream, cb) 444 } 445 446 // Put sends a put request to an endpoint 447 func (i *Identity) Put(endpoint string, reqBody []byte, queryParam map[string]string, result interface{}) error { 448 req, err := i.client.newPut(endpoint, reqBody) 449 if err != nil { 450 return err 451 } 452 if queryParam != nil { 453 for key, value := range queryParam { 454 addQueryParm(req, key, value) 455 } 456 } 457 err = i.addTokenAuthHdr(req, reqBody) 458 if err != nil { 459 return err 460 } 461 return i.client.SendReq(req, result) 462 } 463 464 // Delete sends a delete request to an endpoint 465 func (i *Identity) Delete(endpoint string, result interface{}, queryParam map[string]string) error { 466 req, err := i.client.newDelete(endpoint) 467 if err != nil { 468 return err 469 } 470 if queryParam != nil { 471 for key, value := range queryParam { 472 addQueryParm(req, key, value) 473 } 474 } 475 err = i.addTokenAuthHdr(req, nil) 476 if err != nil { 477 return err 478 } 479 return i.client.SendReq(req, result) 480 } 481 482 // Post sends arbitrary request body (reqBody) to an endpoint. 483 // This adds an authorization header which contains the signature 484 // of this identity over the body and non-signature part of the authorization header. 485 // The return value is the body of the response. 486 func (i *Identity) Post(endpoint string, reqBody []byte, result interface{}, queryParam map[string]string) error { 487 req, err := i.client.newPost(endpoint, reqBody) 488 if err != nil { 489 return err 490 } 491 if queryParam != nil { 492 for key, value := range queryParam { 493 addQueryParm(req, key, value) 494 } 495 } 496 err = i.addTokenAuthHdr(req, reqBody) 497 if err != nil { 498 return err 499 } 500 return i.client.SendReq(req, result) 501 } 502 503 func (i *Identity) addTokenAuthHdr(req *http.Request, body []byte) error { 504 log.Debug("Adding token-based authorization header") 505 cert := i.ecert.cert 506 key := i.ecert.key 507 token, err := util.CreateToken(i.CSP, cert, key, body) 508 if err != nil { 509 return errors.WithMessage(err, "Failed to add token authorization header") 510 } 511 req.Header.Set("authorization", token) 512 return nil 513 }