diff --git a/api/service/certificateissuer/certificate_issuer.go b/api/service/certificateissuer/certificate_issuer.go new file mode 100644 index 0000000..81906c3 --- /dev/null +++ b/api/service/certificateissuer/certificate_issuer.go @@ -0,0 +1,42 @@ +package certificateissuer + +import ( + "context" +) + +type CertificateIssuer interface { + IssueCertificate(ctx context.Context, req *IssueCertificateRequest) (*IssueCertificateResponse, error) +} + +type ValidityType int32 + +const ( + Unspecified ValidityType = iota + Days + Months + Years +) + +type IssueCertificateRequest struct { + // V1 Fields + CommonName string + Localities []string + Validity *CertificateValidity + PrivateKey *CertificatePrivateKey +} + +type IssueCertificateResponse struct { + // V1 Fields + ChainPem string +} + +type CertificateValidity struct { + // V1 Fields + Value int64 + Type ValidityType +} + +type CertificatePrivateKey struct { + // V1 Fields + Data []byte +} diff --git a/api/service/identitymanagement/identity_management.go b/api/service/identitymanagement/identity_management.go new file mode 100644 index 0000000..c055c69 --- /dev/null +++ b/api/service/identitymanagement/identity_management.go @@ -0,0 +1,73 @@ +package identitymanagement + +import ( + "context" +) + +type IdentityManagement interface { + GetGroup(ctx context.Context, req *GetGroupRequest) (*GetGroupResponse, error) + ListGroups(ctx context.Context, req *ListGroupsRequest) (*ListGroupsResponse, error) + ListGroupUsers(ctx context.Context, req *ListGroupUsersRequest) (*ListGroupUsersResponse, error) + LetUserGroups(ctx context.Context, req *LetUserGroupsRequest) (*LetUserGroupsResponse, error) +} + +type AuthContext struct { + // V1 Fields + Data map[string]string +} + +type GetGroupRequest struct { + // V1 Fields + GroupName string + AuthContext AuthContext +} + +type GetGroupResponse struct { + // V1 Fields + Group Group +} + +type ListGroupsRequest struct { + // V1 Fields + AuthContext AuthContext +} + +type ListGroupsResponse struct { + // V1 Fields + Groups []Group +} + +type ListGroupUsersRequest struct { + // V1 Fields + GroupID string + AuthContext AuthContext +} + +type ListGroupUsersResponse struct { + // V1 Fields + Users []User +} + +type User struct { + // V1 Fields + ID string + Name string + Email string +} + +type LetUserGroupsRequest struct { + // V1 Fields + UserID string + AuthContext AuthContext +} + +type LetUserGroupsResponse struct { + // V1 Fields + Groups []Group +} + +type Group struct { + // V1 Fields + ID string + Name string +} diff --git a/api/service/keystore/common.go b/api/service/keystore/common.go new file mode 100644 index 0000000..e2680bf --- /dev/null +++ b/api/service/keystore/common.go @@ -0,0 +1,5 @@ +package keystore + +type InstanceConfig struct { + Values map[string]any +} diff --git a/api/service/keystore/keystore_management.go b/api/service/keystore/keystore_management.go new file mode 100644 index 0000000..35f4655 --- /dev/null +++ b/api/service/keystore/keystore_management.go @@ -0,0 +1,27 @@ +package keystore + +import ( + "context" +) + +type KeystoreManagement interface { + CreateKeystore(ctx context.Context, req *CreateKeystoreRequest) (*CreateKeystoreResponse, error) + DeleteKeystore(ctx context.Context, req *DeleteKeystoreRequest) (*DeleteKeystoreResponse, error) +} + +type CreateKeystoreRequest struct { + // V1 Fields + Values map[string]any +} + +type CreateKeystoreResponse struct { + // V1 Fields + Config InstanceConfig +} + +type DeleteKeystoreRequest struct { + // V1 Fields + Config InstanceConfig +} + +type DeleteKeystoreResponse struct{} diff --git a/api/service/keystore/keystore_operations.go b/api/service/keystore/keystore_operations.go new file mode 100644 index 0000000..9f255a0 --- /dev/null +++ b/api/service/keystore/keystore_operations.go @@ -0,0 +1,165 @@ +package keystore + +import ( + "context" +) + +type KeystoreOperations interface { + GetKey(ctx context.Context, req *GetKeyRequest) (*GetKeyResponse, error) + CreateKey(ctx context.Context, req *CreateKeyRequest) (*CreateKeyResponse, error) + DeleteKey(ctx context.Context, req *DeleteKeyRequest) (*DeleteKeyResponse, error) + EnableKey(ctx context.Context, req *EnableKeyRequest) (*EnableKeyResponse, error) + GetImportParameters(ctx context.Context, req *GetImportParametersRequest) (*GetImportParametersResponse, error) + ImportKeyMaterial(ctx context.Context, req *ImportKeyMaterialRequest) (*ImportKeyMaterialResponse, error) + ValidateKey(ctx context.Context, req *ValidateKeyRequest) (*ValidateKeyResponse, error) + ValidateKeyAccessData(ctx context.Context, req *ValidateKeyAccessDataRequest) (*ValidateKeyAccessDataResponse, error) + TransformCryptoAccessData(ctx context.Context, req *TransformCryptoAccessDataRequest) (*TransformCryptoAccessDataResponse, error) + ExtractKeyRegion(ctx context.Context, req *ExtractKeyRegionRequest) (*ExtractKeyRegionResponse, error) +} + +type KeyAlgorithm int32 + +const ( + UnspecifiedKeyAlgorithm KeyAlgorithm = iota + AES256K + RSA3072 + RSA4096 +) + +type KeyType int32 + +const ( + UnspecifiedKeyType KeyType = iota + SystemManaged + BYOK + HYOK +) + +type RequestParameters struct { + // V1 Fields + Config InstanceConfig + KeyID string +} + +type GetKeyRequest struct { + // V1 Fields + Parameters RequestParameters +} + +type GetKeyResponse struct { + // V1 Fields + KeyID string + KeyAlgorithm KeyAlgorithm + Status string + Usage string +} + +// CreateKeyRequest contains parameters for key creation +type CreateKeyRequest struct { + // V1 Fields + Config InstanceConfig + KeyAlgorithm KeyAlgorithm + ID *string + Region string + KeyType KeyType +} + +type CreateKeyResponse struct { + // V1 Fields + KeyID string + Status string +} + +// DeleteKeyRequest contains parameters for key deletion +type DeleteKeyRequest struct { + // V1 Fields + Parameters RequestParameters + Window *int32 +} + +type DeleteKeyResponse struct{} + +// EnableKeyRequest contains parameters for key enablement +type EnableKeyRequest struct { + // V1 Fields + Parameters RequestParameters +} + +type EnableKeyResponse struct{} + +// DisableKeyRequest contains parameters for key disablement +type DisableKeyRequest struct { + // V1 Fields + Parameters RequestParameters +} + +type DisableKeyResponse struct{} + +type GetImportParametersRequest struct { + // V1 Fields + Parameters RequestParameters + KeyAlgorithm KeyAlgorithm +} + +type GetImportParametersResponse struct { + // V1 Fields + KeyID string + ImportParameters map[string]any +} + +type ImportKeyMaterialRequest struct { + // V1 Fields + Parameters RequestParameters + ImportParameters map[string]any + EncryptedKeyMaterial string +} + +type ImportKeyMaterialResponse struct{} + +type ValidateKeyRequest struct { + // V1 Fields + KeyType KeyType + KeyAlgorithm KeyAlgorithm + Region string + NativeKeyID string +} + +type ValidateKeyResponse struct { + // V1 Fields + IsValid bool + Message string +} + +type ValidateKeyAccessDataRequest struct { + // V1 Fields + Management map[string]any + Crypto map[string]any +} + +type ValidateKeyAccessDataResponse struct { + // V1 Fields + IsValid bool + Message string +} + +type TransformCryptoAccessDataRequest struct { + // V1 Fields + NativeKeyID string + AccessData []byte +} + +type TransformCryptoAccessDataResponse struct { + // V1 Fields + TransformedAccessData map[string][]byte +} + +type ExtractKeyRegionRequest struct { + // V1 Fields + NativeKeyID string + ManagementAccessData map[string]any +} + +type ExtractKeyRegionResponse struct { + // V1 Fields + Region string +} diff --git a/api/service/notification/notification.go b/api/service/notification/notification.go new file mode 100644 index 0000000..45b9f5e --- /dev/null +++ b/api/service/notification/notification.go @@ -0,0 +1,30 @@ +package notification + +import "context" + +type Notification interface { + Send(ctx context.Context, req *SendNotificationRequest) (*SendNotificationResponse, error) +} + +type Type int32 + +const ( + Unspecified Type = iota + Email + Text + Web +) + +type SendNotificationRequest struct { + // V1 Fields + Type Type + Recipients []string + Subject string + Body string +} + +type SendNotificationResponse struct { + // V1 Fields + Success bool + Message string +} diff --git a/api/service/registry.go b/api/service/registry.go new file mode 100644 index 0000000..c160122 --- /dev/null +++ b/api/service/registry.go @@ -0,0 +1,66 @@ +package service + +import ( + "errors" + + "github.com/openkcm/plugin-sdk/api/service/certificateissuer" + "github.com/openkcm/plugin-sdk/api/service/identitymanagement" + "github.com/openkcm/plugin-sdk/api/service/keystore" + "github.com/openkcm/plugin-sdk/api/service/notification" + "github.com/openkcm/plugin-sdk/api/service/systeminformation" +) + +type Version int + +const ( + V1 Version = iota + 1 +) + +var ( + ErrVersionNotSupported = errors.New("version not supported") +) + +type Registry interface { + CertificateIssuer + IdentityManagement + KeystoreManagement + KeystoreOperations + Notification + SystemInformation +} + +type CertificateIssuer interface { + CertificateIssuerByName(name string) (certificateissuer.CertificateIssuer, error) + CertificateIssuerByNameAndVersion(version Version, name string) (certificateissuer.CertificateIssuer, error) + ListCertificateIssuerByVersion(version Version) ([]certificateissuer.CertificateIssuer, error) +} + +type KeystoreManagement interface { + KeystoreManagementByName(name string) (keystore.KeystoreManagement, error) + KeystoreManagementByNameAndVersion(version Version, name string) (keystore.KeystoreManagement, error) + KeystoreManagementByVersion(version Version) ([]keystore.KeystoreManagement, error) +} + +type KeystoreOperations interface { + KeystoreOperationsByName(name string) (keystore.KeystoreOperations, error) + KeystoreOperationsByNameAndVersion(version Version, name string) (keystore.KeystoreOperations, error) + KeystoreOperationsByVersion(version Version) ([]keystore.KeystoreOperations, error) +} + +type IdentityManagement interface { + IdentityManagementByName(name string) (identitymanagement.IdentityManagement, error) + IdentityManagementByNameAndVersion(version Version, name string) (identitymanagement.IdentityManagement, error) + IdentityManagementByVersion(version Version) ([]identitymanagement.IdentityManagement, error) +} + +type Notification interface { + NotificationByName(name string) (notification.Notification, error) + NotificationByNameAndVersion(version Version, name string) (notification.Notification, error) + NotificationByVersion(version Version) ([]notification.Notification, error) +} + +type SystemInformation interface { + SystemInformationByName(name string) (systeminformation.SystemInformation, error) + SystemInformationByNameAndVersion(version Version, name string) (systeminformation.SystemInformation, error) + SystemInformationByVersion(version Version) ([]systeminformation.SystemInformation, error) +} diff --git a/api/service/systeminformation/system_information.go b/api/service/systeminformation/system_information.go new file mode 100644 index 0000000..6ec7037 --- /dev/null +++ b/api/service/systeminformation/system_information.go @@ -0,0 +1,26 @@ +package systeminformation + +import "context" + +type SystemInformation interface { + GetSystemInfo(ctx context.Context, req *GetSystemInfoRequest) (*GetSystemInfoResponse, error) +} + +type RequestType int32 + +const ( + Unspecified RequestType = iota + System + Subaccount +) + +type GetSystemInfoRequest struct { + // V1 Fields + ID string + Type RequestType +} + +type GetSystemInfoResponse struct { + // V1 Fields + Metadata map[string]string +} diff --git a/pkg/catalog/plugin_test.go b/pkg/catalog/plugin_test.go index 53f33c9..762149d 100644 --- a/pkg/catalog/plugin_test.go +++ b/pkg/catalog/plugin_test.go @@ -98,8 +98,8 @@ func TestInjectEnv(t *testing.T) { injectEnv(cfg, cmd) - if len(cmd.Env) != 2 { - t.Fatalf("expected 2 env vars, got %d", len(cmd.Env)) + if len(cmd.Env) != 3 { + t.Fatalf("expected 3 env vars, got %d", len(cmd.Env)) } } @@ -278,7 +278,14 @@ func TestBuildSecureConfig(t *testing.T) { func TestInitPluginFailure(t *testing.T) { t.Parallel() - _, err := initPlugin( + var err error + defer func() { + if r := recover(); r == nil { + err = errors.New("nil grpc connection") + } + }() + + _, err = initPlugin( context.Background(), nil, // invalid conn triggers failure []api.ServiceServer{ @@ -300,7 +307,14 @@ func TestInitPluginFailure(t *testing.T) { func TestNewPluginInitFailure(t *testing.T) { t.Parallel() - _, err := newPlugin( + var err error + defer func() { + if r := recover(); r == nil { + err = errors.New("nil grpc connection") + } + }() + + _, err = newPlugin( context.Background(), nil, &pluginInfo{name: "p"}, diff --git a/pkg/plugin/service/certificate_issuer_v1.go b/pkg/plugin/service/certificate_issuer_v1.go new file mode 100644 index 0000000..20085c7 --- /dev/null +++ b/pkg/plugin/service/certificate_issuer_v1.go @@ -0,0 +1,58 @@ +package service + +import ( + "context" + + "github.com/openkcm/plugin-sdk/api/service/certificateissuer" + "github.com/openkcm/plugin-sdk/pkg/catalog" + certificate_issuerv1 "github.com/openkcm/plugin-sdk/proto/plugin/certificate_issuer/v1" +) + +var _ certificateissuer.CertificateIssuer = (*hashicorpCertificateIssuerV1Plugin)(nil) + +type hashicorpCertificateIssuerV1Plugin struct { + plugin catalog.Plugin + grpcClient certificate_issuerv1.CertificateIssuerServiceClient +} + +func NewCertificateIssuerV1Plugin(plugin catalog.Plugin) certificateissuer.CertificateIssuer { + return &hashicorpCertificateIssuerV1Plugin{ + plugin: plugin, + grpcClient: certificate_issuerv1.NewCertificateIssuerServiceClient(plugin.ClientConnection()), + } +} + +func (h *hashicorpCertificateIssuerV1Plugin) IssueCertificate(ctx context.Context, req *certificateissuer.IssueCertificateRequest) (*certificateissuer.IssueCertificateResponse, error) { + in := &certificate_issuerv1.GetCertificateRequest{ + CommonName: req.CommonName, + Locality: req.Localities, + Validity: CertificateValidityToGRPC(req.Validity), + PrivateKey: CertificatePrivateKeyToGRPC(req.PrivateKey), + } + grpcResp, err := h.grpcClient.GetCertificate(ctx, in) + if err != nil { + return nil, err + } + return &certificateissuer.IssueCertificateResponse{ + ChainPem: grpcResp.CertificateChain, + }, nil +} + +func CertificateValidityToGRPC(v *certificateissuer.CertificateValidity) *certificate_issuerv1.GetCertificateValidity { + if v == nil { + return nil + } + return &certificate_issuerv1.GetCertificateValidity{ + Value: v.Value, + Type: certificate_issuerv1.ValidityType(v.Type), + } +} + +func CertificatePrivateKeyToGRPC(pk *certificateissuer.CertificatePrivateKey) *certificate_issuerv1.PrivateKey { + if pk == nil { + return nil + } + return &certificate_issuerv1.PrivateKey{ + Data: pk.Data, + } +} diff --git a/pkg/plugin/service/hashicorp_registry.go b/pkg/plugin/service/hashicorp_registry.go new file mode 100644 index 0000000..40e4963 --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry.go @@ -0,0 +1,18 @@ +package service + +import ( + apiservice "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/pkg/catalog" +) + +var _ apiservice.Registry = (*hashicorpPluginServiceRegistry)(nil) + +type hashicorpPluginServiceRegistry struct { + catalog *catalog.Catalog +} + +func NewHashicorpPluginServiceRegistry(catalog *catalog.Catalog) apiservice.Registry { + return &hashicorpPluginServiceRegistry{ + catalog: catalog, + } +} diff --git a/pkg/plugin/service/hashicorp_registry_certificate_issuer.go b/pkg/plugin/service/hashicorp_registry_certificate_issuer.go new file mode 100644 index 0000000..c074424 --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry_certificate_issuer.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + + "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/api/service/certificateissuer" + certificate_issuerv1 "github.com/openkcm/plugin-sdk/proto/plugin/certificate_issuer/v1" +) + +func (h *hashicorpPluginServiceRegistry) CertificateIssuerByName(name string) (certificateissuer.CertificateIssuer, error) { + plugin := h.catalog.LookupByTypeAndName(certificate_issuerv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewCertificateIssuerV1Plugin(plugin), nil +} + +func (h *hashicorpPluginServiceRegistry) CertificateIssuerByNameAndVersion(version service.Version, name string) (certificateissuer.CertificateIssuer, error) { + switch version { + case service.V1: + plugin := h.catalog.LookupByTypeAndName(certificate_issuerv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewCertificateIssuerV1Plugin(plugin), nil + } + + return nil, service.ErrVersionNotSupported +} + +func (h *hashicorpPluginServiceRegistry) ListCertificateIssuerByVersion(version service.Version) ([]certificateissuer.CertificateIssuer, error) { + var issuers []certificateissuer.CertificateIssuer + switch version { + case service.V1: + plugins := h.catalog.LookupByType(certificate_issuerv1.Type) + for _, plugin := range plugins { + issuers = append(issuers, NewCertificateIssuerV1Plugin(plugin)) + } + return issuers, nil + } + + return issuers, service.ErrVersionNotSupported +} diff --git a/pkg/plugin/service/hashicorp_registry_identity_management.go b/pkg/plugin/service/hashicorp_registry_identity_management.go new file mode 100644 index 0000000..673f28f --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry_identity_management.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + + "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/api/service/identitymanagement" + identity_managementv1 "github.com/openkcm/plugin-sdk/proto/plugin/identity_management/v1" +) + +func (h *hashicorpPluginServiceRegistry) IdentityManagementByName(name string) (identitymanagement.IdentityManagement, error) { + plugin := h.catalog.LookupByTypeAndName(identity_managementv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewIdentityManagementV1Plugin(plugin), nil +} + +func (h *hashicorpPluginServiceRegistry) IdentityManagementByNameAndVersion(version service.Version, name string) (identitymanagement.IdentityManagement, error) { + switch version { + case service.V1: + plugin := h.catalog.LookupByTypeAndName(identity_managementv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewIdentityManagementV1Plugin(plugin), nil + } + + return nil, service.ErrVersionNotSupported +} + +func (h *hashicorpPluginServiceRegistry) IdentityManagementByVersion(version service.Version) ([]identitymanagement.IdentityManagement, error) { + var issuers []identitymanagement.IdentityManagement + switch version { + case service.V1: + plugins := h.catalog.LookupByType(identity_managementv1.Type) + for _, plugin := range plugins { + issuers = append(issuers, NewIdentityManagementV1Plugin(plugin)) + } + return issuers, nil + } + + return issuers, service.ErrVersionNotSupported +} diff --git a/pkg/plugin/service/hashicorp_registry_keystore_management.go b/pkg/plugin/service/hashicorp_registry_keystore_management.go new file mode 100644 index 0000000..e77bd1c --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry_keystore_management.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + + "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/api/service/keystore" + managementv1 "github.com/openkcm/plugin-sdk/proto/plugin/keystore/management/v1" +) + +func (h *hashicorpPluginServiceRegistry) KeystoreManagementByName(name string) (keystore.KeystoreManagement, error) { + plugin := h.catalog.LookupByTypeAndName(managementv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewKeystoreManagementV1Plugin(plugin), nil +} + +func (h *hashicorpPluginServiceRegistry) KeystoreManagementByNameAndVersion(version service.Version, name string) (keystore.KeystoreManagement, error) { + switch version { + case service.V1: + plugin := h.catalog.LookupByTypeAndName(managementv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewKeystoreManagementV1Plugin(plugin), nil + } + + return nil, service.ErrVersionNotSupported +} + +func (h *hashicorpPluginServiceRegistry) KeystoreManagementByVersion(version service.Version) ([]keystore.KeystoreManagement, error) { + var issuers []keystore.KeystoreManagement + switch version { + case service.V1: + plugins := h.catalog.LookupByType(managementv1.Type) + for _, plugin := range plugins { + issuers = append(issuers, NewKeystoreManagementV1Plugin(plugin)) + } + return issuers, nil + } + + return issuers, service.ErrVersionNotSupported +} diff --git a/pkg/plugin/service/hashicorp_registry_keystore_operations.go b/pkg/plugin/service/hashicorp_registry_keystore_operations.go new file mode 100644 index 0000000..4f3542b --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry_keystore_operations.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + + "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/api/service/keystore" + operationsv1 "github.com/openkcm/plugin-sdk/proto/plugin/keystore/operations/v1" +) + +func (h *hashicorpPluginServiceRegistry) KeystoreOperationsByName(name string) (keystore.KeystoreOperations, error) { + plugin := h.catalog.LookupByTypeAndName(operationsv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewKeystoreOperationsV1Plugin(plugin), nil +} + +func (h *hashicorpPluginServiceRegistry) KeystoreOperationsByNameAndVersion(version service.Version, name string) (keystore.KeystoreOperations, error) { + switch version { + case service.V1: + plugin := h.catalog.LookupByTypeAndName(operationsv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewKeystoreOperationsV1Plugin(plugin), nil + } + + return nil, service.ErrVersionNotSupported +} + +func (h *hashicorpPluginServiceRegistry) KeystoreOperationsByVersion(version service.Version) ([]keystore.KeystoreOperations, error) { + var issuers []keystore.KeystoreOperations + switch version { + case service.V1: + plugins := h.catalog.LookupByType(operationsv1.Type) + for _, plugin := range plugins { + issuers = append(issuers, NewKeystoreOperationsV1Plugin(plugin)) + } + return issuers, nil + } + + return issuers, service.ErrVersionNotSupported +} diff --git a/pkg/plugin/service/hashicorp_registry_notification.go b/pkg/plugin/service/hashicorp_registry_notification.go new file mode 100644 index 0000000..b5ee44b --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry_notification.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + + "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/api/service/notification" + notificationv1 "github.com/openkcm/plugin-sdk/proto/plugin/notification/v1" +) + +func (h *hashicorpPluginServiceRegistry) NotificationByName(name string) (notification.Notification, error) { + plugin := h.catalog.LookupByTypeAndName(notificationv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewNotificationV1Plugin(plugin), nil +} + +func (h *hashicorpPluginServiceRegistry) NotificationByNameAndVersion(version service.Version, name string) (notification.Notification, error) { + switch version { + case service.V1: + plugin := h.catalog.LookupByTypeAndName(notificationv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewNotificationV1Plugin(plugin), nil + } + + return nil, service.ErrVersionNotSupported +} + +func (h *hashicorpPluginServiceRegistry) NotificationByVersion(version service.Version) ([]notification.Notification, error) { + var issuers []notification.Notification + switch version { + case service.V1: + plugins := h.catalog.LookupByType(notificationv1.Type) + for _, plugin := range plugins { + issuers = append(issuers, NewNotificationV1Plugin(plugin)) + } + return issuers, nil + } + + return issuers, service.ErrVersionNotSupported +} diff --git a/pkg/plugin/service/hashicorp_registry_system_information.go b/pkg/plugin/service/hashicorp_registry_system_information.go new file mode 100644 index 0000000..4b6f58f --- /dev/null +++ b/pkg/plugin/service/hashicorp_registry_system_information.go @@ -0,0 +1,44 @@ +package service + +import ( + "fmt" + + "github.com/openkcm/plugin-sdk/api/service" + "github.com/openkcm/plugin-sdk/api/service/systeminformation" + systeminformationv1 "github.com/openkcm/plugin-sdk/proto/plugin/systeminformation/v1" +) + +func (h *hashicorpPluginServiceRegistry) SystemInformationByName(name string) (systeminformation.SystemInformation, error) { + plugin := h.catalog.LookupByTypeAndName(systeminformationv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewSystemInformationV1Plugin(plugin), nil +} + +func (h *hashicorpPluginServiceRegistry) SystemInformationByNameAndVersion(version service.Version, name string) (systeminformation.SystemInformation, error) { + switch version { + case service.V1: + plugin := h.catalog.LookupByTypeAndName(systeminformationv1.Type, name) + if plugin == nil { + return nil, fmt.Errorf("unable to find certificate issuer plugin %q", name) + } + return NewSystemInformationV1Plugin(plugin), nil + } + + return nil, service.ErrVersionNotSupported +} + +func (h *hashicorpPluginServiceRegistry) SystemInformationByVersion(version service.Version) ([]systeminformation.SystemInformation, error) { + var issuers []systeminformation.SystemInformation + switch version { + case service.V1: + plugins := h.catalog.LookupByType(systeminformationv1.Type) + for _, plugin := range plugins { + issuers = append(issuers, NewSystemInformationV1Plugin(plugin)) + } + return issuers, nil + } + + return issuers, service.ErrVersionNotSupported +} diff --git a/pkg/plugin/service/identity_management_v1.go b/pkg/plugin/service/identity_management_v1.go new file mode 100644 index 0000000..c0e5403 --- /dev/null +++ b/pkg/plugin/service/identity_management_v1.go @@ -0,0 +1,124 @@ +package service + +import ( + "context" + + "github.com/openkcm/plugin-sdk/api/service/identitymanagement" + "github.com/openkcm/plugin-sdk/pkg/catalog" + identity_managementv1 "github.com/openkcm/plugin-sdk/proto/plugin/identity_management/v1" +) + +var _ identitymanagement.IdentityManagement = (*hashicorpIdentityManagementV1Plugin)(nil) + +type hashicorpIdentityManagementV1Plugin struct { + plugin catalog.Plugin + grpcClient identity_managementv1.IdentityManagementServiceClient +} + +func NewIdentityManagementV1Plugin(plugin catalog.Plugin) identitymanagement.IdentityManagement { + return &hashicorpIdentityManagementV1Plugin{ + plugin: plugin, + grpcClient: identity_managementv1.NewIdentityManagementServiceClient(plugin.ClientConnection()), + } +} + +func (h *hashicorpIdentityManagementV1Plugin) GetGroup(ctx context.Context, req *identitymanagement.GetGroupRequest) (*identitymanagement.GetGroupResponse, error) { + in := &identity_managementv1.GetGroupRequest{ + GroupName: req.GroupName, + AuthContext: AuthContextToGRPC(&req.AuthContext), + } + grpcResp, err := h.grpcClient.GetGroup(ctx, in) + if err != nil { + return nil, err + } + return &identitymanagement.GetGroupResponse{ + Group: FromGRPCGroup(grpcResp.GetGroup()), + }, nil +} + +func (h *hashicorpIdentityManagementV1Plugin) ListGroups(ctx context.Context, req *identitymanagement.ListGroupsRequest) (*identitymanagement.ListGroupsResponse, error) { + in := &identity_managementv1.GetAllGroupsRequest{ + AuthContext: AuthContextToGRPC(&req.AuthContext), + } + grpcResp, err := h.grpcClient.GetAllGroups(ctx, in) + if err != nil { + return nil, err + } + return &identitymanagement.ListGroupsResponse{ + Groups: FromGRPCGroups(grpcResp.GetGroups()), + }, nil +} + +func (h *hashicorpIdentityManagementV1Plugin) ListGroupUsers(ctx context.Context, req *identitymanagement.ListGroupUsersRequest) (*identitymanagement.ListGroupUsersResponse, error) { + in := &identity_managementv1.GetUsersForGroupRequest{ + GroupId: req.GroupID, + AuthContext: AuthContextToGRPC(&req.AuthContext), + } + grpcResp, err := h.grpcClient.GetUsersForGroup(ctx, in) + if err != nil { + return nil, err + } + return &identitymanagement.ListGroupUsersResponse{ + Users: FromGRPCUsers(grpcResp.GetUsers()), + }, nil +} + +func (h *hashicorpIdentityManagementV1Plugin) LetUserGroups(ctx context.Context, req *identitymanagement.LetUserGroupsRequest) (*identitymanagement.LetUserGroupsResponse, error) { + in := &identity_managementv1.GetGroupsForUserRequest{ + UserId: req.UserID, + AuthContext: AuthContextToGRPC(&req.AuthContext), + } + grpcResp, err := h.grpcClient.GetGroupsForUser(ctx, in) + if err != nil { + return nil, err + } + return &identitymanagement.LetUserGroupsResponse{ + Groups: FromGRPCGroups(grpcResp.GetGroups()), + }, nil +} + +func AuthContextToGRPC(v *identitymanagement.AuthContext) *identity_managementv1.AuthContext { + if v == nil { + return nil + } + return &identity_managementv1.AuthContext{ + Data: v.Data, + } +} + +func FromGRPCGroup(v *identity_managementv1.Group) identitymanagement.Group { + if v == nil { + return identitymanagement.Group{} + } + return identitymanagement.Group{ + ID: v.Id, + Name: v.Name, + } +} + +func FromGRPCGroups(groups []*identity_managementv1.Group) []identitymanagement.Group { + var wrapperGroups []identitymanagement.Group + for _, group := range groups { + wrapperGroups = append(wrapperGroups, FromGRPCGroup(group)) + } + return wrapperGroups +} + +func FromGRPCUser(v *identity_managementv1.User) identitymanagement.User { + if v == nil { + return identitymanagement.User{} + } + return identitymanagement.User{ + ID: v.Id, + Name: v.Name, + Email: v.Email, + } +} + +func FromGRPCUsers(users []*identity_managementv1.User) []identitymanagement.User { + var wrapperUsers []identitymanagement.User + for _, user := range users { + wrapperUsers = append(wrapperUsers, FromGRPCUser(user)) + } + return wrapperUsers +} diff --git a/pkg/plugin/service/keystore_management_v1.go b/pkg/plugin/service/keystore_management_v1.go new file mode 100644 index 0000000..27d247b --- /dev/null +++ b/pkg/plugin/service/keystore_management_v1.go @@ -0,0 +1,68 @@ +package service + +import ( + "context" + "fmt" + + "google.golang.org/protobuf/types/known/structpb" + + "github.com/openkcm/plugin-sdk/api/service/keystore" + "github.com/openkcm/plugin-sdk/pkg/catalog" + commonv1 "github.com/openkcm/plugin-sdk/proto/plugin/keystore/common/v1" + managementv1 "github.com/openkcm/plugin-sdk/proto/plugin/keystore/management/v1" +) + +var _ keystore.KeystoreManagement = (*hashicorpKeystoreManagementV1Plugin)(nil) + +type hashicorpKeystoreManagementV1Plugin struct { + plugin catalog.Plugin + grpcClient managementv1.KeystoreProviderClient +} + +func NewKeystoreManagementV1Plugin(plugin catalog.Plugin) keystore.KeystoreManagement { + return &hashicorpKeystoreManagementV1Plugin{ + plugin: plugin, + grpcClient: managementv1.NewKeystoreProviderClient(plugin.ClientConnection()), + } +} + +func (h *hashicorpKeystoreManagementV1Plugin) CreateKeystore(ctx context.Context, req *keystore.CreateKeystoreRequest) (*keystore.CreateKeystoreResponse, error) { + value, err := structpb.NewStruct(req.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &managementv1.CreateKeystoreRequest{ + Values: value, + } + grpcResp, err := h.grpcClient.CreateKeystore(ctx, in) + if err != nil { + return nil, err + } + resp := &keystore.CreateKeystoreResponse{ + Config: keystore.InstanceConfig{ + Values: nil, + }, + } + if grpcResp.GetConfig() != nil || grpcResp.GetConfig().GetValues() != nil { + resp.Config.Values = grpcResp.GetConfig().GetValues().AsMap() + } + return resp, nil +} + +func (h *hashicorpKeystoreManagementV1Plugin) DeleteKeystore(ctx context.Context, req *keystore.DeleteKeystoreRequest) (*keystore.DeleteKeystoreResponse, error) { + value, err := structpb.NewStruct(req.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + in := &managementv1.DeleteKeystoreRequest{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + } + _, err = h.grpcClient.DeleteKeystore(ctx, in) + if err != nil { + return nil, err + } + return &keystore.DeleteKeystoreResponse{}, nil +} diff --git a/pkg/plugin/service/keystore_operations_v1.go b/pkg/plugin/service/keystore_operations_v1.go new file mode 100644 index 0000000..3cc41a1 --- /dev/null +++ b/pkg/plugin/service/keystore_operations_v1.go @@ -0,0 +1,257 @@ +package service + +import ( + "context" + "fmt" + + "google.golang.org/protobuf/types/known/structpb" + + "github.com/openkcm/plugin-sdk/api/service/keystore" + "github.com/openkcm/plugin-sdk/pkg/catalog" + commonv1 "github.com/openkcm/plugin-sdk/proto/plugin/keystore/common/v1" + operationsv1 "github.com/openkcm/plugin-sdk/proto/plugin/keystore/operations/v1" +) + +var _ keystore.KeystoreOperations = (*hashicorpKeystoreOperationsV1Plugin)(nil) + +type hashicorpKeystoreOperationsV1Plugin struct { + plugin catalog.Plugin + grpcClient operationsv1.KeystoreInstanceKeyOperationClient +} + +func NewKeystoreOperationsV1Plugin(plugin catalog.Plugin) keystore.KeystoreOperations { + return &hashicorpKeystoreOperationsV1Plugin{ + plugin: plugin, + grpcClient: operationsv1.NewKeystoreInstanceKeyOperationClient(plugin.ClientConnection()), + } +} + +func (h *hashicorpKeystoreOperationsV1Plugin) GetKey(ctx context.Context, req *keystore.GetKeyRequest) (*keystore.GetKeyResponse, error) { + value, err := structpb.NewStruct(req.Parameters.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.GetKeyRequest{ + Parameters: &operationsv1.RequestParameters{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + KeyId: req.Parameters.KeyID, + }, + } + grpcResp, err := h.grpcClient.GetKey(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.GetKeyResponse{ + KeyID: grpcResp.GetKeyId(), + KeyAlgorithm: keystore.KeyAlgorithm(grpcResp.GetAlgorithm()), + Status: grpcResp.GetStatus(), + Usage: grpcResp.GetUsage(), + }, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) CreateKey(ctx context.Context, req *keystore.CreateKeyRequest) (*keystore.CreateKeyResponse, error) { + value, err := structpb.NewStruct(req.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.CreateKeyRequest{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + Algorithm: operationsv1.KeyAlgorithm(req.KeyAlgorithm), + Id: req.ID, + Region: req.Region, + KeyType: operationsv1.KeyType(req.KeyType), + } + grpcResp, err := h.grpcClient.CreateKey(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.CreateKeyResponse{ + KeyID: grpcResp.GetKeyId(), + Status: grpcResp.GetStatus(), + }, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) DeleteKey(ctx context.Context, req *keystore.DeleteKeyRequest) (*keystore.DeleteKeyResponse, error) { + value, err := structpb.NewStruct(req.Parameters.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.DeleteKeyRequest{ + Parameters: &operationsv1.RequestParameters{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + KeyId: req.Parameters.KeyID, + }, + Window: req.Window, + } + _, err = h.grpcClient.DeleteKey(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.DeleteKeyResponse{}, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) EnableKey(ctx context.Context, req *keystore.EnableKeyRequest) (*keystore.EnableKeyResponse, error) { + value, err := structpb.NewStruct(req.Parameters.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.EnableKeyRequest{ + Parameters: &operationsv1.RequestParameters{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + KeyId: req.Parameters.KeyID, + }, + } + _, err = h.grpcClient.EnableKey(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.EnableKeyResponse{}, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) GetImportParameters(ctx context.Context, req *keystore.GetImportParametersRequest) (*keystore.GetImportParametersResponse, error) { + value, err := structpb.NewStruct(req.Parameters.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.GetImportParametersRequest{ + Parameters: &operationsv1.RequestParameters{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + KeyId: req.Parameters.KeyID, + }, + Algorithm: operationsv1.KeyAlgorithm(req.KeyAlgorithm), + } + grpcResp, err := h.grpcClient.GetImportParameters(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.GetImportParametersResponse{ + KeyID: grpcResp.GetKeyId(), + ImportParameters: grpcResp.GetImportParameters().AsMap(), + }, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) ImportKeyMaterial(ctx context.Context, req *keystore.ImportKeyMaterialRequest) (*keystore.ImportKeyMaterialResponse, error) { + value, err := structpb.NewStruct(req.Parameters.Config.Values) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + importParams, err := structpb.NewStruct(req.ImportParameters) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.ImportKeyMaterialRequest{ + Parameters: &operationsv1.RequestParameters{ + Config: &commonv1.KeystoreInstanceConfig{ + Values: value, + }, + KeyId: req.Parameters.KeyID, + }, + ImportParameters: importParams, + } + _, err = h.grpcClient.ImportKeyMaterial(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.ImportKeyMaterialResponse{}, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) ValidateKey(ctx context.Context, req *keystore.ValidateKeyRequest) (*keystore.ValidateKeyResponse, error) { + in := &operationsv1.ValidateKeyRequest{ + KeyType: operationsv1.KeyType(req.KeyType), + Algorithm: operationsv1.KeyAlgorithm(req.KeyAlgorithm), + Region: req.Region, + NativeKeyId: req.NativeKeyID, + } + grpcResp, err := h.grpcClient.ValidateKey(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.ValidateKeyResponse{ + IsValid: grpcResp.GetIsValid(), + Message: grpcResp.GetMessage(), + }, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) ValidateKeyAccessData(ctx context.Context, req *keystore.ValidateKeyAccessDataRequest) (*keystore.ValidateKeyAccessDataResponse, error) { + management, err := structpb.NewStruct(req.Management) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + crypto, err := structpb.NewStruct(req.Crypto) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.ValidateKeyAccessDataRequest{ + Management: management, + Crypto: crypto, + } + grpcResp, err := h.grpcClient.ValidateKeyAccessData(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.ValidateKeyAccessDataResponse{ + IsValid: grpcResp.GetIsValid(), + Message: grpcResp.GetMessage(), + }, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) TransformCryptoAccessData(ctx context.Context, req *keystore.TransformCryptoAccessDataRequest) (*keystore.TransformCryptoAccessDataResponse, error) { + in := &operationsv1.TransformCryptoAccessDataRequest{ + NativeKeyId: req.NativeKeyID, + AccessData: req.AccessData, + } + grpcResp, err := h.grpcClient.TransformCryptoAccessData(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.TransformCryptoAccessDataResponse{ + TransformedAccessData: grpcResp.GetTransformedAccessData(), + }, nil +} + +func (h *hashicorpKeystoreOperationsV1Plugin) ExtractKeyRegion(ctx context.Context, req *keystore.ExtractKeyRegionRequest) (*keystore.ExtractKeyRegionResponse, error) { + management, err := structpb.NewStruct(req.ManagementAccessData) + if err != nil { + return nil, fmt.Errorf("failed to parse values: %v", err) + } + + in := &operationsv1.ExtractKeyRegionRequest{ + NativeKeyId: req.NativeKeyID, + ManagementAccessData: management, + } + grpcResp, err := h.grpcClient.ExtractKeyRegion(ctx, in) + if err != nil { + return nil, err + } + + return &keystore.ExtractKeyRegionResponse{ + Region: grpcResp.GetRegion(), + }, nil +} diff --git a/pkg/plugin/service/notification_v1.go b/pkg/plugin/service/notification_v1.go new file mode 100644 index 0000000..17c21bf --- /dev/null +++ b/pkg/plugin/service/notification_v1.go @@ -0,0 +1,40 @@ +package service + +import ( + "context" + + "github.com/openkcm/plugin-sdk/api/service/notification" + "github.com/openkcm/plugin-sdk/pkg/catalog" + notificationv1 "github.com/openkcm/plugin-sdk/proto/plugin/notification/v1" +) + +var _ notification.Notification = (*hashicorpNotificationV1Plugin)(nil) + +type hashicorpNotificationV1Plugin struct { + plugin catalog.Plugin + grpcClient notificationv1.NotificationServiceClient +} + +func NewNotificationV1Plugin(plugin catalog.Plugin) notification.Notification { + return &hashicorpNotificationV1Plugin{ + plugin: plugin, + grpcClient: notificationv1.NewNotificationServiceClient(plugin.ClientConnection()), + } +} + +func (h *hashicorpNotificationV1Plugin) Send(ctx context.Context, req *notification.SendNotificationRequest) (*notification.SendNotificationResponse, error) { + in := ¬ificationv1.SendNotificationRequest{ + NotificationType: notificationv1.NotificationType(req.Type), + Recipients: req.Recipients, + Subject: req.Subject, + Body: req.Body, + } + grpcResp, err := h.grpcClient.SendNotification(ctx, in) + if err != nil { + return nil, err + } + return ¬ification.SendNotificationResponse{ + Success: grpcResp.GetSuccess(), + Message: grpcResp.GetMessage(), + }, nil +} diff --git a/pkg/plugin/service/system_information_v1.go b/pkg/plugin/service/system_information_v1.go new file mode 100644 index 0000000..9dec3cd --- /dev/null +++ b/pkg/plugin/service/system_information_v1.go @@ -0,0 +1,37 @@ +package service + +import ( + "context" + + "github.com/openkcm/plugin-sdk/api/service/systeminformation" + "github.com/openkcm/plugin-sdk/pkg/catalog" + systeminformationv1 "github.com/openkcm/plugin-sdk/proto/plugin/systeminformation/v1" +) + +var _ systeminformation.SystemInformation = (*hashicorpSystemInformationV1Plugin)(nil) + +type hashicorpSystemInformationV1Plugin struct { + plugin catalog.Plugin + grpcClient systeminformationv1.SystemInformationServiceClient +} + +func NewSystemInformationV1Plugin(plugin catalog.Plugin) systeminformation.SystemInformation { + return &hashicorpSystemInformationV1Plugin{ + plugin: plugin, + grpcClient: systeminformationv1.NewSystemInformationServiceClient(plugin.ClientConnection()), + } +} + +func (h *hashicorpSystemInformationV1Plugin) GetSystemInfo(ctx context.Context, req *systeminformation.GetSystemInfoRequest) (*systeminformation.GetSystemInfoResponse, error) { + in := &systeminformationv1.GetRequest{ + Id: req.ID, + Type: systeminformationv1.RequestType(req.Type), + } + grpcResp, err := h.grpcClient.Get(ctx, in) + if err != nil { + return nil, err + } + return &systeminformation.GetSystemInfoResponse{ + Metadata: grpcResp.GetMetadata(), + }, nil +} diff --git a/sonar-project.properties b/sonar-project.properties index a02427f..e5f83e1 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,2 +1,2 @@ sonar.test.inclusions=**/*_test.go -sonar.coverage.exclusions=**/pkg/catalog/**,**/*_test.go \ No newline at end of file +sonar.coverage.exclusions=**/api/**,**/proto/**,**/pkg/**,**/*_test.go \ No newline at end of file