github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/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/zcgolog/zclog"
    18  	http "github.com/hxx258456/ccgo/gmhttp"
    19  	gmux "github.com/hxx258456/ccgo/mux"
    20  	"github.com/hxx258456/ccgo/x509"
    21  	"github.com/hxx258456/cfssl-gm/config"
    22  	"github.com/hxx258456/cfssl-gm/revoke"
    23  	"github.com/hxx258456/cfssl-gm/signer"
    24  	"github.com/hxx258456/fabric-ca-gm/internal/pkg/api"
    25  	"github.com/hxx258456/fabric-ca-gm/internal/pkg/util"
    26  	"github.com/hxx258456/fabric-ca-gm/lib/attr"
    27  	"github.com/hxx258456/fabric-ca-gm/lib/attrmgr"
    28  	"github.com/hxx258456/fabric-ca-gm/lib/caerrors"
    29  	cr "github.com/hxx258456/fabric-ca-gm/lib/server/certificaterequest"
    30  	"github.com/hxx258456/fabric-ca-gm/lib/server/idemix"
    31  	"github.com/hxx258456/fabric-ca-gm/lib/server/user"
    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  }