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