github.com/silveraid/fabric-ca@v1.1.0-preview.0.20180127000700-71974f53ab08/lib/serverrequestcontext.go (about) 1 /* 2 Copyright IBM Corp. 2017 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 "crypto/x509" 21 "encoding/hex" 22 "encoding/json" 23 "fmt" 24 "io/ioutil" 25 "net/http" 26 "strconv" 27 "strings" 28 29 "github.com/cloudflare/cfssl/config" 30 "github.com/cloudflare/cfssl/log" 31 "github.com/cloudflare/cfssl/revoke" 32 "github.com/cloudflare/cfssl/signer" 33 gmux "github.com/gorilla/mux" 34 "github.com/hyperledger/fabric-ca/api" 35 "github.com/hyperledger/fabric-ca/lib/attr" 36 "github.com/hyperledger/fabric-ca/lib/spi" 37 "github.com/hyperledger/fabric-ca/util" 38 "github.com/hyperledger/fabric/common/attrmgr" 39 "github.com/pkg/errors" 40 ) 41 42 // serverRequestContext represents an HTTP request/response context in the server 43 type serverRequestContext struct { 44 req *http.Request 45 resp http.ResponseWriter 46 endpoint *serverEndpoint 47 ca *CA 48 enrollmentID string 49 enrollmentCert *x509.Certificate 50 ui spi.User 51 caller spi.User 52 body struct { 53 read bool // true after body is read 54 buf []byte // the body itself 55 err error // any error from reading the body 56 } 57 callerRoles map[string]bool 58 } 59 60 const ( 61 registrarRole = "hf.Registrar.Roles" 62 ) 63 64 // newServerRequestContext is the constructor for a serverRequestContext 65 func newServerRequestContext(r *http.Request, w http.ResponseWriter, se *serverEndpoint) *serverRequestContext { 66 return &serverRequestContext{ 67 req: r, 68 resp: w, 69 endpoint: se, 70 } 71 } 72 73 // BasicAuthentication authenticates the caller's username and password 74 // found in the authorization header and returns the username 75 func (ctx *serverRequestContext) BasicAuthentication() (string, error) { 76 r := ctx.req 77 // Get the authorization header 78 authHdr := r.Header.Get("authorization") 79 if authHdr == "" { 80 return "", newHTTPErr(401, ErrNoAuthHdr, "No authorization header") 81 } 82 // Extract the username and password from the header 83 username, password, ok := r.BasicAuth() 84 if !ok { 85 return "", newAuthErr(ErrNoUserPass, "No user/pass in authorization header") 86 } 87 // Get the CA that is targeted by this request 88 ca, err := ctx.GetCA() 89 if err != nil { 90 return "", err 91 } 92 // Error if max enrollments is disabled for this CA 93 log.Debugf("ca.Config: %+v", ca.Config) 94 caMaxEnrollments := ca.Config.Registry.MaxEnrollments 95 if caMaxEnrollments == 0 { 96 return "", newAuthErr(ErrEnrollDisabled, "Enroll is disabled") 97 } 98 // Get the user info object for this user 99 ctx.ui, err = ca.registry.GetUser(username, nil) 100 if err != nil { 101 return "", newAuthErr(ErrInvalidUser, "Failed to get user: %s", err) 102 } 103 // Check the user's password and max enrollments if supported by registry 104 err = ctx.ui.Login(password, caMaxEnrollments) 105 if err != nil { 106 return "", newAuthErr(ErrInvalidPass, "Login failure: %s", err) 107 } 108 // Store the enrollment ID associated with this server request context 109 ctx.enrollmentID = username 110 // Return the username 111 return username, nil 112 } 113 114 // TokenAuthentication authenticates the caller by token 115 // in the authorization header. 116 // Returns the enrollment ID or error. 117 func (ctx *serverRequestContext) TokenAuthentication() (string, error) { 118 r := ctx.req 119 // Get the authorization header 120 authHdr := r.Header.Get("authorization") 121 if authHdr == "" { 122 return "", newHTTPErr(401, ErrNoAuthHdr, "No authorization header") 123 } 124 // Get the CA 125 ca, err := ctx.GetCA() 126 if err != nil { 127 return "", err 128 } 129 // Get the request body 130 body, err := ctx.ReadBodyBytes() 131 if err != nil { 132 return "", err 133 } 134 // Verify the token; the signature is over the header and body 135 cert, err2 := util.VerifyToken(ca.csp, authHdr, body) 136 if err2 != nil { 137 return "", newAuthErr(ErrInvalidToken, "Invalid token in authorization header: %s", err2) 138 } 139 // Make sure the caller's cert was issued by this CA 140 err2 = ca.VerifyCertificate(cert) 141 if err2 != nil { 142 return "", newAuthErr(ErrUntrustedCertificate, "Untrusted certificate: %s", err2) 143 } 144 id := util.GetEnrollmentIDFromX509Certificate(cert) 145 log.Debugf("Checking for revocation/expiration of certificate owned by '%s'", id) 146 // VerifyCertificate ensures that the certificate passed in hasn't 147 // expired and checks the CRL for the server. 148 expired, checked := revoke.VerifyCertificate(cert) 149 if !checked { 150 return "", newHTTPErr(401, ErrCertRevokeCheckFailure, "Failed while checking for revocation") 151 } 152 if expired { 153 return "", newAuthErr(ErrCertExpired, 154 "The certificate in the authorization header is a revoked or expired certificate") 155 } 156 aki := hex.EncodeToString(cert.AuthorityKeyId) 157 serial := util.GetSerialAsHex(cert.SerialNumber) 158 aki = strings.ToLower(strings.TrimLeft(aki, "0")) 159 serial = strings.ToLower(strings.TrimLeft(serial, "0")) 160 certs, err := ca.CertDBAccessor().GetCertificate(serial, aki) 161 if err != nil { 162 return "", newHTTPErr(500, ErrCertNotFound, "Failed searching certificates: %s", err) 163 } 164 if len(certs) == 0 { 165 return "", newAuthErr(ErrCertNotFound, "Certificate not found with AKI '%s' and serial '%s'", aki, serial) 166 } 167 for _, certificate := range certs { 168 if certificate.Status == "revoked" { 169 return "", newAuthErr(ErrCertRevoked, "The certificate in the authorization header is a revoked certificate") 170 } 171 } 172 ctx.enrollmentID = id 173 ctx.enrollmentCert = cert 174 log.Debugf("Successful token authentication of '%s'", id) 175 return id, nil 176 } 177 178 // GetECert returns the enrollment certificate of the caller, assuming 179 // token authentication was successful. 180 func (ctx *serverRequestContext) GetECert() *x509.Certificate { 181 return ctx.enrollmentCert 182 } 183 184 // GetCA returns the CA to which this request is targeted and checks to make sure the database has been initialized 185 func (ctx *serverRequestContext) GetCA() (*CA, error) { 186 _, err := ctx.getCA() 187 if err != nil { 188 return nil, errors.WithMessage(err, "Failed to get CA instance") 189 } 190 if !ctx.ca.dbInitialized { 191 err := ctx.ca.initDB() 192 if err != nil { 193 return nil, errors.WithMessage(err, fmt.Sprintf("%s handler failed to initialize DB", strings.TrimLeft(ctx.req.URL.String(), "/"))) 194 } 195 } 196 return ctx.ca, nil 197 } 198 199 // GetCA returns the CA to which this request is targeted 200 func (ctx *serverRequestContext) getCA() (*CA, error) { 201 if ctx.ca == nil { 202 // Get the CA name 203 name, err := ctx.getCAName() 204 if err != nil { 205 return nil, err 206 } 207 // Get the CA by its name 208 ctx.ca, err = ctx.endpoint.Server.GetCA(name) 209 if err != nil { 210 return nil, err 211 } 212 } 213 return ctx.ca, nil 214 } 215 216 // GetAttrExtension returns an attribute extension to place into a signing request 217 func (ctx *serverRequestContext) GetAttrExtension(attrReqs []*api.AttributeRequest, profile string) (*signer.Extension, error) { 218 ca, err := ctx.GetCA() 219 if err != nil { 220 return nil, err 221 } 222 ui, err := ca.registry.GetUser(ctx.enrollmentID, nil) 223 if err != nil { 224 return nil, err 225 } 226 allAttrs, _ := ui.GetAttributes(nil) 227 if attrReqs == nil { 228 attrReqs = getDefaultAttrReqs(allAttrs) 229 if attrReqs == nil { 230 // No attributes are being requested, so we are done 231 return nil, nil 232 } 233 } 234 attrs, err := ca.attrMgr.ProcessAttributeRequests( 235 convertAttrReqs(attrReqs), 236 convertAttrs(allAttrs), 237 ) 238 if err != nil { 239 return nil, err 240 } 241 if attrs != nil { 242 buf, err := json.Marshal(attrs) 243 if err != nil { 244 errors.Wrap(err, "Failed to marshal attributes") 245 } 246 ext := &signer.Extension{ 247 ID: config.OID(attrmgr.AttrOID), 248 Critical: false, 249 Value: hex.EncodeToString(buf), 250 } 251 log.Debugf("Attribute extension being added to certificate is: %+v", ext) 252 return ext, nil 253 } 254 return nil, nil 255 } 256 257 // caNameReqBody is a sparse request body to unmarshal only the CA name 258 type caNameReqBody struct { 259 CAName string `json:"caname,omitempty"` 260 } 261 262 // getCAName returns the targeted CA name for this request 263 func (ctx *serverRequestContext) getCAName() (string, error) { 264 // Check the query parameters first 265 ca := ctx.req.URL.Query().Get("ca") 266 if ca != "" { 267 return ca, nil 268 } 269 // Next, check the request body, if there is one 270 var body caNameReqBody 271 _, err := ctx.TryReadBody(&body) 272 if err != nil { 273 return "", err 274 } 275 if body.CAName != "" { 276 return body.CAName, nil 277 } 278 // No CA name in the request body either, so use the default CA name 279 return ctx.endpoint.Server.CA.Config.CA.Name, nil 280 } 281 282 // ReadBody reads the request body and JSON unmarshals into 'body' 283 func (ctx *serverRequestContext) ReadBody(body interface{}) error { 284 empty, err := ctx.TryReadBody(body) 285 if err != nil { 286 return err 287 } 288 if empty { 289 return newHTTPErr(400, ErrEmptyReqBody, "Empty request body") 290 } 291 return nil 292 } 293 294 // TryReadBody reads the request body into 'body' if not empty 295 func (ctx *serverRequestContext) TryReadBody(body interface{}) (bool, error) { 296 buf, err := ctx.ReadBodyBytes() 297 if err != nil { 298 return false, err 299 } 300 empty := len(buf) == 0 301 if !empty { 302 err = json.Unmarshal(buf, body) 303 if err != nil { 304 return true, newHTTPErr(400, ErrBadReqBody, "Invalid request body: %s; body=%s", 305 err, string(buf)) 306 } 307 } 308 return empty, nil 309 } 310 311 // ReadBodyBytes reads the request body and returns bytes 312 func (ctx *serverRequestContext) ReadBodyBytes() ([]byte, error) { 313 if !ctx.body.read { 314 r := ctx.req 315 buf, err := ioutil.ReadAll(r.Body) 316 ctx.body.buf = buf 317 ctx.body.err = err 318 ctx.body.read = true 319 } 320 err := ctx.body.err 321 if err != nil { 322 return nil, newHTTPErr(400, ErrReadingReqBody, "Failed reading request body: %s", err) 323 } 324 return ctx.body.buf, nil 325 } 326 327 func (ctx *serverRequestContext) GetUser(userName string) (spi.User, error) { 328 ca, err := ctx.getCA() 329 if err != nil { 330 return nil, err 331 } 332 registry := ca.registry 333 334 user, err := registry.GetUser(userName, nil) 335 if err != nil { 336 return nil, err 337 } 338 339 err = ctx.CanManageUser(user) 340 if err != nil { 341 return nil, err 342 } 343 344 return user, nil 345 } 346 347 // CanManageUser determines if the caller has the right type and affiliation to act on on a user 348 func (ctx *serverRequestContext) CanManageUser(user spi.User) error { 349 userAff := strings.Join(user.GetAffiliationPath(), ".") 350 err := ctx.ContainsAffiliation(userAff) 351 if err != nil { 352 return err 353 } 354 355 userType := user.GetType() 356 err = ctx.CanActOnType(userType) 357 if err != nil { 358 return err 359 } 360 361 return nil 362 } 363 364 // CanModifyUser determines if the modifications to the user are allowed 365 func (ctx *serverRequestContext) CanModifyUser(req *api.ModifyIdentityRequest, checkAff bool, checkType bool, checkAttrs bool, userToModify spi.User) error { 366 if checkAff { 367 reqAff := req.Affiliation 368 log.Debugf("Checking if caller is authorized to change affiliation to '%s'", reqAff) 369 err := ctx.ContainsAffiliation(reqAff) 370 if err != nil { 371 return err 372 } 373 } 374 375 if checkType { 376 reqType := req.Type 377 log.Debugf("Checking if caller is authorized to change type to '%s'", reqType) 378 err := ctx.CanActOnType(reqType) 379 if err != nil { 380 return err 381 } 382 } 383 384 if checkAttrs { 385 reqAttrs := req.Attributes 386 log.Debugf("Checking if caller is authorized to change attributes to %+v", reqAttrs) 387 err := attr.CanRegisterRequestedAttributes(reqAttrs, userToModify, ctx.caller) 388 if err != nil { 389 return newAuthErr(ErrRegAttrAuth, "Failed to register attributes: %s", err) 390 } 391 } 392 393 return nil 394 } 395 396 // GetCaller gets the user who is making this server request 397 func (ctx *serverRequestContext) GetCaller() (spi.User, error) { 398 if ctx.caller != nil { 399 return ctx.caller, nil 400 } 401 402 var err error 403 id := ctx.enrollmentID 404 if id == "" { 405 return nil, newAuthErr(ErrCallerIsNotAuthenticated, "Caller is not authenticated") 406 } 407 ca, err := ctx.GetCA() 408 if err != nil { 409 return nil, err 410 } 411 // Get the user info object for this user 412 ctx.caller, err = ca.registry.GetUser(id, nil) 413 if err != nil { 414 return nil, newAuthErr(ErrGettingUser, "Failed to get user") 415 } 416 return ctx.caller, nil 417 } 418 419 // ContainsAffiliation returns an error if the requested affiliation does not contain the caller's affiliation 420 func (ctx *serverRequestContext) ContainsAffiliation(affiliation string) error { 421 validAffiliation, err := ctx.containsAffiliation(affiliation) 422 if err != nil { 423 return newHTTPErr(500, ErrGettingAffiliation, "Failed to validate if caller has authority to get ID: %s", err) 424 } 425 if !validAffiliation { 426 return newAuthErr(ErrCallerNotAffiliated, "Caller does not have authority to act on affiliation '%s'", affiliation) 427 } 428 return nil 429 } 430 431 // containsAffiliation returns true if the requested affiliation contains the caller's affiliation 432 func (ctx *serverRequestContext) containsAffiliation(affiliation string) (bool, error) { 433 caller, err := ctx.GetCaller() 434 if err != nil { 435 return false, err 436 } 437 438 callerAffiliationPath := GetUserAffiliation(caller) 439 log.Debugf("Checking to see if affiliation '%s' contains caller's affiliation '%s'", affiliation, callerAffiliationPath) 440 441 // If the caller has root affiliation return "true" 442 if callerAffiliationPath == "" { 443 log.Debug("Caller has root affiliation") 444 return true, nil 445 } 446 447 if affiliation == callerAffiliationPath { 448 return true, nil 449 } 450 451 callerAffiliationPath = callerAffiliationPath + "." 452 if strings.HasPrefix(affiliation, callerAffiliationPath) { 453 return true, nil 454 } 455 456 return false, nil 457 } 458 459 // IsRegistrar returns an error if the caller is not a registrar 460 func (ctx *serverRequestContext) IsRegistrar() error { 461 _, isRegistrar, err := ctx.isRegistrar() 462 if err != nil { 463 return err 464 } 465 if !isRegistrar { 466 return newAuthErr(ErrMissingRegAttr, "Caller is not a registrar") 467 } 468 469 return nil 470 } 471 472 // isRegistrar returns back true if the caller is a registrar along with the types the registrar is allowed to register 473 func (ctx *serverRequestContext) isRegistrar() (string, bool, error) { 474 caller, err := ctx.GetCaller() 475 if err != nil { 476 return "", false, err 477 } 478 479 log.Debugf("Checking to see if caller '%s' is a registrar", caller.GetName()) 480 481 rolesStr, err := caller.GetAttribute("hf.Registrar.Roles") 482 if err != nil { 483 return "", false, newAuthErr(ErrRegAttrAuth, "'%s' is not a registrar", caller.GetName()) 484 } 485 486 // Has some value for attribute 'hf.Registrar.Roles' then user is a registrar 487 if rolesStr.Value != "" { 488 return rolesStr.Value, true, nil 489 } 490 491 return "", false, nil 492 } 493 494 // CanActOnType returns true if the caller has the proper authority to take action on specific type 495 func (ctx *serverRequestContext) CanActOnType(userType string) error { 496 canAct, err := ctx.canActOnType(userType) 497 if err != nil { 498 return newHTTPErr(500, ErrGettingType, "Failed to verify if user can act on type '%s': %s", userType, err) 499 } 500 if !canAct { 501 return newAuthErr(ErrCallerNotAffiliated, "Registrar does not have authority to act on type '%s'", userType) 502 } 503 return nil 504 } 505 506 func (ctx *serverRequestContext) canActOnType(requestedType string) (bool, error) { 507 caller, err := ctx.GetCaller() 508 if err != nil { 509 return false, err 510 } 511 512 log.Debugf("Checking to see if caller '%s' can act on type '%s'", caller.GetName(), requestedType) 513 514 typesStr, isRegistrar, err := ctx.isRegistrar() 515 if err != nil { 516 return false, err 517 } 518 if !isRegistrar { 519 return false, newAuthErr(ErrRegAttrAuth, "'%s' is not allowed to manage users", caller.GetName()) 520 } 521 522 var types []string 523 if typesStr != "" { 524 types = strings.Split(typesStr, ",") 525 } else { 526 types = make([]string, 0) 527 } 528 529 if !util.StrContained(requestedType, types) { 530 log.Debug("Caller with types '%s' is not authorized to act on '%s'", types, requestedType) 531 return false, nil 532 } 533 534 return true, nil 535 } 536 537 // HasRole returns an error if the caller does not have the attribute or the value is false for a boolean attribute 538 func (ctx *serverRequestContext) HasRole(role string) error { 539 hasRole, err := ctx.hasRole(role) 540 if err != nil { 541 return err 542 } 543 if !hasRole { 544 return newHTTPErr(400, ErrMissingRole, "Caller has a value of 'false' for attribute/role '%s'", role) 545 } 546 return nil 547 } 548 549 // HasRole returns true if the caller has the attribute and value of the attribute is true 550 func (ctx *serverRequestContext) hasRole(role string) (bool, error) { 551 if ctx.callerRoles == nil { 552 ctx.callerRoles = make(map[string]bool) 553 } 554 555 roleStatus, hasRole := ctx.callerRoles[role] 556 if hasRole { 557 return roleStatus, nil 558 } 559 560 caller, err := ctx.GetCaller() 561 if err != nil { 562 return false, err 563 } 564 565 roleAttr, err := caller.GetAttribute(role) 566 if err != nil { 567 return false, err 568 } 569 roleStatus, err = strconv.ParseBool(roleAttr.Value) 570 if err != nil { 571 return false, errors.Wrap(err, fmt.Sprintf("Failed to get boolean value of '%s'", role)) 572 } 573 ctx.callerRoles[role] = roleStatus 574 575 return ctx.callerRoles[role], nil 576 } 577 578 // GetVar returns the parameter path variable from the URL 579 func (ctx *serverRequestContext) GetVar(name string) (string, error) { 580 vars := gmux.Vars(ctx.req) 581 if vars == nil { 582 return "", newHTTPErr(500, ErrHTTPRequest, "Failed to correctly handle HTTP request") 583 } 584 value := vars[name] 585 return value, nil 586 } 587 588 // GetBoolQueryParm returns query parameter from the URL 589 func (ctx *serverRequestContext) GetBoolQueryParm(name string) (bool, error) { 590 var err error 591 592 value := false 593 param := ctx.req.URL.Query().Get(name) 594 if param != "" { 595 value, err = strconv.ParseBool(param) 596 if err != nil { 597 return false, newHTTPErr(400, ErrUpdateConfigRemoveAff, "Failed to correctly parse value of '%s' query parameter: %s", name, err) 598 } 599 } 600 601 return value, nil 602 } 603 604 func convertAttrReqs(attrReqs []*api.AttributeRequest) []attrmgr.AttributeRequest { 605 rtn := make([]attrmgr.AttributeRequest, len(attrReqs)) 606 for i := range attrReqs { 607 rtn[i] = attrmgr.AttributeRequest(attrReqs[i]) 608 } 609 return rtn 610 } 611 612 func convertAttrs(attrs []api.Attribute) []attrmgr.Attribute { 613 rtn := make([]attrmgr.Attribute, len(attrs)) 614 for i := range attrs { 615 rtn[i] = attrmgr.Attribute(&attrs[i]) 616 } 617 return rtn 618 } 619 620 // Return attribute requests for attributes which should by default be added to an ECert 621 func getDefaultAttrReqs(attrs []api.Attribute) []*api.AttributeRequest { 622 count := 0 623 for _, attr := range attrs { 624 if attr.ECert { 625 count++ 626 } 627 } 628 if count == 0 { 629 return nil 630 } 631 reqs := make([]*api.AttributeRequest, count) 632 count = 0 633 for _, attr := range attrs { 634 if attr.ECert { 635 reqs[count] = &api.AttributeRequest{Name: attr.Name} 636 count++ 637 } 638 } 639 return reqs 640 }