Skip to content

Commit

Permalink
feat: added get certificates api
Browse files Browse the repository at this point in the history
Co-authored-by: madhavilosetty-intel <madhavilosetty-intel@users.noreply.github.com>
  • Loading branch information
2 people authored and rjbrache committed Jun 12, 2024
1 parent f603c26 commit 3d2b76b
Show file tree
Hide file tree
Showing 11 changed files with 1,391 additions and 15 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/gin-contrib/cors v1.7.2
github.com/gin-gonic/gin v1.10.0
github.com/golang-migrate/migrate/v4 v4.17.1
github.com/gorilla/websocket v1.5.1
github.com/gorilla/websocket v1.5.2
github.com/ilyakaznacheev/cleanenv v1.5.0
github.com/jackc/pgx/v5 v5.6.0
github.com/prometheus/client_golang v1.19.1
Expand Down Expand Up @@ -59,7 +59,7 @@ require (
github.com/go-openapi/swag v0.22.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0
github.com/go-playground/validator/v10 v10.22.0
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/uuid v1.6.0
github.com/hashicorp/errwrap v1.1.0 // indirect
Expand All @@ -78,7 +78,7 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 v2.7.1
github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 v2.8.0
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao=
github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
Expand All @@ -71,8 +71,8 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/gorilla/websocket v1.5.2 h1:qoW6V1GT3aZxybsbC6oLnailWnB+qTMVwMreOso9XUw=
github.com/gorilla/websocket v1.5.2/go.mod h1:0n9H61RBAcf5/38py2MCYbxzPIY9rOkpvvMT24Rqs30=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -136,8 +136,8 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 v2.7.1 h1:NTSZCy/fAd0susl18MyLxDM3WHAa9iCRMWS4WtR3gaA=
github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 v2.7.1/go.mod h1:jdnbKqKRs4AYG8H7RZF/ss45D93+CfGY7m8esTTbDTs=
github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 v2.8.0 h1:4HlR1Mr1KELUPii2IXJ/WDS/j8bVA8aCjc30nJFF1rY=
github.com/open-amt-cloud-toolkit/go-wsman-messages/v2 v2.8.0/go.mod h1:Z/zRJrraqGMxVTAqVRKE2QgeySouZP2vwkCy9u8UYb0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
Expand Down
14 changes: 14 additions & 0 deletions internal/controller/http/v1/devicemanagement.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func newAmtRoutes(handler *gin.RouterGroup, d devices.Feature, l logger.Interfac
h.POST("userConsentCode/:guid", r.sendConsentCode)

h.GET("networkSettings/:guid", r.getNetworkSettings)
h.GET("certificates/:guid", r.getCertificates)
}
}

Expand Down Expand Up @@ -357,3 +358,16 @@ func (r *deviceManagementRoutes) getNetworkSettings(c *gin.Context) {

c.JSON(http.StatusOK, network)
}

func (r *deviceManagementRoutes) getCertificates(c *gin.Context) {
guid := c.Param("guid")

certs, err := r.d.GetCertificates(c.Request.Context(), guid)
if err != nil {
errorResponse(c, err)

return
}

c.JSON(http.StatusOK, certs)
}
37 changes: 34 additions & 3 deletions internal/controller/http/v1/devicemanagement_mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions internal/controller/http/v1/devicemanagement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"testing"
Expand All @@ -19,6 +20,8 @@ import (
"github.com/open-amt-cloud-toolkit/console/pkg/logger"
)

var ErrGeneral = errors.New("general error")

func deviceManagementTest(t *testing.T) (*MockDeviceManagementFeature, *gin.Engine) {
t.Helper()

Expand Down Expand Up @@ -194,6 +197,28 @@ func TestGetNetworkSettings(t *testing.T) {
expectedCode: http.StatusOK,
response: map[string]interface{}{"": ""},
},
{
name: "getCertificates - successful retrieval",
url: "/api/v1/amt/certificates/valid-guid",
method: http.MethodGet,
mock: func(m *MockDeviceManagementFeature) {
m.EXPECT().GetCertificates(context.Background(), "valid-guid").
Return(map[string]interface{}{"": ""}, nil)
},
expectedCode: http.StatusOK,
response: map[string]interface{}{"": ""},
},
{
name: "getCertificates - failed retrieval",
url: "/api/v1/amt/certificates/valid-guid",
method: http.MethodGet,
mock: func(m *MockDeviceManagementFeature) {
m.EXPECT().GetCertificates(context.Background(), "valid-guid").
Return(nil, ErrGeneral)
},
expectedCode: http.StatusInternalServerError,
response: nil,
},
}

for _, tc := range tests {
Expand Down
174 changes: 174 additions & 0 deletions internal/usecase/devices/certificates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package devices

import (
"context"
"reflect"
"strings"

"github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/amt/publickey"
"github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/amt/publicprivate"
"github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/cim/concrete"
"github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/cim/credential"

"github.com/open-amt-cloud-toolkit/console/internal/usecase/devices/wsman"
)

const (
TypeWireless string = "Wireless"
TypeTLS string = "TLS"
TypeWired string = "Wired"
)

type SecuritySettings struct {
ProfileAssociation []ProfileAssociation `json:"ProfileAssociation"`
Certificates interface{} `json:"Certificates"`
Keys interface{} `json:"PublicKeys"`
}

type ProfileAssociation struct {
Type string `json:"Type"`
ProfileID string `json:"ProfileID"`
RootCertificate interface{} `json:"RootCertificate,omitempty"`
ClientCertificate interface{} `json:"ClientCertificate,omitempty"`
Key interface{} `json:"PublicKey,omitempty"`
}

func processConcreteDependencies(certificateHandle string, profileAssociation *ProfileAssociation, dependancyItems []concrete.ConcreteDependency, keyPairItems []publicprivate.RefinedPublicPrivateKeyPair) {
for x := range dependancyItems {
if dependancyItems[x].Antecedent.ReferenceParameters.SelectorSet.Selectors[0].Text != certificateHandle {
continue
}

keyHandle := dependancyItems[x].Dependent.ReferenceParameters.SelectorSet.Selectors[0].Text

for i := range keyPairItems {
if keyPairItems[i].InstanceID == keyHandle {
profileAssociation.Key = keyPairItems[i]

break
}
}
}
}

func buildCertificateAssociations(profileAssociation ProfileAssociation, securitySettings *SecuritySettings) {
var publicKeyHandle string

// If a client cert, update the associated public key w/ the cert's handle
if profileAssociation.ClientCertificate != nil {
// Loop thru public keys looking for the one that matches the current profileAssociation's key
for i, existingKeyPair := range securitySettings.Keys.(publicprivate.RefinedPullResponse).PublicPrivateKeyPairItems {
// If found update that key with the profileAssociation's certificate handle
if existingKeyPair.InstanceID == profileAssociation.Key.(publicprivate.RefinedPublicPrivateKeyPair).InstanceID {
securitySettings.Keys.(publicprivate.RefinedPullResponse).PublicPrivateKeyPairItems[i].CertificateHandle = profileAssociation.ClientCertificate.(publickey.RefinedPublicKeyCertificateResponse).InstanceID
// save this public key handle since we know it pairs with the profileAssociation's certificate
publicKeyHandle = securitySettings.Keys.(publicprivate.RefinedPullResponse).PublicPrivateKeyPairItems[i].InstanceID

break
}
}
}

// Loop thru certificates looking for the one that matches the current profileAssociation's certificate and append profile name
for i := range securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems {
if (profileAssociation.ClientCertificate != nil && securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems[i].InstanceID == profileAssociation.ClientCertificate.(publickey.RefinedPublicKeyCertificateResponse).InstanceID) ||
(profileAssociation.RootCertificate != nil && securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems[i].InstanceID == profileAssociation.RootCertificate.(publickey.RefinedPublicKeyCertificateResponse).InstanceID) {
// if client cert found, associate the previously found key handle with it
if !securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems[i].TrustedRootCertificate {
securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems[i].PublicKeyHandle = publicKeyHandle
}

securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems[i].AssociatedProfiles = append(securitySettings.Certificates.(publickey.RefinedPullResponse).PublicKeyCertificateItems[i].AssociatedProfiles, profileAssociation.ProfileID)

break
}
}
}

func buildProfileAssociations(certificateHandle string, profileAssociation *ProfileAssociation, response wsman.Certificates, securitySettings *SecuritySettings) {
isNewProfileAssociation := true

for idx := range response.PublicKeyCertificateResponse.PublicKeyCertificateItems {
if response.PublicKeyCertificateResponse.PublicKeyCertificateItems[idx].InstanceID != certificateHandle {
continue
}

if response.PublicKeyCertificateResponse.PublicKeyCertificateItems[idx].TrustedRootCertificate {
profileAssociation.RootCertificate = response.PublicKeyCertificateResponse.PublicKeyCertificateItems[idx]

continue
}

profileAssociation.ClientCertificate = response.PublicKeyCertificateResponse.PublicKeyCertificateItems[idx]

processConcreteDependencies(certificateHandle, profileAssociation, response.ConcreteDependencyResponse.Items, response.PublicPrivateKeyPairResponse.PublicPrivateKeyPairItems)
}

// Check if the certificate is already in the list
for idx := range securitySettings.ProfileAssociation {
if !(securitySettings.ProfileAssociation[idx].ProfileID == profileAssociation.ProfileID) {
continue
}

if profileAssociation.RootCertificate != nil {
securitySettings.ProfileAssociation[idx].RootCertificate = profileAssociation.RootCertificate

Check warning on line 114 in internal/usecase/devices/certificates.go

View check run for this annotation

Codecov / codecov/patch

internal/usecase/devices/certificates.go#L114

Added line #L114 was not covered by tests
}

if profileAssociation.ClientCertificate != nil {
securitySettings.ProfileAssociation[idx].ClientCertificate = profileAssociation.ClientCertificate
}

if profileAssociation.Key != nil {
securitySettings.ProfileAssociation[idx].Key = profileAssociation.Key
}

isNewProfileAssociation = false

break
}

// If the profile is not in the list, add it
if isNewProfileAssociation {
securitySettings.ProfileAssociation = append(securitySettings.ProfileAssociation, *profileAssociation)
}
}

func processCertificates(contextItems []credential.CredentialContext, response wsman.Certificates, profileType string, securitySettings *SecuritySettings) {
for idx := range contextItems {
var profileAssociation ProfileAssociation

profileAssociation.Type = profileType
profileAssociation.ProfileID = strings.TrimPrefix(contextItems[idx].ElementProvidingContext.ReferenceParameters.SelectorSet.Selectors[0].Text, "Intel(r) AMT:IEEE 802.1x Settings ")
certificateHandle := contextItems[idx].ElementInContext.ReferenceParameters.SelectorSet.Selectors[0].Text

buildProfileAssociations(certificateHandle, &profileAssociation, response, securitySettings)
buildCertificateAssociations(profileAssociation, securitySettings)
}
}

func (uc *UseCase) GetCertificates(c context.Context, guid string) (interface{}, error) {
item, err := uc.GetByID(c, guid, "")
if err != nil || item.GUID == "" {
return nil, err
}

uc.device.SetupWsmanClient(*item, false, true)

response, err := uc.device.GetCertificates()
if err != nil {
return nil, err
}

securitySettings := SecuritySettings{
Certificates: response.PublicKeyCertificateResponse,
Keys: response.PublicPrivateKeyPairResponse,
}

if !reflect.DeepEqual(response.CIMCredentialContextResponse, credential.PullResponse{}) {
processCertificates(response.CIMCredentialContextResponse.Items.CredentialContextTLS, response, TypeTLS, &securitySettings)
processCertificates(response.CIMCredentialContextResponse.Items.CredentialContext, response, TypeWireless, &securitySettings)
processCertificates(response.CIMCredentialContextResponse.Items.CredentialContext8021x, response, TypeWired, &securitySettings)
}

return securitySettings, nil
}
Loading

0 comments on commit 3d2b76b

Please sign in to comment.