github.com/dddengyunjie/fabric-ca@v0.0.0-20190606043049-92df60ae2f0f/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 "github.com/pkg/errors" 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 }