Skip to content

Commit

Permalink
Merge pull request #79 from kaleido-io/identities
Browse files Browse the repository at this point in the history
Complete identities endpoints
  • Loading branch information
jimthematrix authored Feb 19, 2022
2 parents 310d3cc + e87dd8f commit a3ade51
Show file tree
Hide file tree
Showing 9 changed files with 944 additions and 346 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ mocks: mockery ${GOFILES}
${MOCKERY} --case underscore --dir internal/kvstore --name KVStore --output mocks/kvstore --outpkg mockkvstore
${MOCKERY} --case underscore --dir internal/kvstore --name KVIterator --output mocks/kvstore --outpkg mockkvstore
${MOCKERY} --case underscore --dir internal/rest/async --name AsyncDispatcher --output mocks/rest/async --outpkg mockasync
${MOCKERY} --case underscore --dir internal/rest/identity --name IdentityClient --output mocks/rest/identity --outpkg mockidentity
${MOCKERY} --case underscore --dir internal/rest/receipt --name ReceiptStore --output mocks/rest/receipt --outpkg mockreceipt
${MOCKERY} --case underscore --dir internal/rest/receipt/api --name ReceiptStorePersistence --output mocks/rest/receipt/api --outpkg mockreceiptapi
${MOCKERY} --case underscore --dir internal/rest/sync --name SyncDispatcher --output mocks/rest/sync --outpkg mocksync
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8
github.com/golang/protobuf v1.5.2
github.com/google/certificate-transparency-go v1.1.1 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.4
Expand Down Expand Up @@ -40,10 +41,10 @@ require (
go.etcd.io/bbolt v1.3.5 // indirect
go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 // indirect
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e // indirect
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da // indirect
golang.org/x/tools v0.1.9 // indirect
gopkg.in/yaml.v2 v2.4.0
sigs.k8s.io/yaml v1.2.0 // indirect
)
Expand Down
11 changes: 6 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
Expand Down Expand Up @@ -1006,8 +1007,8 @@ golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down Expand Up @@ -1093,8 +1094,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da h1:Tno72dYE94v/7SyyIj9iBsc7OOjFu2PyNcl7yxxeZD8=
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
139 changes: 137 additions & 2 deletions internal/fabric/client/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ func (w *idClientWrapper) Register(res http.ResponseWriter, req *http.Request, p
CAName: regreq.CAName,
Secret: regreq.Secret,
}
if regreq.Attributes != nil {
rr.Attributes = []mspApi.Attribute{}
for key, value := range regreq.Attributes {
rr.Attributes = append(rr.Attributes, mspApi.Attribute{Name: key, Value: value})
}
}

secret, err := w.caClient.Register(rr)
if err != nil {
log.Errorf("Failed to register user %s. %s", regreq.Name, err)
Expand All @@ -146,6 +153,43 @@ func (w *idClientWrapper) Register(res http.ResponseWriter, req *http.Request, p
return &result, nil
}

func (w *idClientWrapper) Modify(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*identity.RegisterResponse, *restutil.RestError) {
username := params.ByName("username")
regreq := identity.Identity{}
decoder := json.NewDecoder(req.Body)
decoder.DisallowUnknownFields()
err := decoder.Decode(&regreq)
if err != nil {
return nil, restutil.NewRestError(fmt.Sprintf("failed to decode JSON payload: %s", err), 400)
}

rr := &mspApi.IdentityRequest{
ID: username,
Type: regreq.Type,
MaxEnrollments: regreq.MaxEnrollments,
Affiliation: regreq.Affiliation,
CAName: regreq.CAName,
Secret: regreq.Secret,
}
if regreq.Attributes != nil {
rr.Attributes = []mspApi.Attribute{}
for key, value := range regreq.Attributes {
rr.Attributes = append(rr.Attributes, mspApi.Attribute{Name: key, Value: value})
}
}

_, err = w.caClient.ModifyIdentity(rr)
if err != nil {
log.Errorf("Failed to modify user %s. %s", regreq.Name, err)
return nil, restutil.NewRestError(err.Error())
}

result := identity.RegisterResponse{
Name: rr.ID,
}
return &result, nil
}

func (w *idClientWrapper) Enroll(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*identity.IdentityResponse, *restutil.RestError) {
username := params.ByName("username")
enreq := identity.EnrollRequest{}
Expand All @@ -165,6 +209,12 @@ func (w *idClientWrapper) Enroll(res http.ResponseWriter, req *http.Request, par
CAName: enreq.CAName,
Profile: enreq.Profile,
}
if enreq.AttrReqs != nil {
input.AttrReqs = []*mspApi.AttributeRequest{}
for attr, optional := range enreq.AttrReqs {
input.AttrReqs = append(input.AttrReqs, &mspApi.AttributeRequest{Name: attr, Optional: optional})
}
}

err = w.caClient.Enroll(&input)
if err != nil {
Expand All @@ -179,6 +229,79 @@ func (w *idClientWrapper) Enroll(res http.ResponseWriter, req *http.Request, par
return &result, nil
}

func (w *idClientWrapper) Reenroll(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*identity.IdentityResponse, *restutil.RestError) {
username := params.ByName("username")
enreq := identity.EnrollRequest{}
decoder := json.NewDecoder(req.Body)
decoder.DisallowUnknownFields()
err := decoder.Decode(&enreq)
if err != nil {
return nil, restutil.NewRestError(fmt.Sprintf("failed to decode JSON payload: %s", err), 400)
}

input := mspApi.ReenrollmentRequest{
Name: username,
CAName: enreq.CAName,
Profile: enreq.Profile,
}
if enreq.AttrReqs != nil {
input.AttrReqs = []*mspApi.AttributeRequest{}
for attr, optional := range enreq.AttrReqs {
input.AttrReqs = append(input.AttrReqs, &mspApi.AttributeRequest{Name: attr, Optional: optional})
}
}

err = w.caClient.Reenroll(&input)
if err != nil {
log.Errorf("Failed to re-enroll user %s. %s", enreq.Name, err)
return nil, restutil.NewRestError(err.Error())
}

result := identity.IdentityResponse{
Name: enreq.Name,
Success: true,
}
return &result, nil
}

func (w *idClientWrapper) Revoke(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*identity.RevokeResponse, *restutil.RestError) {
username := params.ByName("username")
enreq := identity.RevokeRequest{}
decoder := json.NewDecoder(req.Body)
decoder.DisallowUnknownFields()
err := decoder.Decode(&enreq)
if err != nil {
return nil, restutil.NewRestError(fmt.Sprintf("failed to decode JSON payload: %s", err), 400)
}

input := mspApi.RevocationRequest{
Name: username,
CAName: enreq.CAName,
Reason: enreq.Reason,
GenCRL: enreq.GenCRL,
}

response, err := w.caClient.Revoke(&input)
if err != nil {
log.Errorf("Failed to revoke certificate for user %s. %s", enreq.Name, err)
return nil, restutil.NewRestError(err.Error())
}

result := identity.RevokeResponse{
CRL: string(response.CRL),
}
if len(response.RevokedCerts) > 0 {
result.RevokedCerts = []map[string]string{}
for _, cert := range response.RevokedCerts {
entry := map[string]string{}
entry["aki"] = cert.AKI
entry["serial"] = cert.Serial
result.RevokedCerts = append(result.RevokedCerts, entry)
}
}
return &result, nil
}

func (w *idClientWrapper) List(res http.ResponseWriter, req *http.Request, params httprouter.Params) ([]*identity.Identity, *restutil.RestError) {
result, err := w.caClient.GetAllIdentities(params.ByName("caname"))
if err != nil {
Expand All @@ -192,6 +315,12 @@ func (w *idClientWrapper) List(res http.ResponseWriter, req *http.Request, param
newId.CAName = v.CAName
newId.Type = v.Type
newId.Affiliation = v.Affiliation
if len(v.Attributes) > 0 {
newId.Attributes = make(map[string]string, len(v.Attributes))
for _, attr := range v.Attributes {
newId.Attributes[attr.Name] = attr.Value
}
}
ret[i] = &newId
}
return ret, nil
Expand All @@ -209,6 +338,12 @@ func (w *idClientWrapper) Get(res http.ResponseWriter, req *http.Request, params
newId.CAName = result.CAName
newId.Type = result.Type
newId.Affiliation = result.Affiliation
if len(result.Attributes) > 0 {
newId.Attributes = make(map[string]string, len(result.Attributes))
for _, attr := range result.Attributes {
newId.Attributes[attr.Name] = attr.Value
}
}

// the SDK identity manager does not persist the certificates
// we have to retrieve it from the identity manager
Expand All @@ -221,7 +356,7 @@ func (w *idClientWrapper) Get(res http.ResponseWriter, req *http.Request, params
ecert := si.EnrollmentCertificate()
mspId := si.Identifier().MSPID
newId.MSPID = mspId
newId.EnrollmentCert = ecert
newId.EnrollmentCert = string(ecert)
}
newId.Organization = w.identityConfig.Client().Organization

Expand All @@ -231,7 +366,7 @@ func (w *idClientWrapper) Get(res http.ResponseWriter, req *http.Request, params
return nil, restutil.NewRestError(err.Error(), 500)
}

newId.CACert = cacert
newId.CACert = string(cacert)
return &newId, nil
}

Expand Down
42 changes: 29 additions & 13 deletions internal/rest/identity/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ import (

type Identity struct {
RegisterResponse
MaxEnrollments int `json:"maxEnrollments"`
Type string `json:"type"`
Affiliation string `json:"affiliation"`
CAName string `json:"caname"`
Organization string `json:"organization,omitempty"`
MSPID string `json:"mspId,omitempty"`
EnrollmentCert []byte `json:"enrollmentCert,omitempty"`
CACert []byte `json:"caCert,omitempty"`
MaxEnrollments int `json:"maxEnrollments"`
Type string `json:"type"`
Affiliation string `json:"affiliation"`
Attributes map[string]string `json:"attributes"`
CAName string `json:"caname"`
Organization string `json:"organization,omitempty"`
MSPID string `json:"mspId,omitempty"`
EnrollmentCert string `json:"enrollmentCert,omitempty"`
CACert string `json:"caCert,omitempty"`
}

type RegisterResponse struct {
Expand All @@ -41,21 +42,36 @@ type RegisterResponse struct {
}

type EnrollRequest struct {
Name string `json:"name"`
Secret string `json:"secret"`
CAName string `json:"caname"`
Profile string `json:"profile"`
CSR string `json:"csr"`
Name string `json:"name"`
Secret string `json:"secret"`
CAName string `json:"caname"`
Profile string `json:"profile"`
AttrReqs map[string]bool `json:"attributes"`
}

type RevokeRequest struct {
Name string `json:"name"`
Reason string `json:"reason"`
CAName string `json:"caname"`
GenCRL bool `json:"generateCRL"`
}

type IdentityResponse struct {
Name string `json:"name"`
Success bool `json:"success"`
}

type RevokeResponse struct {
RevokedCerts []map[string]string `json:"revokedCerts"`
CRL string `json:"CRL"`
}

type IdentityClient interface {
Register(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*RegisterResponse, *restutil.RestError)
Modify(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*RegisterResponse, *restutil.RestError)
Enroll(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*IdentityResponse, *restutil.RestError)
Reenroll(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*IdentityResponse, *restutil.RestError)
Revoke(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*RevokeResponse, *restutil.RestError)
List(res http.ResponseWriter, req *http.Request, params httprouter.Params) ([]*Identity, *restutil.RestError)
Get(res http.ResponseWriter, req *http.Request, params httprouter.Params) (*Identity, *restutil.RestError)
}
Loading

0 comments on commit a3ade51

Please sign in to comment.