gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/serverrequestcontext.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/hex" 11 "encoding/json" 12 "fmt" 13 "io/ioutil" 14 "strconv" 15 "strings" 16 17 "gitee.com/zhaochuninhefei/cfssl-gm/config" 18 "gitee.com/zhaochuninhefei/cfssl-gm/revoke" 19 "gitee.com/zhaochuninhefei/cfssl-gm/signer" 20 "gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/api" 21 "gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/util" 22 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/attr" 23 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/attrmgr" 24 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/caerrors" 25 cr "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/certificaterequest" 26 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/idemix" 27 "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/user" 28 http "gitee.com/zhaochuninhefei/gmgo/gmhttp" 29 gmux "gitee.com/zhaochuninhefei/gmgo/mux" 30 "gitee.com/zhaochuninhefei/gmgo/x509" 31 "gitee.com/zhaochuninhefei/zcgolog/zclog" 32 "github.com/jmoiron/sqlx" 33 "github.com/pkg/errors" 34 ) 35 36 // ServerRequestContext defines the functionality of a server request context object 37 type ServerRequestContext interface { 38 BasicAuthentication() (string, error) 39 TokenAuthentication() (string, error) 40 GetCaller() (user.User, error) 41 HasRole(role string) error 42 ChunksToDeliver(string) (int, error) 43 GetReq() *http.Request 44 GetQueryParm(name string) string 45 GetBoolQueryParm(name string) (bool, error) 46 GetResp() http.ResponseWriter 47 GetCertificates(cr.CertificateRequest, string) (*sqlx.Rows, error) 48 IsLDAPEnabled() bool 49 ReadBody(interface{}) error 50 ContainsAffiliation(string) error 51 CanActOnType(string) error 52 } 53 54 // serverRequestContextImpl represents an HTTP request/response context in the server 55 type serverRequestContextImpl struct { 56 req *http.Request 57 resp http.ResponseWriter 58 endpoint *serverEndpoint 59 ca *CA 60 enrollmentID string 61 enrollmentCert *x509.Certificate 62 ui user.User 63 caller user.User 64 body struct { 65 read bool // true after body is read 66 buf []byte // the body itself 67 err error // any error from reading the body 68 } 69 callerRoles map[string]bool 70 } 71 72 // newServerRequestContext is the constructor for a serverRequestContextImpl 73 func newServerRequestContext(r *http.Request, w http.ResponseWriter, se *serverEndpoint) *serverRequestContextImpl { 74 return &serverRequestContextImpl{ 75 req: r, 76 resp: w, 77 endpoint: se, 78 } 79 } 80 81 // BasicAuthentication authenticates the caller's username and password 82 // found in the authorization header and returns the username 83 func (ctx *serverRequestContextImpl) BasicAuthentication() (string, error) { 84 r := ctx.req 85 // Get the authorization header 86 authHdr := r.Header.Get("authorization") 87 if authHdr == "" { 88 return "", caerrors.NewHTTPErr(401, caerrors.ErrNoAuthHdr, "No authorization header") 89 } 90 // Extract the username and password from the header 91 username, password, ok := r.BasicAuth() 92 if !ok { 93 return "", caerrors.NewAuthenticationErr(caerrors.ErrNoUserPass, "No user/pass in authorization header") 94 } 95 // zclog.Debugf("===== username: %s/n", username) 96 // Get the CA that is targeted by this request 97 ca, err := ctx.GetCA() 98 if err != nil { 99 return "", err 100 } 101 // Error if max enrollments is disabled for this CA 102 // zclog.Debugf("ca.Config: %+v", ca.Config) 103 caMaxEnrollments := ca.Config.Registry.MaxEnrollments 104 if caMaxEnrollments == 0 { 105 return "", caerrors.NewAuthenticationErr(caerrors.ErrEnrollDisabled, "Enroll is disabled") 106 } 107 // Get the user info object for this user 108 ctx.ui, err = ca.registry.GetUser(username, nil) 109 if err != nil { 110 return "", caerrors.NewAuthenticationErr(caerrors.ErrInvalidUser, "Failed to get user: %s", err) 111 } 112 // zclog.Debugf("===== 从ca.registry获取到注册用户 Name:%s Type:%s\n", ctx.ui.GetName(), ctx.ui.GetType()) 113 attempts := ctx.ui.GetFailedLoginAttempts() 114 allowedAttempts := ca.Config.Cfg.Identities.PasswordAttempts 115 if allowedAttempts > 0 { 116 if attempts == ca.Config.Cfg.Identities.PasswordAttempts { 117 msg := fmt.Sprintf("Incorrect password entered %d times, max incorrect password limit of %d reached", attempts, ca.Config.Cfg.Identities.PasswordAttempts) 118 zclog.Error(msg) 119 return "", caerrors.NewHTTPErr(401, caerrors.ErrPasswordAttempts, msg) 120 } 121 } 122 123 // Check the user's password and max enrollments if supported by registry 124 err = ctx.ui.Login(password, caMaxEnrollments) 125 if err != nil { 126 return "", caerrors.NewAuthenticationErr(caerrors.ErrInvalidPass, "Login failure: %s", err) 127 } 128 // Store the enrollment ID associated with this server request context 129 ctx.enrollmentID = username 130 ctx.caller, err = ctx.GetCaller() 131 if err != nil { 132 return "", err 133 } 134 zclog.Debugf("===== caller:(Name:%s , Type:%s) ui:((Name:%s , Type:%s) enrollmentID:%s", ctx.caller.GetName(), ctx.caller.GetType(), ctx.ui.GetName(), ctx.ui.GetType(), username) 135 // Return the username 136 return username, nil 137 } 138 139 // TokenAuthentication authenticates the caller by token 140 // in the authorization header. 141 // Returns the enrollment ID or error. 142 func (ctx *serverRequestContextImpl) TokenAuthentication() (string, error) { 143 r := ctx.req 144 // Get the authorization header 145 authHdr := r.Header.Get("authorization") 146 if authHdr == "" { 147 return "", caerrors.NewHTTPErr(401, caerrors.ErrNoAuthHdr, "No authorization header") 148 } 149 // Get the CA 150 ca, err := ctx.GetCA() 151 if err != nil { 152 return "", err 153 } 154 // Get the request body 155 body, err := ctx.ReadBodyBytes() 156 if err != nil { 157 return "", err 158 } 159 if idemix.IsToken(authHdr) { 160 return ctx.verifyIdemixToken(authHdr, r.Method, r.URL.RequestURI(), body) 161 } 162 return ctx.verifyX509Token(ca, authHdr, r.Method, r.URL.RequestURI(), body) 163 } 164 165 func (ctx *serverRequestContextImpl) verifyIdemixToken(authHdr, method, uri string, body []byte) (string, error) { 166 zclog.Debug("Caller is using Idemix credential") 167 var err error 168 169 ctx.enrollmentID, err = ctx.ca.issuer.VerifyToken(authHdr, method, uri, body) 170 if err != nil { 171 return "", err 172 } 173 174 caller, err := ctx.GetCaller() 175 if err != nil { 176 return "", err 177 } 178 179 if caller.IsRevoked() { 180 return "", caerrors.NewAuthorizationErr(caerrors.ErrRevokedID, "Enrollment ID is revoked, unable to process request") 181 } 182 183 return ctx.enrollmentID, nil 184 } 185 186 func (ctx *serverRequestContextImpl) verifyX509Token(ca *CA, authHdr, method, uri string, body []byte) (string, error) { 187 zclog.Debug("===== Caller is using a x509 certificate") 188 // Verify the token; the signature is over the header and body 189 // 检查http请求携带的token是否有效,并返回对应的x509证书 190 cert, err2 := util.VerifyTokenFromHttpRequest(ca.csp, authHdr, method, uri, body, ca.server.Config.CompMode1_3) 191 if err2 != nil { 192 return "", caerrors.NewAuthenticationErr(caerrors.ErrInvalidToken, "Invalid token in authorization header: %s", err2) 193 } 194 // 确认是否是reenroll请求且忽略证书到期检查。 195 // determine if this being called for a reenroll and the ignore cert expiry property isset 196 // passed to the verify certificate to force it's checking of expiry time to be effectively ignored 197 reenrollIgnoreCertExpiry := ctx.endpoint.Path == "reenroll" && ctx.ca.Config.CA.ReenrollIgnoreCertExpiry 198 // 检查http携带的证书cert是否是由本ca签署的 199 // Make sure the caller's cert was issued by this CA 200 err2 = ca.VerifyCertificate(cert, reenrollIgnoreCertExpiry) 201 if err2 != nil { 202 return "", caerrors.NewAuthenticationErr(caerrors.ErrUntrustedCertificate, "Untrusted certificate: %s", err2) 203 } 204 // 从x509证书获取Subject.CommonName作为EnrollmentID 205 id := util.GetEnrollmentIDFromX509Certificate(cert) 206 zclog.Debugf("Checking for revocation/expiration of certificate owned by '%s'", id) 207 // 检查证书是否过期或被撤销 208 // VerifyCertificate ensures that the certificate passed in hasn't 209 // expired and checks the CRL for the server. 210 expired, checked := revoke.VerifyCertificate(cert) 211 if !checked { 212 return "", caerrors.NewHTTPErr(401, caerrors.ErrCertRevokeCheckFailure, "Failed while checking for revocation") 213 } 214 if expired { 215 zclog.Debugf("Expired Certificate") 216 if reenrollIgnoreCertExpiry { 217 // 根据reenrollIgnoreCertExpiry决定是否忽略证书过期 218 zclog.Infof("Ignoring expired certificate for re-enroll operation") 219 } else { 220 return "", caerrors.NewAuthenticationErr(caerrors.ErrCertExpired, 221 "The certificate in the authorization header is a revoked or expired certificate") 222 } 223 } 224 // 根据aki与serialNumber从ca本地数据库中读取对应的证书 225 aki := hex.EncodeToString(cert.AuthorityKeyId) 226 serial := util.GetSerialAsHex(cert.SerialNumber) 227 aki = strings.ToLower(strings.TrimLeft(aki, "0")) 228 serial = strings.ToLower(strings.TrimLeft(serial, "0")) 229 certificate, err := ca.GetCertificate(serial, aki) 230 if err != nil { 231 return "", err 232 } 233 // 再次检查证书是否被撤销 234 if certificate.Status == "revoked" { 235 return "", caerrors.NewAuthenticationErr(caerrors.ErrCertRevoked, "The certificate in the authorization header is a revoked certificate") 236 } 237 // 将x509证书的Subject.CommonName设置为请求上下文的EnrollmentID 238 ctx.enrollmentID = id 239 // 设置请求上下文的x509证书 240 ctx.enrollmentCert = cert 241 // 将x509证书的Subject.CommonName对应的注册用户取出并设置为请求上下文的caller 242 ctx.caller, err = ctx.GetCaller() 243 if err != nil { 244 return "", err 245 } 246 zclog.Debugf("Successful token authentication of '%s'", id) 247 return id, nil 248 } 249 250 // GetECert returns the enrollment certificate of the caller, assuming 251 // token authentication was successful. 252 func (ctx *serverRequestContextImpl) GetECert() *x509.Certificate { 253 return ctx.enrollmentCert 254 } 255 256 // GetCA returns the CA to which this request is targeted and checks to make sure the database has been initialized 257 func (ctx *serverRequestContextImpl) GetCA() (*CA, error) { 258 _, err := ctx.getCA() 259 if err != nil { 260 return nil, errors.WithMessage(err, "Failed to get CA instance") 261 } 262 if ctx.ca.db == nil || !ctx.ca.db.IsInitialized() { 263 err := ctx.ca.initDB(ctx.ca.server.dbMetrics) 264 if err != nil { 265 return nil, errors.WithMessage(err, fmt.Sprintf("%s handler failed to initialize DB", strings.TrimLeft(ctx.req.URL.String(), "/"))) 266 } 267 err = ctx.ca.issuer.Init(false, ctx.ca.db, ctx.ca.levels) 268 if err != nil { 269 return nil, nil 270 } 271 } 272 return ctx.ca, nil 273 } 274 275 // GetCA returns the CA to which this request is targeted 276 func (ctx *serverRequestContextImpl) getCA() (*CA, error) { 277 if ctx.ca == nil { 278 // Get the CA name 279 name, err := ctx.getCAName() 280 if err != nil { 281 return nil, err 282 } 283 // Get the CA by its name 284 ctx.ca, err = ctx.endpoint.Server.GetCA(name) 285 if err != nil { 286 return nil, err 287 } 288 } 289 return ctx.ca, nil 290 } 291 292 // GetAttrExtension returns an attribute extension to place into a signing request 293 func (ctx *serverRequestContextImpl) GetAttrExtension(attrReqs []*api.AttributeRequest, profile string) (*signer.Extension, error) { 294 ca, err := ctx.GetCA() 295 if err != nil { 296 return nil, err 297 } 298 ui, err := ca.registry.GetUser(ctx.enrollmentID, nil) 299 if err != nil { 300 return nil, err 301 } 302 allAttrs, err := ui.GetAttributes(nil) 303 if err != nil { 304 return nil, err 305 } 306 // 如果没有特意指定哪些扩展属性,就按照ca账户注册时各属性的ecert字段获取默认的扩展属性 307 if attrReqs == nil { 308 // 根据 ecert 是否为true过滤默认属性 309 attrReqs = getDefaultAttrReqs(allAttrs) 310 if attrReqs == nil { 311 // No attributes are being requested, so we are done 312 return nil, nil 313 } 314 } 315 // 获取对应属性 316 attrs, err := ca.attrMgr.ProcessAttributeRequests( 317 convertAttrReqs(attrReqs), // 接口转换:[]*api.AttributeRequest -> []attrmgr.AttributeRequest 318 convertAttrs(allAttrs), // 接口转换:[]api.Attribute -> []attrmgr.Attribute 319 ) 320 if err != nil { 321 return nil, err 322 } 323 if attrs != nil { 324 buf, err := json.Marshal(attrs) 325 if err != nil { 326 errors.Wrap(err, "Failed to marshal attributes") 327 } 328 ext := &signer.Extension{ 329 ID: config.OID(attrmgr.AttrOID), 330 Critical: false, 331 Value: hex.EncodeToString(buf), 332 } 333 zclog.Debugf("Attribute extension being added to certificate is: %s", attrs.Attrs) 334 return ext, nil 335 } 336 return nil, nil 337 } 338 339 // caNameReqBody is a sparse request body to unmarshal only the CA name 340 type caNameReqBody struct { 341 CAName string `json:"caname,omitempty"` 342 } 343 344 // getCAName returns the targeted CA name for this request 345 func (ctx *serverRequestContextImpl) getCAName() (string, error) { 346 // Check the query parameters first 347 ca := ctx.req.URL.Query().Get("ca") 348 if ca != "" { 349 return ca, nil 350 } 351 // Next, check the request body, if there is one 352 var body caNameReqBody 353 _, err := ctx.TryReadBody(&body) 354 if err != nil { 355 return "", err 356 } 357 if body.CAName != "" { 358 return body.CAName, nil 359 } 360 // No CA name in the request body either, so use the default CA name 361 return ctx.endpoint.Server.CA.Config.CA.Name, nil 362 } 363 364 // ReadBody reads the request body and JSON unmarshals into 'body' 365 func (ctx *serverRequestContextImpl) ReadBody(body interface{}) error { 366 empty, err := ctx.TryReadBody(body) 367 if err != nil { 368 return err 369 } 370 if empty { 371 return caerrors.NewHTTPErr(400, caerrors.ErrEmptyReqBody, "Empty request body") 372 } 373 return nil 374 } 375 376 // TryReadBody reads the request body into 'body' if not empty 377 func (ctx *serverRequestContextImpl) TryReadBody(body interface{}) (bool, error) { 378 buf, err := ctx.ReadBodyBytes() 379 if err != nil { 380 return false, err 381 } 382 empty := len(buf) == 0 383 if !empty { 384 err = json.Unmarshal(buf, body) 385 if err != nil { 386 return true, caerrors.NewHTTPErr(400, caerrors.ErrBadReqBody, "Invalid request body: %s; body=%s", 387 err, string(buf)) 388 } 389 } 390 return empty, nil 391 } 392 393 // ReadBodyBytes reads the request body and returns bytes 394 func (ctx *serverRequestContextImpl) ReadBodyBytes() ([]byte, error) { 395 if !ctx.body.read { 396 r := ctx.req 397 buf, err := ioutil.ReadAll(r.Body) 398 ctx.body.buf = buf 399 ctx.body.err = err 400 ctx.body.read = true 401 } 402 err := ctx.body.err 403 if err != nil { 404 return nil, caerrors.NewHTTPErr(500, caerrors.ErrReadingReqBody, "Failed reading request body: %s", err) 405 } 406 return ctx.body.buf, nil 407 } 408 409 func (ctx *serverRequestContextImpl) GetUser(userName string) (user.User, error) { 410 ca, err := ctx.getCA() 411 if err != nil { 412 return nil, err 413 } 414 registry := ca.registry 415 416 user, err := registry.GetUser(userName, nil) 417 if err != nil { 418 return nil, err 419 } 420 421 err = ctx.CanManageUser(user) 422 if err != nil { 423 return nil, err 424 } 425 426 return user, nil 427 } 428 429 // CanManageUser determines if the caller has the right type and affiliation to act on on a user 430 func (ctx *serverRequestContextImpl) CanManageUser(user user.User) error { 431 userAff := strings.Join(user.GetAffiliationPath(), ".") 432 err := ctx.ContainsAffiliation(userAff) 433 if err != nil { 434 return err 435 } 436 437 userType := user.GetType() 438 err = ctx.CanActOnType(userType) 439 if err != nil { 440 return err 441 } 442 443 return nil 444 } 445 446 // CanModifyUser determines if the modifications to the user are allowed 447 func (ctx *serverRequestContextImpl) CanModifyUser(req *api.ModifyIdentityRequest, checkAff bool, checkType bool, checkAttrs bool, userToModify user.User) error { 448 if checkAff { 449 reqAff := req.Affiliation 450 zclog.Debugf("Checking if caller is authorized to change affiliation to '%s'", reqAff) 451 err := ctx.ContainsAffiliation(reqAff) 452 if err != nil { 453 return err 454 } 455 } 456 457 if checkType { 458 reqType := req.Type 459 zclog.Debugf("Checking if caller is authorized to change type to '%s'", reqType) 460 err := ctx.CanActOnType(reqType) 461 if err != nil { 462 return err 463 } 464 } 465 466 if checkAttrs { 467 reqAttrs := req.Attributes 468 zclog.Debugf("Checking if caller is authorized to change attributes to %+v", reqAttrs) 469 err := attr.CanRegisterRequestedAttributes(reqAttrs, userToModify, ctx.caller) 470 if err != nil { 471 return caerrors.NewAuthorizationErr(caerrors.ErrRegAttrAuth, "Failed to register attributes: %s", err) 472 } 473 } 474 475 return nil 476 } 477 478 // 根据ctx.enrollmentID获取对应的注册用户作为caller返回。 479 // GetCaller gets the user who is making this server request 480 func (ctx *serverRequestContextImpl) GetCaller() (user.User, error) { 481 if ctx.caller != nil { 482 return ctx.caller, nil 483 } 484 485 var err error 486 id := ctx.enrollmentID 487 if id == "" { 488 return nil, caerrors.NewAuthenticationErr(caerrors.ErrCallerIsNotAuthenticated, "Caller is not authenticated") 489 } 490 ca, err := ctx.GetCA() 491 if err != nil { 492 return nil, err 493 } 494 // Get the user info object for this user 495 ctx.caller, err = ca.registry.GetUser(id, nil) 496 if err != nil { 497 return nil, caerrors.NewAuthenticationErr(caerrors.ErrGettingUser, "Failed to get user") 498 } 499 return ctx.caller, nil 500 } 501 502 // ContainsAffiliation returns an error if the requested affiliation does not contain the caller's affiliation 503 func (ctx *serverRequestContextImpl) ContainsAffiliation(affiliation string) error { 504 validAffiliation, err := ctx.containsAffiliation(affiliation) 505 if err != nil { 506 return errors.WithMessage(err, "Failed to validate if caller has authority to act on affiliation") 507 } 508 if !validAffiliation { 509 return caerrors.NewAuthorizationErr(caerrors.ErrCallerNotAffiliated, "Caller does not have authority to act on affiliation '%s'", affiliation) 510 } 511 return nil 512 } 513 514 // containsAffiliation returns true if the requested affiliation contains the caller's affiliation 515 func (ctx *serverRequestContextImpl) containsAffiliation(affiliation string) (bool, error) { 516 caller, err := ctx.GetCaller() 517 if err != nil { 518 return false, err 519 } 520 521 callerAffiliationPath := user.GetAffiliation(caller) 522 zclog.Debugf("Checking to see if affiliation '%s' contains caller's affiliation '%s'", affiliation, callerAffiliationPath) 523 524 // If the caller has root affiliation return "true" 525 if callerAffiliationPath == "" { 526 zclog.Debug("Caller has root affiliation") 527 return true, nil 528 } 529 530 if affiliation == callerAffiliationPath { 531 return true, nil 532 } 533 534 callerAffiliationPath = callerAffiliationPath + "." 535 if strings.HasPrefix(affiliation, callerAffiliationPath) { 536 return true, nil 537 } 538 539 return false, nil 540 } 541 542 // IsRegistrar returns an error if the caller is not a registrar 543 func (ctx *serverRequestContextImpl) IsRegistrar() error { 544 _, isRegistrar, err := ctx.isRegistrar() 545 if err != nil { 546 return err 547 } 548 if !isRegistrar { 549 return caerrors.NewAuthorizationErr(caerrors.ErrMissingRegAttr, "Caller is not a registrar") 550 } 551 552 return nil 553 } 554 555 // isRegistrar returns back true if the caller is a registrar along with the types the registrar is allowed to register 556 func (ctx *serverRequestContextImpl) isRegistrar() (string, bool, error) { 557 caller, err := ctx.GetCaller() 558 if err != nil { 559 return "", false, err 560 } 561 562 zclog.Debugf("Checking to see if caller '%s' is a registrar", caller.GetName()) 563 564 rolesStr, err := caller.GetAttribute("hf.Registrar.Roles") 565 if err != nil { 566 return "", false, caerrors.NewAuthorizationErr(caerrors.ErrRegAttrAuth, "'%s' is not a registrar", caller.GetName()) 567 } 568 569 // Has some value for attribute 'hf.Registrar.Roles' then user is a registrar 570 if rolesStr.Value != "" { 571 return rolesStr.Value, true, nil 572 } 573 574 return "", false, nil 575 } 576 577 // CanActOnType returns true if the caller has the proper authority to take action on specific type 578 func (ctx *serverRequestContextImpl) CanActOnType(userType string) error { 579 canAct, err := ctx.canActOnType(userType) 580 if err != nil { 581 return errors.WithMessage(err, "Failed to verify if user can act on type") 582 } 583 if !canAct { 584 return caerrors.NewAuthorizationErr(caerrors.ErrCallerNotAffiliated, "Registrar does not have authority to act on type '%s'", userType) 585 } 586 return nil 587 } 588 589 func (ctx *serverRequestContextImpl) canActOnType(requestedType string) (bool, error) { 590 caller, err := ctx.GetCaller() 591 if err != nil { 592 return false, err 593 } 594 595 zclog.Debugf("Checking to see if caller '%s' can act on type '%s'", caller.GetName(), requestedType) 596 597 typesStr, isRegistrar, err := ctx.isRegistrar() 598 if err != nil { 599 return false, err 600 } 601 if !isRegistrar { 602 return false, caerrors.NewAuthorizationErr(caerrors.ErrRegAttrAuth, "'%s' is not allowed to manage users", caller.GetName()) 603 } 604 605 if util.ListContains(typesStr, "*") { 606 return true, nil 607 } 608 609 var types []string 610 if typesStr != "" { 611 types = strings.Split(typesStr, ",") 612 } else { 613 types = make([]string, 0) 614 } 615 if requestedType == "" { 616 requestedType = "client" 617 } 618 if !strContained(requestedType, types) { 619 zclog.Debugf("Caller with types '%s' is not authorized to act on '%s'", types, requestedType) 620 return false, nil 621 } 622 623 return true, nil 624 } 625 626 func strContained(needle string, haystack []string) bool { 627 for _, s := range haystack { 628 if strings.EqualFold(s, needle) { 629 return true 630 } 631 } 632 return false 633 } 634 635 // HasRole returns an error if the caller does not have the attribute or the value is false for a boolean attribute 636 func (ctx *serverRequestContextImpl) HasRole(role string) error { 637 hasRole, err := ctx.hasRole(role) 638 if err != nil { 639 return err 640 } 641 if !hasRole { 642 return caerrors.NewAuthorizationErr(caerrors.ErrMissingRole, "Caller has a value of 'false' for attribute/role '%s'", role) 643 } 644 return nil 645 } 646 647 // HasRole returns true if the caller has the attribute and value of the attribute is true 648 func (ctx *serverRequestContextImpl) hasRole(role string) (bool, error) { 649 if ctx.callerRoles == nil { 650 ctx.callerRoles = make(map[string]bool) 651 } 652 653 roleStatus, hasRole := ctx.callerRoles[role] 654 if hasRole { 655 return roleStatus, nil 656 } 657 658 caller, err := ctx.GetCaller() 659 if err != nil { 660 return false, err 661 } 662 663 roleAttr, err := caller.GetAttribute(role) 664 if err != nil { 665 return false, caerrors.NewAuthorizationErr(caerrors.ErrInvokerMissAttr, "Invoker does not have following role'%s': '%s'", role, err) 666 } 667 roleStatus, err = strconv.ParseBool(roleAttr.Value) 668 if err != nil { 669 return false, caerrors.NewHTTPErr(400, caerrors.ErrInvalidBool, "Failed to get boolean value of '%s': '%s'", role, err) 670 } 671 ctx.callerRoles[role] = roleStatus 672 673 return ctx.callerRoles[role], nil 674 } 675 676 // GetVar returns the parameter path variable from the URL 677 func (ctx *serverRequestContextImpl) GetVar(name string) (string, error) { 678 vars := gmux.Vars(ctx.req) 679 if vars == nil { 680 return "", caerrors.NewHTTPErr(500, caerrors.ErrHTTPRequest, "Failed to correctly handle HTTP request") 681 } 682 value := vars[name] 683 return value, nil 684 } 685 686 // GetBoolQueryParm returns query parameter from the URL 687 func (ctx *serverRequestContextImpl) GetBoolQueryParm(name string) (bool, error) { 688 var err error 689 690 value := false 691 param := ctx.req.URL.Query().Get(name) 692 if param != "" { 693 value, err = strconv.ParseBool(strings.ToLower(param)) 694 if err != nil { 695 return false, caerrors.NewHTTPErr(400, caerrors.ErrUpdateConfigRemoveAff, "Failed to correctly parse value of '%s' query parameter: %s", name, err) 696 } 697 } 698 699 return value, nil 700 } 701 702 // GetQueryParm returns the value of query param based on name 703 func (ctx *serverRequestContextImpl) GetQueryParm(name string) string { 704 return ctx.req.URL.Query().Get(name) 705 } 706 707 // GetReq returns the http.Request 708 func (ctx *serverRequestContextImpl) GetReq() *http.Request { 709 return ctx.req 710 } 711 712 // GetResp returns the http.ResponseWriter 713 func (ctx *serverRequestContextImpl) GetResp() http.ResponseWriter { 714 return ctx.resp 715 } 716 717 // GetCertificates executes the DB query to get back certificates based on the filters passed in 718 func (ctx *serverRequestContextImpl) GetCertificates(req cr.CertificateRequest, callerAff string) (*sqlx.Rows, error) { 719 return ctx.ca.certDBAccessor.GetCertificates(req, callerAff) 720 } 721 722 // ChunksToDeliver returns the number of chunks to deliver per flush 723 func (ctx *serverRequestContextImpl) ChunksToDeliver(envVar string) (int, error) { 724 var chunkSize int 725 var err error 726 727 if envVar == "" { 728 chunkSize = 100 729 } else { 730 chunkSize, err = strconv.Atoi(envVar) 731 if err != nil { 732 return 0, caerrors.NewHTTPErr(500, caerrors.ErrParsingIntEnvVar, "Incorrect format specified for environment variable '%s', an integer value is required: %s", envVar, err) 733 } 734 } 735 return chunkSize, nil 736 } 737 738 // Registry returns the registry for the ca 739 func (ctx *serverRequestContextImpl) GetRegistry() user.Registry { 740 return ctx.ca.registry 741 } 742 743 func (ctx *serverRequestContextImpl) GetCAConfig() *CAConfig { 744 return ctx.ca.Config 745 } 746 747 func (ctx *serverRequestContextImpl) IsLDAPEnabled() bool { 748 return ctx.ca.Config.LDAP.Enabled 749 } 750 751 func convertAttrReqs(attrReqs []*api.AttributeRequest) []attrmgr.AttributeRequest { 752 rtn := make([]attrmgr.AttributeRequest, len(attrReqs)) 753 for i := range attrReqs { 754 rtn[i] = attrmgr.AttributeRequest(attrReqs[i]) 755 } 756 return rtn 757 } 758 759 func convertAttrs(attrs []api.Attribute) []attrmgr.Attribute { 760 rtn := make([]attrmgr.Attribute, len(attrs)) 761 for i := range attrs { 762 rtn[i] = attrmgr.Attribute(&attrs[i]) 763 } 764 return rtn 765 } 766 767 // Return attribute requests for attributes which should by default be added to an ECert 768 func getDefaultAttrReqs(attrs []api.Attribute) []*api.AttributeRequest { 769 count := 0 770 for _, attr := range attrs { 771 if attr.ECert { 772 count++ 773 } 774 } 775 if count == 0 { 776 return nil 777 } 778 reqs := make([]*api.AttributeRequest, count) 779 count = 0 780 for _, attr := range attrs { 781 if attr.ECert { 782 reqs[count] = &api.AttributeRequest{Name: attr.Name} 783 count++ 784 } 785 } 786 return reqs 787 }