github.com/zcqzcg/fabric-ca@v2.0.0-alpha.0.20200416163940-d878ee6db75a+incompatible/lib/serverregister.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  	"fmt"
    11  	"net/url"
    12  
    13  	"github.com/cloudflare/cfssl/log"
    14  	"github.com/hyperledger/fabric-ca/api"
    15  	"github.com/hyperledger/fabric-ca/lib/attr"
    16  	"github.com/hyperledger/fabric-ca/lib/caerrors"
    17  	"github.com/hyperledger/fabric-ca/lib/server/user"
    18  	"github.com/hyperledger/fabric-ca/util"
    19  
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  func newRegisterEndpoint(s *Server) *serverEndpoint {
    24  	return &serverEndpoint{
    25  		Path:      "register",
    26  		Methods:   []string{"POST"},
    27  		Handler:   registerHandler,
    28  		Server:    s,
    29  		successRC: 201,
    30  	}
    31  }
    32  
    33  // Handle a register request
    34  func registerHandler(ctx *serverRequestContextImpl) (interface{}, error) {
    35  	ca, err := ctx.GetCA()
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	return register(ctx, ca)
    40  }
    41  
    42  func register(ctx ServerRequestContext, ca *CA) (interface{}, error) {
    43  	// Read request body
    44  	var req api.RegistrationRequestNet
    45  	err := ctx.ReadBody(&req)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	// Authenticate
    50  	callerID, err := ctx.TokenAuthentication()
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	log.Debugf("Received registration request from %s: %v", callerID, &req)
    55  	if ctx.IsLDAPEnabled() {
    56  		return nil, caerrors.NewHTTPErr(403, caerrors.ErrInvalidLDAPAction, "Registration is not supported when using LDAP")
    57  	}
    58  	// Register User
    59  	secret, err := registerUser(&req.RegistrationRequest, callerID, ca, ctx)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	// Return response
    64  	resp := &api.RegistrationResponseNet{
    65  		RegistrationResponse: api.RegistrationResponse{Secret: secret},
    66  	}
    67  	return resp, nil
    68  }
    69  
    70  // RegisterUser will register a user and return the secret
    71  func registerUser(req *api.RegistrationRequest, registrar string, ca *CA, ctx ServerRequestContext) (string, error) {
    72  	var err error
    73  	var registrarUser user.User
    74  
    75  	registrarUser, err = ctx.GetCaller()
    76  	if err != nil {
    77  		return "", err
    78  	}
    79  
    80  	normalizeRegistrationRequest(req, registrarUser)
    81  
    82  	// Check the permissions of member named 'registrar' to perform this registration
    83  	err = canRegister(registrarUser, req, ca, ctx)
    84  	if err != nil {
    85  		log.Debugf("Registrar is not allowed to register user '%s': %s", req.Name, err)
    86  		return "", caerrors.NewAuthorizationErr(caerrors.ErrRegistrarRegAuth, "Registration of '%s' failed", req.Name)
    87  	}
    88  
    89  	secret, err := registerUserID(req, ca)
    90  	if err != nil {
    91  		return "", errors.WithMessagef(err, "Registration of '%s' failed", req.Name)
    92  	}
    93  	// Set the location header to the URI of the identity that was created by the registration request
    94  	ctx.GetResp().Header().Set("Location", fmt.Sprintf("%sidentities/%s", apiPathPrefix, url.PathEscape(req.Name)))
    95  	return secret, nil
    96  }
    97  
    98  func normalizeRegistrationRequest(req *api.RegistrationRequest, registrar user.User) {
    99  	if req.Affiliation == "" {
   100  		registrarAff := user.GetAffiliation(registrar)
   101  		log.Debugf("No affiliation provided in registration request, will default to using registrar's affiliation of '%s'", registrarAff)
   102  		req.Affiliation = registrarAff
   103  	} else if req.Affiliation == "." {
   104  		// Affiliation request of '.' signifies request for root affiliation
   105  		req.Affiliation = ""
   106  	}
   107  
   108  	if req.Type == "" {
   109  		req.Type = registrar.GetType()
   110  	}
   111  }
   112  
   113  func validateAffiliation(req *api.RegistrationRequest, ca *CA, ctx ServerRequestContext) error {
   114  	affiliation := req.Affiliation
   115  	log.Debugf("Validating affiliation: %s", affiliation)
   116  	err := ctx.ContainsAffiliation(affiliation)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	// If requested affiliation is for root then don't need to do lookup in affiliation's table
   122  	if affiliation == "" {
   123  		return nil
   124  	}
   125  
   126  	_, err = ca.registry.GetAffiliation(affiliation)
   127  	if err != nil {
   128  		return caerrors.NewHTTPErr(404, caerrors.ErrGettingAffiliation, "Failed getting affiliation '%s': %s", affiliation, err)
   129  	}
   130  
   131  	return nil
   132  }
   133  
   134  // registerUserID registers a new user and its enrollmentID, role and state
   135  func registerUserID(req *api.RegistrationRequest, ca *CA) (string, error) {
   136  	log.Debugf("Registering user id: %s\n", req.Name)
   137  	var err error
   138  
   139  	if req.Secret == "" {
   140  		req.Secret = util.RandomString(12)
   141  	}
   142  
   143  	req.MaxEnrollments, err = getMaxEnrollments(req.MaxEnrollments, ca.Config.Registry.MaxEnrollments)
   144  	if err != nil {
   145  		return "", err
   146  	}
   147  
   148  	// Add attributes containing the enrollment ID, type, and affiliation if not
   149  	// already defined
   150  	addAttributeToRequest(attr.EnrollmentID, req.Name, &req.Attributes)
   151  	addAttributeToRequest(attr.Type, req.Type, &req.Attributes)
   152  	addAttributeToRequest(attr.Affiliation, req.Affiliation, &req.Attributes)
   153  
   154  	insert := user.Info{
   155  		Name:           req.Name,
   156  		Pass:           req.Secret,
   157  		Type:           req.Type,
   158  		Affiliation:    req.Affiliation,
   159  		Attributes:     req.Attributes,
   160  		MaxEnrollments: req.MaxEnrollments,
   161  		Level:          ca.server.levels.Identity,
   162  	}
   163  
   164  	registry := ca.registry
   165  
   166  	_, err = registry.GetUser(req.Name, nil)
   167  	if err == nil {
   168  		return "", caerrors.NewHTTPErr(409, caerrors.ErrDupIdentityReg, "Identity '%s' is already registered", req.Name)
   169  	}
   170  
   171  	err = registry.InsertUser(&insert)
   172  	if err != nil {
   173  		return "", err
   174  	}
   175  
   176  	return req.Secret, nil
   177  }
   178  
   179  func canRegister(registrar user.User, req *api.RegistrationRequest, ca *CA, ctx ServerRequestContext) error {
   180  	log.Debugf("canRegister - Check to see if user '%s' can register", registrar.GetName())
   181  
   182  	err := ctx.CanActOnType(req.Type)
   183  	if err != nil {
   184  		return err
   185  	}
   186  	// Check that the affiliation requested is of the appropriate level
   187  	err = validateAffiliation(req, ca, ctx)
   188  	if err != nil {
   189  		return errors.WithMessagef(err, "Registration of '%s' failed in affiliation validation", req.Name)
   190  	}
   191  
   192  	err = attr.CanRegisterRequestedAttributes(req.Attributes, nil, registrar)
   193  	if err != nil {
   194  		return caerrors.NewAuthorizationErr(caerrors.ErrRegAttrAuth, "Failed to register attribute: %s", err)
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  // Add an attribute to the registration request if not already found.
   201  func addAttributeToRequest(name, value string, attributes *[]api.Attribute) {
   202  	*attributes = append(*attributes, api.Attribute{Name: name, Value: value, ECert: true})
   203  }