github.com/tw-bc-group/fabric-ca-gm@v0.0.0-20201218004200-3b690512bd5a/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/pkg/errors"
    15  	"github.com/tw-bc-group/fabric-ca-gm/api"
    16  	"github.com/tw-bc-group/fabric-ca-gm/lib/attr"
    17  	"github.com/tw-bc-group/fabric-ca-gm/lib/caerrors"
    18  	"github.com/tw-bc-group/fabric-ca-gm/lib/server/user"
    19  	"github.com/tw-bc-group/fabric-ca-gm/util"
    20  )
    21  
    22  func newRegisterEndpoint(s *Server) *serverEndpoint {
    23  	return &serverEndpoint{
    24  		Path:      "register",
    25  		Methods:   []string{"POST"},
    26  		Handler:   registerHandler,
    27  		Server:    s,
    28  		successRC: 201,
    29  	}
    30  }
    31  
    32  // Handle a register request
    33  func registerHandler(ctx *serverRequestContextImpl) (interface{}, error) {
    34  	ca, err := ctx.GetCA()
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  	return register(ctx, ca)
    39  }
    40  
    41  func register(ctx ServerRequestContext, ca *CA) (interface{}, error) {
    42  	// Read request body
    43  	var req api.RegistrationRequestNet
    44  	err := ctx.ReadBody(&req)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	// Authenticate
    49  	callerID, err := ctx.TokenAuthentication()
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	log.Debugf("Received registration request from %s: %v", callerID, &req)
    54  	if ctx.IsLDAPEnabled() {
    55  		return nil, caerrors.NewHTTPErr(403, caerrors.ErrInvalidLDAPAction, "Registration is not supported when using LDAP")
    56  	}
    57  	// Register User
    58  	secret, err := registerUser(&req.RegistrationRequest, callerID, ca, ctx)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	// Return response
    63  	resp := &api.RegistrationResponseNet{
    64  		RegistrationResponse: api.RegistrationResponse{Secret: secret},
    65  	}
    66  	return resp, nil
    67  }
    68  
    69  // RegisterUser will register a user and return the secret
    70  func registerUser(req *api.RegistrationRequest, registrar string, ca *CA, ctx ServerRequestContext) (string, error) {
    71  	var err error
    72  	var registrarUser user.User
    73  
    74  	registrarUser, err = ctx.GetCaller()
    75  	if err != nil {
    76  		return "", err
    77  	}
    78  
    79  	normalizeRegistrationRequest(req, registrarUser)
    80  
    81  	// Check the permissions of member named 'registrar' to perform this registration
    82  	err = canRegister(registrarUser, req, ca, ctx)
    83  	if err != nil {
    84  		log.Debugf("Registration of '%s' failed: %s", req.Name, err)
    85  		return "", err
    86  	}
    87  
    88  	secret, err := registerUserID(req, ca)
    89  
    90  	if err != nil {
    91  		return "", errors.WithMessage(err, fmt.Sprintf("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 errors.WithMessage(err, fmt.Sprintf("Failed getting affiliation '%s'", affiliation))
   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 "", errors.Errorf("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 fmt.Errorf("Registration of '%s' failed in affiliation validation: %s", req.Name, err)
   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  }