diff --git a/api/pkg/apis/v1alpha1/managers/margo/device.go b/api/pkg/apis/v1alpha1/managers/margo/device.go index f66e556a..7ef504af 100644 --- a/api/pkg/apis/v1alpha1/managers/margo/device.go +++ b/api/pkg/apis/v1alpha1/managers/margo/device.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "math/rand/v2" + "os" "strings" "time" @@ -692,3 +693,13 @@ func (s *DeviceManager) GetDeviceClientUsingId(ctx context.Context, clientId str return device, nil } + +func (s *DeviceManager) GetServerCA(ctx context.Context) ([]byte, error) { + // review: this function is not suitable for DeviceManager, it should be kept separately as settings in the vendor itself + serverCAPath, exists := s.Config.Properties["serverCAPath"] + if !exists || serverCAPath == "" { + return nil, fmt.Errorf("serverCAPath property is empty in the config") + } + + return os.ReadFile(serverCAPath) +} diff --git a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go index bc7c6c7b..f48f3052 100644 --- a/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go +++ b/api/pkg/apis/v1alpha1/vendors/margo/device-agent-vendor.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/base64" "encoding/json" "fmt" "io" @@ -148,6 +149,13 @@ func (self *DeviceAgentVendor) GetEndpoints() []v1alpha2.Endpoint { Handler: self.onDeploymentStatusUpdate, Parameters: []string{"clientId?", "deploymentId?"}, }, + { + Methods: []string{fasthttp.MethodGet}, + Route: route + "/onboarding/certificate", + Version: self.Version, + Handler: self.downloadServerCA, + Parameters: []string{}, + }, } } @@ -905,6 +913,28 @@ func (self *DeviceAgentVendor) verifyRequestSignature(ctx context.Context, clien return true, nil } +func (self *DeviceAgentVendor) downloadServerCA(request v1alpha2.COARequest) v1alpha2.COAResponse { + pCtx, span := observability.StartSpan("Margo Device Vendor", + request.Context, + &map[string]string{ + "method": "downloadServerCA", + "route": request.Route, + "verb": request.Method, + }) + defer span.End() + deviceVendorLogger.InfofCtx(pCtx, "V (MargoDeviceVendor): downloadServerCA, method: %s", request.Method) + + ca, err := self.DeviceManager.GetServerCA(pCtx) + if err != nil { + return createErrorResponse2(deviceVendorLogger, span, fmt.Errorf("Unable to find Server CA"), "Server CA download failed", v1alpha2.InternalError) + } + return v1alpha2.COAResponse{ + State: v1alpha2.OK, + Body: []byte(`{"certificate": "` + base64.RawURLEncoding.EncodeToString(ca) + `"}`), + ContentType: "application/json", + } +} + // Create a utility function for consistent header parsing func ParseRequestHeaders(ctx context.Context) (map[string]string, error) { headers := make(map[string]string) diff --git a/api/symphony-api-margo.json b/api/symphony-api-margo.json index 1b01db73..119b49b6 100644 --- a/api/symphony-api-margo.json +++ b/api/symphony-api-margo.json @@ -741,7 +741,8 @@ "type": "managers.margo.device", "properties": { "providers.persistentstate": "redis-state", - "singleton": "true" + "singleton": "true", + "serverCAPath": "./certificates/ca-cert.pem" }, "providers": { "redis-state": {