From 1357e2646068faafadd9e7df23867a370eae263a Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 7 Apr 2025 14:56:13 -0400 Subject: [PATCH 01/25] checkpoint --- .gitignore | 52 +- CHANGELOG.md | 24 +- CreateTemplate.ps1 | 201 ----- HydrantIdProducts.csv | 3 - HydrantIdProxy/Config.json | 60 -- HydrantIdProxy/HydrantIdProxy.sln | 29 - HydrantIdProxy/README.md | 157 ---- HydrantIdProxy/docs/AuthenticationApi.md | 361 --------- HydrantIdProxy/docs/CertRequest.md | 18 - HydrantIdProxy/docs/CertRequestBody.md | 18 - .../docs/CertRequestBodyDnComponents.md | 15 - .../docs/CertRequestBodySubjectAltNames.md | 12 - .../docs/CertRequestBodyValidity.md | 11 - HydrantIdProxy/docs/CertRequestPolicy.md | 10 - HydrantIdProxy/docs/CertRequestStatus.md | 13 - HydrantIdProxy/docs/CertRequestUser.md | 11 - HydrantIdProxy/docs/Certificate.md | 28 - HydrantIdProxy/docs/CertificateRequestsApi.md | 184 ----- HydrantIdProxy/docs/CertificateStatus.md | 12 - HydrantIdProxy/docs/CertificateUser.md | 10 - HydrantIdProxy/docs/CertificatesApi.md | 428 ---------- HydrantIdProxy/docs/GetCertificatesPayload.md | 22 - .../docs/GetCertificatesResponse.md | 10 - .../docs/GetCertificatesResponseItem.md | 16 - HydrantIdProxy/docs/HawkCredential.md | 14 - HydrantIdProxy/docs/HawkCredentialComment.md | 9 - HydrantIdProxy/docs/HawkCredentialComments.md | 9 - .../docs/HawkCredentialDeleteResults.md | 10 - HydrantIdProxy/docs/IssuanceStatus.md | 8 - HydrantIdProxy/docs/NameObject.md | 9 - HydrantIdProxy/docs/PoliciesApi.md | 188 ----- HydrantIdProxy/docs/Policy.md | 15 - HydrantIdProxy/docs/PolicyDetails.md | 15 - .../docs/PolicyDetailsCustomExtensions.md | 13 - .../docs/PolicyDetailsCustomFields.md | 13 - .../docs/PolicyDetailsDnComponents.md | 14 - .../docs/PolicyDetailsExpiryEmails.md | 13 - .../docs/PolicyDetailsSubjectAltNames.md | 13 - HydrantIdProxy/docs/PolicyDetailsValidity.md | 13 - HydrantIdProxy/docs/PolicyEnabled.md | 13 - HydrantIdProxy/docs/RevocationReasons.md | 8 - HydrantIdProxy/docs/RevocationStatusEnum.md | 8 - .../docs/RevokeCertificateReason.md | 9 - .../docs/RevokeCertificateReasonIssuerDN.md | 10 - HydrantIdProxy/docs/SortDirectionEnum.md | 8 - HydrantIdProxy/src/HydrantIdProxy/app.config | 19 - .../src/HydrantIdProxy/packages.config | 16 - README.md | 351 ++++---- SampleConfig.json | 72 -- TemplateSecurity/CaTemplateUserSecurity.csv | 7 - Templates/AutoEnrollment - RSA - 7 Day.json | 38 - Templates/AutoEnrollment - RSA.json | 19 - integration-manifest.json | 19 +- readme_source.md | 318 ++++---- src/HydrantCAProxy/App.config | 19 + .../HydrantCAProxy}/Client/HydrantIdClient.cs | 116 +-- .../Client/Models/CertRequest.cs | 2 +- .../Client/Models/CertRequestBody.cs | 2 +- .../Models/CertRequestBodyDnComponents.cs | 2 +- .../Models/CertRequestBodySubjectAltNames.cs | 2 +- .../Client/Models/CertRequestBodyValidity.cs | 2 +- .../Client/Models/CertRequestPolicy.cs | 2 +- .../Client/Models/CertRequestResult.cs | 2 +- .../Client/Models/CertRequestStatus.cs | 2 +- .../Client/Models/CertRequestUser.cs | 2 +- .../Client/Models/Certificate.cs | 2 +- .../Client/Models/CertificateStatus.cs | 2 +- .../Client/Models/CertificateUser.cs | 2 +- .../Client/Models/Enums/IssuanceStatus.cs | 2 +- .../Client/Models/Enums/RevocationReasons.cs | 2 +- .../Models/Enums/RevocationStatusEnum.cs | 2 +- .../Client/Models/Enums/SortDirectionEnum.cs | 2 +- .../Client/Models/ErrorReturn.cs | 24 +- .../Client/Models/GetCertificatesPayload.cs | 2 +- .../Client/Models/GetCertificatesResponse.cs | 2 +- .../Models/GetCertificatesResponseItem.cs | 2 +- .../Client/Models/NameObject.cs | 2 +- .../HydrantCAProxy}/Client/Models/Policy.cs | 2 +- .../Client/Models/PolicyDetails.cs | 2 +- .../Models/PolicyDetailsCustomExtensions.cs | 2 +- .../Models/PolicyDetailsCustomFields.cs | 2 +- .../Models/PolicyDetailsDnComponents.cs | 2 +- .../Models/PolicyDetailsExpiryEmails.cs | 2 +- .../Models/PolicyDetailsSubjectAltNames.cs | 2 +- .../Client/Models/PolicyDetailsValidity.cs | 2 +- .../Client/Models/PolicyEnabled.cs | 2 +- .../Client/Models/RenewalRequest.cs | 2 +- .../Client/Models/RevokeCertificateReason.cs | 2 +- .../Models/RevokeCertificateReasonIssuerDN.cs | 2 +- .../HydrantCAProxy}/Constants.cs | 2 +- .../Exceptions/RetryCountExceededException.cs | 2 +- .../RevokeReasonNotSupportedException.cs | 2 +- src/HydrantCAProxy/ExtensionMethods.cs | 25 + .../Extensions/HttpClientExtensions.cs | 2 +- .../HydrantCAProxy/HydrantIdCAProxy.cs | 756 +++++++++--------- .../HydrantCAProxy/HydrantIdCAProxy.csproj | 329 ++++---- src/HydrantCAProxy/HydrantIdCAProxy.sln | 37 + .../Interfaces/ICertRequest.cs | 2 +- .../Interfaces/ICertRequestBody.cs | 2 +- .../ICertRequestBodyDnComponents.cs | 2 +- .../ICertRequestBodySubjectAltNames.cs | 2 +- .../Interfaces/ICertRequestBodyValidity.cs | 2 +- .../Interfaces/ICertRequestPolicy.cs | 2 +- .../Interfaces/ICertRequestResult.cs | 2 +- .../Interfaces/ICertRequestStatus.cs | 2 +- .../Interfaces/ICertRequestUser.cs | 2 +- .../Interfaces/ICertificate.cs | 2 +- .../Interfaces/ICertificateStatus.cs | 2 +- .../Interfaces/ICertificateUser.cs | 2 +- .../Interfaces/ICertificatesPayload.cs | 2 +- .../Interfaces/ICertificatesResponse.cs | 2 +- .../Interfaces/ICertificatesResponseItem.cs | 2 +- .../Interfaces/IErrorReturn.cs | 2 +- .../Interfaces/IHawkCredential.cs | 2 +- .../Interfaces/IHawkCredentialComment.cs | 2 +- .../Interfaces/IHawkCredentialComments.cs | 2 +- .../IHawkCredentialDeleteResults.cs | 2 +- .../HydrantCAProxy}/Interfaces/INameObject.cs | 2 +- .../HydrantCAProxy}/Interfaces/IPolicy.cs | 2 +- .../Interfaces/IPolicyDetails.cs | 2 +- .../IPolicyDetailsCustomExtensions.cs | 2 +- .../Interfaces/IPolicyDetailsCustomFields.cs | 2 +- .../Interfaces/IPolicyDetailsDnComponents.cs | 2 +- .../Interfaces/IPolicyDetailsExpiryEmails.cs | 2 +- .../IPolicyDetailsSubjectAltNames.cs | 2 +- .../Interfaces/IPolicyDetailsValidity.cs | 2 +- .../Interfaces/IPolicyEnabled.cs | 2 +- .../Interfaces/IRenewalRequest.cs | 2 +- .../Interfaces/IRenewalResponse.cs | 2 +- .../Interfaces/IRevokeCertificateReason.cs | 2 +- .../IRevokeCertificateReasonIssuerDn.cs | 2 +- .../Properties/AssemblyInfo.cs | 20 +- .../HydrantCAProxy}/RequestManager.cs | 711 ++++++++-------- 133 files changed, 1563 insertions(+), 3590 deletions(-) delete mode 100644 CreateTemplate.ps1 delete mode 100644 HydrantIdProducts.csv delete mode 100644 HydrantIdProxy/Config.json delete mode 100644 HydrantIdProxy/HydrantIdProxy.sln delete mode 100644 HydrantIdProxy/README.md delete mode 100644 HydrantIdProxy/docs/AuthenticationApi.md delete mode 100644 HydrantIdProxy/docs/CertRequest.md delete mode 100644 HydrantIdProxy/docs/CertRequestBody.md delete mode 100644 HydrantIdProxy/docs/CertRequestBodyDnComponents.md delete mode 100644 HydrantIdProxy/docs/CertRequestBodySubjectAltNames.md delete mode 100644 HydrantIdProxy/docs/CertRequestBodyValidity.md delete mode 100644 HydrantIdProxy/docs/CertRequestPolicy.md delete mode 100644 HydrantIdProxy/docs/CertRequestStatus.md delete mode 100644 HydrantIdProxy/docs/CertRequestUser.md delete mode 100644 HydrantIdProxy/docs/Certificate.md delete mode 100644 HydrantIdProxy/docs/CertificateRequestsApi.md delete mode 100644 HydrantIdProxy/docs/CertificateStatus.md delete mode 100644 HydrantIdProxy/docs/CertificateUser.md delete mode 100644 HydrantIdProxy/docs/CertificatesApi.md delete mode 100644 HydrantIdProxy/docs/GetCertificatesPayload.md delete mode 100644 HydrantIdProxy/docs/GetCertificatesResponse.md delete mode 100644 HydrantIdProxy/docs/GetCertificatesResponseItem.md delete mode 100644 HydrantIdProxy/docs/HawkCredential.md delete mode 100644 HydrantIdProxy/docs/HawkCredentialComment.md delete mode 100644 HydrantIdProxy/docs/HawkCredentialComments.md delete mode 100644 HydrantIdProxy/docs/HawkCredentialDeleteResults.md delete mode 100644 HydrantIdProxy/docs/IssuanceStatus.md delete mode 100644 HydrantIdProxy/docs/NameObject.md delete mode 100644 HydrantIdProxy/docs/PoliciesApi.md delete mode 100644 HydrantIdProxy/docs/Policy.md delete mode 100644 HydrantIdProxy/docs/PolicyDetails.md delete mode 100644 HydrantIdProxy/docs/PolicyDetailsCustomExtensions.md delete mode 100644 HydrantIdProxy/docs/PolicyDetailsCustomFields.md delete mode 100644 HydrantIdProxy/docs/PolicyDetailsDnComponents.md delete mode 100644 HydrantIdProxy/docs/PolicyDetailsExpiryEmails.md delete mode 100644 HydrantIdProxy/docs/PolicyDetailsSubjectAltNames.md delete mode 100644 HydrantIdProxy/docs/PolicyDetailsValidity.md delete mode 100644 HydrantIdProxy/docs/PolicyEnabled.md delete mode 100644 HydrantIdProxy/docs/RevocationReasons.md delete mode 100644 HydrantIdProxy/docs/RevocationStatusEnum.md delete mode 100644 HydrantIdProxy/docs/RevokeCertificateReason.md delete mode 100644 HydrantIdProxy/docs/RevokeCertificateReasonIssuerDN.md delete mode 100644 HydrantIdProxy/docs/SortDirectionEnum.md delete mode 100644 HydrantIdProxy/src/HydrantIdProxy/app.config delete mode 100644 HydrantIdProxy/src/HydrantIdProxy/packages.config delete mode 100644 SampleConfig.json delete mode 100644 TemplateSecurity/CaTemplateUserSecurity.csv delete mode 100644 Templates/AutoEnrollment - RSA - 7 Day.json delete mode 100644 Templates/AutoEnrollment - RSA.json create mode 100644 src/HydrantCAProxy/App.config rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/HydrantIdClient.cs (81%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequest.cs (97%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestBody.cs (97%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestBodyDnComponents.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestBodySubjectAltNames.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestBodyValidity.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestPolicy.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestResult.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestStatus.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertRequestUser.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/Certificate.cs (98%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertificateStatus.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/CertificateUser.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/Enums/IssuanceStatus.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/Enums/RevocationReasons.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/Enums/RevocationStatusEnum.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/Enums/SortDirectionEnum.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/ErrorReturn.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/GetCertificatesPayload.cs (97%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/GetCertificatesResponse.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/GetCertificatesResponseItem.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/NameObject.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/Policy.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetails.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetailsCustomExtensions.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetailsCustomFields.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetailsDnComponents.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetailsExpiryEmails.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetailsSubjectAltNames.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyDetailsValidity.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/PolicyEnabled.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/RenewalRequest.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/RevokeCertificateReason.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Client/Models/RevokeCertificateReasonIssuerDN.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Constants.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Exceptions/RetryCountExceededException.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Exceptions/RevokeReasonNotSupportedException.cs (92%) create mode 100644 src/HydrantCAProxy/ExtensionMethods.cs rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Extensions/HttpClientExtensions.cs (95%) rename HydrantIdProxy/src/HydrantIdProxy/HydrantIdProxy.cs => src/HydrantCAProxy/HydrantIdCAProxy.cs (66%) rename HydrantIdProxy/src/HydrantIdProxy/HydrantIdProxy.csproj => src/HydrantCAProxy/HydrantIdCAProxy.csproj (57%) create mode 100644 src/HydrantCAProxy/HydrantIdCAProxy.sln rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequest.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestBody.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestBodyDnComponents.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestBodySubjectAltNames.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestBodyValidity.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestPolicy.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestResult.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestStatus.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertRequestUser.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertificate.cs (96%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertificateStatus.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertificateUser.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertificatesPayload.cs (95%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertificatesResponse.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/ICertificatesResponseItem.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IErrorReturn.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IHawkCredential.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IHawkCredentialComment.cs (91%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IHawkCredentialComments.cs (91%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IHawkCredentialDeleteResults.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/INameObject.cs (91%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicy.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetails.cs (94%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetailsCustomExtensions.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetailsCustomFields.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetailsDnComponents.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetailsExpiryEmails.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetailsSubjectAltNames.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyDetailsValidity.cs (93%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IPolicyEnabled.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IRenewalRequest.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IRenewalResponse.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IRevokeCertificateReason.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Interfaces/IRevokeCertificateReasonIssuerDn.cs (92%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/Properties/AssemblyInfo.cs (60%) rename {HydrantIdProxy/src/HydrantIdProxy => src/HydrantCAProxy}/RequestManager.cs (84%) diff --git a/.gitignore b/.gitignore index dfcfd56..3e759b7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files -*.rsuser *.suo *.user *.userosscache @@ -13,9 +12,6 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs -# Mono auto generated files -mono_crash.* - # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -23,13 +19,10 @@ mono_crash.* [Rr]eleases/ x64/ x86/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ -[Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ @@ -43,10 +36,9 @@ Generated\ Files/ [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUnit +# NUNIT *.VisualState.xml TestResult.xml -nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ @@ -60,6 +52,7 @@ BenchmarkDotNet.Artifacts/ project.lock.json project.fragment.lock.json artifacts/ +**/Properties/launchSettings.json # StyleCop StyleCopReport.xml @@ -67,7 +60,7 @@ StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c -*_h.h +*_i.h *.ilk *.meta *.obj @@ -84,7 +77,6 @@ StyleCopReport.xml *.tlh *.tmp *.tmp_proj -*_wpftmp.csproj *.log *.vspscc *.vssscc @@ -127,6 +119,9 @@ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user +# JustCode is a .NET coding add-in +.JustCode + # TeamCity is a build add-in _TeamCity* @@ -184,8 +179,6 @@ PublishScripts/ # NuGet Packages *.nupkg -# NuGet Symbol Packages -*.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. @@ -210,14 +203,12 @@ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx -*.appxbundle -*.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!?*.[Cc]ache/ +!*.[Cc]ache/ # Others ClientBin/ @@ -230,7 +221,7 @@ ClientBin/ *.publishsettings orleans.codegen.cs -# Including strong name files can present a security risk +# Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk @@ -261,9 +252,6 @@ ServiceFabricBackup/ *.bim.layout *.bim_*.settings *.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ @@ -299,8 +287,12 @@ paket-files/ # FAKE - F# Make .fake/ -# CodeRush personal settings -.cr/personal +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ # Python Tools for Visual Studio (PTVS) __pycache__/ @@ -325,7 +317,7 @@ __pycache__/ # OpenCover UI analysis results OpenCover/ -# Azure Stream Analytics local run output +# Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log @@ -334,17 +326,5 @@ ASALocalRun/ # NVidia Nsight GPU debugger configuration file *.nvuser -# MFractors (Xamarin productivity tool) working folder +# MFractors (Xamarin productivity tool) working folder .mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 126ba1d..7134f25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,15 +1,13 @@ -v1.1.3 -- Fixed sync Issue related to API connectivity to Hydrant ID - -v1.1.2 -- Recompiled agains the latest gateway and Bouncy Castle Frameworks - -v1.1.1 -- Fixed error handing to match Hydrant new API Structure +# v2.0.0 +* Migrate `packages.config` to `PackageReference` format +* Upgrade packages to support Keyfactor AnyCA Gateway DCOM v24.2 + * Upgrade `Keyfactor.AnyGateway.SDK` to `24.2.0-PRERELEASE-47446` +* Add support for [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls) +* Enable configuration of CA Pool-based or CA-specific certificate enrollment. If the `CAId` is specified, certificates are enrolled with the CA specified by `CAId`. Otherwise, GCP CAS selects a CA in the CA Pool based on policy. -v1.1.0 -- Added Support for Meta Data In Keyfactor -- Put enroll on a timer to wait for request so Meta Data Could be Pulled down +# v1.1.0 + - Remove template references from README + - Small bug fixes -v1.0.3: -- Original Release Version +# v1.0.0 +* Initial Release. Support for Google GA CA Service. Sync, Enroll, and Revocation. diff --git a/CreateTemplate.ps1 b/CreateTemplate.ps1 deleted file mode 100644 index 9f119fb..0000000 --- a/CreateTemplate.ps1 +++ /dev/null @@ -1,201 +0,0 @@ -Function ImportWindowsCATemplates($CSVFile,$SecurityCSV) -{ - Import-Csv $CSVFile | ForEach-Object { - - $ConfigContext = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext - $ADSI = [ADSI]"LDAP://CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext" - - $NewTempl = $ADSI.Create("pKICertificateTemplate", "CN=$($_.Code)") - $NewTempl.put("distinguishedName","CN=$($_.Code),CN=Certificate Templates,CN=Public Key Services,CN=Services,$ConfigContext") - # and put other atributes that you need - - $NewTempl.put("flags","131680") - $NewTempl.put("displayName","$($_.ProductName)") - $NewTempl.put("revision","100") - $NewTempl.put("pKIDefaultKeySpec","1") - $NewTempl.SetInfo() - - $NewTempl.put("pKIMaxIssuingDepth","0") - $NewTempl.put("pKICriticalExtensions","2.5.29.15") - $NewTempl.put("pKIExtendedKeyUsage","1.3.6.1.4.1.311.47.1.1, 1.3.6.1.5.5.7.3.2") - $NewTempl.put("pKIDefaultCSPs","1,Microsoft RSA SChannel Cryptographic Provider") - $NewTempl.put("msPKI-RA-Signature","0") - $NewTempl.put("msPKI-Enrollment-Flag","32") - $NewTempl.put("msPKI-Private-Key-Flag","48") - $NewTempl.put("msPKI-Certificate-Name-Flag","134217728") - $NewTempl.put("msPKI-Minimal-Key-Size","2048") - $NewTempl.put("msPKI-Template-Schema-Version","2") - $NewTempl.put("msPKI-Template-Minor-Revision","0") - $NewTempl.put("msPKI-Cert-Template-OID","1.3.6.1.4.1.311.21.8.$(Get-Random -Minimum 10000000 -Maximum 90000000).$(Get-Random -Minimum 10000000 -Maximum 90000000).$(Get-Random -Minimum 1000000 -Maximum 9000000).$(Get-Random -Minimum 1000000 -Maximum 9000000).$(Get-Random -Minimum 1000000 -Maximum 9000000).119.$(Get-Random -Minimum 10000000 -Maximum 90000000).1716 293") - $NewTempl.put("msPKI-Certificate-Application-Policy","1.3.6.1.5.5.7.3.1") - - $NewTempl.SetInfo() - - $WATempl = $ADSI.psbase.children | where {$_.displayName -match "Workstation Authentication"} - - #before - $NewTempl.pKIKeyUsage = $WATempl.pKIKeyUsage - $NewTempl.pKIExpirationPeriod = $WATempl.pKIExpirationPeriod - $NewTempl.pKIOverlapPeriod = $WATempl.pKIOverlapPeriod - $NewTempl.SetInfo() - - $NewTempl | select * - - $acl = $NewTempl.psbase.ObjectSecurity - $acl | select -ExpandProperty Access - - Import-Csv $SecurityCSV | ForEach-Object { - $AdObj = New-Object System.Security.Principal.NTAccount("$($_.UserName)") - $identity = $AdObj.Translate([System.Security.Principal.SecurityIdentifier]) - $adRights = "$($_.Rights)" - $type = "Allow" - - $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($identity,$adRights,$type) - $NewTempl.psbase.ObjectSecurity.SetAccessRule($ACE) - $NewTempl.psbase.commitchanges() - } - } -} - -function Get-Data([string]$username, [string]$password, [string]$url) { - - $credPair = "$($username):$($password)" - $encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair)) - $headers = @{ Authorization = "Basic $encodedCredentials";'Accept' = 'application/json';'x-keyfactor-requested-with' = 'APIClient'} - $responseData = Invoke-WebRequest -Uri $url -Method Get -Headers $headers -UseBasicParsing - - return $responseData -} - -function Put-Data([string]$username, [string]$password, [string]$url,[string]$body) { - - $json = $body | ConvertTo-Json - $credPair = "$($username):$($password)" - $encodedCredentials = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($credPair)) - $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]" - $headers.Add("Authorization","Basic $encodedCredentials") - $headers.Add("Accept","application/json") - $headers.Add("Content-Type","application/json") - $headers.Add("x-keyfactor-requested-with","APIClient") - $responseData = Invoke-WebRequest -Uri $url -Method Put -Headers $headers -ContentType "application/json" -Body ($json|ConvertFrom-Json) - - return $responseData -} - -function Get-API-Settings -{ - $RestAPIURLDefault="https://kftrain.keyfactor.lab/KeyfactorAPI/Templates?sq.returnLimit=1000" - $RestAPIURL = Read-Host "`r`nEnter url for Rest API (Hit Enter To Accept Default) [$($RestAPIURLDefault)]" - if($RestAPIURL -eq "") - { - $RestAPIURL=$RestAPIURLDefault - } - - - $RestAPIUserDefault="keyfactor.lab\Administrator" - $RestAPIUser = Read-Host "`r`nEnter Rest API User (Hit Enter To Accept Default) [$($RestAPIUserDefault)]" - if($RestAPIUser -eq "") - { - $RestAPIUser=$RestAPIUserDefault - } - - $RestAPIPasswordDefault="Password1" - $RestAPIPassword = Read-Host "`r`nEnter Rest API Password (Hit Enter To Accept Default) [$($RestAPIPasswordDefault)]" - if($RestAPIPassword -eq "") - { - $RestAPIPassword=$RestAPIPasswordDefault - } - - $value = "" | Select-Object -Property ApiURL,ApiUser,ApiPassword - $value.ApiUrl = $RestAPIURL - $value.ApiUser = $RestAPIUser - $value.ApiPassword = $RestAPIPassword - return $value -} - -function Show-Keyfactor-Templates -{ - $ApiSettings=Get-API-Settings - $templatesResponse=Get-Data $ApiSettings.ApiUser $ApiSettings.ApiPassword $ApiSettings.ApiUrl - $templatesResponse| ConvertFrom-Json | Select-Object|Format-Table -Property Id,CommonName,TemplateName -} - -Function Update-Keyfactor-Templates($CSVFile) -{ - $ApiSettings=Get-API-Settings - $templatesResponse=Get-Data $ApiSettings.ApiUser $ApiSettings.ApiPassword $ApiSettings.ApiUrl|ConvertFrom-Json - - Import-Csv $CSVFile | ForEach-Object{ - $Template=$templatesResponse|where CommonName -eq $_.Code - - #Call Put Tempate for Keyfactor to update the template and enrollment fields - $filebase = Join-Path $PSScriptRoot "\Templates\$($_.Code).json" - - $fileContent=Get-Content -Path $filebase - $keyfactorJson=$fileContent -replace "`"Id`": 999999","`"Id`":$($Template.Id)" - $keyfactorJson=$keyfactorJson -replace "`"Oid`": `"Replace OID`"","`"Oid`":`"$($Template.Oid)`"" - $keyfactorJson=$keyfactorJson -replace "`"FriendlyName`": `"Replace Friendly Name`"","`"FriendlyName`":`"$($_.ProductName[0..46] -join `"`")`"" - $keyfactorJson=$keyfactorJson -replace "`"DisplayName`": `"Replace Display Name`"","`"DisplayName`":`"$($_.ProductName[0..46] -join `"`")`"" - - $templateResponse=Put-Data $ApiSettings.ApiUser $ApiSettings.ApiPassword $ApiSettings.ApiUrl $keyfactorJson - - $templateResponse| ConvertFrom-Json | Select-Object|Format-Table -Property Id,CommonName,TemplateName - - Write-Host "The Above Template has been updated" - - } -} - -Function Generate-Keyfactor-Config($CSVFile) -{ - $configOutput="{" - $RowCount=Import-Csv $CSVFile | Measure-Object | Select-Object -expand count - $Counter=0 - - Import-Csv $CSVFile | ForEach-Object{ - $Counter++ - $configOutput=$configOutput + "`"$($_.Code)`": {`r`n`"ProductID`": `"$($_.Code)`",`r`n`"Parameters`": {}`r`n}" - if($Counter -ne $RowCount) - { - $configOutput=$configOutput + ",`r`n" - } - } - - $configOutput=$configOutput + "}" - - $FileName=$CSVFile -replace ".csv",".txt" - - $configOutput|Out-File -FilePath $FileName - -} - - -#Show all possible CSV files to import, skip the security template -Get-ChildItem -Filter *.csv -Recurse -Exclude CaTemplateUserSecurity.csv - -$FileName = Read-Host "`r`nEnter the name of the CSV File to process" - -#Show available operations -$table = @( @{OperationNumber=1;OperationName="Create Windows CA Templates"}, - @{OperationNumber=2;OperationName="Check Sync'd Templates in Keyfactor"}, - @{OperationNumber=3;OperationName="Update Keyfactor Templates"}, - @{OperationNumber=4;OperationName="Generate Keyfactor Config Template JSON"}) - -$(foreach ($ht in $table) - {new-object PSObject -Property $ht}) | Format-Table -AutoSize - -$filebase = Join-Path $PSScriptRoot $FileName -$CSVfilebase = Join-Path $PSScriptRoot "TemplateSecurity\CaTemplateUserSecurity.csv" - -#Process Operation -$Operation = Read-Host "Enter the OperationNumber shown above" -Switch ($Operation) -{ - 1 {ImportWindowsCATemplates $filebase $CSVfilebase} - 2 {Show-Keyfactor-Templates} - 3 {Update-Keyfactor-Templates $filebase} - 4 {Generate-Keyfactor-Config $filebase} -} - - - diff --git a/HydrantIdProducts.csv b/HydrantIdProducts.csv deleted file mode 100644 index 1f2e2a3..0000000 --- a/HydrantIdProducts.csv +++ /dev/null @@ -1,3 +0,0 @@ -ProductName,Code,Vendor,Product Type,IsMultiDomain -AutoEnrollment - RSA,AutoEnrollment - RSA,HydrantId,DV,Yes -AutoEnrollment - RSA - 7 Day,AutoEnrollment - RSA - 7 Day,HydrantId,DV,No diff --git a/HydrantIdProxy/Config.json b/HydrantIdProxy/Config.json deleted file mode 100644 index 5c05d79..0000000 --- a/HydrantIdProxy/Config.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - } - }, - "CAConnection": { - "CscGlobalURL": "https://apis-ote.cscglobal.com/dbs/api/v2", - "ApiKey": "SomeAPIKey", - "BearerToken": "SomeBearerToken", - "TemplateSync": "On" - }, - "Templates": { - "CSC TrustedSecure Premium Certificate": { - "ProductID": "CSC TrustedSecure Premium Certificate", - "Parameters": {} - }, - "CSC TrustedSecure EV Certificate": { - "ProductID": "CSC TrustedSecure EV Certificate", - "Parameters": {} - }, - "CSC TrustedSecure UC Certificate": { - "ProductID": "CSC TrustedSecure UC Certificate", - "Parameters": {} - }, - "CSC TrustedSecure Premium Wildcard Certificate": { - "ProductID": "CSC TrustedSecure Premium Wildcard Certificate", - "Parameters": {} - } - }, - "CertificateManagers": null, - "GatewayRegistration": { - "LogicalName": "CscGlobal", - "GatewayCertificate": { - "StoreName": "CA", - "StoreLocation": "LocalMachine", - "Thumbprint": "d1eb23a46d17d68fd92564c2f1f1601764d8e349" - } - }, - "ServiceSettings": { - "ViewIdleMinutes": 1, - "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 - } -} \ No newline at end of file diff --git a/HydrantIdProxy/HydrantIdProxy.sln b/HydrantIdProxy/HydrantIdProxy.sln deleted file mode 100644 index da67613..0000000 --- a/HydrantIdProxy/HydrantIdProxy.sln +++ /dev/null @@ -1,29 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30717.126 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HydrantIdProxy", "src\HydrantIdProxy\HydrantIdProxy.csproj", "{7847E86E-41F8-4849-BBAD-44A30CE9300B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2BBB9F20-3A03-4CCC-BCD7-C2EA2A9CAE95}" - ProjectSection(SolutionItems) = preProject - Config.json = Config.json - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {7847E86E-41F8-4849-BBAD-44A30CE9300B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7847E86E-41F8-4849-BBAD-44A30CE9300B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7847E86E-41F8-4849-BBAD-44A30CE9300B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7847E86E-41F8-4849-BBAD-44A30CE9300B}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {CC69852F-4B1A-4A37-BFD5-39CE27479101} - EndGlobalSection -EndGlobal diff --git a/HydrantIdProxy/README.md b/HydrantIdProxy/README.md deleted file mode 100644 index e12df80..0000000 --- a/HydrantIdProxy/README.md +++ /dev/null @@ -1,157 +0,0 @@ -# IO.Swagger - the C# library for the HydrantID Account Certificate Manager (ACM) API - -HydrantID provides customers the ability to manage the lifecycle of PKI certificates via the web based ACM REST API service. This document outlines the methods to control the generation, retrieval and revocation of certificates. ACM groups methods into 3 categories when dealing with the certificate lifecycle: * Policies * Certificate Requests * Certificates ### Policies Describes the required, optional and default value for data elements that make up a certificate request. Includes: * Subject DN components - CN, OU, O, C, etc. * SAN elements - DNSName, IPAddress, RFC822Name, UPN, etc. * Custom Extensions - X509v3 extensions included in the certificate, i.e. Microsoft Application Policies, Template Information, etc. * Custom Fields - descriptive non-certificate attributes used by the customer for reporting/identification, i.e. Department, Charge code, etc. ACTION | URI | DESCRIPTION - -- -- - | - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | - -- -- -- -- -- GET | /api/v2/policies | Retrieves all policies available to user GET | /api/v2/policies/{policyId} | Retrieves a given policy ### Certificate Requests Describes all requests to generate certificates. After issued, links to a certificateId for operations on the actual certificate. ACTION | URI | DESCRIPTION - -- -- - | - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | - -- -- -- -- -- POST | /api/v2/csr | Creates a new request, returning certRequestId GET | /api/v2/csr/{certRequestId} | Retrieves a given certRequest, including all details GET | /api/v2/csr/{certRequestId}/status | Retrieves issuance status of certRequest, including certificateId if issued ### Certificates Describes all certificates issued by the user or others the user has access to. ACTION | URI | DESCRIPTION - -- -- - | - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | - -- -- -- -- -- POST | /api/v2/certificates | Retrieves all certificates available to user GET | /api/v2/certificates/{certificateId} | Retrieves a given certificate, including status & PEM format cert GET | /api/v2/certificates/{certificateId}/der | Retrieves a binary DER format certificate GET | /api/v2/certificates/{certificateId}/pem | Retrieves a PEM format certificate PATCH | /api/v2/certificates/{certificateId} | Revokes a given certificate, given a certificateId PATCH | /api/v2/certificates/{serialNumber} | Revokes a given certificate, given a serialNumber and issuerDN GET | /api/v2/certificates/{certificateId}/status | Retrieves current revocation status ## Authentication All REST methods are require authentication via the \"HTTP Holder-Of-Key Authentication Scheme\", known as \"Hawk Authentication\" (see ). Hawk is an HTTP authentication scheme providing mechanisms for making authenticated HTTP requests with partial cryptographic verification of the request and response, covering the HTTP method, request URI, host, and optionally the request payload. With Hawk Auth, each user will be issued a two randomly generated strings by HydrantID - an ID that will appear in the request, as well as a key that will be used to sign the request. Each REST method requires an `Authorization` header formatted as below: ```http Authorization: Hawk id=\"\", ts=\"\", nonce=\"\", mac=\"\", hash=\"\" ``` Also, please note that any REST actions that require a payload (POST/PATCH, etc.) will require the \"hash\" element for payload validation - see [Payload Validation](https://github.com/mozilla/hawk/blob/main/API.md#payload-validation) for more information. Responses may contain a `Server-Authorization` header with a hash of the response payload - see [Response Payload Validation](https://github.com/mozilla/hawk/blob/main/API.md#response-payload-validation). See the [Hawk Authentication](https://github.com/mozilla/hawk/blob/main/API.md#response-payload-validation) page on GitHub for links to implementations in NodeJS, .Net, Ruby, Java, etc. ACM provides REST API methods to manage Hawk credentials for a user. Each user account is allowed up to 5 sets of Hawk credentials to access the REST API. It is recommended that users \"roll\" their credentials from the initial values set by HydrantID and on as as needed basis for security. Optional comments can be added to credentials for descriptive purposes. The following actions are available: ACTION | URI | DESCRIPTION - -- -- - | - -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- | - -- -- -- -- -- POST | /api/v2/hawk | Creates a new request, returning certRequestId GET | /api/v2/hawk | Retrieves all credentials associated with the current user GET | /api/v2/hawk/{hawkId} | Retrieves a specific Hawk credential PUT | /api/v2/hawk/{hawkId} | Rolls a credential by establishing a new secret key DELETE | /api/v2/hawk/{hawkId} | Disables and removes a credential ## Certificate Request Pseudocode Requesting a certificate will normally flow like this: ``` Generate CSR Submit Request via POST /api/v2/csr, returning certRequestId While CertRequest issuanceStatus == APPROVAL_REQUIRED | IN_PROCESS | PENDING Get CertRequest Status via GET /api/v2/csr/{certRequestId}/status If issuanceStatus == ISSUED Download PEM certificate via GET /api/v2/certificates/{certificateId} ``` Please contact HydrantID for sample code in various languages. - -This C# SDK is automatically generated by the [Swagger Codegen](https://github.com/swagger-api/swagger-codegen) project: - -- API version: 1.3.4 -- SDK version: 1.0.0 -- Build package: io.swagger.codegen.v3.generators.dotnet.CSharpClientCodegen - - -## Frameworks supported -- .NET 4.0 or later -- Windows Phone 7.1 (Mango) - - -## Dependencies -- [RestSharp](https://www.nuget.org/packages/RestSharp) - 105.1.0 or later -- [Json.NET](https://www.nuget.org/packages/Newtonsoft.Json/) - 7.0.0 or later -- [JsonSubTypes](https://www.nuget.org/packages/JsonSubTypes/) - 1.2.0 or later - -The DLLs included in the package may not be the latest version. We recommend using [NuGet](https://docs.nuget.org/consume/installing-nuget) to obtain the latest version of the packages: -``` -Install-Package RestSharp -Install-Package Newtonsoft.Json -Install-Package JsonSubTypes -``` - -NOTE: RestSharp versions greater than 105.1.0 have a bug which causes file uploads to fail. See [RestSharp#742](https://github.com/restsharp/RestSharp/issues/742) - - -## Installation -Run the following command to generate the DLL -- [Mac/Linux] `/bin/sh build.sh` -- [Windows] `build.bat` - -Then include the DLL (under the `bin` folder) in the C# project, and use the namespaces: -```csharp -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; -``` - -## Packaging - -A `.nuspec` is included with the project. You can follow the Nuget quickstart to [create](https://docs.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package#create-the-package) and [publish](https://docs.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package#publish-the-package) packages. - -This `.nuspec` uses placeholders from the `.csproj`, so build the `.csproj` directly: - -``` -nuget pack -Build -OutputDirectory out IO.Swagger.csproj -``` - -Then, publish to a [local feed](https://docs.microsoft.com/en-us/nuget/hosting-packages/local-feeds) or [other host](https://docs.microsoft.com/en-us/nuget/hosting-packages/overview) and consume the new package via Nuget as usual. - - -## Getting Started - -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class Example - { - public void main() - { - var apiInstance = new AuthenticationApi(); - - try - { - // Get all HAWK Credentials associated with the current user user - List result = apiInstance.HawkGet(); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkGet: " + e.Message ); - } - } - } -} -``` - - -## Documentation for API Endpoints - -All URIs are relative to *https://acm-stage.hydrantid.com/api/v2* - -Class | Method | HTTP request | Description ------------- | ------------- | ------------- | ------------- -*AuthenticationApi* | [**HawkGet**](docs/AuthenticationApi.md#hawkget) | **GET** /hawk | Get all HAWK Credentials associated with the current user user -*AuthenticationApi* | [**HawkIdDelete**](docs/AuthenticationApi.md#hawkiddelete) | **DELETE** /hawk/{id} | Delete a specific HAWK credential -*AuthenticationApi* | [**HawkIdGet**](docs/AuthenticationApi.md#hawkidget) | **GET** /hawk/{id} | Get a specific HAWK Credential -*AuthenticationApi* | [**HawkIdPatch**](docs/AuthenticationApi.md#hawkidpatch) | **PATCH** /hawk/{id} | Add/update a comment for a specific HAWK credential. -*AuthenticationApi* | [**HawkIdPut**](docs/AuthenticationApi.md#hawkidput) | **PUT** /hawk/{id} | Create a new secret for a specific HAWK credential. -*AuthenticationApi* | [**HawkPost**](docs/AuthenticationApi.md#hawkpost) | **POST** /hawk | Create a new HAWK Credential for the current user -*CertificateRequestsApi* | [**CsrIdGet**](docs/CertificateRequestsApi.md#csridget) | **GET** /csr/{id} | Retrieves a given certRequest, including all details -*CertificateRequestsApi* | [**CsrIdStatusGet**](docs/CertificateRequestsApi.md#csridstatusget) | **GET** /csr/{id}/status | Retrieves issuance status of certRequest, including certificateId if issued -*CertificateRequestsApi* | [**CsrPost**](docs/CertificateRequestsApi.md#csrpost) | **POST** /csr | Create a certificate request -*CertificatesApi* | [**CertificatesIdDerGet**](docs/CertificatesApi.md#certificatesidderget) | **GET** /certificates/{id}/der | Download DER format certificate -*CertificatesApi* | [**CertificatesIdGet**](docs/CertificatesApi.md#certificatesidget) | **GET** /certificates/{id} | Get a specific certificate -*CertificatesApi* | [**CertificatesIdPatch**](docs/CertificatesApi.md#certificatesidpatch) | **PATCH** /certificates/{id} | Revoke a certificate given a certificate id -*CertificatesApi* | [**CertificatesIdPemGet**](docs/CertificatesApi.md#certificatesidpemget) | **GET** /certificates/{id}/pem | Download PEM format certificate -*CertificatesApi* | [**CertificatesIdStatusGet**](docs/CertificatesApi.md#certificatesidstatusget) | **GET** /certificates/{id}/status | Get certificate status -*CertificatesApi* | [**CertificatesPost**](docs/CertificatesApi.md#certificatespost) | **POST** /certificates | Get Certificates -*CertificatesApi* | [**CertificatesSerialNumberPatch**](docs/CertificatesApi.md#certificatesserialnumberpatch) | **PATCH** /certificates/{serialNumber} | Revoke a certificate given a serialNumber and issuerDN -*PoliciesApi* | [**PoliciesGet**](docs/PoliciesApi.md#policiesget) | **GET** /policies | Get all policies -*PoliciesApi* | [**PoliciesIdGet**](docs/PoliciesApi.md#policiesidget) | **GET** /policies/{id} | Get a specific policy -*PoliciesApi* | [**PoliciesIdPut**](docs/PoliciesApi.md#policiesidput) | **PUT** /policies/{id} | Update a policy with preview changes - - -## Documentation for Models - - - [Model.CertRequest](docs/CertRequest.md) - - [Model.CertRequestBody](docs/CertRequestBody.md) - - [Model.CertRequestBodyDnComponents](docs/CertRequestBodyDnComponents.md) - - [Model.CertRequestBodySubjectAltNames](docs/CertRequestBodySubjectAltNames.md) - - [Model.CertRequestBodyValidity](docs/CertRequestBodyValidity.md) - - [Model.CertRequestPolicy](docs/CertRequestPolicy.md) - - [Model.CertRequestStatus](docs/CertRequestStatus.md) - - [Model.CertRequestUser](docs/CertRequestUser.md) - - [Model.Certificate](docs/Certificate.md) - - [Model.CertificateStatus](docs/CertificateStatus.md) - - [Model.CertificateUser](docs/CertificateUser.md) - - [Model.GetCertificatesPayload](docs/GetCertificatesPayload.md) - - [Model.GetCertificatesResponse](docs/GetCertificatesResponse.md) - - [Model.GetCertificatesResponseItem](docs/GetCertificatesResponseItem.md) - - [Model.HawkCredential](docs/HawkCredential.md) - - [Model.HawkCredentialComment](docs/HawkCredentialComment.md) - - [Model.HawkCredentialComments](docs/HawkCredentialComments.md) - - [Model.HawkCredentialDeleteResults](docs/HawkCredentialDeleteResults.md) - - [Model.IssuanceStatus](docs/IssuanceStatus.md) - - [Model.NameObject](docs/NameObject.md) - - [Model.Policy](docs/Policy.md) - - [Model.PolicyDetails](docs/PolicyDetails.md) - - [Model.PolicyDetailsCustomExtensions](docs/PolicyDetailsCustomExtensions.md) - - [Model.PolicyDetailsCustomFields](docs/PolicyDetailsCustomFields.md) - - [Model.PolicyDetailsDnComponents](docs/PolicyDetailsDnComponents.md) - - [Model.PolicyDetailsExpiryEmails](docs/PolicyDetailsExpiryEmails.md) - - [Model.PolicyDetailsSubjectAltNames](docs/PolicyDetailsSubjectAltNames.md) - - [Model.PolicyDetailsValidity](docs/PolicyDetailsValidity.md) - - [Model.PolicyEnabled](docs/PolicyEnabled.md) - - [Model.RevocationReasons](docs/RevocationReasons.md) - - [Model.RevocationStatusEnum](docs/RevocationStatusEnum.md) - - [Model.RevokeCertificateReason](docs/RevokeCertificateReason.md) - - [Model.RevokeCertificateReasonIssuerDN](docs/RevokeCertificateReasonIssuerDN.md) - - [Model.SortDirectionEnum](docs/SortDirectionEnum.md) - - -## Documentation for Authorization - -All endpoints do not require authorization. diff --git a/HydrantIdProxy/docs/AuthenticationApi.md b/HydrantIdProxy/docs/AuthenticationApi.md deleted file mode 100644 index 89989c8..0000000 --- a/HydrantIdProxy/docs/AuthenticationApi.md +++ /dev/null @@ -1,361 +0,0 @@ -# IO.Swagger.Api.AuthenticationApi - -All URIs are relative to *https://acm-stage.hydrantid.com/api/v2* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**HawkGet**](AuthenticationApi.md#hawkget) | **GET** /hawk | Get all HAWK Credentials associated with the current user user -[**HawkIdDelete**](AuthenticationApi.md#hawkiddelete) | **DELETE** /hawk/{id} | Delete a specific HAWK credential -[**HawkIdGet**](AuthenticationApi.md#hawkidget) | **GET** /hawk/{id} | Get a specific HAWK Credential -[**HawkIdPatch**](AuthenticationApi.md#hawkidpatch) | **PATCH** /hawk/{id} | Add/update a comment for a specific HAWK credential. -[**HawkIdPut**](AuthenticationApi.md#hawkidput) | **PUT** /hawk/{id} | Create a new secret for a specific HAWK credential. -[**HawkPost**](AuthenticationApi.md#hawkpost) | **POST** /hawk | Create a new HAWK Credential for the current user - - -# **HawkGet** -> List HawkGet () - -Get all HAWK Credentials associated with the current user user - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class HawkGetExample - { - public void main() - { - var apiInstance = new AuthenticationApi(); - - try - { - // Get all HAWK Credentials associated with the current user user - List<HawkCredential> result = apiInstance.HawkGet(); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkGet: " + e.Message ); - } - } - } -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**List**](HawkCredential.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **HawkIdDelete** -> HawkCredentialDeleteResults HawkIdDelete (string id) - -Delete a specific HAWK credential - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class HawkIdDeleteExample - { - public void main() - { - var apiInstance = new AuthenticationApi(); - var id = id_example; // string | Identifier of HAWK credential to delete - - try - { - // Delete a specific HAWK credential - HawkCredentialDeleteResults result = apiInstance.HawkIdDelete(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkIdDelete: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **string**| Identifier of HAWK credential to delete | - -### Return type - -[**HawkCredentialDeleteResults**](HawkCredentialDeleteResults.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **HawkIdGet** -> HawkCredential HawkIdGet (string id) - -Get a specific HAWK Credential - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class HawkIdGetExample - { - public void main() - { - var apiInstance = new AuthenticationApi(); - var id = id_example; // string | Identifier of HAWK credential to retrieve - - try - { - // Get a specific HAWK Credential - HawkCredential result = apiInstance.HawkIdGet(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkIdGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **string**| Identifier of HAWK credential to retrieve | - -### Return type - -[**HawkCredential**](HawkCredential.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **HawkIdPatch** -> HawkCredential HawkIdPatch (string id, HawkCredentialComment body = null) - -Add/update a comment for a specific HAWK credential. - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class HawkIdPatchExample - { - public void main() - { - var apiInstance = new AuthenticationApi(); - var id = id_example; // string | Identifier of HAWK credential to update comments - var body = new HawkCredentialComment(); // HawkCredentialComment | Optional comment (max 255 characters) (optional) - - try - { - // Add/update a comment for a specific HAWK credential. - HawkCredential result = apiInstance.HawkIdPatch(id, body); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkIdPatch: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **string**| Identifier of HAWK credential to update comments | - **body** | [**HawkCredentialComment**](HawkCredentialComment.md)| Optional comment (max 255 characters) | [optional] - -### Return type - -[**HawkCredential**](HawkCredential.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **HawkIdPut** -> HawkCredential HawkIdPut (string id, HawkCredentialComment body = null) - -Create a new secret for a specific HAWK credential. - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class HawkIdPutExample - { - public void main() - { - var apiInstance = new AuthenticationApi(); - var id = id_example; // string | Identifier of HAWK credential to update - var body = new HawkCredentialComment(); // HawkCredentialComment | Optional comment (max 255 characters) (optional) - - try - { - // Create a new secret for a specific HAWK credential. - HawkCredential result = apiInstance.HawkIdPut(id, body); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkIdPut: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **string**| Identifier of HAWK credential to update | - **body** | [**HawkCredentialComment**](HawkCredentialComment.md)| Optional comment (max 255 characters) | [optional] - -### Return type - -[**HawkCredential**](HawkCredential.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **HawkPost** -> HawkCredential HawkPost (HawkCredentialComments body = null) - -Create a new HAWK Credential for the current user - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class HawkPostExample - { - public void main() - { - var apiInstance = new AuthenticationApi(); - var body = new HawkCredentialComments(); // HawkCredentialComments | Optional comment (max 255 characters) (optional) - - try - { - // Create a new HAWK Credential for the current user - HawkCredential result = apiInstance.HawkPost(body); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling AuthenticationApi.HawkPost: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **body** | [**HawkCredentialComments**](HawkCredentialComments.md)| Optional comment (max 255 characters) | [optional] - -### Return type - -[**HawkCredential**](HawkCredential.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/HydrantIdProxy/docs/CertRequest.md b/HydrantIdProxy/docs/CertRequest.md deleted file mode 100644 index a171488..0000000 --- a/HydrantIdProxy/docs/CertRequest.md +++ /dev/null @@ -1,18 +0,0 @@ -# IO.Swagger.Model.CertRequest -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | -**Source** | **string** | | -**Fingerprint** | **string** | | -**Csr** | **string** | | -**CommonName** | **string** | | -**Details** | **Dictionary<string, Object>** | | -**IssuanceStatus** | **IssuanceStatus** | | -**CreateAt** | **DateTime?** | | [optional] -**Policy** | [**CertRequestPolicy**](CertRequestPolicy.md) | | [optional] -**User** | [**CertRequestUser**](CertRequestUser.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestBody.md b/HydrantIdProxy/docs/CertRequestBody.md deleted file mode 100644 index bf762e9..0000000 --- a/HydrantIdProxy/docs/CertRequestBody.md +++ /dev/null @@ -1,18 +0,0 @@ -# IO.Swagger.Model.CertRequestBody -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Policy** | **Guid?** | | -**Csr** | **string** | | -**Validity** | [**CertRequestBodyValidity**](CertRequestBodyValidity.md) | | [optional] -**DnComponents** | [**CertRequestBodyDnComponents**](CertRequestBodyDnComponents.md) | | -**SubjectAltNames** | [**CertRequestBodySubjectAltNames**](CertRequestBodySubjectAltNames.md) | | [optional] -**CustomFields** | **Dictionary<string, Object>** | | [optional] -**CustomExtensions** | **Dictionary<string, Object>** | | [optional] -**Comment** | **string** | | [optional] -**ExpiryEmails** | **List<string>** | | [optional] -**ClearRemindersCertificateId** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestBodyDnComponents.md b/HydrantIdProxy/docs/CertRequestBodyDnComponents.md deleted file mode 100644 index 9a514ea..0000000 --- a/HydrantIdProxy/docs/CertRequestBodyDnComponents.md +++ /dev/null @@ -1,15 +0,0 @@ -# IO.Swagger.Model.CertRequestBodyDnComponents -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**CN** | **string** | | [optional] -**OU** | **List<string>** | | [optional] -**O** | **string** | | [optional] -**L** | **string** | | [optional] -**ST** | **string** | | [optional] -**C** | **string** | | [optional] -**DC** | **List<string>** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestBodySubjectAltNames.md b/HydrantIdProxy/docs/CertRequestBodySubjectAltNames.md deleted file mode 100644 index c82a43e..0000000 --- a/HydrantIdProxy/docs/CertRequestBodySubjectAltNames.md +++ /dev/null @@ -1,12 +0,0 @@ -# IO.Swagger.Model.CertRequestBodySubjectAltNames -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**DNSNAME** | **List<string>** | | [optional] -**IPADDRESS** | **List<string>** | | [optional] -**RFC822NAME** | **List<string>** | | [optional] -**UPN** | **List<string>** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestBodyValidity.md b/HydrantIdProxy/docs/CertRequestBodyValidity.md deleted file mode 100644 index 83f0382..0000000 --- a/HydrantIdProxy/docs/CertRequestBodyValidity.md +++ /dev/null @@ -1,11 +0,0 @@ -# IO.Swagger.Model.CertRequestBodyValidity -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Years** | **int?** | | [optional] -**Months** | **int?** | | [optional] -**Days** | **int?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestPolicy.md b/HydrantIdProxy/docs/CertRequestPolicy.md deleted file mode 100644 index 280175c..0000000 --- a/HydrantIdProxy/docs/CertRequestPolicy.md +++ /dev/null @@ -1,10 +0,0 @@ -# IO.Swagger.Model.CertRequestPolicy -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | [optional] -**Name** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestStatus.md b/HydrantIdProxy/docs/CertRequestStatus.md deleted file mode 100644 index 0bc73bf..0000000 --- a/HydrantIdProxy/docs/CertRequestStatus.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.CertRequestStatus -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **string** | | -**IssuanceStatus** | **IssuanceStatus** | | -**IssuanceStatusDetails** | **Dictionary<string, Object>** | | [optional] -**CertificateId** | **Guid?** | | [optional] -**RevocationStatus** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertRequestUser.md b/HydrantIdProxy/docs/CertRequestUser.md deleted file mode 100644 index bf9b927..0000000 --- a/HydrantIdProxy/docs/CertRequestUser.md +++ /dev/null @@ -1,11 +0,0 @@ -# IO.Swagger.Model.CertRequestUser -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | [optional] -**FirstName** | **string** | | [optional] -**LastName** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/Certificate.md b/HydrantIdProxy/docs/Certificate.md deleted file mode 100644 index e7c973f..0000000 --- a/HydrantIdProxy/docs/Certificate.md +++ /dev/null @@ -1,28 +0,0 @@ -# IO.Swagger.Model.Certificate -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | -**Serial** | **string** | | -**CommonName** | **string** | | -**SubjectDN** | **string** | | -**IssuerDN** | **string** | | -**NotBefore** | **DateTime?** | | -**NotAfter** | **DateTime?** | | -**SignatureAlgorithm** | **string** | | -**RevocationStatus** | **RevocationStatusEnum** | | -**RevocationReason** | **int?** | | -**RevocationDate** | **DateTime?** | | [optional] -**Pem** | **string** | | -**Imported** | **bool?** | | -**CreatedAt** | **DateTime?** | | -**SANs** | **List<string>** | | [optional] -**Policy** | [**CertRequestPolicy**](CertRequestPolicy.md) | | [optional] -**User** | [**CertificateUser**](CertificateUser.md) | | [optional] -**Account** | [**CertRequestPolicy**](CertRequestPolicy.md) | | [optional] -**Organization** | [**CertRequestPolicy**](CertRequestPolicy.md) | | [optional] -**ExpiryNotifications** | **List<string>** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertificateRequestsApi.md b/HydrantIdProxy/docs/CertificateRequestsApi.md deleted file mode 100644 index b0491f3..0000000 --- a/HydrantIdProxy/docs/CertificateRequestsApi.md +++ /dev/null @@ -1,184 +0,0 @@ -# IO.Swagger.Api.CertificateRequestsApi - -All URIs are relative to *https://acm-stage.hydrantid.com/api/v2* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**CsrIdGet**](CertificateRequestsApi.md#csridget) | **GET** /csr/{id} | Retrieves a given certRequest, including all details -[**CsrIdStatusGet**](CertificateRequestsApi.md#csridstatusget) | **GET** /csr/{id}/status | Retrieves issuance status of certRequest, including certificateId if issued -[**CsrPost**](CertificateRequestsApi.md#csrpost) | **POST** /csr | Create a certificate request - - -# **CsrIdGet** -> CertRequest CsrIdGet (Guid? id) - -Retrieves a given certRequest, including all details - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CsrIdGetExample - { - public void main() - { - var apiInstance = new CertificateRequestsApi(); - var id = new Guid?(); // Guid? | Certificate Request ID - - try - { - // Retrieves a given certRequest, including all details - CertRequest result = apiInstance.CsrIdGet(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificateRequestsApi.CsrIdGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**Guid?**](Guid?.md)| Certificate Request ID | - -### Return type - -[**CertRequest**](CertRequest.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CsrIdStatusGet** -> CertRequestStatus CsrIdStatusGet (Guid? id) - -Retrieves issuance status of certRequest, including certificateId if issued - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CsrIdStatusGetExample - { - public void main() - { - var apiInstance = new CertificateRequestsApi(); - var id = new Guid?(); // Guid? | Certificate Request ID - - try - { - // Retrieves issuance status of certRequest, including certificateId if issued - CertRequestStatus result = apiInstance.CsrIdStatusGet(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificateRequestsApi.CsrIdStatusGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**Guid?**](Guid?.md)| Certificate Request ID | - -### Return type - -[**CertRequestStatus**](CertRequestStatus.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CsrPost** -> CertRequestStatus CsrPost (CertRequestBody body = null) - -Create a certificate request - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CsrPostExample - { - public void main() - { - var apiInstance = new CertificateRequestsApi(); - var body = new CertRequestBody(); // CertRequestBody | (optional) - - try - { - // Create a certificate request - CertRequestStatus result = apiInstance.CsrPost(body); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificateRequestsApi.CsrPost: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **body** | [**CertRequestBody**](CertRequestBody.md)| | [optional] - -### Return type - -[**CertRequestStatus**](CertRequestStatus.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/HydrantIdProxy/docs/CertificateStatus.md b/HydrantIdProxy/docs/CertificateStatus.md deleted file mode 100644 index eb1d1e2..0000000 --- a/HydrantIdProxy/docs/CertificateStatus.md +++ /dev/null @@ -1,12 +0,0 @@ -# IO.Swagger.Model.CertificateStatus -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | -**RevocationStatus** | **RevocationStatusEnum** | | -**RevocationReason** | **RevocationReasons** | | [optional] -**RevocationDate** | **DateTime?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertificateUser.md b/HydrantIdProxy/docs/CertificateUser.md deleted file mode 100644 index cd02911..0000000 --- a/HydrantIdProxy/docs/CertificateUser.md +++ /dev/null @@ -1,10 +0,0 @@ -# IO.Swagger.Model.CertificateUser -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | [optional] -**Email** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/CertificatesApi.md b/HydrantIdProxy/docs/CertificatesApi.md deleted file mode 100644 index b9b05b1..0000000 --- a/HydrantIdProxy/docs/CertificatesApi.md +++ /dev/null @@ -1,428 +0,0 @@ -# IO.Swagger.Api.CertificatesApi - -All URIs are relative to *https://acm-stage.hydrantid.com/api/v2* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**CertificatesIdDerGet**](CertificatesApi.md#certificatesidderget) | **GET** /certificates/{id}/der | Download DER format certificate -[**CertificatesIdGet**](CertificatesApi.md#certificatesidget) | **GET** /certificates/{id} | Get a specific certificate -[**CertificatesIdPatch**](CertificatesApi.md#certificatesidpatch) | **PATCH** /certificates/{id} | Revoke a certificate given a certificate id -[**CertificatesIdPemGet**](CertificatesApi.md#certificatesidpemget) | **GET** /certificates/{id}/pem | Download PEM format certificate -[**CertificatesIdStatusGet**](CertificatesApi.md#certificatesidstatusget) | **GET** /certificates/{id}/status | Get certificate status -[**CertificatesPost**](CertificatesApi.md#certificatespost) | **POST** /certificates | Get Certificates -[**CertificatesSerialNumberPatch**](CertificatesApi.md#certificatesserialnumberpatch) | **PATCH** /certificates/{serialNumber} | Revoke a certificate given a serialNumber and issuerDN - - -# **CertificatesIdDerGet** -> byte[] CertificatesIdDerGet (Guid? id, bool? chain = null) - -Download DER format certificate - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesIdDerGetExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var id = new Guid?(); // Guid? | Certificate ID - var chain = true; // bool? | Include Chain (optional) - - try - { - // Download DER format certificate - byte[] result = apiInstance.CertificatesIdDerGet(id, chain); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesIdDerGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**Guid?**](Guid?.md)| Certificate ID | - **chain** | **bool?**| Include Chain | [optional] - -### Return type - -**byte[]** - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/pkix-cert - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CertificatesIdGet** -> Certificate CertificatesIdGet (Guid? id) - -Get a specific certificate - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesIdGetExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var id = new Guid?(); // Guid? | Certificate ID - - try - { - // Get a specific certificate - Certificate result = apiInstance.CertificatesIdGet(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesIdGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**Guid?**](Guid?.md)| Certificate ID | - -### Return type - -[**Certificate**](Certificate.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CertificatesIdPatch** -> CertificateStatus CertificatesIdPatch (RevokeCertificateReason body, string id) - -Revoke a certificate given a certificate id - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesIdPatchExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var body = new RevokeCertificateReason(); // RevokeCertificateReason | Revocation reason. - var id = id_example; // string | Certificate id - - try - { - // Revoke a certificate given a certificate id - CertificateStatus result = apiInstance.CertificatesIdPatch(body, id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesIdPatch: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **body** | [**RevokeCertificateReason**](RevokeCertificateReason.md)| Revocation reason. | - **id** | **string**| Certificate id | - -### Return type - -[**CertificateStatus**](CertificateStatus.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CertificatesIdPemGet** -> byte[] CertificatesIdPemGet (Guid? id, bool? chain = null) - -Download PEM format certificate - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesIdPemGetExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var id = new Guid?(); // Guid? | Certificate ID - var chain = true; // bool? | Include Chain (optional) - - try - { - // Download PEM format certificate - byte[] result = apiInstance.CertificatesIdPemGet(id, chain); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesIdPemGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**Guid?**](Guid?.md)| Certificate ID | - **chain** | **bool?**| Include Chain | [optional] - -### Return type - -**byte[]** - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/x-pem-file - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CertificatesIdStatusGet** -> CertificateStatus CertificatesIdStatusGet (string id) - -Get certificate status - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesIdStatusGetExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var id = id_example; // string | Certificate ID - - try - { - // Get certificate status - CertificateStatus result = apiInstance.CertificatesIdStatusGet(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesIdStatusGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **string**| Certificate ID | - -### Return type - -[**CertificateStatus**](CertificateStatus.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CertificatesPost** -> GetCertificatesResponse CertificatesPost (GetCertificatesPayload body = null) - -Get Certificates - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesPostExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var body = new GetCertificatesPayload(); // GetCertificatesPayload | Filter Certificates (optional) - - try - { - // Get Certificates - GetCertificatesResponse result = apiInstance.CertificatesPost(body); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesPost: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **body** | [**GetCertificatesPayload**](GetCertificatesPayload.md)| Filter Certificates | [optional] - -### Return type - -[**GetCertificatesResponse**](GetCertificatesResponse.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **CertificatesSerialNumberPatch** -> CertificateStatus CertificatesSerialNumberPatch (RevokeCertificateReasonIssuerDN body, string serialNumber) - -Revoke a certificate given a serialNumber and issuerDN - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class CertificatesSerialNumberPatchExample - { - public void main() - { - var apiInstance = new CertificatesApi(); - var body = new RevokeCertificateReasonIssuerDN(); // RevokeCertificateReasonIssuerDN | Revocation reason and issuer DN - var serialNumber = serialNumber_example; // string | Serial number in hexadecimal format. - - try - { - // Revoke a certificate given a serialNumber and issuerDN - CertificateStatus result = apiInstance.CertificatesSerialNumberPatch(body, serialNumber); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling CertificatesApi.CertificatesSerialNumberPatch: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **body** | [**RevokeCertificateReasonIssuerDN**](RevokeCertificateReasonIssuerDN.md)| Revocation reason and issuer DN | - **serialNumber** | **string**| Serial number in hexadecimal format. | - -### Return type - -[**CertificateStatus**](CertificateStatus.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/HydrantIdProxy/docs/GetCertificatesPayload.md b/HydrantIdProxy/docs/GetCertificatesPayload.md deleted file mode 100644 index b02d0e6..0000000 --- a/HydrantIdProxy/docs/GetCertificatesPayload.md +++ /dev/null @@ -1,22 +0,0 @@ -# IO.Swagger.Model.GetCertificatesPayload -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**CommonName** | **string** | | [optional] -**Serial** | **string** | | [optional] -**NotBefore** | **DateTime?** | | [optional] -**NotAfter** | **DateTime?** | | [optional] -**Expired** | **bool?** | | [optional] [default to false] -**Status** | **RevocationStatusEnum** | | [optional] -**Account** | **Guid?** | | [optional] -**Organization** | **Guid?** | | [optional] -**Policy** | **Guid?** | | [optional] -**Limit** | **int?** | | [optional] [default to 10] -**Offset** | **int?** | | [optional] [default to 0] -**SortType** | **string** | | [optional] -**SortDirection** | **SortDirectionEnum** | | [optional] -**Pem** | **bool?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/GetCertificatesResponse.md b/HydrantIdProxy/docs/GetCertificatesResponse.md deleted file mode 100644 index 2c1dbf5..0000000 --- a/HydrantIdProxy/docs/GetCertificatesResponse.md +++ /dev/null @@ -1,10 +0,0 @@ -# IO.Swagger.Model.GetCertificatesResponse -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Count** | **int?** | | [optional] -**Items** | [**List<GetCertificatesResponseItem>**](GetCertificatesResponseItem.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/GetCertificatesResponseItem.md b/HydrantIdProxy/docs/GetCertificatesResponseItem.md deleted file mode 100644 index f183454..0000000 --- a/HydrantIdProxy/docs/GetCertificatesResponseItem.md +++ /dev/null @@ -1,16 +0,0 @@ -# IO.Swagger.Model.GetCertificatesResponseItem -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **string** | | [optional] -**CommonName** | **string** | | [optional] -**Serial** | **string** | | [optional] -**NotBefore** | **DateTime?** | | [optional] -**NotAfter** | **DateTime?** | | [optional] -**RevocationStatus** | **RevocationStatusEnum** | | [optional] -**SANs** | **List<string>** | | [optional] -**Policy** | [**NameObject**](NameObject.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/HawkCredential.md b/HydrantIdProxy/docs/HawkCredential.md deleted file mode 100644 index e0168cb..0000000 --- a/HydrantIdProxy/docs/HawkCredential.md +++ /dev/null @@ -1,14 +0,0 @@ -# IO.Swagger.Model.HawkCredential -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **string** | HAWK Identifier | -**Key** | **string** | HAWK Key - *Only returned on create or roll* | [optional] -**Comments** | **string** | Comment for HAWK credential | [optional] -**LastUsed** | **DateTime?** | Date/time HAWK credential last used | [optional] -**CreatedAt** | **DateTime?** | Date/time HAWK credential created | -**UpdatedAt** | **DateTime?** | Date/time HAWK credential updated | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/HawkCredentialComment.md b/HydrantIdProxy/docs/HawkCredentialComment.md deleted file mode 100644 index 98be76f..0000000 --- a/HydrantIdProxy/docs/HawkCredentialComment.md +++ /dev/null @@ -1,9 +0,0 @@ -# IO.Swagger.Model.HawkCredentialComment -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Comments** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/HawkCredentialComments.md b/HydrantIdProxy/docs/HawkCredentialComments.md deleted file mode 100644 index 8a81f6c..0000000 --- a/HydrantIdProxy/docs/HawkCredentialComments.md +++ /dev/null @@ -1,9 +0,0 @@ -# IO.Swagger.Model.HawkCredentialComments -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Comments** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/HawkCredentialDeleteResults.md b/HydrantIdProxy/docs/HawkCredentialDeleteResults.md deleted file mode 100644 index d363d56..0000000 --- a/HydrantIdProxy/docs/HawkCredentialDeleteResults.md +++ /dev/null @@ -1,10 +0,0 @@ -# IO.Swagger.Model.HawkCredentialDeleteResults -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **string** | | [optional] -**Deleted** | **bool?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/IssuanceStatus.md b/HydrantIdProxy/docs/IssuanceStatus.md deleted file mode 100644 index 24527c0..0000000 --- a/HydrantIdProxy/docs/IssuanceStatus.md +++ /dev/null @@ -1,8 +0,0 @@ -# IO.Swagger.Model.IssuanceStatus -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/NameObject.md b/HydrantIdProxy/docs/NameObject.md deleted file mode 100644 index 6396d1e..0000000 --- a/HydrantIdProxy/docs/NameObject.md +++ /dev/null @@ -1,9 +0,0 @@ -# IO.Swagger.Model.NameObject -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Name** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PoliciesApi.md b/HydrantIdProxy/docs/PoliciesApi.md deleted file mode 100644 index 21c6386..0000000 --- a/HydrantIdProxy/docs/PoliciesApi.md +++ /dev/null @@ -1,188 +0,0 @@ -# IO.Swagger.Api.PoliciesApi - -All URIs are relative to *https://acm-stage.hydrantid.com/api/v2* - -Method | HTTP request | Description -------------- | ------------- | ------------- -[**PoliciesGet**](PoliciesApi.md#policiesget) | **GET** /policies | Get all policies -[**PoliciesIdGet**](PoliciesApi.md#policiesidget) | **GET** /policies/{id} | Get a specific policy -[**PoliciesIdPut**](PoliciesApi.md#policiesidput) | **PUT** /policies/{id} | Update a policy with preview changes - - -# **PoliciesGet** -> List PoliciesGet (string imported = null) - -Get all policies - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class PoliciesGetExample - { - public void main() - { - var apiInstance = new PoliciesApi(); - var imported = imported_example; // string | Load imported policies (type = IMPORTED) - true: include imported, false: exclude imported, only: only imported (optional) - - try - { - // Get all policies - List<Policy> result = apiInstance.PoliciesGet(imported); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling PoliciesApi.PoliciesGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **imported** | **string**| Load imported policies (type = IMPORTED) - true: include imported, false: exclude imported, only: only imported | [optional] - -### Return type - -[**List**](Policy.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **PoliciesIdGet** -> Policy PoliciesIdGet (Guid? id) - -Get a specific policy - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class PoliciesIdGetExample - { - public void main() - { - var apiInstance = new PoliciesApi(); - var id = new Guid?(); // Guid? | Policy id - - try - { - // Get a specific policy - Policy result = apiInstance.PoliciesIdGet(id); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling PoliciesApi.PoliciesIdGet: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | [**Guid?**](Guid?.md)| Policy id | - -### Return type - -[**Policy**](Policy.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - -# **PoliciesIdPut** -> Policy PoliciesIdPut (string id, Policy body = null, string commit = null) - -Update a policy with preview changes - -### Example -```csharp -using System; -using System.Diagnostics; -using IO.Swagger.Api; -using IO.Swagger.Client; -using IO.Swagger.Model; - -namespace Example -{ - public class PoliciesIdPutExample - { - public void main() - { - var apiInstance = new PoliciesApi(); - var id = id_example; // string | Policy id - var body = new Policy(); // Policy | (optional) - var commit = commit_example; // string | if commit=true then the policy will be updated (optional) - - try - { - // Update a policy with preview changes - Policy result = apiInstance.PoliciesIdPut(id, body, commit); - Debug.WriteLine(result); - } - catch (Exception e) - { - Debug.Print("Exception when calling PoliciesApi.PoliciesIdPut: " + e.Message ); - } - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **id** | **string**| Policy id | - **body** | [**Policy**](Policy.md)| | [optional] - **commit** | **string**| if commit=true then the policy will be updated | [optional] - -### Return type - -[**Policy**](Policy.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: application/json - - **Accept**: application/json - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/HydrantIdProxy/docs/Policy.md b/HydrantIdProxy/docs/Policy.md deleted file mode 100644 index fc8bfde..0000000 --- a/HydrantIdProxy/docs/Policy.md +++ /dev/null @@ -1,15 +0,0 @@ -# IO.Swagger.Model.Policy -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Id** | **Guid?** | | -**Name** | **string** | | -**ApiId** | **int?** | | -**Details** | [**PolicyDetails**](PolicyDetails.md) | | -**Enabled** | [**PolicyEnabled**](PolicyEnabled.md) | | -**OrganizationId** | **Guid?** | | -**CertificateAuthorityId** | **Guid?** | | - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetails.md b/HydrantIdProxy/docs/PolicyDetails.md deleted file mode 100644 index aa6d890..0000000 --- a/HydrantIdProxy/docs/PolicyDetails.md +++ /dev/null @@ -1,15 +0,0 @@ -# IO.Swagger.Model.PolicyDetails -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Validity** | [**PolicyDetailsValidity**](PolicyDetailsValidity.md) | | [optional] -**DnComponents** | [**List<PolicyDetailsDnComponents>**](PolicyDetailsDnComponents.md) | | -**SubjectAltNames** | [**List<PolicyDetailsSubjectAltNames>**](PolicyDetailsSubjectAltNames.md) | | [optional] -**ApprovalRequired** | **bool?** | | [optional] -**ExpiryEmails** | [**PolicyDetailsExpiryEmails**](PolicyDetailsExpiryEmails.md) | | [optional] -**CustomFields** | [**List<PolicyDetailsCustomFields>**](PolicyDetailsCustomFields.md) | | [optional] -**CustomExtensions** | [**List<PolicyDetailsCustomExtensions>**](PolicyDetailsCustomExtensions.md) | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetailsCustomExtensions.md b/HydrantIdProxy/docs/PolicyDetailsCustomExtensions.md deleted file mode 100644 index aa371c3..0000000 --- a/HydrantIdProxy/docs/PolicyDetailsCustomExtensions.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.PolicyDetailsCustomExtensions -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Oid** | **string** | | [optional] -**Label** | **string** | | [optional] -**Required** | **bool?** | | [optional] -**Modifiable** | **bool?** | | [optional] -**DefaultValue** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetailsCustomFields.md b/HydrantIdProxy/docs/PolicyDetailsCustomFields.md deleted file mode 100644 index c413fdd..0000000 --- a/HydrantIdProxy/docs/PolicyDetailsCustomFields.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.PolicyDetailsCustomFields -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Tag** | **string** | | [optional] -**Label** | **string** | | [optional] -**Required** | **bool?** | | [optional] -**Modifiable** | **bool?** | | [optional] -**DefaultValue** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetailsDnComponents.md b/HydrantIdProxy/docs/PolicyDetailsDnComponents.md deleted file mode 100644 index 726636f..0000000 --- a/HydrantIdProxy/docs/PolicyDetailsDnComponents.md +++ /dev/null @@ -1,14 +0,0 @@ -# IO.Swagger.Model.PolicyDetailsDnComponents -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Tag** | **string** | | [optional] -**Label** | **string** | | [optional] -**Required** | **bool?** | | [optional] -**Modifiable** | **bool?** | | [optional] -**DefaultValue** | **string** | | [optional] -**CopyAsFirstSAN** | **bool?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetailsExpiryEmails.md b/HydrantIdProxy/docs/PolicyDetailsExpiryEmails.md deleted file mode 100644 index cfe090a..0000000 --- a/HydrantIdProxy/docs/PolicyDetailsExpiryEmails.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.PolicyDetailsExpiryEmails -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Tag** | **string** | | [optional] -**Label** | **string** | | [optional] -**Required** | **bool?** | | [optional] -**Modifiable** | **bool?** | | [optional] -**DefaultValue** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetailsSubjectAltNames.md b/HydrantIdProxy/docs/PolicyDetailsSubjectAltNames.md deleted file mode 100644 index 55ba2aa..0000000 --- a/HydrantIdProxy/docs/PolicyDetailsSubjectAltNames.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.PolicyDetailsSubjectAltNames -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Tag** | **string** | | [optional] -**Label** | **string** | | [optional] -**Required** | **bool?** | | [optional] -**Modifiable** | **bool?** | | [optional] -**DefaultValue** | **string** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyDetailsValidity.md b/HydrantIdProxy/docs/PolicyDetailsValidity.md deleted file mode 100644 index 0e2c176..0000000 --- a/HydrantIdProxy/docs/PolicyDetailsValidity.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.PolicyDetailsValidity -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Years** | **string** | | [optional] -**Months** | **string** | | [optional] -**Days** | **string** | | [optional] -**Required** | **bool?** | | [optional] -**Modifiable** | **bool?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/PolicyEnabled.md b/HydrantIdProxy/docs/PolicyEnabled.md deleted file mode 100644 index 1e798dd..0000000 --- a/HydrantIdProxy/docs/PolicyEnabled.md +++ /dev/null @@ -1,13 +0,0 @@ -# IO.Swagger.Model.PolicyEnabled -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Ui** | **bool?** | | [optional] -**Rest** | **bool?** | | [optional] -**Acme** | **bool?** | | [optional] -**Scep** | **bool?** | | [optional] -**Est** | **bool?** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/RevocationReasons.md b/HydrantIdProxy/docs/RevocationReasons.md deleted file mode 100644 index ab8e947..0000000 --- a/HydrantIdProxy/docs/RevocationReasons.md +++ /dev/null @@ -1,8 +0,0 @@ -# IO.Swagger.Model.RevocationReasons -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/RevocationStatusEnum.md b/HydrantIdProxy/docs/RevocationStatusEnum.md deleted file mode 100644 index 3a5c97f..0000000 --- a/HydrantIdProxy/docs/RevocationStatusEnum.md +++ /dev/null @@ -1,8 +0,0 @@ -# IO.Swagger.Model.RevocationStatusEnum -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/RevokeCertificateReason.md b/HydrantIdProxy/docs/RevokeCertificateReason.md deleted file mode 100644 index 5b7416f..0000000 --- a/HydrantIdProxy/docs/RevokeCertificateReason.md +++ /dev/null @@ -1,9 +0,0 @@ -# IO.Swagger.Model.RevokeCertificateReason -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Reason** | **RevocationReasons** | | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/RevokeCertificateReasonIssuerDN.md b/HydrantIdProxy/docs/RevokeCertificateReasonIssuerDN.md deleted file mode 100644 index fadb03f..0000000 --- a/HydrantIdProxy/docs/RevokeCertificateReasonIssuerDN.md +++ /dev/null @@ -1,10 +0,0 @@ -# IO.Swagger.Model.RevokeCertificateReasonIssuerDN -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**Reason** | **RevocationReasons** | | [optional] -**IssuerDN** | **string** | Issuer distinguished name | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/docs/SortDirectionEnum.md b/HydrantIdProxy/docs/SortDirectionEnum.md deleted file mode 100644 index cca3e67..0000000 --- a/HydrantIdProxy/docs/SortDirectionEnum.md +++ /dev/null @@ -1,8 +0,0 @@ -# IO.Swagger.Model.SortDirectionEnum -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - diff --git a/HydrantIdProxy/src/HydrantIdProxy/app.config b/HydrantIdProxy/src/HydrantIdProxy/app.config deleted file mode 100644 index e7bfe44..0000000 --- a/HydrantIdProxy/src/HydrantIdProxy/app.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/HydrantIdProxy/src/HydrantIdProxy/packages.config b/HydrantIdProxy/src/HydrantIdProxy/packages.config deleted file mode 100644 index 398501b..0000000 --- a/HydrantIdProxy/src/HydrantIdProxy/packages.config +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index b244def..e6ecb96 100644 --- a/README.md +++ b/README.md @@ -1,223 +1,264 @@ +

+ GCP CAS AnyCA Gateway DCOM plugin +

-# HydrantId +

+ +Integration Status: production +Release +Issues +GitHub Downloads (all assets, all releases) +

-HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command the ability to: - Sync certificates issued from the CA - Request new certificates from the CA - Revoke certificates directly from Keyfactor Command -Renew or Reissue Certificates from the CA +

+ + + Support + + · + + License + + · + + Related Integrations + +

-#### Integration status: Production - Ready for use in production environments. +## Support +The GCP CAS AnyCA Gateway DCOM plugin is open source and there is **no SLA**. Keyfactor will address issues as resources become available. Keyfactor customers may request escalation by opening up a support ticket through their Keyfactor representative. -## About the Keyfactor AnyCA Gateway DCOM Connector +> To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. -This repository contains an AnyCA Gateway Connector, which is a plugin to the Keyfactor AnyGateway. AnyCA Gateway Connectors allow Keyfactor Command to be used for inventory, issuance, and revocation of certificates from a third-party certificate authority. -## Support for HydrantId +## Overview -HydrantId is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com +The [Google Cloud Platform (GCP) CA Services (CAS)](https://cloud.google.com/security/products/certificate-authority-service) AnyCA Gateway DCOM plugin extends the capabilities of connected GCP CAS CAs to [Keyfactor Command](https://www.keyfactor.com/products/command/) via the Keyfactor AnyCA Gateway DCOM. The plugin represents a fully featured AnyCA DCOM Plugin with the following capabilies: -###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. +* CA Sync: + * Download all certificates issued by connected Enterprise tier CAs in GCP CAS (full sync). + * Download all certificates issued by connected Enterprise tier CAs in GCP CAS issued after a specified time (incremental sync). +* Certificate enrollment for all published GoDaddy Certificate SKUs: + * Support certificate enrollment (new keys/certificate). +* Certificate revocation: + * Request revocation of a previously issued certificate. ---- +> The GCP CAS AnyCA Gateway DCOM plugin is **not** supported for [DevOps Tier](https://cloud.google.com/certificate-authority-service/docs/tiers) Certificate Authority Pools. +> +> DevOps tier CA Pools don't offer listing, describing, or revoking certificates. +## Compatibility ---- +This AnyGateway is designed to be used with version 24.2 of the Keyfactor AnyCA Gateway DCOM Framework. +## Requirements +### Application Default Credentials +The GCP CAS AnyCA Gateway DCOM plugin connects to and authenticates with GCP CAS implicitly using [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials). This means that all authentication-related configuration of the GCP CAS AnyCA Gateway REST plugin is implied by the environment where the AnyCA Gateway REST itself is running. +Please refer to [Google's documentation](https://cloud.google.com/docs/authentication/provide-credentials-adc) to configure ADC on the server running the AnyCA Gateway REST. -## Keyfactor AnyCA Gateway Framework Supported -The Keyfactor gateway framework implements common logic shared across various gateway implementations and handles communication with Keyfactor Command. The gateway framework hosts gateway implementations or plugins that understand how to communicate with specific CAs. This allows you to integrate your third-party CAs with Keyfactor Command such that they behave in a manner similar to the CAs natively supported by Keyfactor Command. +> The easiest way to configure ADC for non-production environments is to use [User Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev). +> +> For production environments that use an ADC method requiring the `GOOGLE_APPLICATION_CREDENTIALS` environment variable, you must ensure the following: +> +> 1. The service account that the AnyCA Gateway REST runs under must have read permission to the GCP credential JSON file. +> 2. You must set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable for the Windows Service running the AnyCA Gateway REST using the [Windows registry editor](https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/windows-registry-advanced-users). +> * Refer to the [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment](https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables) docs. +If the selected ADC mechanism is [Service Account Key](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif-key), it's recommended that a [custom role is created](https://cloud.google.com/iam/docs/creating-custom-roles) that has the following minimum permissions: +* `privateca.certificateTemplates.list` +* `privateca.certificateTemplates.use` +* `privateca.certificateAuthorities.get` +* `privateca.certificates.create` +* `privateca.certificates.get` +* `privateca.certificates.list` +* `privateca.certificates.update` +* `privateca.caPools.get` +> The built-in CA Service Operation Manager `roles/privateca.caManager` role can also be used, but is more permissive than a custom role with the above permissions. -This gateway extension was compiled against version of the AnyCA Gateway DCOM Framework. You will need at least this version of the framework Installed. If you have a later AnyGateway Framework Installed you will probably need to add binding redirects in the CAProxyServer.exe.config file to make things work properly. +### Root CA Configuration +Both the Keyfactor Command and AnyCA Gateway DCOM servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from GCP [CAS](https://console.cloud.google.com/security/cas), and import them into the appropriate certificate store on the AnyCA Gateway DCOM server. -[Keyfactor CAGateway Install Guide](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm) +* **Windows** - The root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. + * Certificates can be imported in MMC by "File" -> "Add/Remove Snap-in" -> "Certificates" -> "Add >" -> "Computer account" -> "Local computer". + * Root CAs must go in the `Trusted Root Certification Authorities` certificate store. + * Subordinate CAs must go in the `Intermediate Certification Authorities` certificate store. +> If the Root CA and chain are not known by the server hosting the AnyCA Gateway DCOM, the certificate chain _may not_ be returned to Command in certificate enrollment requests. +### Template Identification ---- +The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). Certificate Templates exist at the Project level in GCP. Before installing the plugin, identify the [Certificate Templates](https://console.cloud.google.com/security/cas) that you want to make available to Keyfactor Command and [create Certificate Templates in AD](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Preparing_Templates.htm). +> Certificate Templates in GCP are not required. The plugin will not specify a template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate) if the `ProductId` (discussed later) is set to `Default`. -*** -# Getting Started -## Standard Gateway Installation -To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the HydrantId plugin. This integration was tested with Keyfactor 9.3.0.0. -To install the gateway follow these instructions. +## Installation -1) Gateway Server - run the installation .msi obtained from Keyfactor +1. Install AnyCA Gateway DCOM v24.2 per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm). -2) Gateway Server - If you have the rights to install the database (usually in a Non SQL PAAS Environment) Using Powershell, run the following command to create the gateway database. +2. Download the [latest GCP CAS AnyCA Gateway DCOM plugin assemblies](https://github.com/Keyfactor/gcp-cloud-cagateway/releases/latest). - **SQL Server Windows Auth** - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] - ``` - Note if you are using SQL Authentication, then you need to run - - **SQL Server SQL Authentication** +3. Copy `*.dll` to the `C:\Program Files\Keyfactor\Keyfactor AnyGateway` directory. - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` +4. Update the `CAProxyServer.config` file. + 1. Update the `$.configuration.unity.CAConnector` section to point at the `HydrantIdCAProxy` class. - If you do **not** have rights to created the database then have the database created ahead of time by the support team and just populate the database + ```xml + + ``` - ## Populate commands below + 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`. - **Windows Authentication** + ```xml + + + + + ``` - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] - ``` + 3. Add a `bindingRedirect` for `Google.Apis.Auth` to redirect versions from `0.0.0.0-1.67.0.0` to `1.67.0.0`. - **SQL Server SQL Authentication** + ```xml + + + + + ``` - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` + 4. Add a `bindingRedirect` for `System.Memory` to redirect versions from `0.0.0.0-4.0.1.2` to `4.0.1.1`. -3) Gateway Server - run the following Powershell to import the Cmdlets + ```xml + + + + + ``` - C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll (must be imported into Powershell) - ```ps - Import-Module C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll - ``` + > Depending on additional environment-specific factors, additional binding redirects may need to be applied to `CAProxyServer.config`. -4) Gateway Server - Run the Following Powershell script to set the gateway encryption cert +## Configuration +The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA. - ### Set-KeyfactorGatewayEncryptionCert - This cmdlet will generate a self-signed certificate used to encrypt the database connection string. It populates a registry value with the serial number of the certificate to be used. The certificate is stored in the LocalMachine Personal Store and the registry key populated is: +### Templates - ```HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvcProxy\Parameters\EncryptSerialNumber``` - No parameters are required to run this cmdlet. +As discussed in the [Template Identification](#template-identification), the GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). The Keyfactor AnyCA Gateway DCOM maps [AD Certificate Templates](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/certificate-template-concepts) to GCP Certificate Templates via the `ProductID` property in the `Templates` section of configuration files. -5) Gateway Server - Run the following Powershell Script to Set the Database Connection +_At least one_ Certificate Template must be defined in this section with the `ProductID` set to `Default`. This Product ID corresponds to no Certificate Template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate). - ### Set-KeyfactorGatewayDatabaseConnection - This cmdlet will set and encrypt the database connection string used by the AnyGateway service. +Subsequent Certificate Templates should set the `ProductID` to the Certificate Template ID in GCP CAS. - **Windows Authentication** - ```ps - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] - ``` - - **SQL Authentication** - ```ps - $KeyfactorCredentials = Get-Credentials - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] -Account [$KeyfactorCredentials] - ``` -## Standard Gateway Configuration Finished ---- +```json +"Templates": { + "GCPCASDefault": { + "ProductID": "Default", + "Parameters": { + "Lifetime": "300", /* Certificate validity in days */ + } + } +} +``` +> The `Lifetime` key should be added as a Custom Enrollment Parameter/Field for each Certificate Template in Keyfactor Command per the [official Keyfactor documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm). + +## Security + +Refer to the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/cmdlets.htm) to configure the `Security` section. The following is provided as an example. + +```json +/* Grant permissions on the CA to users or groups in the local domain. + READ: Enumerate and read contents of certificates. + ENROLL: Request certificates from the CA. + OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA. + ADMINISTRATOR: Configure/reconfigure the gateway. + + Valid permission settings are "Allow", "None", and "Deny". +*/ +"Security": { + "Keyfactor\\Administrator": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "Keyfactor\\gateway_test": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "Keyfactor\\SVC_TimerService": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "None" + }, + "Keyfactor\\SVC_AppPool": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + } +} +``` -## HydrantId AnyGateway Specific Configuration -It is important to note that importing the HydrantId configuration into the CA Gateway after installing the binaries must be completed. Additionally, the CA Gateway service -must be running in order to succesfully import the configuation. When the CA Gateway service starts it will attempt to validate the connection information to -the CA. Without the imported configuration, the service will fail to start. +## CAConnection -### Binary Installation +The `CAConnection` section selects the GCP Project/CA Pool/CA whose certificate operations will be extended to Keyfactor. There are three required fields. -1) Get the Latest Zip File from [Here](https://github.com/Keyfactor/hydrantid-cagateway/releases/) -2) Gateway Server - Copy the HawkNet.dll, The HydrantIdProxy.dll and the HydrantIdProxy.dll.config to the location where the Gateway Framework was installed (usually C:\Program Files\Keyfactor\Keyfactor AnyGateway) +* `ProjectId` - The Resource ID of the project that contains the Google CA Service. +* `LocationId` - The GCP location ID where the project containing the target GCP CAS CA is located. For example, 'us-central1'. +* `CAPoolId` - The CA Pool ID in GCP CAS to use for certificate operations. If the CA Pool has resource name `projects/my-project/locations/us-central1/caPools/my-pool`, this field should be set to `my-pool`. +* `CAId` (optional) - The CA ID of a CA in the same CA Pool as CAPool. For example, to issue certificates from a CA with resource name `projects/my-project/locations/us-central1/caPools/my-pool/certificateAuthorities/my-ca`, this field should be set to `my-ca`. -### Configuration Changes -1) Gateway Server - Edit the CAProxyServer.exe.config file and replace the line that says "NoOp" with the line below: - ``` - - ``` -2) Gateway Server - Install the Root HydrantId Certificate that was received from HydrantId +```json +"CAConnection": { + "LocationId": "us-east1", + "ProjectId": "concise-frame-296019", + "CAPoolId":"gcp-test-pool", + "CAId":"ca-enterprise-subordinate-sandbox-tls" +} +``` -3) Gateway Server - Install the Intermediate HydrantId Certificate that was received from HydrantId +> If `CAId` is not specified, CA selection will defer to GCP CAS - a CA in the CA Pool identified by `CAPoolId` will be selected automatically. -4) Gateway Server - Take the sample Config.json located [Here](https://github.com/Keyfactor/hydrantid-cagateway/raw/main/SampleConfig.json) and make the following modifications +## GatewayRegistration -- *Security Settings Modifications* (Swap this out for the typical Gateway Security Settings for Test or Prod) +There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway -``` - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" +```json + "GatewayRegistration": { + "LogicalName": "GoogleCASandbox", + "GatewayCertificate": { + "StoreName": "CA", + "StoreLocation": "LocalMachine", + "Thumbprint": "bc6d6b168ce5c08a690c15e03be596bbaa095ebf" } -``` -- *Hydrant Environment Settings* (Modify these with the keys and Urls obtained from HydrantId) -``` - "CAConnection": { - "HydrantIdBaseUrl": "https://acm-stage.hydrantid.com", - "AuthId": "SomeAuthId", - "AuthKey": "SomeAuthPassword", - "TemplateSync": "On" } ``` -- *Service Settings* (Modify these to be in accordance with Keyfactor Standard Gateway Production Settings) -``` +## ServiceSettings + +There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway + +```json "ServiceSettings": { - "ViewIdleMinutes": 1, + "ViewIdleMinutes": 8, "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 + "PartialScanPeriodMinutes": 60 } ``` -5) Gateway Server - Save the newly modified config.json to the following location "C:\Program Files\Keyfactor\Keyfactor AnyGateway" - -### Template Installation - -The Template section will map the CA's products to an AD template. -* ```ProductID``` -This is the ID of the HydrantId product to map to the specified template. If you don't know the available product IDs in your Hydrant account, put a placeholder value here and run the Set-KeyfactorGatewayConfig cmdlet according to the AnyGateway documentation. The list of available product IDs will be returned. -* ```ValidityPeriod``` -REQUIRED: The period to use when requesting certs. It could be, Days, Months, Years depending on the Template. -* ```ValidityUnits``` -REQUIRED: The numeric value corresponding to the ValidityPeriod. For years 1 would be 1 year, for days 7 would be 7 days. - - ```json - "Templates": { - "AutoEnrollment - RSA": { - "ProductID": "AutoEnrollment - RSA", - "Parameters": { - "ValidityPeriod": "Years", - "ValidityUnits": 1 - } - }, - "AutoEnrollment - RSA - 7 Day": { - "ProductID": "AutoEnrollment - RSA - 7 Day", - "Parameters": { - "ValidityPeriod": "Days", - "ValidityUnits": 7 - } - } - } - ``` - -### Certificate Authority Installation -1) Gateway Server - Start the Keyfactor Gateway Service -2) Run the set Gateway command similar to below -```ps -Set-KeyfactorGatewayConfig -LogicalName "HydrantId" -FilePath [path to json file] -PublishAd -``` -3) Command Server - Import the certificate authority in Keyfactor Portal -*** +## License -### License -[Apache](https://apache.org/licenses/LICENSE-2.0) +Apache License 2.0, see [LICENSE](LICENSE). +## Related Integrations +See all [Keyfactor integrations](https://github.com/topics/keyfactor-integration). \ No newline at end of file diff --git a/SampleConfig.json b/SampleConfig.json deleted file mode 100644 index b6bca44..0000000 --- a/SampleConfig.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - } - }, - "CAConnection": { - "HydrantIdBaseUrl": "https://acm-stage.hydrantid.com", - "AuthId": "getAuthIdFromHydrant", - "AuthKey": "getAuthKeyFromHydrant", - "TemplateSync": "On" - }, - "Templates": { - "AutoEnrollment - ECDSA": { - "ProductID": "AutoEnrollment - ECDSA", - "Parameters": { - "ValidityPeriod": "Years", - "ValidityUnits": 1 - } - }, - "AutoEnrollment - ECDSA - 7 Day": { - "ProductID": "AutoEnrollment - ECDSA - 7 Day", - "Parameters": { - "ValidityPeriod": "Days", - "ValidityUnits": 7 - } - }, - "AutoEnrollment - RSA": { - "ProductID": "AutoEnrollment - RSA", - "Parameters": { - "ValidityPeriod": "Years", - "ValidityUnits": 1 - } - }, - "AutoEnrollment - RSA - 7 Day": { - "ProductID": "AutoEnrollment - RSA - 7 Day", - "Parameters": { - "ValidityPeriod": "Days", - "ValidityUnits": 7 - } - } - }, - "CertificateManagers": null, - "GatewayRegistration": { - "LogicalName": "HydrantId", - "GatewayCertificate": { - "StoreName": "CA", - "StoreLocation": "LocalMachine", - "Thumbprint": "3c97cbb4491fc8d63d12b4890c28548164198edb" - } - }, - "ServiceSettings": { - "ViewIdleMinutes": 1, - "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 - } -} \ No newline at end of file diff --git a/TemplateSecurity/CaTemplateUserSecurity.csv b/TemplateSecurity/CaTemplateUserSecurity.csv deleted file mode 100644 index 6a5fba8..0000000 --- a/TemplateSecurity/CaTemplateUserSecurity.csv +++ /dev/null @@ -1,7 +0,0 @@ -UserName,Rights -Authenticated Users,GenericAll -kftrain\Administrator,GenericAll -keyfactor\Domain Admins,GenericAll -keyfactor\Domain Users,GenericAll -keyfactor\Domain Computers,GenericAll -keyfactor\Enterprise Admins,GenericAll diff --git a/Templates/AutoEnrollment - RSA - 7 Day.json b/Templates/AutoEnrollment - RSA - 7 Day.json deleted file mode 100644 index 18392d8..0000000 --- a/Templates/AutoEnrollment - RSA - 7 Day.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "Id": 999999, - "CommonName": "AutoEnrollment - RSA - 7 Day", - "TemplateName": "AutoEnrollment - RSA - 7 Day", - "Oid": "Replace OID", - "KeySize": "2048", - "KeyType": "RSA", - "ForestRoot": "keyfactor.lab", - "FriendlyName": "Replace Friendly Name", - "KeyRetention": "AfterExpiration", - "KeyRetentionDays": 55, - "KeyArchival": false, - "EnrollmentFields": [ - { - "Id": 2222961, - "Name": "Validity Period", - "Options": [ - "Years", - "Days", - "Months" - ], - "DataType": 2 - }, - { - "Id": 2222962, - "Name": "Validity Units", - "Options": [ - "" - ], - "DataType": 1 - } - ], - "AllowedEnrollmentTypes": 7, - "TemplateRegexes": [], - "UseAllowedRequesters": false, - "AllowedRequesters": [], - "DisplayName": "Replace Display Name" -} diff --git a/Templates/AutoEnrollment - RSA.json b/Templates/AutoEnrollment - RSA.json deleted file mode 100644 index 5f37b20..0000000 --- a/Templates/AutoEnrollment - RSA.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "Id": 999999, - "CommonName": "AutoEnrollment - RSA", - "TemplateName": "AutoEnrollment - RSA", - "Oid": "Replace OID", - "KeySize": "2048", - "KeyType": "RSA", - "ForestRoot": "keyfactor.lab", - "FriendlyName": "Replace Friendly Name", - "KeyRetention": "AfterExpiration", - "KeyRetentionDays": 55, - "KeyArchival": false, - "EnrollmentFields": [], - "AllowedEnrollmentTypes": 7, - "TemplateRegexes": [], - "UseAllowedRequesters": false, - "AllowedRequesters": [], - "DisplayName": "Replace Display Name" -} \ No newline at end of file diff --git a/integration-manifest.json b/integration-manifest.json index 7699ddc..4cd0beb 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,12 +1,11 @@ { - "$schema": "https://keyfactor.github.io/integration-manifest-schema.json", - "integration_type": "ca-gateway", - "name": "HydrantId", - "status": "production", - "description": "HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command the ability to: - Sync certificates issued from the CA - Request new certificates from the CA - Revoke certificates directly from Keyfactor Command -Renew or Reissue Certificates from the CA", - "link_github": true, - "update_catalog": true, - "support_level": "kf-supported", - "release_dir": "HydrantIdProxy/src/HydrantIdProxy/bin/Release" - + "$schema": "https://keyfactor.github.io/v2/integration-manifest-schema.json", + "integration_type": "ca-gateway", + "name": "GCP CAS AnyCA Gateway DCOM plugin", + "status": "production", + "description": "AnyCA Gateway DCOM plugin that extends Google Cloud Platform Certificate Authority Service to Keyfactor Command", + "link_github": true, + "update_catalog": true, + "support_level": "kf-community", + "release_dir": "src\\GoogleCAProxy\\bin\\Release" } diff --git a/readme_source.md b/readme_source.md index 1771e70..e7b6074 100644 --- a/readme_source.md +++ b/readme_source.md @@ -1,179 +1,221 @@ -*** -# Getting Started -## Standard Gateway Installation -To begin, you must have the CA Gateway Service 21.3.2 installed and operational before attempting to configure the HydrantId plugin. This integration was tested with Keyfactor 9.3.0.0. -To install the gateway follow these instructions. +## Overview -1) Gateway Server - run the installation .msi obtained from Keyfactor +The [Google Cloud Platform (GCP) CA Services (CAS)](https://cloud.google.com/security/products/certificate-authority-service) AnyCA Gateway DCOM plugin extends the capabilities of connected GCP CAS CAs to [Keyfactor Command](https://www.keyfactor.com/products/command/) via the Keyfactor AnyCA Gateway DCOM. The plugin represents a fully featured AnyCA DCOM Plugin with the following capabilies: -2) Gateway Server - If you have the rights to install the database (usually in a Non SQL PAAS Environment) Using Powershell, run the following command to create the gateway database. +* CA Sync: + * Download all certificates issued by connected Enterprise tier CAs in GCP CAS (full sync). + * Download all certificates issued by connected Enterprise tier CAs in GCP CAS issued after a specified time (incremental sync). +* Certificate enrollment for all published GoDaddy Certificate SKUs: + * Support certificate enrollment (new keys/certificate). +* Certificate revocation: + * Request revocation of a previously issued certificate. - **SQL Server Windows Auth** - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] - ``` - Note if you are using SQL Authentication, then you need to run - - **SQL Server SQL Authentication** +> The GCP CAS AnyCA Gateway DCOM plugin is **not** supported for [DevOps Tier](https://cloud.google.com/certificate-authority-service/docs/tiers) Certificate Authority Pools. +> +> DevOps tier CA Pools don't offer listing, describing, or revoking certificates. - ``` - %InstallLocation%\DatabaseManagementConsole.exe create -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` +## Compatibility - If you do **not** have rights to created the database then have the database created ahead of time by the support team and just populate the database +This AnyGateway is designed to be used with version 24.2 of the Keyfactor AnyCA Gateway DCOM Framework. - ## Populate commands below +## Requirements - **Windows Authentication** +### Application Default Credentials - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] - ``` +The GCP CAS AnyCA Gateway DCOM plugin connects to and authenticates with GCP CAS implicitly using [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials). This means that all authentication-related configuration of the GCP CAS AnyCA Gateway REST plugin is implied by the environment where the AnyCA Gateway REST itself is running. - **SQL Server SQL Authentication** +Please refer to [Google's documentation](https://cloud.google.com/docs/authentication/provide-credentials-adc) to configure ADC on the server running the AnyCA Gateway REST. - ``` - %InstallLocation%\DatabaseManagementConsole.exe populate -s [database server name] -d [database name] -u [sql user] -p [sql password] - ``` +> The easiest way to configure ADC for non-production environments is to use [User Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev). +> +> For production environments that use an ADC method requiring the `GOOGLE_APPLICATION_CREDENTIALS` environment variable, you must ensure the following: +> +> 1. The service account that the AnyCA Gateway REST runs under must have read permission to the GCP credential JSON file. +> 2. You must set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable for the Windows Service running the AnyCA Gateway REST using the [Windows registry editor](https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/windows-registry-advanced-users). +> * Refer to the [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment](https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables) docs. -3) Gateway Server - run the following Powershell to import the Cmdlets +If the selected ADC mechanism is [Service Account Key](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif-key), it's recommended that a [custom role is created](https://cloud.google.com/iam/docs/creating-custom-roles) that has the following minimum permissions: - C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll (must be imported into Powershell) - ```ps - Import-Module C:\Program Files\Keyfactor\Keyfactor AnyGateway\ConfigurationCmdlets.dll - ``` +* `privateca.certificateTemplates.list` +* `privateca.certificateTemplates.use` +* `privateca.certificateAuthorities.get` +* `privateca.certificates.create` +* `privateca.certificates.get` +* `privateca.certificates.list` +* `privateca.certificates.update` +* `privateca.caPools.get` -4) Gateway Server - Run the Following Powershell script to set the gateway encryption cert +> The built-in CA Service Operation Manager `roles/privateca.caManager` role can also be used, but is more permissive than a custom role with the above permissions. - ### Set-KeyfactorGatewayEncryptionCert - This cmdlet will generate a self-signed certificate used to encrypt the database connection string. It populates a registry value with the serial number of the certificate to be used. The certificate is stored in the LocalMachine Personal Store and the registry key populated is: +### Root CA Configuration - ```HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CertSvcProxy\Parameters\EncryptSerialNumber``` - No parameters are required to run this cmdlet. +Both the Keyfactor Command and AnyCA Gateway DCOM servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from GCP [CAS](https://console.cloud.google.com/security/cas), and import them into the appropriate certificate store on the AnyCA Gateway DCOM server. -5) Gateway Server - Run the following Powershell Script to Set the Database Connection +* **Windows** - The root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. + * Certificates can be imported in MMC by "File" -> "Add/Remove Snap-in" -> "Certificates" -> "Add >" -> "Computer account" -> "Local computer". + * Root CAs must go in the `Trusted Root Certification Authorities` certificate store. + * Subordinate CAs must go in the `Intermediate Certification Authorities` certificate store. - ### Set-KeyfactorGatewayDatabaseConnection - This cmdlet will set and encrypt the database connection string used by the AnyGateway service. +> If the Root CA and chain are not known by the server hosting the AnyCA Gateway DCOM, the certificate chain _may not_ be returned to Command in certificate enrollment requests. - **Windows Authentication** - ```ps - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] - ``` +### Template Identification - **SQL Authentication** - ```ps - $KeyfactorCredentials = Get-Credentials - Set-KeyfactorGatewayDatabaseConnection -Server [db server name] -Database [database name] -Account [$KeyfactorCredentials] - ``` -## Standard Gateway Configuration Finished ---- +The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). Certificate Templates exist at the Project level in GCP. Before installing the plugin, identify the [Certificate Templates](https://console.cloud.google.com/security/cas) that you want to make available to Keyfactor Command and [create Certificate Templates in AD](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Preparing_Templates.htm). +> Certificate Templates in GCP are not required. The plugin will not specify a template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate) if the `ProductId` (discussed later) is set to `Default`. -## HydrantId AnyGateway Specific Configuration -It is important to note that importing the HydrantId configuration into the CA Gateway after installing the binaries must be completed. Additionally, the CA Gateway service -must be running in order to succesfully import the configuation. When the CA Gateway service starts it will attempt to validate the connection information to -the CA. Without the imported configuration, the service will fail to start. +## Installation -### Binary Installation +1. Install AnyCA Gateway DCOM v24.2 per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm). -1) Get the Latest Zip File from [Here](https://github.com/Keyfactor/hydrantid-cagateway/releases/) -2) Gateway Server - Copy the HawkNet.dll, The HydrantIdProxy.dll and the HydrantIdProxy.dll.config to the location where the Gateway Framework was installed (usually C:\Program Files\Keyfactor\Keyfactor AnyGateway) +2. Download the [latest GCP CAS AnyCA Gateway DCOM plugin assemblies](https://github.com/Keyfactor/gcp-cloud-cagateway/releases/latest). -### Configuration Changes -1) Gateway Server - Edit the CAProxyServer.exe.config file and replace the line that says "NoOp" with the line below: - ``` - - ``` -2) Gateway Server - Install the Root HydrantId Certificate that was received from HydrantId +3. Copy `*.dll` to the `C:\Program Files\Keyfactor\Keyfactor AnyGateway` directory. -3) Gateway Server - Install the Intermediate HydrantId Certificate that was received from HydrantId +4. Update the `CAProxyServer.config` file. + 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class. -4) Gateway Server - Take the sample Config.json located [Here](https://github.com/Keyfactor/hydrantid-cagateway/raw/main/SampleConfig.json) and make the following modifications + ```xml + + ``` -- *Security Settings Modifications* (Swap this out for the typical Gateway Security Settings for Test or Prod) + 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`. + ```xml + + + + + ``` + + 3. Add a `bindingRedirect` for `Google.Apis.Auth` to redirect versions from `0.0.0.0-1.67.0.0` to `1.67.0.0`. + + ```xml + + + + + ``` + + 4. Add a `bindingRedirect` for `System.Memory` to redirect versions from `0.0.0.0-4.0.1.2` to `4.0.1.1`. + + ```xml + + + + + ``` + + > Depending on additional environment-specific factors, additional binding redirects may need to be applied to `CAProxyServer.config`. + +## Configuration +The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA. + +### Templates + +As discussed in the [Template Identification](#template-identification), the GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). The Keyfactor AnyCA Gateway DCOM maps [AD Certificate Templates](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/certificate-template-concepts) to GCP Certificate Templates via the `ProductID` property in the `Templates` section of configuration files. + +_At least one_ Certificate Template must be defined in this section with the `ProductID` set to `Default`. This Product ID corresponds to no Certificate Template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate). + +Subsequent Certificate Templates should set the `ProductID` to the Certificate Template ID in GCP CAS. + +```json +"Templates": { + "GCPCASDefault": { + "ProductID": "Default", + "Parameters": { + "Lifetime": "300", /* Certificate validity in days */ + } + } +} ``` - "Security": { - "KEYFACTOR\\administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" + +> The `Lifetime` key should be added as a Custom Enrollment Parameter/Field for each Certificate Template in Keyfactor Command per the [official Keyfactor documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm). + +## Security + +Refer to the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/cmdlets.htm) to configure the `Security` section. The following is provided as an example. + +```json +/* Grant permissions on the CA to users or groups in the local domain. + READ: Enumerate and read contents of certificates. + ENROLL: Request certificates from the CA. + OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA. + ADMINISTRATOR: Configure/reconfigure the gateway. + + Valid permission settings are "Allow", "None", and "Deny". +*/ +"Security": { + "Keyfactor\\Administrator": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" }, - "KEYFACTOR\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" + "Keyfactor\\gateway_test": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" + }, + "Keyfactor\\SVC_TimerService": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "None" }, - "KEYFACTOR\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" + "Keyfactor\\SVC_AppPool": { + "READ": "Allow", + "ENROLL": "Allow", + "OFFICER": "Allow", + "ADMINISTRATOR": "Allow" } +} ``` -- *Hydrant Environment Settings* (Modify these with the keys and Urls obtained from HydrantId) + +## CAConnection + +The `CAConnection` section selects the GCP Project/CA Pool/CA whose certificate operations will be extended to Keyfactor. There are three required fields. + +* `ProjectId` - The Resource ID of the project that contains the Google CA Service. +* `LocationId` - The GCP location ID where the project containing the target GCP CAS CA is located. For example, 'us-central1'. +* `CAPoolId` - The CA Pool ID in GCP CAS to use for certificate operations. If the CA Pool has resource name `projects/my-project/locations/us-central1/caPools/my-pool`, this field should be set to `my-pool`. +* `CAId` (optional) - The CA ID of a CA in the same CA Pool as CAPool. For example, to issue certificates from a CA with resource name `projects/my-project/locations/us-central1/caPools/my-pool/certificateAuthorities/my-ca`, this field should be set to `my-ca`. + +```json +"CAConnection": { + "LocationId": "us-east1", + "ProjectId": "concise-frame-296019", + "CAPoolId":"gcp-test-pool", + "CAId":"ca-enterprise-subordinate-sandbox-tls" +} ``` - "CAConnection": { - "HydrantIdBaseUrl": "https://acm-stage.hydrantid.com", - "AuthId": "SomeAuthId", - "AuthKey": "SomeAuthPassword", - "TemplateSync": "On" + +> If `CAId` is not specified, CA selection will defer to GCP CAS - a CA in the CA Pool identified by `CAPoolId` will be selected automatically. + +## GatewayRegistration + +There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway + +```json + "GatewayRegistration": { + "LogicalName": "GoogleCASandbox", + "GatewayCertificate": { + "StoreName": "CA", + "StoreLocation": "LocalMachine", + "Thumbprint": "bc6d6b168ce5c08a690c15e03be596bbaa095ebf" + } } ``` -- *Service Settings* (Modify these to be in accordance with Keyfactor Standard Gateway Production Settings) -``` +## ServiceSettings + +There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway + +```json "ServiceSettings": { - "ViewIdleMinutes": 1, + "ViewIdleMinutes": 8, "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 1 + "PartialScanPeriodMinutes": 60 } ``` - -5) Gateway Server - Save the newly modified config.json to the following location "C:\Program Files\Keyfactor\Keyfactor AnyGateway" - -### Template Installation - -The Template section will map the CA's products to an AD template. -* ```ProductID``` -This is the ID of the HydrantId product to map to the specified template. If you don't know the available product IDs in your Hydrant account, put a placeholder value here and run the Set-KeyfactorGatewayConfig cmdlet according to the AnyGateway documentation. The list of available product IDs will be returned. -* ```ValidityPeriod``` -REQUIRED: The period to use when requesting certs. It could be, Days, Months, Years depending on the Template. -* ```ValidityUnits``` -REQUIRED: The numeric value corresponding to the ValidityPeriod. For years 1 would be 1 year, for days 7 would be 7 days. - - ```json - "Templates": { - "AutoEnrollment - RSA": { - "ProductID": "AutoEnrollment - RSA", - "Parameters": { - "ValidityPeriod": "Years", - "ValidityUnits": 1 - } - }, - "AutoEnrollment - RSA - 7 Day": { - "ProductID": "AutoEnrollment - RSA - 7 Day", - "Parameters": { - "ValidityPeriod": "Days", - "ValidityUnits": 7 - } - } - } - ``` - -### Certificate Authority Installation -1) Gateway Server - Start the Keyfactor Gateway Service -2) Run the set Gateway command similar to below -```ps -Set-KeyfactorGatewayConfig -LogicalName "HydrantId" -FilePath [path to json file] -PublishAd -``` -3) Command Server - Import the certificate authority in Keyfactor Portal - - -*** - -### License -[Apache](https://apache.org/licenses/LICENSE-2.0) diff --git a/src/HydrantCAProxy/App.config b/src/HydrantCAProxy/App.config new file mode 100644 index 0000000..5da3322 --- /dev/null +++ b/src/HydrantCAProxy/App.config @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/HydrantIdProxy/src/HydrantIdProxy/Client/HydrantIdClient.cs b/src/HydrantCAProxy/Client/HydrantIdClient.cs similarity index 81% rename from HydrantIdProxy/src/HydrantIdProxy/Client/HydrantIdClient.cs rename to src/HydrantCAProxy/Client/HydrantIdClient.cs index 64d7a97..fa4172d 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Client/HydrantIdClient.cs +++ b/src/HydrantCAProxy/Client/HydrantIdClient.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless @@ -19,7 +19,7 @@ using System.Threading; using System.Threading.Tasks; using CAProxy.AnyGateway.Interfaces; -using CSS.Common.Logging; +using Keyfactor.Logging; using HawkNet; using Keyfactor.HydrantId.Client.Models; using Keyfactor.HydrantId.Client.Models.Enums; @@ -28,16 +28,20 @@ using Keyfactor.HydrantId.Interfaces; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; +using Keyfactor.AnyGateway.Google; +using Microsoft.Extensions.Logging; namespace Keyfactor.HydrantId.Client { - public sealed class HydrantIdClient : LoggingClientBase + public sealed class HydrantIdClient { + private static readonly ILogger Log = LogHandler.GetClassLogger < HydrantIdClient>(); + public HydrantIdClient(ICAConnectorConfigProvider config) { try { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); if (config.CAConnectionData.ContainsKey(Constants.HydrantIdAuthId)) { ConfigProvider = config; @@ -47,7 +51,7 @@ public HydrantIdClient(ICAConnectorConfigProvider config) } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.HydrantIdClient: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.HydrantIdClient: {e.Message}"); throw; } } @@ -62,9 +66,9 @@ public HydrantIdClient(ICAConnectorConfigProvider config) public async Task GetSubmitEnrollmentAsync( CertRequestBody registerRequest) { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); var apiEndpoint = "/api/v2/csr"; - Logger.Trace($"API Url {BaseUrl + apiEndpoint}"); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); var traceWriter = new MemoryTraceWriter(); @@ -73,7 +77,7 @@ public async Task GetSubmitEnrollmentAsync( { try { - Logger.Trace($"Register Request JSON: {JsonConvert.SerializeObject(registerRequest)}"); + Log.LogTrace($"Register Request JSON: {JsonConvert.SerializeObject(registerRequest)}"); var settings = new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore, TraceWriter = traceWriter}; var _ = await resp.Content.ReadAsStringAsync(); @@ -83,7 +87,7 @@ public async Task GetSubmitEnrollmentAsync( var errorResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), settings); - Logger.Error($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); + Log.LogError($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); var responseReturn = new CertRequestResult {ErrorReturn = errorResponse, RequestStatus = null}; return responseReturn; } @@ -91,13 +95,13 @@ public async Task GetSubmitEnrollmentAsync( var validResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), settings); - Logger.Error($"validResponse Response JSON: {JsonConvert.SerializeObject(validResponse)}"); + Log.LogError($"validResponse Response JSON: {JsonConvert.SerializeObject(validResponse)}"); var validReturn = new CertRequestResult {ErrorReturn = null, RequestStatus = validResponse}; return validReturn; } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.GetSubmitEnrollmentAsync: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.GetSubmitEnrollmentAsync: {e.Message}"); throw; } } @@ -109,16 +113,16 @@ public async Task GetSubmitRenewalAsync(string certificateId, { try { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); var apiEndpoint = $"/api/v2/certificates/{certificateId}/renew"; var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); - Logger.Trace($"API Url {BaseUrl + apiEndpoint}"); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); var traceWriter = new MemoryTraceWriter(); using (var resp = await restClient.PostAsync(apiEndpoint, new StringContent( JsonConvert.SerializeObject(renewRequest), Encoding.UTF8, "application/json"))) { - Logger.Trace($"Renew Request: {JsonConvert.SerializeObject(renewRequest)}"); + Log.LogTrace($"Renew Request: {JsonConvert.SerializeObject(renewRequest)}"); var settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, TraceWriter = traceWriter }; var _ = await resp.Content.ReadAsStringAsync(); @@ -128,7 +132,7 @@ public async Task GetSubmitRenewalAsync(string certificateId, var errorResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), settings); - Logger.Error($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); + Log.LogError($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); var responseReturn = new CertRequestResult { ErrorReturn = errorResponse, RequestStatus = null }; return responseReturn; } @@ -136,14 +140,14 @@ public async Task GetSubmitRenewalAsync(string certificateId, var validResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), settings); - Logger.Error($"validResponse Response JSON: {JsonConvert.SerializeObject(validResponse)}"); + Log.LogError($"validResponse Response JSON: {JsonConvert.SerializeObject(validResponse)}"); var validReturn = new CertRequestResult { ErrorReturn = null, RequestStatus = validResponse }; return validReturn; } } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.GetSubmitRenewalAsync: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.GetSubmitRenewalAsync: {e.Message}"); throw; } } @@ -153,9 +157,9 @@ public async Task> GetPolicyList() { try { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); var apiEndpoint = "/api/v2/policies"; - Logger.Trace($"API Url {BaseUrl + apiEndpoint}"); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); var traceWriter = new MemoryTraceWriter(); @@ -167,13 +171,13 @@ public async Task> GetPolicyList() var policiesResponse = JsonConvert.DeserializeObject>(await resp.Content.ReadAsStringAsync(), settings); - Logger.Debug(traceWriter.ToString()); + Log.LogDebug(traceWriter.ToString()); return policiesResponse; } } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.GetPolicyList: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.GetPolicyList: {e.Message}"); throw; } } @@ -183,9 +187,9 @@ public async Task GetSubmitGetCertificateAsync(string certificateId { try { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); var apiEndpoint = $"/api/v2/certificates/{certificateId}"; - Logger.Trace($"API Url {BaseUrl + apiEndpoint}"); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); using (var resp = await restClient.GetAsync(apiEndpoint)) @@ -198,18 +202,18 @@ public async Task GetSubmitGetCertificateAsync(string certificateId } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); throw; } - } - + } + public async Task GetSubmitGetCertificateByCsrAsync(string requestTrackingId) { try { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); var apiEndpoint = $"/api/v2/csr/{requestTrackingId}/certificate"; - Logger.Trace($"API Url {BaseUrl + apiEndpoint}"); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); using (var resp = await restClient.GetAsync(apiEndpoint)) @@ -222,7 +226,7 @@ public async Task GetSubmitGetCertificateByCsrAsync(string requestT } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); throw; } } @@ -232,12 +236,12 @@ public async Task GetSubmitRevokeCertificateAsync(string hydr { try { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); var apiEndpoint = $"/api/v2/certificates/{hydrantId}"; - Logger.Trace($"API Url {BaseUrl + apiEndpoint}"); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); var restClient = ConfigureRestClient("patch", BaseUrl + apiEndpoint); var revokeRequest = RequestManager.GetRevokeRequest(revokeReason); - Logger.Trace($"Revoke Request JSON: {JsonConvert.SerializeObject(revokeRequest)}"); + Log.LogTrace($"Revoke Request JSON: {JsonConvert.SerializeObject(revokeRequest)}"); using (var resp = await restClient.PatchAsync(new Uri(BaseUrl + apiEndpoint), new StringContent( JsonConvert.SerializeObject(revokeRequest), Encoding.UTF8, "application/json"))) { @@ -245,13 +249,13 @@ public async Task GetSubmitRevokeCertificateAsync(string hydr var getRevokeResponse = JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), jsonSerializerSettings); - Logger.Trace($"Revoke Response JSON: {JsonConvert.SerializeObject(getRevokeResponse)}"); + Log.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(getRevokeResponse)}"); return getRevokeResponse; } } catch (Exception e) { - Logger.Error($"Error Occured in HydrantIdClient.GetSubmitRevokeCertificateAsync: {e.Message}"); + Log.LogError($"Error Occured in HydrantIdClient.GetSubmitRevokeCertificateAsync: {e.Message}"); throw; } } @@ -259,7 +263,7 @@ public async Task GetSubmitRevokeCertificateAsync(string hydr public async Task GetSubmitCertificateListRequestAsync(BlockingCollection bc, CancellationToken ct) { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); + Log.MethodEntry(); try { var itemsProcessed = 0; @@ -268,13 +272,13 @@ public async Task GetSubmitCertificateListRequestAsync(BlockingCollection 5) @@ -298,27 +302,27 @@ public async Task GetSubmitCertificateListRequestAsync(BlockingCollection(stringResponse); - Logger.Trace($"batchResponse JSON: {JsonConvert.SerializeObject(batchResponse)}"); + Log.LogTrace($"batchResponse JSON: {JsonConvert.SerializeObject(batchResponse)}"); if (batchResponse != null) { var batchCount = batchResponse.Items.Count; - Logger.Trace($"Processing {batchCount} items in batch"); + Log.LogTrace($"Processing {batchCount} items in batch"); do { var r = batchResponse.Items[batchItemsProcessed]; if (bc.TryAdd(r, 10, ct)) { - Logger.Trace($"Added Template ID {r.Id} to Queue for processing"); + Log.LogTrace($"Added Template ID {r.Id} to Queue for processing"); batchItemsProcessed++; itemsProcessed++; - Logger.Trace($"Processed {batchItemsProcessed} of {batchCount}"); - Logger.Trace($"Total Items Processed: {itemsProcessed}"); + Log.LogTrace($"Processed {batchItemsProcessed} of {batchCount}"); + Log.LogTrace($"Total Items Processed: {itemsProcessed}"); } else { - Logger.Trace($"Adding {r} blocked. Retry"); + Log.LogTrace($"Adding {r} blocked. Retry"); } } while (batchItemsProcessed < batchCount); //batch loop } @@ -334,28 +338,28 @@ public async Task GetSubmitCertificateListRequestAsync(BlockingCollection - await HydrantIdClient.GetSubmitRevokeCertificateAsync(hydrantId, revokeReason)) - .Result; - - Logger.Trace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return 1; - } - catch (Exception e) - { - Logger.Error($"An Error has occurred during the revoke process {e.Message}"); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return -1; - } - } - - [Obsolete] - public override void Synchronize(ICertificateDataReader certificateDataReader, - BlockingCollection blockingBuffer, - CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, CancellationToken cancelToken, - string logicalName) - { - } - - public override void Synchronize(ICertificateDataReader certificateDataReader, - BlockingCollection blockingBuffer, - CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, - CancellationToken cancelToken) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - try - { - var certs = new BlockingCollection(100); - _ = HydrantIdClient.GetSubmitCertificateListRequestAsync(certs, cancelToken); - - foreach (var currentResponseItem in certs.GetConsumingEnumerable(cancelToken)) - { - if (cancelToken.IsCancellationRequested) - { - Logger.Error("Synchronize was canceled."); - break; - } - - try - { - Logger.Trace($"Took Certificate ID {currentResponseItem?.Id} from Queue"); - if (currentResponseItem != null) - { - var certStatus = _requestManager.GetMapReturnStatus(currentResponseItem.RevocationStatus); - Logger.Trace($"Numeric Status {certStatus}"); - - if (certStatus == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.ISSUED) || - certStatus == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED)) - { - var productId = currentResponseItem.Policy.Name; - Logger.Trace($"Product Id {productId}"); - - var singleCert = HydrantIdClient.GetSubmitGetCertificateAsync(currentResponseItem.Id); - - var fileContent = singleCert.Result.Pem ?? string.Empty; - - Logger.Trace($"Certificate Content: {fileContent}"); - - if (fileContent.Length > 0) - { - var certData = fileContent.Replace("\n", string.Empty); - var splitCerts = - certData.Split( - new[] {"-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----"}, - StringSplitOptions.RemoveEmptyEntries); - foreach (var cert in splitCerts) - try - { - var currentCert = new X509Certificate2(Encoding.ASCII.GetBytes(cert)); - var caReqId = $"{currentResponseItem.Id}-{currentCert.SerialNumber}"; - Logger.Trace($"Split Cert Value: {cert}"); - blockingBuffer.Add(new CAConnectorCertificate - { - CARequestID =$"{currentResponseItem.Id}", - Certificate = cert, - SubmissionDate = Convert.ToDateTime(singleCert.Result.CreatedAt), - Status = certStatus, - ProductID = productId - }, cancelToken); - } - catch (Exception e) - { - Logger.Error( - $"Exception occurred Adding Cert to buffer: {e.Message} HydrantId: {currentResponseItem.Id} CommonName: {currentResponseItem.CommonName} Serial: {currentResponseItem.Serial}"); - } - } - } - } - } - catch (OperationCanceledException) - { - Logger.Error("Synchronize was canceled."); - break; - } - } - } - catch (AggregateException aggEx) - { - Logger.Error("Csc Global Synchronize Task failed!"); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - // ReSharper disable once PossibleIntendedRethrow - throw aggEx; - } - - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - } - - [Obsolete] - public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, - EnrollmentProductInfo productInfo, - PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) - { - return null; - } - - public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader, string csr, - string subject, Dictionary san, EnrollmentProductInfo productInfo, - PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - CertRequestResult enrollmentResponse = null; - int timerTries = 0; - Certificate csrTrackingResponse=null; - - switch (enrollmentType) - { - case RequestUtilities.EnrollmentType.New: - case RequestUtilities.EnrollmentType.Reissue: - Logger.Trace("Entering New Enrollment"); - - var policyListResult = - Task.Run(async () => await HydrantIdClient.GetPolicyList()) - .Result; - - Logger.Trace($"Policy Result List: {JsonConvert.SerializeObject(policyListResult)}"); - var policyId = policyListResult.Single(p => p.Name.Equals(productInfo.ProductID)); - - Logger.Trace($"PolicyId: {JsonConvert.SerializeObject(policyId)}"); - - var enrollmentRequest = - _requestManager.GetEnrollmentRequest(policyId.Id, productInfo, csr, san); - - Logger.Trace($"Enrollment Request JSON: {JsonConvert.SerializeObject(enrollmentRequest)}"); - enrollmentResponse = - Task.Run(async () => await HydrantIdClient.GetSubmitEnrollmentAsync(enrollmentRequest)) - .Result; - Logger.Trace($"Enrollment Response JSON: {JsonConvert.SerializeObject(enrollmentResponse)}"); - - if (enrollmentResponse?.ErrorReturn?.Status != "Failure") - { - timerTries = +1; - csrTrackingResponse = GetCertificateOnTimer(enrollmentResponse?.RequestStatus?.Id); - } - else - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Enrollment Failed with error {enrollmentResponse?.ErrorReturn?.Error}" - }; - } - - - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - - break; - - case RequestUtilities.EnrollmentType.Renew: - Logger.Trace("Entering Renew..."); - - var renewalRequest = _requestManager.GetRenewalRequest(csr, false); - Logger.Trace($"Renewal Request JSON: {JsonConvert.SerializeObject(renewalRequest)}"); - var sn = productInfo.ProductParameters["PriorCertSN"]; - Logger.Trace($"Prior Cert Serial Number= {sn}"); - var priorCert = certificateDataReader.GetCertificateRecord( - DataConversion.HexToBytes(sn)); - - var uUId = priorCert.CARequestID; //uUId is a GUID - - Logger.Trace($"Hydrant Certificate Id Plus Serial #= {uUId}"); - - Logger.Trace($"Reissue CA RequestId: {uUId}"); - var certificateId = uUId.Substring(0, 36); - enrollmentResponse = - Task.Run(async () => - await HydrantIdClient.GetSubmitRenewalAsync(certificateId, renewalRequest)) - .Result; - Logger.Trace($"Renew Response JSON: {JsonConvert.SerializeObject(enrollmentResponse)}"); - - if (enrollmentResponse?.ErrorReturn?.Status != "Failure") - { - timerTries = +1; - csrTrackingResponse = GetCertificateOnTimer(enrollmentResponse?.RequestStatus?.Id); - } - else - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Enrollment Failed with error {enrollmentResponse?.ErrorReturn?.Error}" - }; - } - break; - } - - if(csrTrackingResponse==null && timerTries>0) - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Certificate may still waiting on Hydrant and is not ready for download" - }; - } - - var cert = GetSingleRecord(csrTrackingResponse.Id.ToString()); - return _requestManager.GetEnrollmentResult(csrTrackingResponse,cert); - } - - private Certificate GetCertificateOnTimer(string Id) - { - //Get the csr tracking response from the tracking Id returned from Enrollment - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - Certificate csrTrackingResponse = null; - - while (stopwatch.Elapsed < TimeSpan.FromSeconds(30) && csrTrackingResponse == null) - { - try - { - csrTrackingResponse = - Task.Run(async () => await HydrantIdClient.GetSubmitGetCertificateByCsrAsync(Id)) - .Result; - } - catch (System.AggregateException e) - { - Logger.Trace($"Enrollment Response Not Available Yet, try again {LogHandler.FlattenException(e)}."); - } - Thread.Sleep(1000); - } - - return csrTrackingResponse; - } - - public override CAConnectorCertificate GetSingleRecord(string caRequestId) - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - Logger.Trace($"Keyfactor Ca Id: {caRequestId}"); - try - { - var certificateResponse = - Task.Run(async () => - await HydrantIdClient.GetSubmitGetCertificateAsync(caRequestId.Substring(0, 36))) - .Result; - - Logger.Trace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return new CAConnectorCertificate - { - CARequestID = caRequestId, - Certificate = certificateResponse.Pem, - ResolutionDate = Convert.ToDateTime(certificateResponse.NotAfter), - Status = _requestManager.GetMapReturnStatus(certificateResponse.RevocationStatus), - SubmissionDate = Convert.ToDateTime(certificateResponse.CreatedAt) - }; - } - catch (Exception) //Most likely cert is not available yet, just get it on the sync - { - return new CAConnectorCertificate - { - CARequestID = caRequestId, - Status = _requestManager.GetMapReturnStatus(0) //Unknown - }; - } - } - - public override void Initialize(ICAConnectorConfigProvider configProvider) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - HydrantIdClient = new HydrantIdClient(configProvider); - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - } - catch (Exception e) - { - Logger.Error($"Error Occured in HydrantIdProxy.Initialize: {e.Message}"); - throw; - } - } - - public override void Ping() - { - } - - public override void ValidateCAConnectionInfo(Dictionary connectionInfo) - { - } - - public override void ValidateProductInfo(EnrollmentProductInfo productInfo, - Dictionary connectionInfo) - { - } - } +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading; +using CAProxy.AnyGateway; +using CAProxy.AnyGateway.Interfaces; +using CAProxy.AnyGateway.Models; +using CAProxy.Common; +using CSS.PKI; +using Keyfactor.HydrantId.Client; +using Keyfactor.HydrantId.Interfaces; +using Keyfactor.HydrantId; +using Keyfactor.Logging; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; +using CSS.Common.Logging; +using System.Threading.Tasks; +using LogHandler = Keyfactor.Logging.LogHandler; +using CSS.Common; +using Keyfactor.HydrantId.Client.Models; +using System.Diagnostics; + +namespace Keyfactor.AnyGateway.Google +{ + public class HydrantIdCAProxy : BaseCAConnector + { + private static readonly ILogger Log = LogHandler.GetClassLogger(); + private RequestManager _requestManager; + private ICAConnectorConfigProvider Config { get; set; } + + public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader, string csr, + string subject, Dictionary san, EnrollmentProductInfo productInfo, + PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) + { + Log.MethodEntry(); + _requestManager=new RequestManager(); + CertRequestResult enrollmentResponse = null; + int timerTries = 0; + Certificate csrTrackingResponse = null; + var client = new HydrantIdClient(Config); + + switch (enrollmentType) + { + case RequestUtilities.EnrollmentType.New: + case RequestUtilities.EnrollmentType.Reissue: + Log.LogTrace("Entering New Enrollment"); + + var policyListResult = + Task.Run(async () => await client.GetPolicyList()) + .Result; + + Log.LogTrace($"Policy Result List: {JsonConvert.SerializeObject(policyListResult)}"); + var policyId = policyListResult.Single(p => p.Name.Equals(productInfo.ProductID)); + + Log.LogTrace($"PolicyId: {JsonConvert.SerializeObject(policyId)}"); + + var enrollmentRequest = + _requestManager.GetEnrollmentRequest(policyId.Id, productInfo, csr, san); + + Log.LogTrace($"Enrollment Request JSON: {JsonConvert.SerializeObject(enrollmentRequest)}"); + enrollmentResponse = + Task.Run(async () => await client.GetSubmitEnrollmentAsync(enrollmentRequest)) + .Result; + Log.LogTrace($"Enrollment Response JSON: {JsonConvert.SerializeObject(enrollmentResponse)}"); + + if (enrollmentResponse?.ErrorReturn?.Status != "Failure") + { + timerTries = +1; + csrTrackingResponse = GetCertificateOnTimer(enrollmentResponse?.RequestStatus?.Id); + } + else + { + return new EnrollmentResult + { + Status = 30, //failure + StatusMessage = $"Enrollment Failed with error {enrollmentResponse?.ErrorReturn?.Error}" + }; + } + + + Log.MethodExit(); + + break; + + case RequestUtilities.EnrollmentType.Renew: + Log.LogTrace("Entering Renew..."); + + var renewalRequest = _requestManager.GetRenewalRequest(csr, false); + Log.LogTrace($"Renewal Request JSON: {JsonConvert.SerializeObject(renewalRequest)}"); + var sn = productInfo.ProductParameters["PriorCertSN"]; + Log.LogTrace($"Prior Cert Serial Number= {sn}"); + var priorCert = certificateDataReader.GetCertificateRecord( + DataConversion.HexToBytes(sn)); + + var uUId = priorCert.CARequestID; //uUId is a GUID + + Log.LogTrace($"Hydrant Certificate Id Plus Serial #= {uUId}"); + + Log.LogTrace($"Reissue CA RequestId: {uUId}"); + var certificateId = uUId.Substring(0, 36); + enrollmentResponse = + Task.Run(async () => + await client.GetSubmitRenewalAsync(certificateId, renewalRequest)) + .Result; + Log.LogTrace($"Renew Response JSON: {JsonConvert.SerializeObject(enrollmentResponse)}"); + + if (enrollmentResponse?.ErrorReturn?.Status != "Failure") + { + timerTries = +1; + csrTrackingResponse = GetCertificateOnTimer(enrollmentResponse?.RequestStatus?.Id); + } + else + { + return new EnrollmentResult + { + Status = 30, //failure + StatusMessage = $"Enrollment Failed with error {enrollmentResponse?.ErrorReturn?.Error}" + }; + } + break; + } + + if (csrTrackingResponse == null && timerTries > 0) + { + return new EnrollmentResult + { + Status = 30, //failure + StatusMessage = $"Certificate may still waiting on Hydrant and is not ready for download" + }; + } + + var cert = GetSingleRecord(csrTrackingResponse.Id.ToString()); + return _requestManager.GetEnrollmentResult(csrTrackingResponse, cert); + } + + public override CAConnectorCertificate GetSingleRecord(string caRequestId) + { + Logger.MethodEntry(); + _requestManager = new RequestManager(); + Log.LogTrace($"Keyfactor Ca Id: {caRequestId}"); + try + { + var client = new HydrantIdClient(Config); + var certificateResponse = + Task.Run(async () => + await client.GetSubmitGetCertificateAsync(caRequestId.Substring(0, 36))) + .Result; + + Log.LogTrace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); + Log.MethodExit(); + return new CAConnectorCertificate + { + CARequestID = caRequestId, + Certificate = certificateResponse.Pem, + ResolutionDate = Convert.ToDateTime(certificateResponse.NotAfter), + Status = _requestManager.GetMapReturnStatus(certificateResponse.RevocationStatus), + SubmissionDate = Convert.ToDateTime(certificateResponse.CreatedAt) + }; + } + catch (Exception) //Most likely cert is not available yet, just get it on the sync + { + return new CAConnectorCertificate + { + CARequestID = caRequestId, + Status = _requestManager.GetMapReturnStatus(0) //Unknown + }; + } + } + + public override void Initialize(ICAConnectorConfigProvider configProvider) + { + Log.MethodEntry(); + try + { + Config = configProvider; + } + catch (Exception ex) + { + Log.LogError($"Failed to initialize GCP CAS CAPlugin: {ex}"); + } + } + + public override void Ping() + { + Log.MethodEntry(); + Log.MethodExit(); + } + + public override int Revoke(string caRequestId, string hexSerialNumber, uint revocationReason) + { + try + { + Logger.LogTrace("Staring Revoke Method"); + _requestManager = new RequestManager(); + var client = new HydrantIdClient(Config); + var hydrantId = caRequestId.Substring(0, 36); + var revokeReason = _requestManager.GetMapRevokeReasons(revocationReason); + + Logger.LogTrace($"Revoke Reason {revokeReason}"); + + var revokeResponse = Task.Run(async () => + await client.GetSubmitRevokeCertificateAsync(hydrantId, revokeReason)) + .Result; + + Logger.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); + Logger.MethodExit(); + return 1; + } + catch (Exception e) + { + Logger.LogError($"An Error has occurred during the revoke process {e.Message}"); + Logger.MethodExit(); + return -1; + } + } + + private Certificate GetCertificateOnTimer(string Id) + { + //Get the csr tracking response from the tracking Id returned from Enrollment + var stopwatch = new Stopwatch(); + stopwatch.Start(); + var client = new HydrantIdClient(Config); + Certificate csrTrackingResponse = null; + + while (stopwatch.Elapsed < TimeSpan.FromSeconds(30) && csrTrackingResponse == null) + { + try + { + csrTrackingResponse = + Task.Run(async () => await client.GetSubmitGetCertificateByCsrAsync(Id)) + .Result; + } + catch (System.AggregateException e) + { + Log.LogTrace($"Enrollment Response Not Available Yet, try again {LogHandler.FlattenException(e)}."); + } + Thread.Sleep(1000); + } + + return csrTrackingResponse; + } + + public override void Synchronize(ICertificateDataReader certificateDataReader, + BlockingCollection blockingBuffer, + CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, + CancellationToken cancelToken) + { + Log.MethodEntry(); + _requestManager = new RequestManager(); + try + { + var certs = new BlockingCollection(100); + var client = new HydrantIdClient(Config); + _ = client.GetSubmitCertificateListRequestAsync(certs, cancelToken); + + foreach (var currentResponseItem in certs.GetConsumingEnumerable(cancelToken)) + { + if (cancelToken.IsCancellationRequested) + { + Log.LogError("Synchronize was canceled."); + break; + } + + try + { + Log.LogTrace($"Took Certificate ID {currentResponseItem?.Id} from Queue"); + if (currentResponseItem != null) + { + var certStatus = _requestManager.GetMapReturnStatus(currentResponseItem.RevocationStatus); + Log.LogTrace($"Numeric Status {certStatus}"); + + if (certStatus == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.ISSUED) || + certStatus == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED)) + { + var productId = currentResponseItem.Policy.Name; + Log.LogTrace($"Product Id {productId}"); + + var singleCert = client.GetSubmitGetCertificateAsync(currentResponseItem.Id); + + var fileContent = singleCert.Result.Pem ?? string.Empty; + + Log.LogTrace($"Certificate Content: {fileContent}"); + + if (fileContent.Length > 0) + { + var certData = fileContent.Replace("\n", string.Empty); + var splitCerts = + certData.Split( + new[] { "-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----" }, + StringSplitOptions.RemoveEmptyEntries); + foreach (var cert in splitCerts) + try + { + var currentCert = new X509Certificate2(Encoding.ASCII.GetBytes(cert)); + var caReqId = $"{currentResponseItem.Id}-{currentCert.SerialNumber}"; + Log.LogTrace($"Split Cert Value: {cert}"); + blockingBuffer.Add(new CAConnectorCertificate + { + CARequestID = $"{currentResponseItem.Id}", + Certificate = cert, + SubmissionDate = Convert.ToDateTime(singleCert.Result.CreatedAt), + Status = certStatus, + ProductID = productId + }, cancelToken); + } + catch (Exception e) + { + Log.LogError( + $"Exception occurred Adding Cert to buffer: {e.Message} HydrantId: {currentResponseItem.Id} CommonName: {currentResponseItem.CommonName} Serial: {currentResponseItem.Serial}"); + } + } + } + } + } + catch (OperationCanceledException) + { + Log.LogError("Synchronize was canceled."); + break; + } + } + } + catch (AggregateException aggEx) + { + Log.LogError("Csc Global Synchronize Task failed!"); + Log.MethodExit(); + // ReSharper disable once PossibleIntendedRethrow + throw aggEx; + } + + Log.MethodExit(); + } + + + public override void ValidateCAConnectionInfo(Dictionary connectionInfo) + { + Log.MethodEntry(); + List errors = new List(); + + Log.LogTrace("Checking required CAConnection config"); + errors.AddRange(CheckRequiredValues(connectionInfo)); + + if (errors.Any()) throw new Exception(string.Join("|", errors.ToArray())); + } + + public override void ValidateProductInfo(EnrollmentProductInfo productInfo, + Dictionary connectionInfo) + { + Log.MethodEntry(); + //TODO: Evaluate Template (if avaiable) based on ProductInfo + Log.MethodExit(); + } + + private static List CheckRequiredValues(Dictionary connectionInfo, params string[] args) + { + List errors = new List(); + foreach (string s in args) + if (string.IsNullOrEmpty(connectionInfo[s] as string)) + errors.Add($"{s} is a required value"); + return errors; + } + + + private static readonly Func pemify = ss => + ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64)); + + + + #region Obsolete Methods + + [Obsolete] + public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, + EnrollmentProductInfo productInfo, PKIConstants.X509.RequestFormat requestFormat, + RequestUtilities.EnrollmentType enrollmentType) + { + throw new NotImplementedException(); + } + + [Obsolete] + public override void Synchronize(ICertificateDataReader certificateDataReader, + BlockingCollection blockingBuffer, + CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, + CancellationToken cancelToken, + string logicalName) + { + throw new NotImplementedException(); + } + + #endregion + } } \ No newline at end of file diff --git a/HydrantIdProxy/src/HydrantIdProxy/HydrantIdProxy.csproj b/src/HydrantCAProxy/HydrantIdCAProxy.csproj similarity index 57% rename from HydrantIdProxy/src/HydrantIdProxy/HydrantIdProxy.csproj rename to src/HydrantCAProxy/HydrantIdCAProxy.csproj index 3d26feb..61b90fd 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/HydrantIdProxy.csproj +++ b/src/HydrantCAProxy/HydrantIdCAProxy.csproj @@ -1,164 +1,167 @@ - - - - Debug - AnyCPU - {7847E86E-41F8-4849-BBAD-44A30CE9300B} - Library - Properties - Keyfactor.HydrantId - HydrantIdProxy - v4.6.2 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\packages\BouncyCastle.1.8.5\lib\BouncyCastle.Crypto.dll - - - ..\..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.AnyGateway.Core.dll - - - ..\..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxy.Interfaces.dll - - - ..\..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CAProxyDAL.dll - - - ..\..\packages\Common.Logging.3.4.1\lib\net40\Common.Logging.dll - - - ..\..\packages\Common.Logging.Core.3.4.1\lib\net40\Common.Logging.Core.dll - - - ..\..\packages\Keyfactor.AnyGateway.SDK.21.3.2\lib\net462\CommonCAProxy.dll - - - ..\..\packages\CSS.Common.1.7.0\lib\net462\CSS.Common.dll - - - ..\..\packages\CSS.PKI.2.13.0\lib\net462\CSS.PKI.dll - - - ..\..\packages\HawkNet.1.4.4.0\lib\net45\HawkNet.dll - - - ..\..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll - - - - - - - ..\..\packages\System.Security.Cryptography.Algorithms.4.3.1\lib\net461\System.Security.Cryptography.Algorithms.dll - - - ..\..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll - - - ..\..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + AnyCPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355} + Library + Properties + Keyfactor.AnyGateway.Google + HydrantIdCAProxy + v4.7.2 + 512 + true + OnBuildSuccess + true + + + true + full + false + bin\Debug + DEBUG;TRACE + prompt + 4 + False + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + False + + + + $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CAProxy.AnyGateway.Core.dll + + + $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CAProxy.Interfaces.dll + + + $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CommonCAProxy.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.4.4 + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.sln b/src/HydrantCAProxy/HydrantIdCAProxy.sln new file mode 100644 index 0000000..e54ecf8 --- /dev/null +++ b/src/HydrantCAProxy/HydrantIdCAProxy.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35027.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HydrantIdCAProxy", "HydrantIdCAProxy.csproj", "{011DC646-BEF9-4D3B-9D20-CA444A26B355}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5505EA55-BEBD-4DBC-9ED2-448CFB9BCD37}" + ProjectSection(SolutionItems) = preProject + ..\..\.gitignore = ..\..\.gitignore + ..\..\CHANGELOG.md = ..\..\CHANGELOG.md + ..\..\.github\workflows\keyfactor-extension-prerelease.yml = ..\..\.github\workflows\keyfactor-extension-prerelease.yml + ..\..\.github\workflows\keyfactor-extension-release.yml = ..\..\.github\workflows\keyfactor-extension-release.yml + ..\..\README.md = ..\..\README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Prerelease|Any CPU = Prerelease|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.Build.0 = Release|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0E1B1C00-FE0C-4138-85D7-51AA99D8745F} + EndGlobalSection +EndGlobal diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequest.cs b/src/HydrantCAProxy/Interfaces/ICertRequest.cs similarity index 95% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequest.cs rename to src/HydrantCAProxy/Interfaces/ICertRequest.cs index 36b00c4..77fed05 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequest.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequest.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBody.cs b/src/HydrantCAProxy/Interfaces/ICertRequestBody.cs similarity index 95% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBody.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestBody.cs index 3e66f35..9bd827e 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBody.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestBody.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodyDnComponents.cs b/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodyDnComponents.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs index e617c5e..829e7ce 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodyDnComponents.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodySubjectAltNames.cs b/src/HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodySubjectAltNames.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs index b00f43e..60a2025 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodySubjectAltNames.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodyValidity.cs b/src/HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodyValidity.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs index 94e6e83..d4d1fe3 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestBodyValidity.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestPolicy.cs b/src/HydrantCAProxy/Interfaces/ICertRequestPolicy.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestPolicy.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestPolicy.cs index 5824de4..5be76ac 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestPolicy.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestPolicy.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestResult.cs b/src/HydrantCAProxy/Interfaces/ICertRequestResult.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestResult.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestResult.cs index 86c577e..95476cb 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestResult.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestResult.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestStatus.cs b/src/HydrantCAProxy/Interfaces/ICertRequestStatus.cs similarity index 94% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestStatus.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestStatus.cs index 5dd8645..d13e5ad 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestStatus.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestStatus.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestUser.cs b/src/HydrantCAProxy/Interfaces/ICertRequestUser.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestUser.cs rename to src/HydrantCAProxy/Interfaces/ICertRequestUser.cs index 41761c2..7b02f46 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertRequestUser.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestUser.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificate.cs b/src/HydrantCAProxy/Interfaces/ICertificate.cs similarity index 96% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificate.cs rename to src/HydrantCAProxy/Interfaces/ICertificate.cs index ee2cd4e..6135442 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificate.cs +++ b/src/HydrantCAProxy/Interfaces/ICertificate.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificateStatus.cs b/src/HydrantCAProxy/Interfaces/ICertificateStatus.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificateStatus.cs rename to src/HydrantCAProxy/Interfaces/ICertificateStatus.cs index 9478af2..14e89ab 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificateStatus.cs +++ b/src/HydrantCAProxy/Interfaces/ICertificateStatus.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificateUser.cs b/src/HydrantCAProxy/Interfaces/ICertificateUser.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificateUser.cs rename to src/HydrantCAProxy/Interfaces/ICertificateUser.cs index 243cb5a..10ed0c4 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificateUser.cs +++ b/src/HydrantCAProxy/Interfaces/ICertificateUser.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesPayload.cs b/src/HydrantCAProxy/Interfaces/ICertificatesPayload.cs similarity index 95% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesPayload.cs rename to src/HydrantCAProxy/Interfaces/ICertificatesPayload.cs index f5126a8..b803694 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesPayload.cs +++ b/src/HydrantCAProxy/Interfaces/ICertificatesPayload.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesResponse.cs b/src/HydrantCAProxy/Interfaces/ICertificatesResponse.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesResponse.cs rename to src/HydrantCAProxy/Interfaces/ICertificatesResponse.cs index be985a5..e1e44c4 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesResponse.cs +++ b/src/HydrantCAProxy/Interfaces/ICertificatesResponse.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesResponseItem.cs b/src/HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs similarity index 94% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesResponseItem.cs rename to src/HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs index 4956505..b89df7e 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/ICertificatesResponseItem.cs +++ b/src/HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IErrorReturn.cs b/src/HydrantCAProxy/Interfaces/IErrorReturn.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IErrorReturn.cs rename to src/HydrantCAProxy/Interfaces/IErrorReturn.cs index 0edffa9..3cb0edc 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IErrorReturn.cs +++ b/src/HydrantCAProxy/Interfaces/IErrorReturn.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredential.cs b/src/HydrantCAProxy/Interfaces/IHawkCredential.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredential.cs rename to src/HydrantCAProxy/Interfaces/IHawkCredential.cs index d3e2912..d3addd4 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredential.cs +++ b/src/HydrantCAProxy/Interfaces/IHawkCredential.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialComment.cs b/src/HydrantCAProxy/Interfaces/IHawkCredentialComment.cs similarity index 91% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialComment.cs rename to src/HydrantCAProxy/Interfaces/IHawkCredentialComment.cs index 37a8f17..873e9a6 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialComment.cs +++ b/src/HydrantCAProxy/Interfaces/IHawkCredentialComment.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialComments.cs b/src/HydrantCAProxy/Interfaces/IHawkCredentialComments.cs similarity index 91% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialComments.cs rename to src/HydrantCAProxy/Interfaces/IHawkCredentialComments.cs index 791c64d..fb12241 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialComments.cs +++ b/src/HydrantCAProxy/Interfaces/IHawkCredentialComments.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialDeleteResults.cs b/src/HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialDeleteResults.cs rename to src/HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs index 8b17063..2657723 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IHawkCredentialDeleteResults.cs +++ b/src/HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/INameObject.cs b/src/HydrantCAProxy/Interfaces/INameObject.cs similarity index 91% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/INameObject.cs rename to src/HydrantCAProxy/Interfaces/INameObject.cs index 2b82794..c25fea8 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/INameObject.cs +++ b/src/HydrantCAProxy/Interfaces/INameObject.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicy.cs b/src/HydrantCAProxy/Interfaces/IPolicy.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicy.cs rename to src/HydrantCAProxy/Interfaces/IPolicy.cs index e7339bb..024d93b 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicy.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicy.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetails.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetails.cs similarity index 94% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetails.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetails.cs index 20682b1..b6670e0 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetails.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetails.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsCustomExtensions.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsCustomExtensions.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs index 9731b7d..40d14ed 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsCustomExtensions.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsCustomFields.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsCustomFields.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs index eb41f8c..9f19e45 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsCustomFields.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsDnComponents.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsDnComponents.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs index ae15ad9..925bdf7 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsDnComponents.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsExpiryEmails.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsExpiryEmails.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs index 36f5e06..ebffd00 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsExpiryEmails.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs index f4dceac..b1efa6d 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsValidity.cs b/src/HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs similarity index 93% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsValidity.cs rename to src/HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs index 42badb5..1405aa7 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyDetailsValidity.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyEnabled.cs b/src/HydrantCAProxy/Interfaces/IPolicyEnabled.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyEnabled.cs rename to src/HydrantCAProxy/Interfaces/IPolicyEnabled.cs index 6cd8a3d..656f958 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IPolicyEnabled.cs +++ b/src/HydrantCAProxy/Interfaces/IPolicyEnabled.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRenewalRequest.cs b/src/HydrantCAProxy/Interfaces/IRenewalRequest.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRenewalRequest.cs rename to src/HydrantCAProxy/Interfaces/IRenewalRequest.cs index 0fe3088..5528ab4 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRenewalRequest.cs +++ b/src/HydrantCAProxy/Interfaces/IRenewalRequest.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRenewalResponse.cs b/src/HydrantCAProxy/Interfaces/IRenewalResponse.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRenewalResponse.cs rename to src/HydrantCAProxy/Interfaces/IRenewalResponse.cs index 041791f..26d7c57 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRenewalResponse.cs +++ b/src/HydrantCAProxy/Interfaces/IRenewalResponse.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRevokeCertificateReason.cs b/src/HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRevokeCertificateReason.cs rename to src/HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs index a2e0bc4..4d1df84 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRevokeCertificateReason.cs +++ b/src/HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs b/src/HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs similarity index 92% rename from HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs rename to src/HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs index 4513640..7b02453 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs +++ b/src/HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs @@ -1,4 +1,4 @@ -// Copyright 2023 Keyfactor +// Copyright 2025 Keyfactor // Licensed under the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a // copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless diff --git a/HydrantIdProxy/src/HydrantIdProxy/Properties/AssemblyInfo.cs b/src/HydrantCAProxy/Properties/AssemblyInfo.cs similarity index 60% rename from HydrantIdProxy/src/HydrantIdProxy/Properties/AssemblyInfo.cs rename to src/HydrantCAProxy/Properties/AssemblyInfo.cs index f3b9f7d..8543e07 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/Properties/AssemblyInfo.cs +++ b/src/HydrantCAProxy/Properties/AssemblyInfo.cs @@ -1,15 +1,16 @@ -using System.Reflection; +using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("Swagger Library")] -[assembly: AssemblyDescription("A library generated from a Swagger doc")] +[assembly: AssemblyTitle("HydrantIdCAProxy")] +[assembly: AssemblyDescription("Keyfactor AnyGateway Implementation for the Google Cloud Private CA")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Swagger")] -[assembly: AssemblyProduct("SwaggerLibrary")] -[assembly: AssemblyCopyright("No Copyright")] +[assembly: AssemblyCompany("Keyfactor, Inc")] +[assembly: AssemblyProduct("Keyfactor AnyGateway")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -18,6 +19,9 @@ // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("011dc646-bef9-4d3b-9d20-ca444a26b355")] + // Version information for an assembly consists of the following four values: // // Major Version @@ -28,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0")] -[assembly: AssemblyFileVersion("1.0.0")] +[assembly: AssemblyVersion("0.0.1.0")] +[assembly: AssemblyFileVersion("0.0.1.0")] diff --git a/HydrantIdProxy/src/HydrantIdProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs similarity index 84% rename from HydrantIdProxy/src/HydrantIdProxy/RequestManager.cs rename to src/HydrantCAProxy/RequestManager.cs index 25aff76..29ba18c 100644 --- a/HydrantIdProxy/src/HydrantIdProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -1,353 +1,358 @@ -// Copyright 2023 Keyfactor -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a -// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless -// required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES -// OR CONDITIONS OF ANY KIND, either express or implied. See the License for -// thespecific language governing permissions and limitations under the -// License. -using System; -using System.Collections.Generic; -using System.IO; -using CAProxy.AnyGateway.Models; -using CSS.Common.Logging; -using CSS.PKI; -using Keyfactor.HydrantId.Client.Models; -using Keyfactor.HydrantId.Client.Models.Enums; -using Keyfactor.HydrantId.Interfaces; -using Keyfactor.HydrantId.Exceptions; -using Org.BouncyCastle.OpenSsl; -using Org.BouncyCastle.Pkcs; - -namespace Keyfactor.HydrantId -{ - public class RequestManager : LoggingClientBase - { - public int GetMapReturnStatus(RevocationStatusEnum hydrantIdStatus) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - PKIConstants.Microsoft.RequestDisposition returnStatus; - Logger.Trace($"hydrantIdStatus: {hydrantIdStatus}"); - switch (hydrantIdStatus) - { - case RevocationStatusEnum.Valid: - returnStatus = PKIConstants.Microsoft.RequestDisposition.ISSUED; - break; - case RevocationStatusEnum.Pending: - returnStatus = PKIConstants.Microsoft.RequestDisposition.PENDING; - break; - case RevocationStatusEnum.Revoked: - returnStatus = PKIConstants.Microsoft.RequestDisposition.REVOKED; - break; - default: - returnStatus = PKIConstants.Microsoft.RequestDisposition.UNKNOWN; - break; - } - Logger.MethodExit(ILogExtensions.MethodLogLevel.Debug); - return Convert.ToInt32(returnStatus); - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetMapReturnStatus: {e.Message}"); - throw; - } - } - - public RevocationReasons GetMapRevokeReasons(uint keyfactorRevokeReason) - { - - try - { - RevocationReasons returnStatus = RevocationReasons.KeyCompromise; - if (keyfactorRevokeReason == 1 | keyfactorRevokeReason == 3 | keyfactorRevokeReason == 4 | keyfactorRevokeReason == 5) - { - - switch (keyfactorRevokeReason) - { - case 1: - returnStatus = RevocationReasons.KeyCompromise; - break; - case 3: - returnStatus = RevocationReasons.AffiliationChanged; - break; - case 4: - returnStatus = RevocationReasons.Superseded; - break; - case 5: - returnStatus = RevocationReasons.CessationOfOperation; - break; - } - - return returnStatus; - } - - throw new RevokeReasonNotSupportedException("This Revoke Reason is not Supported"); - - } - catch(Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetMapRevokeReasons: {e.Message}"); - throw; - } - } - - public RevokeCertificateReason GetRevokeRequest(RevocationReasons reason) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - return new RevokeCertificateReason - { - Reason = reason - }; - } - - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetRevokeRequest: {e.Message}"); - throw; - } - } - - public CertificatesPayload GetCertificatesListRequest(int offset,int limit) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - return new CertificatesPayload - { - Limit = limit, - Offset = offset, - Status = 0, - Expired = true - }; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetCertificatesListRequest: {e.Message}"); - throw; - } - } - - public CertRequestBody GetEnrollmentRequest(Guid? policyId,EnrollmentProductInfo productInfo, string csr, Dictionary san) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - if (san.ContainsKey("dns")) - { - return new CertRequestBody - { - Policy = policyId, - Csr = csr, - DnComponents = GetDnComponentsRequest(csr), - SubjectAltNames = GetSansRequest(san), - Validity = GetValidity(productInfo.ProductParameters["ValidityPeriod"],Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) - }; - } - - return new CertRequestBody - { - Policy = policyId, - Csr = csr, - DnComponents = GetDnComponentsRequest(csr), - Validity=GetValidity(productInfo.ProductParameters["ValidityPeriod"], Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) - }; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetEnrollmentRequest: {e.Message}"); - throw; - } - } - - public RenewalRequest GetRenewalRequest(string csr, bool reuseCsr) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - return new RenewalRequest - { - Csr = csr, - ReuseCsr = reuseCsr - }; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetRenewalRequest: {e.Message}"); - throw; - } - } - - private CertRequestBodyValidity GetValidity(string period,int units) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - CertRequestBodyValidity validity = new CertRequestBodyValidity(); - switch(period) - { - case "Years": - validity.Years = units; - break; - case "Months": - validity.Months = units; - break; - case "Days": - validity.Days = units; - break; - } - - return validity; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetValidity: {e.Message}"); - throw; - } - } - - public CertRequestBodySubjectAltNames GetSansRequest(Dictionary sans) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - var san = new CertRequestBodySubjectAltNames(); - List dnsNames = new List(); - foreach (var v in sans["dns"]) - { - dnsNames.Add(v); - } - san.Dnsname=dnsNames; - return san; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetSansRequest: {e.Message}"); - throw; - } - } - - public EnrollmentResult - GetEnrollmentResult( - ICertificate enrollmentResult, CAConnectorCertificate cert) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - if (enrollmentResult==null) - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Enrollment Failed with could not get the certificate from the request tracking id" - }; - } - - if (!enrollmentResult.Id.HasValue) - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Enrollment Failed with could not get the certificate from the request tracking id" - }; - } - - if (enrollmentResult.Id.HasValue) - { - return new EnrollmentResult - { - Status = (int)PKIConstants.Microsoft.RequestDisposition.ISSUED, //success - CARequestID = enrollmentResult.Id.ToString(), - Certificate = cert.Certificate, - StatusMessage = $"Order Successfully Created With Product {cert.ProductID}" - }; - } - - return null; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetEnrollmentResult: {e.Message}"); - throw; - } - } - - public static Func Pemify = ss => - ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + Pemify(ss.Substring(64)); - - public CertRequestBodyDnComponents GetDnComponentsRequest(string csr) - { - try - { - Logger.MethodEntry(ILogExtensions.MethodLogLevel.Debug); - var c = String.Empty; - var o = String.Empty; - var cn = string.Empty; - var l = string.Empty; - var st = string.Empty; - var ou = string.Empty; - - Logger.Trace($"CSR: {csr}"); - var cert = "-----BEGIN CERTIFICATE REQUEST-----\r\n"; - cert = cert + Pemify(csr); - cert = cert + "\r\n-----END CERTIFICATE REQUEST-----"; - Logger.Trace($"cert: {cert}"); - - var reader = new PemReader(new StringReader(cert)); - if (reader.ReadObject() is Pkcs10CertificationRequest req) - { - var info = req.GetCertificationRequestInfo(); - Logger.Trace($"subject: {info.Subject}"); - - var array1 = info.Subject.ToString().Split(','); - foreach (var x in array1) - { - var itemArray = x.Split('='); - - switch (itemArray[0].ToUpper()) - { - case "C": - c = itemArray[1]; - break; - case "O": - o = itemArray[1]; - break; - case "CN": - cn = itemArray[1]; - break; - case "OU": - ou = itemArray[1]; - break; - case "ST": - st = itemArray[1]; - break; - case "L": - l = itemArray[1]; - break; - } - } - } - - return new CertRequestBodyDnComponents - { - Cn = cn, - Ou = new List{ou}, - O=o, - L=l, - St = st, - C=c - }; - } - catch (Exception e) - { - Logger.Error($"Error Occured in RequestManager.GetDnComponentsRequest: {e.Message}"); - throw; - } - } - } -} - +// Copyright 2025 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using System; +using System.Collections.Generic; +using System.IO; +using CAProxy.AnyGateway.Models; +using CSS.Common.Logging; +using CSS.PKI; +using Keyfactor.HydrantId.Client.Models; +using Keyfactor.HydrantId.Client.Models.Enums; +using Keyfactor.HydrantId.Interfaces; +using Keyfactor.HydrantId.Exceptions; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Pkcs; +using Microsoft.Extensions.Logging; +using Keyfactor.Logging; +using LogHandler = Keyfactor.Logging.LogHandler; + +namespace Keyfactor.HydrantId +{ + public class RequestManager + { + private static readonly ILogger Log = LogHandler.GetClassLogger(); + + public int GetMapReturnStatus(RevocationStatusEnum hydrantIdStatus) + { + try + { + Log.MethodEntry(); + PKIConstants.Microsoft.RequestDisposition returnStatus; + Log.LogTrace($"hydrantIdStatus: {hydrantIdStatus}"); + switch (hydrantIdStatus) + { + case RevocationStatusEnum.Valid: + returnStatus = PKIConstants.Microsoft.RequestDisposition.ISSUED; + break; + case RevocationStatusEnum.Pending: + returnStatus = PKIConstants.Microsoft.RequestDisposition.PENDING; + break; + case RevocationStatusEnum.Revoked: + returnStatus = PKIConstants.Microsoft.RequestDisposition.REVOKED; + break; + default: + returnStatus = PKIConstants.Microsoft.RequestDisposition.UNKNOWN; + break; + } + Log.MethodExit(); + return Convert.ToInt32(returnStatus); + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetMapReturnStatus: {e.Message}"); + throw; + } + } + + public RevocationReasons GetMapRevokeReasons(uint keyfactorRevokeReason) + { + + try + { + RevocationReasons returnStatus = RevocationReasons.KeyCompromise; + if (keyfactorRevokeReason == 1 | keyfactorRevokeReason == 3 | keyfactorRevokeReason == 4 | keyfactorRevokeReason == 5) + { + + switch (keyfactorRevokeReason) + { + case 1: + returnStatus = RevocationReasons.KeyCompromise; + break; + case 3: + returnStatus = RevocationReasons.AffiliationChanged; + break; + case 4: + returnStatus = RevocationReasons.Superseded; + break; + case 5: + returnStatus = RevocationReasons.CessationOfOperation; + break; + } + + return returnStatus; + } + + throw new RevokeReasonNotSupportedException("This Revoke Reason is not Supported"); + + } + catch(Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetMapRevokeReasons: {e.Message}"); + throw; + } + } + + public RevokeCertificateReason GetRevokeRequest(RevocationReasons reason) + { + try + { + Log.MethodEntry(); + return new RevokeCertificateReason + { + Reason = reason + }; + } + + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetRevokeRequest: {e.Message}"); + throw; + } + } + + public CertificatesPayload GetCertificatesListRequest(int offset,int limit) + { + try + { + Log.MethodEntry(); + return new CertificatesPayload + { + Limit = limit, + Offset = offset, + Status = 0, + Expired = true + }; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetCertificatesListRequest: {e.Message}"); + throw; + } + } + + public CertRequestBody GetEnrollmentRequest(Guid? policyId,EnrollmentProductInfo productInfo, string csr, Dictionary san) + { + try + { + Log.MethodEntry(); + if (san.ContainsKey("dns")) + { + return new CertRequestBody + { + Policy = policyId, + Csr = csr, + DnComponents = GetDnComponentsRequest(csr), + SubjectAltNames = GetSansRequest(san), + Validity = GetValidity(productInfo.ProductParameters["ValidityPeriod"],Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) + }; + } + + return new CertRequestBody + { + Policy = policyId, + Csr = csr, + DnComponents = GetDnComponentsRequest(csr), + Validity=GetValidity(productInfo.ProductParameters["ValidityPeriod"], Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) + }; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetEnrollmentRequest: {e.Message}"); + throw; + } + } + + public RenewalRequest GetRenewalRequest(string csr, bool reuseCsr) + { + try + { + Log.MethodEntry(); + return new RenewalRequest + { + Csr = csr, + ReuseCsr = reuseCsr + }; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetRenewalRequest: {e.Message}"); + throw; + } + } + + private CertRequestBodyValidity GetValidity(string period,int units) + { + try + { + Log.MethodEntry(); + CertRequestBodyValidity validity = new CertRequestBodyValidity(); + switch(period) + { + case "Years": + validity.Years = units; + break; + case "Months": + validity.Months = units; + break; + case "Days": + validity.Days = units; + break; + } + + return validity; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetValidity: {e.Message}"); + throw; + } + } + + public CertRequestBodySubjectAltNames GetSansRequest(Dictionary sans) + { + try + { + Log.MethodEntry(); + var san = new CertRequestBodySubjectAltNames(); + List dnsNames = new List(); + foreach (var v in sans["dns"]) + { + dnsNames.Add(v); + } + san.Dnsname=dnsNames; + return san; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetSansRequest: {e.Message}"); + throw; + } + } + + public EnrollmentResult + GetEnrollmentResult( + ICertificate enrollmentResult, CAConnectorCertificate cert) + { + try + { + Log.MethodEntry(); + if (enrollmentResult==null) + { + return new EnrollmentResult + { + Status = 30, //failure + StatusMessage = $"Enrollment Failed with could not get the certificate from the request tracking id" + }; + } + + if (!enrollmentResult.Id.HasValue) + { + return new EnrollmentResult + { + Status = 30, //failure + StatusMessage = $"Enrollment Failed with could not get the certificate from the request tracking id" + }; + } + + if (enrollmentResult.Id.HasValue) + { + return new EnrollmentResult + { + Status = (int)PKIConstants.Microsoft.RequestDisposition.ISSUED, //success + CARequestID = enrollmentResult.Id.ToString(), + Certificate = cert.Certificate, + StatusMessage = $"Order Successfully Created With Product {cert.ProductID}" + }; + } + + return null; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetEnrollmentResult: {e.Message}"); + throw; + } + } + + public static Func Pemify = ss => + ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + Pemify(ss.Substring(64)); + + public CertRequestBodyDnComponents GetDnComponentsRequest(string csr) + { + try + { + Log.MethodEntry(); + var c = String.Empty; + var o = String.Empty; + var cn = string.Empty; + var l = string.Empty; + var st = string.Empty; + var ou = string.Empty; + + Log.LogTrace($"CSR: {csr}"); + var cert = "-----BEGIN CERTIFICATE REQUEST-----\r\n"; + cert = cert + Pemify(csr); + cert = cert + "\r\n-----END CERTIFICATE REQUEST-----"; + Log.LogTrace($"cert: {cert}"); + + var reader = new PemReader(new StringReader(cert)); + if (reader.ReadObject() is Pkcs10CertificationRequest req) + { + var info = req.GetCertificationRequestInfo(); + Log.LogTrace($"subject: {info.Subject}"); + + var array1 = info.Subject.ToString().Split(','); + foreach (var x in array1) + { + var itemArray = x.Split('='); + + switch (itemArray[0].ToUpper()) + { + case "C": + c = itemArray[1]; + break; + case "O": + o = itemArray[1]; + break; + case "CN": + cn = itemArray[1]; + break; + case "OU": + ou = itemArray[1]; + break; + case "ST": + st = itemArray[1]; + break; + case "L": + l = itemArray[1]; + break; + } + } + } + + return new CertRequestBodyDnComponents + { + Cn = cn, + Ou = new List{ou}, + O=o, + L=l, + St = st, + C=c + }; + } + catch (Exception e) + { + Log.LogError($"Error Occured in RequestManager.GetDnComponentsRequest: {e.Message}"); + throw; + } + } + } +} + From 71756baf8d7fa98ae04ac9e2ea878ac78c55e4d2 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Mon, 7 Apr 2025 18:56:42 +0000 Subject: [PATCH 02/25] Update generated README --- README.md | 83 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e6ecb96..43a49cc 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,43 @@ -

- GCP CAS AnyCA Gateway DCOM plugin -

- -

- -Integration Status: production -Release -Issues -GitHub Downloads (all assets, all releases) -

- -

- - - Support - - · - - License - - · - - Related Integrations - -

- -## Support -The GCP CAS AnyCA Gateway DCOM plugin is open source and there is **no SLA**. Keyfactor will address issues as resources become available. Keyfactor customers may request escalation by opening up a support ticket through their Keyfactor representative. - -> To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. + +# GCP CAS AnyCA Gateway DCOM plugin + +AnyCA Gateway DCOM plugin that extends Google Cloud Platform Certificate Authority Service to Keyfactor Command + +#### Integration status: Production - Ready for use in production environments. + +## About the Keyfactor AnyCA Gateway DCOM Connector + +This repository contains an AnyCA Gateway Connector, which is a plugin to the Keyfactor AnyGateway. AnyCA Gateway Connectors allow Keyfactor Command to be used for inventory, issuance, and revocation of certificates from a third-party certificate authority. + +## Support for GCP CAS AnyCA Gateway DCOM plugin + +GCP CAS AnyCA Gateway DCOM plugin is open source and supported on best effort level for this tool/library/client. This means customers can report Bugs, Feature Requests, Documentation amendment or questions as well as requests for customer information required for setup that needs Keyfactor access to obtain. Such requests do not follow normal SLA commitments for response or resolution. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com/ + +###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. + +--- + + +--- + + + + + +## Keyfactor AnyCA Gateway Framework Supported +The Keyfactor gateway framework implements common logic shared across various gateway implementations and handles communication with Keyfactor Command. The gateway framework hosts gateway implementations or plugins that understand how to communicate with specific CAs. This allows you to integrate your third-party CAs with Keyfactor Command such that they behave in a manner similar to the CAs natively supported by Keyfactor Command. + + + + +This gateway extension was compiled against version of the AnyCA Gateway DCOM Framework. You will need at least this version of the framework Installed. If you have a later AnyGateway Framework Installed you will probably need to add binding redirects in the CAProxyServer.exe.config file to make things work properly. + + +[Keyfactor CAGateway Install Guide](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm) + + + +--- ## Overview @@ -106,10 +115,10 @@ The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](h 3. Copy `*.dll` to the `C:\Program Files\Keyfactor\Keyfactor AnyGateway` directory. 4. Update the `CAProxyServer.config` file. - 1. Update the `$.configuration.unity.CAConnector` section to point at the `HydrantIdCAProxy` class. + 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class. ```xml - + ``` 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`. @@ -254,11 +263,3 @@ There are no Google Specific Changes for the GatewayRegistration section. Refer ``` - -## License - -Apache License 2.0, see [LICENSE](LICENSE). - -## Related Integrations - -See all [Keyfactor integrations](https://github.com/topics/keyfactor-integration). \ No newline at end of file From cb79d1261df529c014100b9551dd431fa4b0b562 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 11 Apr 2025 18:14:20 +0000 Subject: [PATCH 03/25] checkpoint --- src/HydrantCAProxy/Client/HydrantIdClient.cs | 507 +++++++------- src/HydrantCAProxy/Constants.cs | 19 - src/HydrantCAProxy/HydrantIdCAProxy.cs | 694 ++++++++++--------- src/HydrantCAProxy/HydrantIdCAProxy.csproj | 186 +---- src/HydrantCAProxy/HydrantIdCAProxyConfig.cs | 95 +++ src/HydrantCAProxy/RequestManager.cs | 70 +- 6 files changed, 762 insertions(+), 809 deletions(-) delete mode 100644 src/HydrantCAProxy/Constants.cs create mode 100644 src/HydrantCAProxy/HydrantIdCAProxyConfig.cs diff --git a/src/HydrantCAProxy/Client/HydrantIdClient.cs b/src/HydrantCAProxy/Client/HydrantIdClient.cs index fa4172d..410f738 100644 --- a/src/HydrantCAProxy/Client/HydrantIdClient.cs +++ b/src/HydrantCAProxy/Client/HydrantIdClient.cs @@ -1,16 +1,15 @@ -// Copyright 2025 Keyfactor -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a -// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless -// required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES -// OR CONDITIONS OF ANY KIND, either express or implied. See the License for -// thespecific language governing permissions and limitations under the -// License. -using System; +// Copyright 2025 Keyfactor +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain a +// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless +// required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES +// OR CONDITIONS OF ANY KIND, either express or implied. See the License for +// thespecific language governing permissions and limitations under the +// License. +using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; using System.Net; using System.Net.Http; using System.Net.Http.Headers; @@ -18,18 +17,16 @@ using System.Text; using System.Threading; using System.Threading.Tasks; -using CAProxy.AnyGateway.Interfaces; using Keyfactor.Logging; -using HawkNet; using Keyfactor.HydrantId.Client.Models; using Keyfactor.HydrantId.Client.Models.Enums; using Keyfactor.HydrantId.Exceptions; -using Keyfactor.HydrantId.Extensions; using Keyfactor.HydrantId.Interfaces; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -using Keyfactor.AnyGateway.Google; using Microsoft.Extensions.Logging; +using Keyfactor.Extensions.CAPlugin.HydrantId; +using Keyfactor.AnyGateway.Extensions; namespace Keyfactor.HydrantId.Client { @@ -37,15 +34,16 @@ public sealed class HydrantIdClient { private static readonly ILogger Log = LogHandler.GetClassLogger < HydrantIdClient>(); - public HydrantIdClient(ICAConnectorConfigProvider config) + public HydrantIdClient(IAnyCAPluginConfigProvider config) { try { Log.MethodEntry(); - if (config.CAConnectionData.ContainsKey(Constants.HydrantIdAuthId)) + + if (config.CAConnectionData.ContainsKey(HydrantIdCAProxyConfig.ConfigConstants.HydrantIdAuthId)) { ConfigProvider = config; - BaseUrl = ConfigProvider.CAConnectionData[Constants.HydrantIdBaseUrl].ToString(); + BaseUrl = ConfigProvider.CAConnectionData[HydrantIdCAProxyConfig.ConfigConstants.HydrantIdBaseUrl].ToString(); RequestManager = new RequestManager(); } } @@ -61,152 +59,123 @@ public HydrantIdClient(ICAConnectorConfigProvider config) private string ApiId { get; set; } private RequestManager RequestManager { get; } - private ICAConnectorConfigProvider ConfigProvider { get; } - - public async Task GetSubmitEnrollmentAsync( - CertRequestBody registerRequest) - { - Log.MethodEntry(); - var apiEndpoint = "/api/v2/csr"; - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); - var traceWriter = new MemoryTraceWriter(); - - using (var resp = await restClient.PostAsync(apiEndpoint, new StringContent( - JsonConvert.SerializeObject(registerRequest), Encoding.UTF8, "application/json"))) - { - try - { - Log.LogTrace($"Register Request JSON: {JsonConvert.SerializeObject(registerRequest)}"); - var settings = new JsonSerializerSettings - {NullValueHandling = NullValueHandling.Ignore, TraceWriter = traceWriter}; - var _ = await resp.Content.ReadAsStringAsync(); - - if (resp.StatusCode == HttpStatusCode.InternalServerError) - { - var errorResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), - settings); - Log.LogError($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); - var responseReturn = new CertRequestResult {ErrorReturn = errorResponse, RequestStatus = null}; - return responseReturn; - } - - var validResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), - settings); - Log.LogError($"validResponse Response JSON: {JsonConvert.SerializeObject(validResponse)}"); - var validReturn = new CertRequestResult {ErrorReturn = null, RequestStatus = validResponse}; - return validReturn; - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.GetSubmitEnrollmentAsync: {e.Message}"); - throw; - } - } - } + private IAnyCAPluginConfigProvider ConfigProvider { get; } + + public async Task GetSubmitEnrollmentAsync(CertRequestBody registerRequest) + { + Log.MethodEntry(); + var apiEndpoint = "/api/v2/csr"; + var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); + + var json = JsonConvert.SerializeObject(registerRequest); + Log.LogTrace($"Register Request JSON: {json}"); + + var traceWriter = new MemoryTraceWriter(); + var settings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + TraceWriter = traceWriter + }; + + using var resp = await restClient.PostAsync(apiEndpoint, new StringContent(json, Encoding.UTF8, "application/json")); + var responseContent = await resp.Content.ReadAsStringAsync(); + + if (resp.StatusCode == HttpStatusCode.InternalServerError) + { + var errorResponse = JsonConvert.DeserializeObject(responseContent, settings); + Log.LogError($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); + return new CertRequestResult { ErrorReturn = errorResponse }; + } + + var validResponse = JsonConvert.DeserializeObject(responseContent, settings); + Log.LogTrace($"Valid Response JSON: {JsonConvert.SerializeObject(validResponse)}"); + return new CertRequestResult { RequestStatus = validResponse }; + } + + + public async Task GetSubmitRenewalAsync(string certificateId, RenewalRequest renewRequest) + { + Log.MethodEntry(); + var apiEndpoint = $"/api/v2/certificates/{certificateId}/renew"; + var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); + + var json = JsonConvert.SerializeObject(renewRequest); + Log.LogTrace($"Renew Request JSON: {json}"); + + var traceWriter = new MemoryTraceWriter(); + var settings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + TraceWriter = traceWriter + }; + + using var resp = await restClient.PostAsync(apiEndpoint, new StringContent(json, Encoding.UTF8, "application/json")); + var responseContent = await resp.Content.ReadAsStringAsync(); + + if (resp.StatusCode == HttpStatusCode.InternalServerError) + { + var errorResponse = JsonConvert.DeserializeObject(responseContent, settings); + Log.LogError($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); + return new CertRequestResult { ErrorReturn = errorResponse }; + } + + var validResponse = JsonConvert.DeserializeObject(responseContent, settings); + Log.LogTrace($"Valid Response JSON: {JsonConvert.SerializeObject(validResponse)}"); + return new CertRequestResult { RequestStatus = validResponse }; + } + + + + public async Task> GetPolicyList() + { + Log.MethodEntry(); + var apiEndpoint = "/api/v2/policies"; + var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); + + var traceWriter = new MemoryTraceWriter(); + var settings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + TraceWriter = traceWriter + }; + + using var resp = await restClient.GetAsync(apiEndpoint); + var responseContent = await resp.Content.ReadAsStringAsync(); + var policies = JsonConvert.DeserializeObject>(responseContent, settings); + Log.LogDebug(traceWriter.ToString()); + + return policies; + } + + + + public async Task GetSubmitGetCertificateAsync(string certificateId) + { + Log.MethodEntry(); + + var apiEndpoint = $"/api/v2/certificates/{certificateId}"; + Log.LogTrace($"API Url: {BaseUrl + apiEndpoint}"); + + try + { + var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); + using var response = await restClient.GetAsync(apiEndpoint); + response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsStringAsync(); + return JsonConvert.DeserializeObject(content); + } + catch (Exception e) + { + Log.LogError($"Error in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); + throw; + } + } - public async Task GetSubmitRenewalAsync(string certificateId, - RenewalRequest renewRequest) - { - try - { - Log.MethodEntry(); - var apiEndpoint = $"/api/v2/certificates/{certificateId}/renew"; - var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var traceWriter = new MemoryTraceWriter(); - - using (var resp = await restClient.PostAsync(apiEndpoint, new StringContent( - JsonConvert.SerializeObject(renewRequest), Encoding.UTF8, "application/json"))) - { - Log.LogTrace($"Renew Request: {JsonConvert.SerializeObject(renewRequest)}"); - var settings = new JsonSerializerSettings - { NullValueHandling = NullValueHandling.Ignore, TraceWriter = traceWriter }; - var _ = await resp.Content.ReadAsStringAsync(); - - if (resp.StatusCode == HttpStatusCode.InternalServerError) - { - var errorResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), - settings); - Log.LogError($"Error Response JSON: {JsonConvert.SerializeObject(errorResponse)}"); - var responseReturn = new CertRequestResult { ErrorReturn = errorResponse, RequestStatus = null }; - return responseReturn; - } - - var validResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), - settings); - Log.LogError($"validResponse Response JSON: {JsonConvert.SerializeObject(validResponse)}"); - var validReturn = new CertRequestResult { ErrorReturn = null, RequestStatus = validResponse }; - return validReturn; - } - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.GetSubmitRenewalAsync: {e.Message}"); - throw; - } - } - - - public async Task> GetPolicyList() - { - try - { - Log.MethodEntry(); - var apiEndpoint = "/api/v2/policies"; - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); - - var traceWriter = new MemoryTraceWriter(); - - using (var resp = await restClient.GetAsync(apiEndpoint)) - { - var settings = new JsonSerializerSettings - {NullValueHandling = NullValueHandling.Ignore, TraceWriter = traceWriter}; - var policiesResponse = - JsonConvert.DeserializeObject>(await resp.Content.ReadAsStringAsync(), - settings); - Log.LogDebug(traceWriter.ToString()); - return policiesResponse; - } - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.GetPolicyList: {e.Message}"); - throw; - } - } - - - public async Task GetSubmitGetCertificateAsync(string certificateId) - { - try - { - Log.MethodEntry(); - var apiEndpoint = $"/api/v2/certificates/{certificateId}"; - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); - - using (var resp = await restClient.GetAsync(apiEndpoint)) - { - resp.EnsureSuccessStatusCode(); - var getCertificateResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); - return getCertificateResponse; - } - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); - throw; - } - } - public async Task GetSubmitGetCertificateByCsrAsync(string requestTrackingId) { try @@ -229,36 +198,41 @@ public async Task GetSubmitGetCertificateByCsrAsync(string requestT Log.LogError($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); throw; } - } + } + + public async Task GetSubmitRevokeCertificateAsync(string hydrantId, RevocationReasons revokeReason) + { + Log.MethodEntry(); + + var apiEndpoint = $"/api/v2/certificates/{hydrantId}"; + var fullUrl = BaseUrl + apiEndpoint; + + Log.LogTrace($"API Url: {fullUrl}"); + + var restClient = ConfigureRestClient("patch", fullUrl); + var revokeRequest = RequestManager.GetRevokeRequest(revokeReason); + Log.LogTrace($"Revoke Request JSON: {JsonConvert.SerializeObject(revokeRequest)}"); + + try + { + using var response = await restClient.PatchAsync(new Uri(fullUrl), new StringContent( + JsonConvert.SerializeObject(revokeRequest), Encoding.UTF8, "application/json")); + + var json = await response.Content.ReadAsStringAsync(); + var revokeResponse = JsonConvert.DeserializeObject( + json, + new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); + + Log.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); + return revokeResponse; + } + catch (Exception e) + { + Log.LogError($"Error in HydrantIdClient.GetSubmitRevokeCertificateAsync: {e.Message}"); + throw; + } + } - public async Task GetSubmitRevokeCertificateAsync(string hydrantId, - RevocationReasons revokeReason) - { - try - { - Log.MethodEntry(); - var apiEndpoint = $"/api/v2/certificates/{hydrantId}"; - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var restClient = ConfigureRestClient("patch", BaseUrl + apiEndpoint); - var revokeRequest = RequestManager.GetRevokeRequest(revokeReason); - Log.LogTrace($"Revoke Request JSON: {JsonConvert.SerializeObject(revokeRequest)}"); - using (var resp = await restClient.PatchAsync(new Uri(BaseUrl + apiEndpoint), new StringContent( - JsonConvert.SerializeObject(revokeRequest), Encoding.UTF8, "application/json"))) - { - var jsonSerializerSettings = new JsonSerializerSettings {NullValueHandling = NullValueHandling.Ignore}; - var getRevokeResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync(), - jsonSerializerSettings); - Log.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(getRevokeResponse)}"); - return getRevokeResponse; - } - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.GetSubmitRevokeCertificateAsync: {e.Message}"); - throw; - } - } public async Task GetSubmitCertificateListRequestAsync(BlockingCollection bc, CancellationToken ct) @@ -342,72 +316,121 @@ public async Task GetSubmitCertificateListRequestAsync(BlockingCollection Ping() + { + Log.MethodEntry(); + + var apiEndpoint = "/api/v2/policies"; // Lightweight, safe endpoint + var fullUrl = BaseUrl + apiEndpoint; + Log.LogTrace($"Ping API Url: {fullUrl}"); + + try + { + var restClient = ConfigureRestClient("get", fullUrl); + using var response = await restClient.GetAsync(apiEndpoint); + var content = await response.Content.ReadAsStringAsync(); + + if (!response.IsSuccessStatusCode) + { + Log.LogError($"Ping failed. Status: {response.StatusCode}, Response: {content}"); + return false; + } + + Log.LogTrace("Ping successful."); + return true; + } + catch (Exception e) + { + Log.LogError($"Error in HydrantIdClient.Ping: {e.Message}"); + return false; + } + } + + + // ReSharper disable once InconsistentNaming + private HttpClient ConfigureRestClient(string method, string url) + { + try + { + Log.MethodEntry(); + var bUrl = new Uri(BaseUrl); + + var apiId = ConfigProvider.CAConnectionData[HydrantIdCAProxyConfig.ConfigConstants.HydrantIdAuthId].ToString(); + var apiKey = ConfigProvider.CAConnectionData[HydrantIdCAProxyConfig.ConfigConstants.HydrantIdAuthKey].ToString(); + + var byteArray = new byte[20]; + using (var rnd = RandomNumberGenerator.Create()) + { + rnd.GetBytes(byteArray); + } + + var nonce = Convert.ToBase64String(byteArray); + var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); + + // Build normalized string according to Hawk spec (beware of spacing/line endings!) + var uri = new Uri(url); + var requestPath = uri.PathAndQuery; + var normalized = new StringBuilder(); + normalized.AppendLine("hawk.1.header"); + normalized.AppendLine(timestamp); + normalized.AppendLine(nonce); + normalized.AppendLine(method.ToUpperInvariant()); + normalized.AppendLine(requestPath); + normalized.AppendLine(uri.Host); + normalized.AppendLine(uri.Port.ToString()); + normalized.AppendLine(); // No hash + normalized.AppendLine(); // No ext + normalized.AppendLine(); // No app + normalized.Append(""); // No dlg + + var normalizedString = normalized.ToString(); + + // Calculate MAC using HMACSHA256 + byte[] keyBytes = Encoding.UTF8.GetBytes(apiKey); + byte[] dataBytes = Encoding.UTF8.GetBytes(normalizedString); + string mac; + + using (var hmac = new HMACSHA256(keyBytes)) + { + var hashBytes = hmac.ComputeHash(dataBytes); + mac = Convert.ToBase64String(hashBytes); + } + + var authorization = $"Hawk id=\"{apiId}\", ts=\"{timestamp}\", nonce=\"{nonce}\", mac=\"{mac}\""; + Log.LogTrace($"Authorization: {authorization}"); + + var handler = new HttpClientHandler(); + var client = new HttpClient(handler, true) { BaseAddress = bUrl }; + client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + client.DefaultRequestHeaders.Add("Authorization", authorization); + + return client; + } + catch (Exception e) + { + Log.LogError($"Error Occurred in ConfigureRestClient: {e}"); + throw; + } } } } \ No newline at end of file diff --git a/src/HydrantCAProxy/Constants.cs b/src/HydrantCAProxy/Constants.cs deleted file mode 100644 index a2f038b..0000000 --- a/src/HydrantCAProxy/Constants.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2025 Keyfactor -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a -// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless -// required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES -// OR CONDITIONS OF ANY KIND, either express or implied. See the License for -// thespecific language governing permissions and limitations under the -// License. -namespace Keyfactor.HydrantId -{ - public class Constants - { - public static string HydrantIdBaseUrl = "HydrantIdBaseUrl"; - public static string HydrantIdAuthId = "AuthId"; - public static string HydrantIdAuthKey = "AuthKey"; - public static int DefaultPageSize = 100; - } -} diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.cs b/src/HydrantCAProxy/HydrantIdCAProxy.cs index 0bb8dc6..b20f53d 100644 --- a/src/HydrantCAProxy/HydrantIdCAProxy.cs +++ b/src/HydrantCAProxy/HydrantIdCAProxy.cs @@ -5,352 +5,75 @@ using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; -using CAProxy.AnyGateway; -using CAProxy.AnyGateway.Interfaces; -using CAProxy.AnyGateway.Models; -using CAProxy.Common; -using CSS.PKI; using Keyfactor.HydrantId.Client; using Keyfactor.HydrantId.Interfaces; using Keyfactor.HydrantId; using Keyfactor.Logging; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using CSS.Common.Logging; using System.Threading.Tasks; using LogHandler = Keyfactor.Logging.LogHandler; -using CSS.Common; using Keyfactor.HydrantId.Client.Models; using System.Diagnostics; +using Keyfactor.AnyGateway.Extensions; +using Keyfactor.PKI; +using System.Data; +using Keyfactor.Extensions.CAPlugin.HydrantId; namespace Keyfactor.AnyGateway.Google { - public class HydrantIdCAProxy : BaseCAConnector + public class HydrantIdCAProxy : IAnyCAPlugin { - private static readonly ILogger Log = LogHandler.GetClassLogger(); + private static readonly ILogger _logger = LogHandler.GetClassLogger(); private RequestManager _requestManager; - private ICAConnectorConfigProvider Config { get; set; } + private IAnyCAPluginConfigProvider Config { get; set; } + private ICertificateDataReader certDataReader; - public override EnrollmentResult Enroll(ICertificateDataReader certificateDataReader, string csr, - string subject, Dictionary san, EnrollmentProductInfo productInfo, - PKIConstants.X509.RequestFormat requestFormat, RequestUtilities.EnrollmentType enrollmentType) + public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDataReader certificateDataReader) { - Log.MethodEntry(); - _requestManager=new RequestManager(); - CertRequestResult enrollmentResponse = null; - int timerTries = 0; - Certificate csrTrackingResponse = null; - var client = new HydrantIdClient(Config); - - switch (enrollmentType) - { - case RequestUtilities.EnrollmentType.New: - case RequestUtilities.EnrollmentType.Reissue: - Log.LogTrace("Entering New Enrollment"); - - var policyListResult = - Task.Run(async () => await client.GetPolicyList()) - .Result; - - Log.LogTrace($"Policy Result List: {JsonConvert.SerializeObject(policyListResult)}"); - var policyId = policyListResult.Single(p => p.Name.Equals(productInfo.ProductID)); - - Log.LogTrace($"PolicyId: {JsonConvert.SerializeObject(policyId)}"); - - var enrollmentRequest = - _requestManager.GetEnrollmentRequest(policyId.Id, productInfo, csr, san); - - Log.LogTrace($"Enrollment Request JSON: {JsonConvert.SerializeObject(enrollmentRequest)}"); - enrollmentResponse = - Task.Run(async () => await client.GetSubmitEnrollmentAsync(enrollmentRequest)) - .Result; - Log.LogTrace($"Enrollment Response JSON: {JsonConvert.SerializeObject(enrollmentResponse)}"); - - if (enrollmentResponse?.ErrorReturn?.Status != "Failure") - { - timerTries = +1; - csrTrackingResponse = GetCertificateOnTimer(enrollmentResponse?.RequestStatus?.Id); - } - else - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Enrollment Failed with error {enrollmentResponse?.ErrorReturn?.Error}" - }; - } - - - Log.MethodExit(); - - break; - - case RequestUtilities.EnrollmentType.Renew: - Log.LogTrace("Entering Renew..."); - - var renewalRequest = _requestManager.GetRenewalRequest(csr, false); - Log.LogTrace($"Renewal Request JSON: {JsonConvert.SerializeObject(renewalRequest)}"); - var sn = productInfo.ProductParameters["PriorCertSN"]; - Log.LogTrace($"Prior Cert Serial Number= {sn}"); - var priorCert = certificateDataReader.GetCertificateRecord( - DataConversion.HexToBytes(sn)); - - var uUId = priorCert.CARequestID; //uUId is a GUID - - Log.LogTrace($"Hydrant Certificate Id Plus Serial #= {uUId}"); - - Log.LogTrace($"Reissue CA RequestId: {uUId}"); - var certificateId = uUId.Substring(0, 36); - enrollmentResponse = - Task.Run(async () => - await client.GetSubmitRenewalAsync(certificateId, renewalRequest)) - .Result; - Log.LogTrace($"Renew Response JSON: {JsonConvert.SerializeObject(enrollmentResponse)}"); - - if (enrollmentResponse?.ErrorReturn?.Status != "Failure") - { - timerTries = +1; - csrTrackingResponse = GetCertificateOnTimer(enrollmentResponse?.RequestStatus?.Id); - } - else - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Enrollment Failed with error {enrollmentResponse?.ErrorReturn?.Error}" - }; - } - break; - } - - if (csrTrackingResponse == null && timerTries > 0) - { - return new EnrollmentResult - { - Status = 30, //failure - StatusMessage = $"Certificate may still waiting on Hydrant and is not ready for download" - }; - } - - var cert = GetSingleRecord(csrTrackingResponse.Id.ToString()); - return _requestManager.GetEnrollmentResult(csrTrackingResponse, cert); - } - - public override CAConnectorCertificate GetSingleRecord(string caRequestId) - { - Logger.MethodEntry(); - _requestManager = new RequestManager(); - Log.LogTrace($"Keyfactor Ca Id: {caRequestId}"); - try - { - var client = new HydrantIdClient(Config); - var certificateResponse = - Task.Run(async () => - await client.GetSubmitGetCertificateAsync(caRequestId.Substring(0, 36))) - .Result; - - Log.LogTrace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); - Log.MethodExit(); - return new CAConnectorCertificate - { - CARequestID = caRequestId, - Certificate = certificateResponse.Pem, - ResolutionDate = Convert.ToDateTime(certificateResponse.NotAfter), - Status = _requestManager.GetMapReturnStatus(certificateResponse.RevocationStatus), - SubmissionDate = Convert.ToDateTime(certificateResponse.CreatedAt) - }; - } - catch (Exception) //Most likely cert is not available yet, just get it on the sync - { - return new CAConnectorCertificate - { - CARequestID = caRequestId, - Status = _requestManager.GetMapReturnStatus(0) //Unknown - }; - } - } - - public override void Initialize(ICAConnectorConfigProvider configProvider) - { - Log.MethodEntry(); + _logger.MethodEntry(); try { + certDataReader= certificateDataReader; Config = configProvider; } catch (Exception ex) { - Log.LogError($"Failed to initialize GCP CAS CAPlugin: {ex}"); + _logger.LogError($"Failed to initialize GCP CAS CAPlugin: {ex}"); } } - public override void Ping() - { - Log.MethodEntry(); - Log.MethodExit(); + public void ValidateCAConnectionInfo(Dictionary connectionInfo) + { + _logger.MethodEntry(); + _logger.LogDebug($"Validating GCP CAS CA Connection properties"); + var rawData = JsonConvert.SerializeObject(connectionInfo); + HydrantIdCAProxyConfig.Config config = JsonConvert.DeserializeObject(rawData); + + _logger.LogTrace($"HydrantIdClientFromCAConnectionData - HydrantIdBaseUrl: {config.HydrantIdBaseUrl}"); + _logger.LogTrace($"HydrantIdClientFromCAConnectionData - HydrantIdAuthId: {config.HydrantIdAuthId}"); + _logger.LogTrace($"HydrantIdClientFromCAConnectionData - HydrantIdAuthKey: {config.HydrantIdAuthKey}"); + + List missingFields = new List(); + + if (string.IsNullOrEmpty(config.HydrantIdBaseUrl)) missingFields.Add(nameof(config.HydrantIdBaseUrl)); + if (string.IsNullOrEmpty(config.HydrantIdAuthId)) missingFields.Add(nameof(config.HydrantIdAuthId)); + if (string.IsNullOrEmpty(config.HydrantIdAuthKey)) missingFields.Add(nameof(config.HydrantIdAuthKey)); + + if (missingFields.Count > 0) + { + throw new ArgumentException($"The following required fields are missing or empty: {string.Join(", ", missingFields)}"); + } + + _logger.MethodExit(); } - public override int Revoke(string caRequestId, string hexSerialNumber, uint revocationReason) - { - try - { - Logger.LogTrace("Staring Revoke Method"); - _requestManager = new RequestManager(); - var client = new HydrantIdClient(Config); - var hydrantId = caRequestId.Substring(0, 36); - var revokeReason = _requestManager.GetMapRevokeReasons(revocationReason); - - Logger.LogTrace($"Revoke Reason {revokeReason}"); - - var revokeResponse = Task.Run(async () => - await client.GetSubmitRevokeCertificateAsync(hydrantId, revokeReason)) - .Result; - - Logger.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); - Logger.MethodExit(); - return 1; - } - catch (Exception e) - { - Logger.LogError($"An Error has occurred during the revoke process {e.Message}"); - Logger.MethodExit(); - return -1; - } - } - - private Certificate GetCertificateOnTimer(string Id) - { - //Get the csr tracking response from the tracking Id returned from Enrollment - var stopwatch = new Stopwatch(); - stopwatch.Start(); - var client = new HydrantIdClient(Config); - Certificate csrTrackingResponse = null; - - while (stopwatch.Elapsed < TimeSpan.FromSeconds(30) && csrTrackingResponse == null) - { - try - { - csrTrackingResponse = - Task.Run(async () => await client.GetSubmitGetCertificateByCsrAsync(Id)) - .Result; - } - catch (System.AggregateException e) - { - Log.LogTrace($"Enrollment Response Not Available Yet, try again {LogHandler.FlattenException(e)}."); - } - Thread.Sleep(1000); - } - - return csrTrackingResponse; - } - - public override void Synchronize(ICertificateDataReader certificateDataReader, - BlockingCollection blockingBuffer, - CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, - CancellationToken cancelToken) - { - Log.MethodEntry(); - _requestManager = new RequestManager(); - try - { - var certs = new BlockingCollection(100); - var client = new HydrantIdClient(Config); - _ = client.GetSubmitCertificateListRequestAsync(certs, cancelToken); - - foreach (var currentResponseItem in certs.GetConsumingEnumerable(cancelToken)) - { - if (cancelToken.IsCancellationRequested) - { - Log.LogError("Synchronize was canceled."); - break; - } - - try - { - Log.LogTrace($"Took Certificate ID {currentResponseItem?.Id} from Queue"); - if (currentResponseItem != null) - { - var certStatus = _requestManager.GetMapReturnStatus(currentResponseItem.RevocationStatus); - Log.LogTrace($"Numeric Status {certStatus}"); - - if (certStatus == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.ISSUED) || - certStatus == Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED)) - { - var productId = currentResponseItem.Policy.Name; - Log.LogTrace($"Product Id {productId}"); - - var singleCert = client.GetSubmitGetCertificateAsync(currentResponseItem.Id); - - var fileContent = singleCert.Result.Pem ?? string.Empty; - - Log.LogTrace($"Certificate Content: {fileContent}"); - - if (fileContent.Length > 0) - { - var certData = fileContent.Replace("\n", string.Empty); - var splitCerts = - certData.Split( - new[] { "-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----" }, - StringSplitOptions.RemoveEmptyEntries); - foreach (var cert in splitCerts) - try - { - var currentCert = new X509Certificate2(Encoding.ASCII.GetBytes(cert)); - var caReqId = $"{currentResponseItem.Id}-{currentCert.SerialNumber}"; - Log.LogTrace($"Split Cert Value: {cert}"); - blockingBuffer.Add(new CAConnectorCertificate - { - CARequestID = $"{currentResponseItem.Id}", - Certificate = cert, - SubmissionDate = Convert.ToDateTime(singleCert.Result.CreatedAt), - Status = certStatus, - ProductID = productId - }, cancelToken); - } - catch (Exception e) - { - Log.LogError( - $"Exception occurred Adding Cert to buffer: {e.Message} HydrantId: {currentResponseItem.Id} CommonName: {currentResponseItem.CommonName} Serial: {currentResponseItem.Serial}"); - } - } - } - } - } - catch (OperationCanceledException) - { - Log.LogError("Synchronize was canceled."); - break; - } - } - } - catch (AggregateException aggEx) - { - Log.LogError("Csc Global Synchronize Task failed!"); - Log.MethodExit(); - // ReSharper disable once PossibleIntendedRethrow - throw aggEx; - } - - Log.MethodExit(); - } - - - public override void ValidateCAConnectionInfo(Dictionary connectionInfo) - { - Log.MethodEntry(); - List errors = new List(); - - Log.LogTrace("Checking required CAConnection config"); - errors.AddRange(CheckRequiredValues(connectionInfo)); - - if (errors.Any()) throw new Exception(string.Join("|", errors.ToArray())); - } - - public override void ValidateProductInfo(EnrollmentProductInfo productInfo, + public void ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) { - Log.MethodEntry(); + _logger.MethodEntry(); //TODO: Evaluate Template (if avaiable) based on ProductInfo - Log.MethodExit(); + _logger.MethodExit(); } private static List CheckRequiredValues(Dictionary connectionInfo, params string[] args) @@ -362,32 +85,321 @@ private static List CheckRequiredValues(Dictionary conne return errors; } - private static readonly Func pemify = ss => - ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64)); - - - - #region Obsolete Methods - - [Obsolete] - public override EnrollmentResult Enroll(string csr, string subject, Dictionary san, - EnrollmentProductInfo productInfo, PKIConstants.X509.RequestFormat requestFormat, - RequestUtilities.EnrollmentType enrollmentType) - { - throw new NotImplementedException(); - } - - [Obsolete] - public override void Synchronize(ICertificateDataReader certificateDataReader, - BlockingCollection blockingBuffer, - CertificateAuthoritySyncInfo certificateAuthoritySyncInfo, - CancellationToken cancelToken, - string logicalName) - { - throw new NotImplementedException(); - } - - #endregion + ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64)); + + public async Task Ping() + { + _logger.MethodEntry(); + try + { + var client = new HydrantIdClient(Config); + var success = await client.Ping(); + + if (!success) + { + throw new Exception("HydrantIdClient Ping failed."); + } + + _logger.LogTrace("HydrantIdCAProxy Ping succeeded."); + } + catch (Exception e) + { + _logger.LogError($"Error during HydrantIdCAProxy Ping: {e.Message}"); + throw; + } + finally + { + _logger.MethodExit(); + } + } + + Task IAnyCAPlugin.ValidateCAConnectionInfo(Dictionary connectionInfo) + { + throw new NotImplementedException(); + } + + Task IAnyCAPlugin.ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) + { + throw new NotImplementedException(); + } + + + public List GetProductIds() + { + var client = new HydrantIdClient(Config); + var policies = client.GetPolicyList().GetAwaiter().GetResult(); + + var ids = policies + .Where(p => p.Id.HasValue) + .Select(p => p.Id.Value.ToString()) + .ToList(); + + return ids; + } + + public async Task Synchronize(BlockingCollection blockingBuffer, DateTime? lastSync, bool fullSync, CancellationToken cancelToken) + { + _logger.MethodEntry(); + _requestManager = new RequestManager(); + + var certs = new BlockingCollection(100); + var client = new HydrantIdClient(Config); + + _ = client.GetSubmitCertificateListRequestAsync(certs, cancelToken); + + try + { + foreach (var item in certs.GetConsumingEnumerable(cancelToken)) + { + cancelToken.ThrowIfCancellationRequested(); + + if (item == null) + continue; + + _logger.LogTrace($"Took Certificate ID {item.Id} from Queue"); + + var certStatus = _requestManager.GetMapReturnStatus(item.RevocationStatus); + _logger.LogTrace($"Numeric Status: {certStatus}"); + + if (certStatus != Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.ISSUED) && + certStatus != Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED)) + continue; + + _logger.LogTrace($"Product Id: {item.Policy.Name}"); + + try + { + var cert = await client.GetSubmitGetCertificateAsync(item.Id); + var fileContent = cert.Pem ?? string.Empty; + + if (string.IsNullOrWhiteSpace(fileContent)) + continue; + + var certsClean = fileContent + .Replace("\n", string.Empty) + .Split(new[] { "-----END CERTIFICATE-----", "-----BEGIN CERTIFICATE-----" }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var certStr in certsClean) + { + try + { + var x509Cert = new X509Certificate2(Encoding.ASCII.GetBytes(certStr)); + var requestId = $"{item.Id}-{x509Cert.SerialNumber}"; + + blockingBuffer.Add(new AnyCAPluginCertificate + { + CARequestID = item.Id, + Certificate = certStr, + Status = certStatus, + ProductID = item.Policy.Name + }, cancelToken); + + _logger.LogTrace($"Processed cert with serial {x509Cert.SerialNumber}"); + } + catch (Exception ex) + { + _logger.LogError($"Error parsing cert: {ex.Message}, ID: {item.Id}, CN: {item.CommonName}, Serial: {item.Serial}"); + } + } + } + catch (Exception certEx) + { + _logger.LogError($"Failed to retrieve or process cert {item.Id}: {certEx.Message}"); + } + } + } + catch (OperationCanceledException) + { + _logger.LogError("Synchronize was canceled."); + } + catch (AggregateException) + { + _logger.LogError("Csc Global Synchronize Task failed!"); + throw; + } + finally + { + _logger.MethodExit(); + } + } + + public async Task Enroll(string csr, string subject, Dictionary san, EnrollmentProductInfo productInfo, RequestFormat requestFormat, EnrollmentType enrollmentType) + { + _logger.MethodEntry(); + _requestManager = new RequestManager(); + int timerTries = 0; + Certificate csrTrackingResponse = null; + var client = new HydrantIdClient(Config); + + try + { + CertRequestResult enrollmentResponse = null; + + if (enrollmentType == EnrollmentType.New || enrollmentType == EnrollmentType.Reissue) + { + _logger.LogTrace("Entering New Enrollment"); + var policyListResult = await client.GetPolicyList(); + _logger.LogTrace($"Policy Result List: {JsonConvert.SerializeObject(policyListResult)}"); + + var policyId = policyListResult.Single(p => p.Name.Equals(productInfo.ProductID)); + _logger.LogTrace($"PolicyId: {JsonConvert.SerializeObject(policyId)}"); + + var enrollmentRequest = _requestManager.GetEnrollmentRequest(policyId.Id, productInfo, csr, san); + _logger.LogTrace($"Enrollment Request JSON: {JsonConvert.SerializeObject(enrollmentRequest)}"); + + enrollmentResponse = await client.GetSubmitEnrollmentAsync(enrollmentRequest); + } + else if (enrollmentType == EnrollmentType.Renew) + { + _logger.LogTrace("Entering Renew..."); + + var renewRequest = _requestManager.GetRenewalRequest(csr, false); + _logger.LogTrace($"Renewal Request JSON: {JsonConvert.SerializeObject(renewRequest)}"); + + var sn = productInfo.ProductParameters["PriorCertSN"]; + _logger.LogTrace($"Prior Cert Serial Number: {sn}"); + + //var priorCert = certDataReader.(DataConversion.HexToBytes(sn)); + var certificateId = await certDataReader.GetRequestIDBySerialNumber(sn); + + _logger.LogTrace($"Renewal CA RequestId: {certificateId}"); + + enrollmentResponse = await client.GetSubmitRenewalAsync(certificateId, renewRequest); + } + + if (enrollmentResponse?.ErrorReturn?.Status == "Failure") + { + return new EnrollmentResult + { + Status = 30, + StatusMessage = $"Enrollment Failed with error {enrollmentResponse.ErrorReturn.Error}" + }; + } + + timerTries++; + csrTrackingResponse = await GetCertificateOnTimerAsync(enrollmentResponse?.RequestStatus?.Id); + + if (csrTrackingResponse == null) + { + return new EnrollmentResult + { + Status = 30, + StatusMessage = "Certificate may still be pending in Hydrant and is not ready for download" + }; + } + + var cert = await GetSingleRecord(csrTrackingResponse.Id.ToString()); + return _requestManager.GetEnrollmentResult(csrTrackingResponse, cert); + } + finally + { + _logger.MethodExit(); + } + } + + public async Task Revoke(string caRequestID, string hexSerialNumber, uint revocationReason) + { + _logger.MethodEntry(); + _requestManager = new RequestManager(); + + try + { + _logger.LogTrace("Starting Revoke Method"); + + var client = new HydrantIdClient(Config); + var hydrantId = caRequestID.Substring(0, 36); + var revokeReason = _requestManager.GetMapRevokeReasons(revocationReason); + + _logger.LogTrace($"Revoke Reason: {revokeReason}"); + + var revokeResponse = await client.GetSubmitRevokeCertificateAsync(hydrantId, revokeReason); + _logger.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); + + return 1; + } + catch (Exception e) + { + _logger.LogError($"Error during revoke process: {e.Message}"); + return -1; + } + finally + { + _logger.MethodExit(); + } + } + + private async Task GetCertificateOnTimerAsync(string id) + { + var stopwatch = Stopwatch.StartNew(); + var client = new HydrantIdClient(Config); + + while (stopwatch.Elapsed < TimeSpan.FromSeconds(30)) + { + try + { + var result = await client.GetSubmitGetCertificateByCsrAsync(id); + if (result != null) + return result; + } + catch (Exception e) + { + _logger.LogTrace($"Enrollment Response not available yet: {LogHandler.FlattenException(e)}"); + } + + await Task.Delay(1000); + } + + return null; + } + + public async Task GetSingleRecord(string caRequestID) + { + _logger.MethodEntry(); + _requestManager = new RequestManager(); + _logger.LogTrace($"Keyfactor CA ID: {caRequestID}"); + + try + { + var client = new HydrantIdClient(Config); + var certId = caRequestID.Substring(0, 36); + var certificateResponse = await client.GetSubmitGetCertificateAsync(certId); + + _logger.LogTrace($"Single Cert JSON: {JsonConvert.SerializeObject(certificateResponse)}"); + _logger.MethodExit(); + + return new AnyCAPluginCertificate + { + CARequestID = caRequestID, + Certificate = certificateResponse.Pem, + Status = _requestManager.GetMapReturnStatus(certificateResponse.RevocationStatus), + }; + } + catch (Exception ex) + { + _logger.LogWarning($"Could not retrieve cert for CARequestID {caRequestID}: {ex.Message}"); + + return new AnyCAPluginCertificate + { + CARequestID = caRequestID, + Status = _requestManager.GetMapReturnStatus(0) // Unknown + }; + } + } + + public Dictionary GetCAConnectorAnnotations() + { + _logger.MethodEntry(); + _logger.MethodExit(); + return HydrantIdCAProxyConfig.GetPluginAnnotations(); + } + + public Dictionary GetTemplateParameterAnnotations() + { + _logger.MethodEntry(); + _logger.MethodExit(); + return HydrantIdCAProxyConfig.GetTemplateParameterAnnotations(); + } + } } \ No newline at end of file diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.csproj b/src/HydrantCAProxy/HydrantIdCAProxy.csproj index 61b90fd..5243e31 100644 --- a/src/HydrantCAProxy/HydrantIdCAProxy.csproj +++ b/src/HydrantCAProxy/HydrantIdCAProxy.csproj @@ -1,167 +1,21 @@ - - - - - Debug - AnyCPU - {011DC646-BEF9-4D3B-9D20-CA444A26B355} - Library - Properties - Keyfactor.AnyGateway.Google - HydrantIdCAProxy - v4.7.2 - 512 - true - OnBuildSuccess - true - - - true - full - false - bin\Debug - DEBUG;TRACE - prompt - 4 - False - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - False - - - - $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CAProxy.AnyGateway.Core.dll - - - $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CAProxy.Interfaces.dll - - - $(NuGetPackageRoot)keyfactor.anygateway.sdk\24.2.0-prerelease-47446\lib\net472\CommonCAProxy.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.4.4 - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - + + + net6.0 + disable + true + false + Keyfactor.Extensions.CAPlugin.HydrantId + HydrantIdCAPlugin + + + + + + + + + + Always + + \ No newline at end of file diff --git a/src/HydrantCAProxy/HydrantIdCAProxyConfig.cs b/src/HydrantCAProxy/HydrantIdCAProxyConfig.cs new file mode 100644 index 0000000..4ab8f17 --- /dev/null +++ b/src/HydrantCAProxy/HydrantIdCAProxyConfig.cs @@ -0,0 +1,95 @@ +/* +Copyright © 2025 Keyfactor + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +using Keyfactor.AnyGateway.Extensions; +using System.Collections.Generic; + +namespace Keyfactor.Extensions.CAPlugin.HydrantId +{ + public class HydrantIdCAProxyConfig + { + public const int DefaultPageSize = 100; + + public class ConfigConstants + { + public static string HydrantIdBaseUrl = "HydrantIdBaseUrl"; + public static string HydrantIdAuthId = "AuthId"; + public static string HydrantIdAuthKey = "AuthKey"; + public static string DefaultPageSize = "DefaultPageSize"; + } + + public class Config + { + public string HydrantIdBaseUrl { get; set; } + public string HydrantIdAuthId { get; set; } + public string HydrantIdAuthKey { get; set; } + } + + public static class EnrollmentParametersConstants + { + public const string ValidityPeriod = "ValidityPeriod"; + public const string ValidityUnits = "ValidityUnits"; + } + + public static Dictionary GetPluginAnnotations() + { + return new Dictionary() + { + [ConfigConstants.HydrantIdBaseUrl] = new PropertyConfigInfo() + { + Comments = "The Base URL For the HydrantId Endpoint similar to https://acm-stage.hydrantid.com. Get this from HydrantId.", + Hidden = false, + DefaultValue = "", + Type = "String" + }, + [ConfigConstants.HydrantIdAuthId] = new PropertyConfigInfo() + { + Comments = "The AuthId Obtained from HydrantId.", + Hidden = false, + DefaultValue = "", + Type = "Secret" + }, + [ConfigConstants.HydrantIdAuthKey] = new PropertyConfigInfo() + { + Comments = "The AuthKey Obtained from HydrantId.", + Hidden = false, + DefaultValue = "", + Type = "Secret" + } + }; + } + + public static Dictionary GetTemplateParameterAnnotations() + { + return new Dictionary() + { + [EnrollmentParametersConstants.ValidityPeriod] = new PropertyConfigInfo() + { + Comments = $"The desired lifetime time period could be Days, Months or Years.", + Hidden = false, + DefaultValue = "Years", + Type = "String" + }, + [EnrollmentParametersConstants.ValidityUnits] = new PropertyConfigInfo() + { + Comments = $"The desired lifetime time value some number indicating days, months or years.", + Hidden = false, + DefaultValue = 1, + Type = "Number" + } + }; + } + } +} diff --git a/src/HydrantCAProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs index 29ba18c..f3b0004 100644 --- a/src/HydrantCAProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -10,9 +10,6 @@ using System; using System.Collections.Generic; using System.IO; -using CAProxy.AnyGateway.Models; -using CSS.Common.Logging; -using CSS.PKI; using Keyfactor.HydrantId.Client.Models; using Keyfactor.HydrantId.Client.Models.Enums; using Keyfactor.HydrantId.Interfaces; @@ -22,6 +19,8 @@ using Microsoft.Extensions.Logging; using Keyfactor.Logging; using LogHandler = Keyfactor.Logging.LogHandler; +using Keyfactor.AnyGateway.Extensions; +using Keyfactor.PKI; namespace Keyfactor.HydrantId { @@ -92,7 +91,7 @@ public RevocationReasons GetMapRevokeReasons(uint keyfactorRevokeReason) throw new RevokeReasonNotSupportedException("This Revoke Reason is not Supported"); } - catch(Exception e) + catch (Exception e) { Log.LogError($"Error Occured in RequestManager.GetMapRevokeReasons: {e.Message}"); throw; @@ -117,7 +116,7 @@ public RevokeCertificateReason GetRevokeRequest(RevocationReasons reason) } } - public CertificatesPayload GetCertificatesListRequest(int offset,int limit) + public CertificatesPayload GetCertificatesListRequest(int offset, int limit) { try { @@ -137,38 +136,27 @@ public CertificatesPayload GetCertificatesListRequest(int offset,int limit) } } - public CertRequestBody GetEnrollmentRequest(Guid? policyId,EnrollmentProductInfo productInfo, string csr, Dictionary san) + public CertRequestBody GetEnrollmentRequest(Guid? policyId, EnrollmentProductInfo productInfo, string csr, Dictionary san) { - try + Log.MethodEntry(); + + var request = new CertRequestBody { - Log.MethodEntry(); - if (san.ContainsKey("dns")) - { - return new CertRequestBody - { - Policy = policyId, - Csr = csr, - DnComponents = GetDnComponentsRequest(csr), - SubjectAltNames = GetSansRequest(san), - Validity = GetValidity(productInfo.ProductParameters["ValidityPeriod"],Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) - }; - } + Policy = policyId, + Csr = csr, + DnComponents = GetDnComponentsRequest(csr), + Validity = GetValidity(productInfo.ProductParameters["ValidityPeriod"], Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) + }; - return new CertRequestBody - { - Policy = policyId, - Csr = csr, - DnComponents = GetDnComponentsRequest(csr), - Validity=GetValidity(productInfo.ProductParameters["ValidityPeriod"], Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) - }; - } - catch (Exception e) + if (san.ContainsKey("dns")) { - Log.LogError($"Error Occured in RequestManager.GetEnrollmentRequest: {e.Message}"); - throw; + request.SubjectAltNames = GetSansRequest(san); } + + return request; } + public RenewalRequest GetRenewalRequest(string csr, bool reuseCsr) { try @@ -187,13 +175,13 @@ public RenewalRequest GetRenewalRequest(string csr, bool reuseCsr) } } - private CertRequestBodyValidity GetValidity(string period,int units) + private CertRequestBodyValidity GetValidity(string period, int units) { try { Log.MethodEntry(); CertRequestBodyValidity validity = new CertRequestBodyValidity(); - switch(period) + switch (period) { case "Years": validity.Years = units; @@ -204,8 +192,8 @@ private CertRequestBodyValidity GetValidity(string period,int units) case "Days": validity.Days = units; break; - } - + } + return validity; } catch (Exception e) @@ -226,7 +214,7 @@ public CertRequestBodySubjectAltNames GetSansRequest(Dictionary{ou}, - O=o, - L=l, + Ou = new List { ou }, + O = o, + L = l, St = st, - C=c + C = c }; } catch (Exception e) From 3431c71625c7b680f0ede2740c7befed50ae00ed Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 11 Apr 2025 18:56:13 +0000 Subject: [PATCH 04/25] checkpoint --- README.md | 2 +- src/HydrantCAProxy/Client/HydrantIdClient.cs | 8 +- src/HydrantCAProxy/ExtensionMethods.cs | 2 +- ...drantIdCAProxy.cs => HydrantIdCAPlugin.cs} | 17 ++--- ...AProxy.csproj => HydrantIdCAPlugin.csproj} | 0 ...xyConfig.cs => HydrantIdCAPluginConfig.cs} | 2 +- src/HydrantCAProxy/HydrantIdCAProxy.sln | 74 +++++++++---------- src/HydrantCAProxy/Properties/AssemblyInfo.cs | 2 +- src/HydrantCAProxy/manifest.json | 10 +++ 9 files changed, 63 insertions(+), 54 deletions(-) rename src/HydrantCAProxy/{HydrantIdCAProxy.cs => HydrantIdCAPlugin.cs} (94%) rename src/HydrantCAProxy/{HydrantIdCAProxy.csproj => HydrantIdCAPlugin.csproj} (100%) rename src/HydrantCAProxy/{HydrantIdCAProxyConfig.cs => HydrantIdCAPluginConfig.cs} (96%) create mode 100644 src/HydrantCAProxy/manifest.json diff --git a/README.md b/README.md index 43a49cc..e1616bd 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](h 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class. ```xml - + ``` 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`. diff --git a/src/HydrantCAProxy/Client/HydrantIdClient.cs b/src/HydrantCAProxy/Client/HydrantIdClient.cs index 410f738..2ce79be 100644 --- a/src/HydrantCAProxy/Client/HydrantIdClient.cs +++ b/src/HydrantCAProxy/Client/HydrantIdClient.cs @@ -40,10 +40,10 @@ public HydrantIdClient(IAnyCAPluginConfigProvider config) { Log.MethodEntry(); - if (config.CAConnectionData.ContainsKey(HydrantIdCAProxyConfig.ConfigConstants.HydrantIdAuthId)) + if (config.CAConnectionData.ContainsKey(HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId)) { ConfigProvider = config; - BaseUrl = ConfigProvider.CAConnectionData[HydrantIdCAProxyConfig.ConfigConstants.HydrantIdBaseUrl].ToString(); + BaseUrl = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdBaseUrl].ToString(); RequestManager = new RequestManager(); } } @@ -375,8 +375,8 @@ private HttpClient ConfigureRestClient(string method, string url) Log.MethodEntry(); var bUrl = new Uri(BaseUrl); - var apiId = ConfigProvider.CAConnectionData[HydrantIdCAProxyConfig.ConfigConstants.HydrantIdAuthId].ToString(); - var apiKey = ConfigProvider.CAConnectionData[HydrantIdCAProxyConfig.ConfigConstants.HydrantIdAuthKey].ToString(); + var apiId = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId].ToString(); + var apiKey = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthKey].ToString(); var byteArray = new byte[20]; using (var rnd = RandomNumberGenerator.Create()) diff --git a/src/HydrantCAProxy/ExtensionMethods.cs b/src/HydrantCAProxy/ExtensionMethods.cs index 9ce72b9..b1f193b 100644 --- a/src/HydrantCAProxy/ExtensionMethods.cs +++ b/src/HydrantCAProxy/ExtensionMethods.cs @@ -5,7 +5,7 @@ using System.Text; using System.Threading.Tasks; -namespace Keyfactor.AnyGateway.Google +namespace Keyfactor.Extensions.CAPlugin.HydrantId { public static class ExtensionMethods { public static bool IsFullPathReadable(this string filePath) diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs similarity index 94% rename from src/HydrantCAProxy/HydrantIdCAProxy.cs rename to src/HydrantCAProxy/HydrantIdCAPlugin.cs index b20f53d..06436d2 100644 --- a/src/HydrantCAProxy/HydrantIdCAProxy.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -18,13 +18,12 @@ using Keyfactor.AnyGateway.Extensions; using Keyfactor.PKI; using System.Data; -using Keyfactor.Extensions.CAPlugin.HydrantId; -namespace Keyfactor.AnyGateway.Google +namespace Keyfactor.Extensions.CAPlugin.HydrantId { - public class HydrantIdCAProxy : IAnyCAPlugin + public class HydrantIdCAPlugin : IAnyCAPlugin { - private static readonly ILogger _logger = LogHandler.GetClassLogger(); + private static readonly ILogger _logger = LogHandler.GetClassLogger(); private RequestManager _requestManager; private IAnyCAPluginConfigProvider Config { get; set; } private ICertificateDataReader certDataReader; @@ -48,7 +47,7 @@ public void ValidateCAConnectionInfo(Dictionary connectionInfo) _logger.MethodEntry(); _logger.LogDebug($"Validating GCP CAS CA Connection properties"); var rawData = JsonConvert.SerializeObject(connectionInfo); - HydrantIdCAProxyConfig.Config config = JsonConvert.DeserializeObject(rawData); + HydrantIdCAPluginConfig.Config config = JsonConvert.DeserializeObject(rawData); _logger.LogTrace($"HydrantIdClientFromCAConnectionData - HydrantIdBaseUrl: {config.HydrantIdBaseUrl}"); _logger.LogTrace($"HydrantIdClientFromCAConnectionData - HydrantIdAuthId: {config.HydrantIdAuthId}"); @@ -101,11 +100,11 @@ public async Task Ping() throw new Exception("HydrantIdClient Ping failed."); } - _logger.LogTrace("HydrantIdCAProxy Ping succeeded."); + _logger.LogTrace("HydrantIdCAPlugin Ping succeeded."); } catch (Exception e) { - _logger.LogError($"Error during HydrantIdCAProxy Ping: {e.Message}"); + _logger.LogError($"Error during HydrantIdCAPlugin Ping: {e.Message}"); throw; } finally @@ -391,14 +390,14 @@ public Dictionary GetCAConnectorAnnotations() { _logger.MethodEntry(); _logger.MethodExit(); - return HydrantIdCAProxyConfig.GetPluginAnnotations(); + return HydrantIdCAPluginConfig.GetPluginAnnotations(); } public Dictionary GetTemplateParameterAnnotations() { _logger.MethodEntry(); _logger.MethodExit(); - return HydrantIdCAProxyConfig.GetTemplateParameterAnnotations(); + return HydrantIdCAPluginConfig.GetTemplateParameterAnnotations(); } } diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.csproj b/src/HydrantCAProxy/HydrantIdCAPlugin.csproj similarity index 100% rename from src/HydrantCAProxy/HydrantIdCAProxy.csproj rename to src/HydrantCAProxy/HydrantIdCAPlugin.csproj diff --git a/src/HydrantCAProxy/HydrantIdCAProxyConfig.cs b/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs similarity index 96% rename from src/HydrantCAProxy/HydrantIdCAProxyConfig.cs rename to src/HydrantCAProxy/HydrantIdCAPluginConfig.cs index 4ab8f17..59dbd99 100644 --- a/src/HydrantCAProxy/HydrantIdCAProxyConfig.cs +++ b/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs @@ -18,7 +18,7 @@ limitations under the License. namespace Keyfactor.Extensions.CAPlugin.HydrantId { - public class HydrantIdCAProxyConfig + public class HydrantIdCAPluginConfig { public const int DefaultPageSize = 100; diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.sln b/src/HydrantCAProxy/HydrantIdCAProxy.sln index e54ecf8..cb0f624 100644 --- a/src/HydrantCAProxy/HydrantIdCAProxy.sln +++ b/src/HydrantCAProxy/HydrantIdCAProxy.sln @@ -1,37 +1,37 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.10.35027.167 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HydrantIdCAProxy", "HydrantIdCAProxy.csproj", "{011DC646-BEF9-4D3B-9D20-CA444A26B355}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5505EA55-BEBD-4DBC-9ED2-448CFB9BCD37}" - ProjectSection(SolutionItems) = preProject - ..\..\.gitignore = ..\..\.gitignore - ..\..\CHANGELOG.md = ..\..\CHANGELOG.md - ..\..\.github\workflows\keyfactor-extension-prerelease.yml = ..\..\.github\workflows\keyfactor-extension-prerelease.yml - ..\..\.github\workflows\keyfactor-extension-release.yml = ..\..\.github\workflows\keyfactor-extension-release.yml - ..\..\README.md = ..\..\README.md - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Prerelease|Any CPU = Prerelease|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.Build.0 = Debug|Any CPU - {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU - {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.Build.0 = Release|Any CPU - {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.ActiveCfg = Release|Any CPU - {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {0E1B1C00-FE0C-4138-85D7-51AA99D8745F} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.10.35027.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HydrantIdCAPlugin", "HydrantIdCAPlugin.csproj", "{011DC646-BEF9-4D3B-9D20-CA444A26B355}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5505EA55-BEBD-4DBC-9ED2-448CFB9BCD37}" + ProjectSection(SolutionItems) = preProject + ..\..\.gitignore = ..\..\.gitignore + ..\..\CHANGELOG.md = ..\..\CHANGELOG.md + ..\..\.github\workflows\keyfactor-extension-prerelease.yml = ..\..\.github\workflows\keyfactor-extension-prerelease.yml + ..\..\.github\workflows\keyfactor-extension-release.yml = ..\..\.github\workflows\keyfactor-extension-release.yml + ..\..\README.md = ..\..\README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Prerelease|Any CPU = Prerelease|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.ActiveCfg = Release|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Prerelease|Any CPU.Build.0 = Release|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {011DC646-BEF9-4D3B-9D20-CA444A26B355}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0E1B1C00-FE0C-4138-85D7-51AA99D8745F} + EndGlobalSection +EndGlobal diff --git a/src/HydrantCAProxy/Properties/AssemblyInfo.cs b/src/HydrantCAProxy/Properties/AssemblyInfo.cs index 8543e07..725e12d 100644 --- a/src/HydrantCAProxy/Properties/AssemblyInfo.cs +++ b/src/HydrantCAProxy/Properties/AssemblyInfo.cs @@ -5,7 +5,7 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("HydrantIdCAProxy")] +[assembly: AssemblyTitle("HydrantIdCAPlugin")] [assembly: AssemblyDescription("Keyfactor AnyGateway Implementation for the Google Cloud Private CA")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Keyfactor, Inc")] diff --git a/src/HydrantCAProxy/manifest.json b/src/HydrantCAProxy/manifest.json new file mode 100644 index 0000000..c823cf1 --- /dev/null +++ b/src/HydrantCAProxy/manifest.json @@ -0,0 +1,10 @@ +{ + "extensions": { + "Keyfactor.AnyGateway.Extensions.IAnyCAPlugin": { + "GCPCASCAPlugin": { + "assemblypath": "HydrantIdCAPlugin.dll", + "TypeFullName": "Keyfactor.Extensions.CAPlugin.HydrantId.HydrantIdCAPlugin" + } + } + } +} \ No newline at end of file From cf5b5345525283751bca71fe638ade5e8849e2ed Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Fri, 11 Apr 2025 18:56:45 +0000 Subject: [PATCH 05/25] Update generated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e1616bd..43a49cc 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](h 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class. ```xml - + ``` 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`. From 7c657c1c2c5378dc8e987371985d467ef5e2a0df Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 15 Apr 2025 15:15:58 -0400 Subject: [PATCH 06/25] checkpoint --- .../Client/Authentication/Hawk.cs | 751 ++++++++++++++++++ .../Client/Authentication/HawkCredential.cs | 58 ++ .../HttpWebRequestExtensions.cs | 58 ++ .../Client/Authentication/LICENSE | 21 + src/HydrantCAProxy/Client/HydrantIdClient.cs | 84 +- src/HydrantCAProxy/HydrantIdCAPlugin.cs | 80 +- src/HydrantCAProxy/HydrantIdCAPluginConfig.cs | 4 +- 7 files changed, 957 insertions(+), 99 deletions(-) create mode 100644 src/HydrantCAProxy/Client/Authentication/Hawk.cs create mode 100644 src/HydrantCAProxy/Client/Authentication/HawkCredential.cs create mode 100644 src/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs create mode 100644 src/HydrantCAProxy/Client/Authentication/LICENSE diff --git a/src/HydrantCAProxy/Client/Authentication/Hawk.cs b/src/HydrantCAProxy/Client/Authentication/Hawk.cs new file mode 100644 index 0000000..a2f40af --- /dev/null +++ b/src/HydrantCAProxy/Client/Authentication/Hawk.cs @@ -0,0 +1,751 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Linq; +using System.Security; +using System.Security.Cryptography; +using System.Security.Principal; +using System.Text; +using System.Web; +using System.Diagnostics; + +#if NET45 || CORE +using System.Net.Http; +using System.Security.Claims; +using System.Threading.Tasks; +#endif + +namespace HawkNet +{ + /// + /// Hawk main class. It provides methods for generating a Hawk authorization header on the client side and authenticate it on the + /// service side. + /// + public static class Hawk + { + readonly static string[] RequiredAttributes = { "id", "ts", "mac", "nonce" }; + readonly static string[] OptionalAttributes = { "ext", "hash" }; + readonly static string[] SupportedAttributes; + readonly static string[] SupportedAlgorithms = { "sha1", "sha256" }; + + readonly static string RandomSource = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + + static TraceSource TraceSource = new TraceSource("HawkNet"); + + static Hawk() + { + SupportedAttributes = RequiredAttributes.Concat(OptionalAttributes).ToArray(); + } + +#if NET45 || CORE + /// + /// Authenticates an upcoming request message + /// + /// Authorization header + /// Host header + /// Request method + /// Request Uri + /// A method for searching across the available credentials + /// Accepted Time skew for timestamp verification + /// Hash of the request payload + /// + public static async Task AuthenticateAsync(string authorization, string host, string method, Uri uri, Func> credentials, int timestampSkewSec = 60, Func> requestPayload = null, string mediaType = null) + { + if (Trace.CorrelationManager.ActivityId == Guid.Empty) + Trace.CorrelationManager.ActivityId = Guid.NewGuid(); + + TraceSource.TraceInformation(string.Format("{0} - Received Auth header: {1}", + Trace.CorrelationManager.ActivityId, authorization)); + + if (string.IsNullOrEmpty(authorization)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Authorization parameter can not be null or empty", + Trace.CorrelationManager.ActivityId)); + + throw new ArgumentException("Authorization parameter can not be null or empty", "authorization"); + } + + if (string.IsNullOrEmpty(host)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Host header can not be null or empty", + Trace.CorrelationManager.ActivityId)); + + throw new ArgumentException("Host header can not be null or empty", "host"); + } + + var attributes = ParseAttributes(authorization); + + ValidateAttributes(timestampSkewSec, attributes); + + HawkCredential credential = null; + try + { + credential = await credentials(attributes["id"]); + } + catch (Exception ex) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Unknown user", + Trace.CorrelationManager.ActivityId)); + + throw new SecurityException("Unknown user", ex); + } + + ValidateCredentials(credential); + + if (!string.IsNullOrEmpty(attributes["hash"])) + { + if (requestPayload != null && string.IsNullOrEmpty(mediaType)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Media Type can not be null when the payload hash must be calculated", + Trace.CorrelationManager.ActivityId)); + + throw new ArgumentException("MediaType can not be null or empty", "mediaType"); + } + + var hash = CalculatePayloadHash(await requestPayload(), mediaType, credential); + + if (attributes["hash"] != hash) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Bad payload hash. Received hash {1}. Calculated hash {2}", + Trace.CorrelationManager.ActivityId, attributes["hash"], hash)); + + throw new SecurityException("Bad payload hash"); + } + } + + var mac = CalculateMac(host, + method, + uri, + attributes["ext"], + attributes["ts"], + attributes["nonce"], + credential, "header", + attributes["hash"]); + + if (!IsEqual(mac, attributes["mac"])) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Bad Mac. Received mac {1}. Calculated Mac {2}", + Trace.CorrelationManager.ActivityId, attributes["mac"], mac)); + + throw new SecurityException("Bad mac"); + } + + var userClaim = new Claim(ClaimTypes.Name, credential.User); + var allClaims = Enumerable.Concat(new Claim[] { userClaim }, + (credential.AdditionalClaims != null) ? credential.AdditionalClaims : Enumerable.Empty()); + + var identity = new ClaimsIdentity(allClaims, "Hawk"); + var principal = new ClaimsPrincipal(new ClaimsIdentity[] { identity }); + + return principal; + } +#endif + + /// + /// Authenticates an upcoming request message + /// + /// Authorization header + /// Host header + /// Request method + /// Request Uri + /// A method for searching across the available credentials + /// Accepted Time skew for timestamp verification + /// Hash of the request payload + /// + public static IPrincipal Authenticate(string authorization, string host, string method, Uri uri, Func credentials, int timestampSkewSec = 60, Func requestPayload = null, string mediaType = null) + { + if (Trace.CorrelationManager.ActivityId == Guid.Empty) + Trace.CorrelationManager.ActivityId = Guid.NewGuid(); + + TraceSource.TraceInformation(string.Format("{0} - Received Auth header: {1}", + Trace.CorrelationManager.ActivityId, authorization)); + + if (string.IsNullOrEmpty(authorization)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Authorization parameter can not be null or empty", + Trace.CorrelationManager.ActivityId)); + + throw new ArgumentException("Authorization parameter can not be null or empty", "authorization"); + } + + if (string.IsNullOrEmpty(host)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Host header can not be null or empty", + Trace.CorrelationManager.ActivityId)); + + throw new ArgumentException("Host header can not be null or empty", "host"); + } + + var attributes = ParseAttributes(authorization); + + ValidateAttributes(timestampSkewSec, attributes); + + HawkCredential credential = null; + try + { + credential = credentials(attributes["id"]); + } + catch (Exception ex) + { + TraceSource.TraceData(TraceEventType.Warning, 0, "{0} - Unknown user", + Trace.CorrelationManager.ActivityId); + + throw new SecurityException("Unknown user", ex); + } + + ValidateCredentials(credential); + + if (!string.IsNullOrEmpty(attributes["hash"])) + { + if (requestPayload != null && string.IsNullOrEmpty(mediaType)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Media Type can not be null when the payload hash must be calculated", + Trace.CorrelationManager.ActivityId)); + + throw new ArgumentException("MediaType can not be null or empty", "mediaType"); + } + + var hash = CalculatePayloadHash(requestPayload(), mediaType, credential); + + if (attributes["hash"] != hash) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Bad payload hash. Received hash {1}. Calculated hash {2}", + Trace.CorrelationManager.ActivityId, attributes["hash"], hash)); + + throw new SecurityException("Bad payload hash"); + } + } + + var mac = CalculateMac(host, + method, + uri, + attributes["ext"], + attributes["ts"], + attributes["nonce"], + credential, "header", + attributes["hash"]); + + if (!IsEqual(mac, attributes["mac"])) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Bad Mac. Received mac {1}. Calculated Mac {2}", + Trace.CorrelationManager.ActivityId, attributes["mac"], mac)); + + throw new SecurityException("Bad mac"); + } + +#if NET45 || CORE + var userClaim = new Claim(ClaimTypes.Name, credential.User); + var allClaims = Enumerable.Concat(new Claim[] { userClaim }, + (credential.AdditionalClaims != null) ? credential.AdditionalClaims : Enumerable.Empty()); + + var identity = new ClaimsIdentity(allClaims, "Hawk"); + var principal = new ClaimsPrincipal(new ClaimsIdentity[] { identity }); +#else + var identity = new GenericIdentity(credential.User, "Hawk"); + var principal = new GenericPrincipal(identity, credential.Roles); +#endif + return principal; + } + + /// + /// Creates a new Hawk Authorization header based on the provided parameters + /// + /// Host header + /// Request method + /// Request uri + /// Credential used to calculate the MAC + /// Optional extension attribute + /// Timestamp + /// Random Nonce + /// Hash of the request payload + /// Type used as header for the normalized string. Default value is 'header' + /// Hawk authorization header + public static string GetAuthorizationHeader(string host, string method, Uri uri, HawkCredential credential, string ext = null, DateTime? ts = null, string nonce = null, string payloadHash = null, string type = null) + { + if (string.IsNullOrEmpty(host)) + throw new ArgumentException("The host can not be null or empty", "host"); + + if (string.IsNullOrEmpty(method)) + throw new ArgumentException("The method can not be null or empty", "method"); + + if (credential == null) + throw new ArgumentNullException("The credential can not be null", "credential"); + + if (string.IsNullOrEmpty(nonce)) + { + nonce = GetRandomString(6); + } + + if (string.IsNullOrEmpty(type)) + { + type = "header"; + } + + var normalizedTs = ((int)Math.Floor((ConvertToUnixTimestamp((ts.HasValue) + ? ts.Value : DateTime.UtcNow)))).ToString(); + + var mac = CalculateMac(host, + method, + uri, + ext, + normalizedTs, + nonce, + credential, + type, + payloadHash); + + var authorization = string.Format("id=\"{0}\", ts=\"{1}\", nonce=\"{2}\", mac=\"{3}\", ext=\"{4}\"", + credential.Id, normalizedTs, nonce, mac, ext); + + if (!string.IsNullOrEmpty(payloadHash)) + { + authorization += string.Format(", hash=\"{0}\"", payloadHash); + } + + return authorization; + } + + /// + /// Gets a new Bewit for Single URI authorization + /// + /// Host name + /// Request uri + /// Hawk credential + /// Time to live in seconds for the Bewit + /// Extension attributes + /// A fresh Bewit + public static string GetBewit(string host, Uri uri, HawkCredential credential, int ttlSec, string ext = null) + { + var now = ConvertToUnixTimestamp(DateTime.Now); + + var expiration = Math.Floor(now) + ttlSec; + + var mac = CalculateMac(host, "GET", uri, ext, expiration.ToString(), "", credential, "bewit"); + + var bewit = Convert.ToBase64String( + Encoding.UTF8.GetBytes(credential.Id + '\\' + expiration + '\\' + mac + '\\' + ext)); + + return bewit; + } + +#if NET45 || CORE + /// + /// Authenticates a request message using a bewit + /// + /// + /// + /// + /// + /// + /// + public static async Task AuthenticateBewitAsync(string bewit, string host, Uri uri, Func> credentials, int timestampSkewSec = 60) + { + if (Trace.CorrelationManager.ActivityId == Guid.Empty) + Trace.CorrelationManager.ActivityId = Guid.NewGuid(); + + var bewitParts = ValidateBewit(bewit); + + HawkCredential credential = null; + try + { + credential = await credentials(bewitParts[0]); + } + catch (Exception ex) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Unknow user {1} in bewit", + Trace.CorrelationManager.ActivityId, bewitParts[0])); + + throw new SecurityException("Unknown user", ex); + } + + ValidateCredentials(credential); + + var mac = CalculateMac(uri.Host, "GET", RemoveBewitFromQuery(uri), + bewitParts[3], bewitParts[1], "", credential, "bewit"); + + if (!IsEqual(mac, bewitParts[2])) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Bad mac in bewit. Received mac {1}. Calculated mac {2}", + Trace.CorrelationManager.ActivityId, bewitParts[2], mac)); + + throw new SecurityException("Bad mac"); + } + + var userClaim = new Claim(ClaimTypes.Name, credential.User); + var allClaims = Enumerable.Concat(new Claim[] { userClaim }, + (credential.AdditionalClaims != null) ? credential.AdditionalClaims : Enumerable.Empty()); + + var identity = new ClaimsIdentity(allClaims, "Hawk"); + var principal = new ClaimsPrincipal(new ClaimsIdentity[] { identity }); + + return principal; + } +#endif + /// + /// Authenticates a request message using a bewit + /// + /// + /// + /// + /// + /// + /// + public static IPrincipal AuthenticateBewit(string bewit, string host, Uri uri, Func credentials, int timestampSkewSec = 60) + { + if (Trace.CorrelationManager.ActivityId == Guid.Empty) + Trace.CorrelationManager.ActivityId = Guid.NewGuid(); + + var bewitParts = ValidateBewit(bewit); + + HawkCredential credential = null; + try + { + credential = credentials(bewitParts[0]); + } + catch (Exception ex) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Unknow user {1} in bewit", + Trace.CorrelationManager.ActivityId, bewitParts[0])); + + throw new SecurityException("Unknown user", ex); + } + + ValidateCredentials(credential); + + var mac = CalculateMac(uri.Host, "GET", RemoveBewitFromQuery(uri), + bewitParts[3], bewitParts[1], "", credential, "bewit"); + + if (!IsEqual(mac, bewitParts[2])) + { + TraceSource.TraceData(TraceEventType.Warning, 0, string.Format("{0} - Bad mac in bewit. Received mac {1}. Calculated mac {2}", + Trace.CorrelationManager.ActivityId, bewitParts[2], mac)); + + throw new SecurityException("Bad mac"); + } + +#if NET45 || CORE + var userClaim = new Claim(ClaimTypes.Name, credential.User); + var allClaims = Enumerable.Concat(new Claim[] { userClaim }, + (credential.AdditionalClaims != null) ? credential.AdditionalClaims : Enumerable.Empty()); + + var identity = new ClaimsIdentity(allClaims, "Hawk"); + var principal = new ClaimsPrincipal(new ClaimsIdentity[] { identity }); +#else + var identity = new GenericIdentity(credential.User, "Hawk"); + var principal = new GenericPrincipal(identity, credential.Roles); +#endif + return principal; + } + + /// + /// Gets a random string of a given size + /// + /// Expected size for the generated string + /// Random string + public static string GetRandomString(int size) + { + var result = new StringBuilder(); + var random = new Random(); + + for (var i = 0; i < size; ++i) + { + result.Append(RandomSource[random.Next(RandomSource.Length)]); + } + + return result.ToString(); + } + + /// + /// Parse all the attributes present in the Hawk authorization header + /// + /// Authorization header + /// List of parsed attributes + public static NameValueCollection ParseAttributes(string authorization) + { + var allAttributes = new NameValueCollection(); + + foreach (var attribute in authorization.Split(',')) + { + var index = attribute.IndexOf('='); + if (index > 0) + { + var key = attribute.Substring(0, index).Trim(); + var value = attribute.Substring(index + 1).Trim(); + + if (value.StartsWith("\"")) + value = value.Substring(1, value.Length - 2); + + allAttributes.Add(key, value); + } + } + + return allAttributes; + } + + /// + /// Computes a mac following the Hawk rules + /// + /// Host header + /// Request method + /// Request uri + /// Extesion attribute + /// Timestamp + /// Nonce + /// Credential + /// Hash of the request payload + /// Generated mac + public static string CalculateMac(string host, string method, Uri uri, string ext, string ts, string nonce, HawkCredential credential, string type, string payloadHash = null) + { + HMAC hmac = null; + + if (credential.Algorithm.Equals("sha1", StringComparison.InvariantCultureIgnoreCase)) + hmac = new HMACSHA1(); + else if (credential.Algorithm.Equals("sha256", StringComparison.InvariantCultureIgnoreCase)) + hmac = new HMACSHA256(); + else + throw new Exception("Not supported algorithm"); + + hmac.Key = Encoding.UTF8.GetBytes(credential.Key); + + var sanitizedHost = (host.IndexOf(':') > 0) ? + host.Substring(0, host.IndexOf(':')) : + host; + + var normalized = "hawk.1." + type + "\n" + + ts + "\n" + + nonce + "\n" + + method.ToUpper() + "\n" + + uri.PathAndQuery + "\n" + + sanitizedHost + "\n" + + uri.Port.ToString() + "\n" + + ((!string.IsNullOrEmpty(payloadHash)) ? payloadHash : "") + "\n" + + ((!string.IsNullOrEmpty(ext)) ? ext : "") + "\n"; + + TraceSource.TraceInformation(string.Format("Normalized String: {0}", + normalized)); + + var messageBytes = Encoding.UTF8.GetBytes(normalized); + + var mac = hmac.ComputeHash(messageBytes); + + var encodedMac = Convert.ToBase64String(mac); + + TraceSource.TraceInformation(string.Format("Calculated mac: {0}", + encodedMac)); + + return encodedMac; + } + + /// + /// Converts a Datatime to an equivalent Unix Timestamp, in seconds + /// + /// + /// + public static double ConvertToUnixTimestamp(DateTime date) + { + var origin = new DateTime(1970, 1, 1, 0, 0, 0, 0); + var diff = date.ToUniversalTime() - origin; + return Math.Floor(diff.TotalSeconds); + } + + /// + /// Generates a mac hash using the supplied payload and credentials + /// + /// + /// + /// + public static string CalculatePayloadHash(string payload, string mediaType, HawkCredential credential) + { + var normalized = "hawk.1.payload\n" + + mediaType + "\n" + + payload + "\n"; + + TraceSource.TraceInformation(string.Format("Normalized Payload String: {0}", + normalized)); + + var algorithm = HashAlgorithm.Create(credential.Algorithm); + + var encodedMac = Convert.ToBase64String(algorithm + .ComputeHash(Encoding.UTF8.GetBytes(normalized))); + + TraceSource.TraceInformation(string.Format("Calculated payload hash: {0}", + encodedMac)); + + return encodedMac; + } + + private static bool CheckTimestamp(string ts, int timestampSkewSec) + { + double parsedTs; + if (double.TryParse(ts, out parsedTs)) + { + var now = ConvertToUnixTimestamp(DateTime.Now); + var result = Math.Abs(parsedTs - now); + + // Check timestamp staleness + if (result > timestampSkewSec) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Timestamp does not match. Current ts = {1}. Received ts = {2}. {3} exceeds the configured timestamp skew, which is {4}", + Trace.CorrelationManager.ActivityId, now, parsedTs, result, timestampSkewSec)); + + return false; + } + else + { + return true; + } + } + + return false; + + } + + private static Uri RemoveBewitFromQuery(Uri uri) + { + var qs = uri.Query; + var ixs = qs.IndexOf("bewit=", 0, StringComparison.InvariantCultureIgnoreCase); + if (ixs > 0) + { + var ixe = qs.IndexOf("&", ixs); + if (ixe > 0) + { + qs = qs.Substring(0, ixs) + qs.Substring(ixe); + } + else + { + qs = qs.Substring(0, ixs); + } + + if (qs.EndsWith("&")) + { + qs = qs.Substring(0, qs.Length - 1); + } + + if (qs.StartsWith("?&")) + { + qs = qs.Substring(2); + } + else if (qs.StartsWith("?")) + { + qs = qs.Substring(1); + } + } + + var newUri = string.Format("{0}://{1}:{2}{3}", + uri.Scheme, + uri.Host, + uri.Port, + uri.AbsolutePath); + + if (!string.IsNullOrEmpty(qs) && qs.Length > 1) + { + newUri += "?" + qs; + } + + return new Uri(newUri); + } + + private static void ValidateAttributes(int timestampSkewSec, NameValueCollection attributes) + { + if (!RequiredAttributes.All(a => attributes.AllKeys.Any(k => k == a))) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Missing attributes", Trace.CorrelationManager.ActivityId)); + + throw new SecurityException("Missing attributes"); + } + + if (!attributes.AllKeys.All(a => SupportedAttributes.Any(k => k == a))) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Unknown attributes", Trace.CorrelationManager.ActivityId)); + + throw new SecurityException("Unknown attributes"); + } + + // Check timestamp staleness + if (!CheckTimestamp(attributes["ts"], timestampSkewSec)) + { + throw new SecurityException("Stale or missing timestamp"); + } + } + + private static void ValidateCredentials(HawkCredential credential) + { + if (credential == null) + { + throw new SecurityException("Missing credentials"); + } + + if (string.IsNullOrEmpty(credential.Algorithm) || + string.IsNullOrEmpty(credential.Key)) + { + throw new SecurityException("Invalid credentials"); + } + + if (!SupportedAlgorithms.Any(a => + string.Equals(a, credential.Algorithm, StringComparison.InvariantCultureIgnoreCase))) + { + throw new SecurityException("Unknown algorithm"); + } + } + + private static string[] ValidateBewit(string bewit) + { + var decodedBewit = Encoding.UTF8.GetString(Convert.FromBase64String(bewit)); + + var bewitParts = decodedBewit.Split('\\'); + if (bewitParts.Length != 4) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Invalid bewit structure. Received bewit {1}", + Trace.CorrelationManager.ActivityId, decodedBewit)); + + throw new SecurityException("Invalid bewit structure"); + } + + double expiration; + if (!double.TryParse(bewitParts[1], out expiration)) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Invalid expiration in bewit structure", + Trace.CorrelationManager.ActivityId)); + + throw new SecurityException("Invalid expiration in bewit structure"); + } + + var now = ConvertToUnixTimestamp(DateTime.Now); + + if (expiration <= now) + { + TraceSource.TraceData(TraceEventType.Warning, 0, + string.Format("{0} - Access expired - Now {1}. Expiration {2}", + Trace.CorrelationManager.ActivityId, now, expiration)); + + throw new SecurityException("Access expired"); + } + return bewitParts; + } + + // Fixed time comparision + private static bool IsEqual(string a, string b) + { + if (a.Length != b.Length) + { + return false; + } + + int result = 0; + for (int i = 0; i < a.Length; i++) + { + result |= a[i] ^ b[i]; + } + + return result == 0; + } + } +} \ No newline at end of file diff --git a/src/HydrantCAProxy/Client/Authentication/HawkCredential.cs b/src/HydrantCAProxy/Client/Authentication/HawkCredential.cs new file mode 100644 index 0000000..8eb0c8b --- /dev/null +++ b/src/HydrantCAProxy/Client/Authentication/HawkCredential.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +#if NET45 || CORE +using System.Security.Claims; +using System.Threading.Tasks; +#endif + +namespace HawkNet +{ + /// + /// Contains private information about an user + /// + public class HawkCredential + { + public HawkCredential() + { + this.User = string.Empty; +#if !NET45 && !CORE + this.Roles = new string[] { }; +#endif + } + + /// + /// Key Id + /// + public string Id { get; set; } + + /// + /// Symmetric Key + /// + public string Key { get; set; } + + /// + /// Hashing Algorithm + /// + public string Algorithm { get; set; } + + /// + /// User name + /// + public string User { get; set; } + +#if NET45 || CORE + /// + /// Additional Claims + /// + public Claim[] AdditionalClaims { get; set; } +#else + /// + /// User roles + /// + public string[] Roles { get; set; } +#endif + } +} \ No newline at end of file diff --git a/src/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs b/src/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs new file mode 100644 index 0000000..28e1bfe --- /dev/null +++ b/src/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs @@ -0,0 +1,58 @@ +using HawkNet; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; + +namespace HawkNet +{ + public static class HttpWebRequestExtensions + { + /// + /// Adds the Hawk authorization header to a request message + /// + /// Request instance + /// Hawk credentials + public static void SignRequest(this HttpWebRequest request, HawkCredential credential) + { + SignRequest(request, credential, null, null, null, null); + } + + /// + /// Adds the Hawk Authorization header to a HttpWebRequest instance + /// + /// Request instance + /// Hawk credentials + /// Optional extension + /// Timestamp + /// Random nonce + /// Request payload hash + public static void SignRequest(this HttpWebRequest request, + HawkCredential credential, + string ext, + DateTime? ts, + string nonce, + string payloadHash) + { +#if NET45 + var host = (request.Host != null) ? request.Host : + request.RequestUri.Host + + ((request.RequestUri.Port != 80) ? ":" + request.RequestUri.Port : ""); +#else + var host = request.RequestUri.Host + + ((request.RequestUri.Port != 80) ? ":" + request.RequestUri.Port : ""); +#endif + var hawk = Hawk.GetAuthorizationHeader(host, + request.Method, + request.RequestUri, + credential, + ext, + ts, + nonce, + payloadHash); + + request.Headers.Add("Authorization", "Hawk " + hawk); + } + } +} \ No newline at end of file diff --git a/src/HydrantCAProxy/Client/Authentication/LICENSE b/src/HydrantCAProxy/Client/Authentication/LICENSE new file mode 100644 index 0000000..efe278a --- /dev/null +++ b/src/HydrantCAProxy/Client/Authentication/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012 Pablo Cibraro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/src/HydrantCAProxy/Client/HydrantIdClient.cs b/src/HydrantCAProxy/Client/HydrantIdClient.cs index 2ce79be..43ba6c7 100644 --- a/src/HydrantCAProxy/Client/HydrantIdClient.cs +++ b/src/HydrantCAProxy/Client/HydrantIdClient.cs @@ -27,6 +27,9 @@ using Microsoft.Extensions.Logging; using Keyfactor.Extensions.CAPlugin.HydrantId; using Keyfactor.AnyGateway.Extensions; +using HawkNet; +using Microsoft.VisualBasic; +using System.Globalization; namespace Keyfactor.HydrantId.Client { @@ -374,63 +377,60 @@ private HttpClient ConfigureRestClient(string method, string url) { Log.MethodEntry(); var bUrl = new Uri(BaseUrl); + ApiId = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId].ToString(); - var apiId = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId].ToString(); - var apiKey = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthKey].ToString(); + var credentials = new HawkCredential + { + Id = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId].ToString(), + Key = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthKey].ToString(), + Algorithm = "sha256" + }; var byteArray = new byte[20]; + //Generate a cryptographically random set of bytes using (var rnd = RandomNumberGenerator.Create()) { rnd.GetBytes(byteArray); } - var nonce = Convert.ToBase64String(byteArray); - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); - - // Build normalized string according to Hawk spec (beware of spacing/line endings!) - var uri = new Uri(url); - var requestPath = uri.PathAndQuery; - var normalized = new StringBuilder(); - normalized.AppendLine("hawk.1.header"); - normalized.AppendLine(timestamp); - normalized.AppendLine(nonce); - normalized.AppendLine(method.ToUpperInvariant()); - normalized.AppendLine(requestPath); - normalized.AppendLine(uri.Host); - normalized.AppendLine(uri.Port.ToString()); - normalized.AppendLine(); // No hash - normalized.AppendLine(); // No ext - normalized.AppendLine(); // No app - normalized.Append(""); // No dlg - - var normalizedString = normalized.ToString(); - - // Calculate MAC using HMACSHA256 - byte[] keyBytes = Encoding.UTF8.GetBytes(apiKey); - byte[] dataBytes = Encoding.UTF8.GetBytes(normalizedString); - string mac; - - using (var hmac = new HMACSHA256(keyBytes)) - { - var hashBytes = hmac.ComputeHash(dataBytes); - mac = Convert.ToBase64String(hashBytes); - } + var nOnce = Convert.ToBase64String(byteArray); + var date = DateTime.Now; + var ts = Hawk.ConvertToUnixTimestamp(date); + var mac = Hawk.CalculateMac(bUrl.Host + ":" + bUrl.Port, method, new Uri(url), "", + ts.ToString(CultureInfo.InvariantCulture), nOnce, credentials, "header"); + var authorization = + $"id=\"{ApiId}\", ts=\"{ts}\", nonce=\"{nOnce}\", mac=\"{mac}\""; - var authorization = $"Hawk id=\"{apiId}\", ts=\"{timestamp}\", nonce=\"{nonce}\", mac=\"{mac}\""; - Log.LogTrace($"Authorization: {authorization}"); - var handler = new HttpClientHandler(); - var client = new HttpClient(handler, true) { BaseAddress = bUrl }; - client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - client.DefaultRequestHeaders.Add("Authorization", authorization); + var clientHandler = new HttpClientHandler(); // Replaces WebRequestHandler in .NET 6 - return client; + var returnClient = new HttpClient(clientHandler, disposeHandler: true) + { + BaseAddress = bUrl + }; + + returnClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + returnClient.DefaultRequestHeaders.Add("Authorization", "Hawk " + authorization); + + return returnClient; } catch (Exception e) { - Log.LogError($"Error Occurred in ConfigureRestClient: {e}"); + Log.LogError($"Error Occured in HydrantIdClient.ConfigureRestClient: {e.Message}"); throw; } - } + } + + private static byte[] ConvertHexStringToBytes(string hex) + { + if (hex.Length % 2 != 0) + throw new ArgumentException("Invalid length for hex string."); + + var bytes = new byte[hex.Length / 2]; + for (int i = 0; i < bytes.Length; i++) + bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); + return bytes; + } } + } \ No newline at end of file diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs index 06436d2..6786115 100644 --- a/src/HydrantCAProxy/HydrantIdCAPlugin.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -42,7 +42,24 @@ public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDa } } - public void ValidateCAConnectionInfo(Dictionary connectionInfo) + private static List CheckRequiredValues(Dictionary connectionInfo, params string[] args) + { + List errors = new List(); + foreach (string s in args) + if (string.IsNullOrEmpty(connectionInfo[s] as string)) + errors.Add($"{s} is a required value"); + return errors; + } + + private static readonly Func pemify = ss => + ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64)); + + public async Task Ping() + { + + } + + public Task ValidateCAConnectionInfo(Dictionary connectionInfo) { _logger.MethodEntry(); _logger.LogDebug($"Validating GCP CAS CA Connection properties"); @@ -65,62 +82,15 @@ public void ValidateCAConnectionInfo(Dictionary connectionInfo) } _logger.MethodExit(); - } - - public void ValidateProductInfo(EnrollmentProductInfo productInfo, - Dictionary connectionInfo) - { - _logger.MethodEntry(); - //TODO: Evaluate Template (if avaiable) based on ProductInfo - _logger.MethodExit(); - } - - private static List CheckRequiredValues(Dictionary connectionInfo, params string[] args) - { - List errors = new List(); - foreach (string s in args) - if (string.IsNullOrEmpty(connectionInfo[s] as string)) - errors.Add($"{s} is a required value"); - return errors; - } - - private static readonly Func pemify = ss => - ss.Length <= 64 ? ss : ss.Substring(0, 64) + "\n" + pemify(ss.Substring(64)); - - public async Task Ping() - { - _logger.MethodEntry(); - try - { - var client = new HydrantIdClient(Config); - var success = await client.Ping(); - - if (!success) - { - throw new Exception("HydrantIdClient Ping failed."); - } - - _logger.LogTrace("HydrantIdCAPlugin Ping succeeded."); - } - catch (Exception e) - { - _logger.LogError($"Error during HydrantIdCAPlugin Ping: {e.Message}"); - throw; - } - finally - { - _logger.MethodExit(); - } - } - - Task IAnyCAPlugin.ValidateCAConnectionInfo(Dictionary connectionInfo) - { - throw new NotImplementedException(); + return Ping(); } - Task IAnyCAPlugin.ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) + public Task ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary connectionInfo) { - throw new NotImplementedException(); + _logger.MethodEntry(); + //TODO: Evaluate Template (if avaiable) based on ProductInfo + _logger.MethodExit(); + return Task.CompletedTask; } @@ -131,7 +101,7 @@ public List GetProductIds() var ids = policies .Where(p => p.Id.HasValue) - .Select(p => p.Id.Value.ToString()) + .Select(p => p.Name.ToString()) .ToList(); return ids; diff --git a/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs b/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs index 59dbd99..5dbd640 100644 --- a/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs +++ b/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs @@ -25,8 +25,8 @@ public class HydrantIdCAPluginConfig public class ConfigConstants { public static string HydrantIdBaseUrl = "HydrantIdBaseUrl"; - public static string HydrantIdAuthId = "AuthId"; - public static string HydrantIdAuthKey = "AuthKey"; + public static string HydrantIdAuthId = "HydrantIdAuthId"; + public static string HydrantIdAuthKey = "HydrantIdAuthKey"; public static string DefaultPageSize = "DefaultPageSize"; } From e8665211bae57c2cfbe83a0ec0fe0a55d6f81889 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Wed, 16 Apr 2025 13:49:01 -0400 Subject: [PATCH 07/25] checkpoint --- src/HydrantCAProxy/Client/HydrantIdClient.cs | 366 +++++++++---------- src/HydrantCAProxy/HydrantIdCAPlugin.cs | 5 +- src/HydrantCAProxy/RequestManager.cs | 15 +- 3 files changed, 195 insertions(+), 191 deletions(-) diff --git a/src/HydrantCAProxy/Client/HydrantIdClient.cs b/src/HydrantCAProxy/Client/HydrantIdClient.cs index 43ba6c7..516591c 100644 --- a/src/HydrantCAProxy/Client/HydrantIdClient.cs +++ b/src/HydrantCAProxy/Client/HydrantIdClient.cs @@ -7,61 +7,61 @@ // OR CONDITIONS OF ANY KIND, either express or implied. See the License for // thespecific language governing permissions and limitations under the // License. -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Net; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Security.Cryptography; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Keyfactor.Logging; -using Keyfactor.HydrantId.Client.Models; -using Keyfactor.HydrantId.Client.Models.Enums; -using Keyfactor.HydrantId.Exceptions; -using Keyfactor.HydrantId.Interfaces; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using Microsoft.Extensions.Logging; -using Keyfactor.Extensions.CAPlugin.HydrantId; -using Keyfactor.AnyGateway.Extensions; -using HawkNet; -using Microsoft.VisualBasic; -using System.Globalization; - -namespace Keyfactor.HydrantId.Client -{ - public sealed class HydrantIdClient - { - private static readonly ILogger Log = LogHandler.GetClassLogger < HydrantIdClient>(); - - public HydrantIdClient(IAnyCAPluginConfigProvider config) - { - try - { - Log.MethodEntry(); - - if (config.CAConnectionData.ContainsKey(HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId)) - { - ConfigProvider = config; - BaseUrl = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdBaseUrl].ToString(); - RequestManager = new RequestManager(); - } - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.HydrantIdClient: {e.Message}"); - throw; - } - } - - private string BaseUrl { get; } - private int PageSize { get; } = 100; - private string ApiId { get; set; } - private RequestManager RequestManager { get; } - +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Keyfactor.Logging; +using Keyfactor.HydrantId.Client.Models; +using Keyfactor.HydrantId.Client.Models.Enums; +using Keyfactor.HydrantId.Exceptions; +using Keyfactor.HydrantId.Interfaces; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Microsoft.Extensions.Logging; +using Keyfactor.Extensions.CAPlugin.HydrantId; +using Keyfactor.AnyGateway.Extensions; +using HawkNet; +using Microsoft.VisualBasic; +using System.Globalization; + +namespace Keyfactor.HydrantId.Client +{ + public sealed class HydrantIdClient + { + private static readonly ILogger Log = LogHandler.GetClassLogger < HydrantIdClient>(); + + public HydrantIdClient(IAnyCAPluginConfigProvider config) + { + try + { + Log.MethodEntry(); + + if (config.CAConnectionData.ContainsKey(HydrantIdCAPluginConfig.ConfigConstants.HydrantIdAuthId)) + { + ConfigProvider = config; + BaseUrl = ConfigProvider.CAConnectionData[HydrantIdCAPluginConfig.ConfigConstants.HydrantIdBaseUrl].ToString(); + RequestManager = new RequestManager(); + } + } + catch (Exception e) + { + Log.LogError($"Error Occured in HydrantIdClient.HydrantIdClient: {e.Message}"); + throw; + } + } + + private string BaseUrl { get; } + private int PageSize { get; } = 100; + private string ApiId { get; set; } + private RequestManager RequestManager { get; } + private IAnyCAPluginConfigProvider ConfigProvider { get; } public async Task GetSubmitEnrollmentAsync(CertRequestBody registerRequest) @@ -177,30 +177,30 @@ public async Task GetSubmitGetCertificateAsync(string certificateId throw; } } - - - public async Task GetSubmitGetCertificateByCsrAsync(string requestTrackingId) - { - try - { - Log.MethodEntry(); - var apiEndpoint = $"/api/v2/csr/{requestTrackingId}/certificate"; - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); - - using (var resp = await restClient.GetAsync(apiEndpoint)) - { - resp.EnsureSuccessStatusCode(); - var getCertificateResponse = - JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); - return getCertificateResponse; - } - } - catch (Exception e) - { - Log.LogError($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); - throw; - } + + + public async Task GetSubmitGetCertificateByCsrAsync(string requestTrackingId) + { + try + { + Log.MethodEntry(); + var apiEndpoint = $"/api/v2/csr/{requestTrackingId}/certificate"; + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); + var restClient = ConfigureRestClient("get", BaseUrl + apiEndpoint); + + using (var resp = await restClient.GetAsync(apiEndpoint)) + { + resp.EnsureSuccessStatusCode(); + var getCertificateResponse = + JsonConvert.DeserializeObject(await resp.Content.ReadAsStringAsync()); + return getCertificateResponse; + } + } + catch (Exception e) + { + Log.LogError($"Error Occured in HydrantIdClient.GetSubmitGetCertificateAsync: {e.Message}"); + throw; + } } public async Task GetSubmitRevokeCertificateAsync(string hydrantId, RevocationReasons revokeReason) @@ -235,108 +235,108 @@ public async Task GetSubmitRevokeCertificateAsync(string hydr throw; } } - - - public async Task GetSubmitCertificateListRequestAsync(BlockingCollection bc, - CancellationToken ct) - { - Log.MethodEntry(); - try - { - var itemsProcessed = 0; - var pageCounter = 0; - var isComplete = false; - var retryCount = 0; - do - { - Log.LogTrace($"pageCounter: {pageCounter} pageSize: {PageSize}"); - var queryOrderRequest = RequestManager.GetCertificatesListRequest(pageCounter, PageSize); - Log.LogTrace($"queryOrderRequest JSON: {JsonConvert.SerializeObject(queryOrderRequest)}"); - var batchItemsProcessed = 0; - - var apiEndpoint = "/api/v2/certificates"; - Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); - var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); - - using (var resp = await restClient.PostAsync(apiEndpoint, new StringContent( - JsonConvert.SerializeObject(queryOrderRequest), Encoding.UTF8, "application/json"), ct)) - { - if (!resp.IsSuccessStatusCode) - { - var responseMessage = resp.Content.ReadAsStringAsync().Result; - Log.LogError( - $"Failed Request to Keyfactor. Retrying request. Status Code {resp.StatusCode} | Message: {responseMessage}"); - retryCount++; - if (retryCount > 5) - throw new RetryCountExceededException( - $"5 consecutive failures to {resp.RequestMessage.RequestUri}"); - - continue; - } - - var stringResponse = await resp.Content.ReadAsStringAsync(); - - var batchResponse = - JsonConvert.DeserializeObject(stringResponse); - - Log.LogTrace($"batchResponse JSON: {JsonConvert.SerializeObject(batchResponse)}"); - - if (batchResponse != null) - { - var batchCount = batchResponse.Items.Count; - - Log.LogTrace($"Processing {batchCount} items in batch"); - do - { - var r = batchResponse.Items[batchItemsProcessed]; - if (bc.TryAdd(r, 10, ct)) - { - Log.LogTrace($"Added Template ID {r.Id} to Queue for processing"); - batchItemsProcessed++; - itemsProcessed++; - Log.LogTrace($"Processed {batchItemsProcessed} of {batchCount}"); - Log.LogTrace($"Total Items Processed: {itemsProcessed}"); - } - else - { - Log.LogTrace($"Adding {r} blocked. Retry"); - } - } while (batchItemsProcessed < batchCount); //batch loop - } - } - - //assume that if we process less records than requested that we have reached the end of the certificate list - if (batchItemsProcessed < PageSize) - isComplete = true; - pageCounter = pageCounter + PageSize; - } while (!isComplete); //page loop - - bc.CompleteAdding(); - } - catch (OperationCanceledException cancelEx) - { - Log.LogWarning($"Synchronize method was cancelled. Message: {cancelEx.Message}"); - bc.CompleteAdding(); - Log.MethodExit(); - // ReSharper disable once PossibleIntendedRethrow - throw; - } - catch (RetryCountExceededException retryEx) - { - Log.LogError($"Retries Failed: {retryEx.Message}"); - Log.MethodExit(); - bc.CompleteAdding(); - throw; - } - catch (HttpRequestException ex) - { - Log.LogError($"HttpRequest Failed: {ex.Message}"); - Log.MethodExit(); - bc.CompleteAdding(); - throw; - } - - Log.MethodExit(); + + + public async Task GetSubmitCertificateListRequestAsync(BlockingCollection bc, + CancellationToken ct) + { + Log.MethodEntry(); + try + { + var itemsProcessed = 0; + var pageCounter = 0; + var isComplete = false; + var retryCount = 0; + do + { + Log.LogTrace($"pageCounter: {pageCounter} pageSize: {PageSize}"); + var queryOrderRequest = RequestManager.GetCertificatesListRequest(pageCounter, PageSize); + Log.LogTrace($"queryOrderRequest JSON: {JsonConvert.SerializeObject(queryOrderRequest)}"); + var batchItemsProcessed = 0; + + var apiEndpoint = "/api/v2/certificates"; + Log.LogTrace($"API Url {BaseUrl + apiEndpoint}"); + var restClient = ConfigureRestClient("post", BaseUrl + apiEndpoint); + + using (var resp = await restClient.PostAsync(apiEndpoint, new StringContent( + JsonConvert.SerializeObject(queryOrderRequest), Encoding.UTF8, "application/json"), ct)) + { + if (!resp.IsSuccessStatusCode) + { + var responseMessage = resp.Content.ReadAsStringAsync().Result; + Log.LogError( + $"Failed Request to Keyfactor. Retrying request. Status Code {resp.StatusCode} | Message: {responseMessage}"); + retryCount++; + if (retryCount > 5) + throw new RetryCountExceededException( + $"5 consecutive failures to {resp.RequestMessage.RequestUri}"); + + continue; + } + + var stringResponse = await resp.Content.ReadAsStringAsync(); + + var batchResponse = + JsonConvert.DeserializeObject(stringResponse); + + Log.LogTrace($"batchResponse JSON: {JsonConvert.SerializeObject(batchResponse)}"); + + if (batchResponse != null) + { + var batchCount = batchResponse.Items.Count; + + Log.LogTrace($"Processing {batchCount} items in batch"); + do + { + var r = batchResponse.Items[batchItemsProcessed]; + if (bc.TryAdd(r, 10, ct)) + { + Log.LogTrace($"Added Template ID {r.Id} to Queue for processing"); + batchItemsProcessed++; + itemsProcessed++; + Log.LogTrace($"Processed {batchItemsProcessed} of {batchCount}"); + Log.LogTrace($"Total Items Processed: {itemsProcessed}"); + } + else + { + Log.LogTrace($"Adding {r} blocked. Retry"); + } + } while (batchItemsProcessed < batchCount); //batch loop + } + } + + //assume that if we process less records than requested that we have reached the end of the certificate list + if (batchItemsProcessed < PageSize) + isComplete = true; + pageCounter = pageCounter + PageSize; + } while (!isComplete); //page loop + + bc.CompleteAdding(); + } + catch (OperationCanceledException cancelEx) + { + Log.LogWarning($"Synchronize method was cancelled. Message: {cancelEx.Message}"); + bc.CompleteAdding(); + Log.MethodExit(); + // ReSharper disable once PossibleIntendedRethrow + throw; + } + catch (RetryCountExceededException retryEx) + { + Log.LogError($"Retries Failed: {retryEx.Message}"); + Log.MethodExit(); + bc.CompleteAdding(); + throw; + } + catch (HttpRequestException ex) + { + Log.LogError($"HttpRequest Failed: {ex.Message}"); + Log.MethodExit(); + bc.CompleteAdding(); + throw; + } + + Log.MethodExit(); } public async Task Ping() @@ -431,6 +431,6 @@ private static byte[] ConvertHexStringToBytes(string hex) bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); return bytes; } - } - + } + } \ No newline at end of file diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs index 6786115..3fa4a0f 100644 --- a/src/HydrantCAProxy/HydrantIdCAPlugin.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -18,6 +18,7 @@ using Keyfactor.AnyGateway.Extensions; using Keyfactor.PKI; using System.Data; +using System.Drawing; namespace Keyfactor.Extensions.CAPlugin.HydrantId { @@ -259,7 +260,9 @@ public async Task Enroll(string csr, string subject, Dictionar } var cert = await GetSingleRecord(csrTrackingResponse.Id.ToString()); - return _requestManager.GetEnrollmentResult(csrTrackingResponse, cert); + + var result = _requestManager.GetEnrollmentResult(csrTrackingResponse, cert); + return result; } finally { diff --git a/src/HydrantCAProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs index f3b0004..dc70d4d 100644 --- a/src/HydrantCAProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -21,6 +21,7 @@ using LogHandler = Keyfactor.Logging.LogHandler; using Keyfactor.AnyGateway.Extensions; using Keyfactor.PKI; +using Keyfactor.PKI.Enums.EJBCA; namespace Keyfactor.HydrantId { @@ -235,7 +236,7 @@ public EnrollmentResult { return new EnrollmentResult { - Status = 30, //failure + Status = (int)EndEntityStatus.FAILED, //failure StatusMessage = $"Enrollment Failed with could not get the certificate from the request tracking id" }; } @@ -244,7 +245,7 @@ public EnrollmentResult { return new EnrollmentResult { - Status = 30, //failure + Status = (int)EndEntityStatus.FAILED, //failure StatusMessage = $"Enrollment Failed with could not get the certificate from the request tracking id" }; } @@ -253,10 +254,10 @@ public EnrollmentResult { return new EnrollmentResult { - Status = (int)PKIConstants.Microsoft.RequestDisposition.ISSUED, //success + Status = (int)EndEntityStatus.GENERATED, //success CARequestID = enrollmentResult.Id.ToString(), Certificate = cert.Certificate, - StatusMessage = $"Order Successfully Created With Product {cert.ProductID}" + StatusMessage = $"Order Successfully Created" }; } @@ -285,9 +286,9 @@ public CertRequestBodyDnComponents GetDnComponentsRequest(string csr) var ou = string.Empty; Log.LogTrace($"CSR: {csr}"); - var cert = "-----BEGIN CERTIFICATE REQUEST-----\r\n"; - cert = cert + Pemify(csr); - cert = cert + "\r\n-----END CERTIFICATE REQUEST-----"; + //var cert = "-----BEGIN CERTIFICATE REQUEST-----\r\n"; + var cert = csr; + //cert = cert + "\r\n-----END CERTIFICATE REQUEST-----"; Log.LogTrace($"cert: {cert}"); var reader = new PemReader(new StringReader(cert)); From 232b6a3233fd428344cd92d4b46e57683bc82510 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Thu, 17 Apr 2025 13:11:47 -0400 Subject: [PATCH 08/25] checkpoint --- src/HydrantCAProxy/HydrantIdCAPlugin.cs | 11 ++++++----- src/HydrantCAProxy/RequestManager.cs | 13 ++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs index 3fa4a0f..5e2e7e0 100644 --- a/src/HydrantCAProxy/HydrantIdCAPlugin.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -19,6 +19,7 @@ using Keyfactor.PKI; using System.Data; using System.Drawing; +using Keyfactor.PKI.Enums.EJBCA; namespace Keyfactor.Extensions.CAPlugin.HydrantId { @@ -132,8 +133,8 @@ public async Task Synchronize(BlockingCollection blockin var certStatus = _requestManager.GetMapReturnStatus(item.RevocationStatus); _logger.LogTrace($"Numeric Status: {certStatus}"); - if (certStatus != Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.ISSUED) && - certStatus != Convert.ToInt32(PKIConstants.Microsoft.RequestDisposition.REVOKED)) + if (certStatus != Convert.ToInt32(EndEntityStatus.GENERATED) && + certStatus != Convert.ToInt32(EndEntityStatus.REVOKED)) continue; _logger.LogTrace($"Product Id: {item.Policy.Name}"); @@ -242,7 +243,7 @@ public async Task Enroll(string csr, string subject, Dictionar { return new EnrollmentResult { - Status = 30, + Status = (int)EndEntityStatus.FAILED, StatusMessage = $"Enrollment Failed with error {enrollmentResponse.ErrorReturn.Error}" }; } @@ -254,7 +255,7 @@ public async Task Enroll(string csr, string subject, Dictionar { return new EnrollmentResult { - Status = 30, + Status = (int)EndEntityStatus.FAILED, StatusMessage = "Certificate may still be pending in Hydrant and is not ready for download" }; } @@ -354,7 +355,7 @@ public async Task GetSingleRecord(string caRequestID) return new AnyCAPluginCertificate { CARequestID = caRequestID, - Status = _requestManager.GetMapReturnStatus(0) // Unknown + Status = _requestManager.GetMapReturnStatus(0) // Failed }; } } diff --git a/src/HydrantCAProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs index dc70d4d..eaae9d6 100644 --- a/src/HydrantCAProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -34,21 +34,24 @@ public int GetMapReturnStatus(RevocationStatusEnum hydrantIdStatus) try { Log.MethodEntry(); - PKIConstants.Microsoft.RequestDisposition returnStatus; + int returnStatus; Log.LogTrace($"hydrantIdStatus: {hydrantIdStatus}"); switch (hydrantIdStatus) { case RevocationStatusEnum.Valid: - returnStatus = PKIConstants.Microsoft.RequestDisposition.ISSUED; + returnStatus = (int)EndEntityStatus.GENERATED; break; case RevocationStatusEnum.Pending: - returnStatus = PKIConstants.Microsoft.RequestDisposition.PENDING; + returnStatus = (int)EndEntityStatus.INPROCESS; break; case RevocationStatusEnum.Revoked: - returnStatus = PKIConstants.Microsoft.RequestDisposition.REVOKED; + returnStatus =(int)EndEntityStatus.REVOKED; + break; + case RevocationStatusEnum.Failed: + returnStatus = (int)EndEntityStatus.FAILED; break; default: - returnStatus = PKIConstants.Microsoft.RequestDisposition.UNKNOWN; + returnStatus = (int)EndEntityStatus.FAILED; break; } Log.MethodExit(); From b260e7e19fb69aa75e2c99d9c37240a1af123598 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Thu, 17 Apr 2025 14:40:43 -0400 Subject: [PATCH 09/25] checkpoint --- src/HydrantCAProxy/HydrantIdCAPlugin.cs | 41 ++++++++++++++----- src/HydrantCAProxy/HydrantIdCAPluginConfig.cs | 8 ++++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs index 5e2e7e0..24562e1 100644 --- a/src/HydrantCAProxy/HydrantIdCAPlugin.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -207,7 +207,7 @@ public async Task Enroll(string csr, string subject, Dictionar { CertRequestResult enrollmentResponse = null; - if (enrollmentType == EnrollmentType.New || enrollmentType == EnrollmentType.Reissue) + if (enrollmentType == EnrollmentType.New) { _logger.LogTrace("Entering New Enrollment"); var policyListResult = await client.GetPolicyList(); @@ -221,22 +221,43 @@ public async Task Enroll(string csr, string subject, Dictionar enrollmentResponse = await client.GetSubmitEnrollmentAsync(enrollmentRequest); } - else if (enrollmentType == EnrollmentType.Renew) + else if (enrollmentType == EnrollmentType.RenewOrReissue) { - _logger.LogTrace("Entering Renew..."); - - var renewRequest = _requestManager.GetRenewalRequest(csr, false); - _logger.LogTrace($"Renewal Request JSON: {JsonConvert.SerializeObject(renewRequest)}"); + _logger.LogTrace("Entering Renew/Reissue Logic..."); var sn = productInfo.ProductParameters["PriorCertSN"]; _logger.LogTrace($"Prior Cert Serial Number: {sn}"); - //var priorCert = certDataReader.(DataConversion.HexToBytes(sn)); var certificateId = await certDataReader.GetRequestIDBySerialNumber(sn); - - _logger.LogTrace($"Renewal CA RequestId: {certificateId}"); - enrollmentResponse = await client.GetSubmitRenewalAsync(certificateId, renewRequest); + //1) Get Single Certificate for the previous certificate + var previousCert = await GetSingleRecord(certificateId); + + //2) Look up the Expiration Date for that cert + var previousX509 = new X509Certificate2(Encoding.ASCII.GetBytes(previousCert.Certificate)); + var expiration = previousX509.NotAfter; + var now = DateTime.UtcNow; + + //3) Determine if it is a Renewal vs Re-Issue + var isRenewal = (expiration - now).TotalDays <= Convert.ToInt16(productInfo.ProductParameters["RenewalDays"]); + _logger.LogTrace($"Certificate Expiration: {expiration}, Current Time: {now}, IsRenewal: {isRenewal}"); + + if (isRenewal) + { + _logger.LogTrace("Proceeding with Renewal Request..."); + var renewRequest = _requestManager.GetRenewalRequest(csr, false); + _logger.LogTrace($"Renewal Request JSON: {JsonConvert.SerializeObject(renewRequest)}"); + enrollmentResponse = await client.GetSubmitRenewalAsync(certificateId, renewRequest); + } + else + { + _logger.LogTrace("Proceeding with Re-Issue Request..."); + var policyListResult = await client.GetPolicyList(); + var policyId = policyListResult.Single(p => p.Name.Equals(productInfo.ProductID)); + var reissueRequest = _requestManager.GetEnrollmentRequest(policyId.Id, productInfo, csr, san); + _logger.LogTrace($"Re-Issue Request JSON: {JsonConvert.SerializeObject(reissueRequest)}"); + enrollmentResponse = await client.GetSubmitEnrollmentAsync(reissueRequest); + } } if (enrollmentResponse?.ErrorReturn?.Status == "Failure") diff --git a/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs b/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs index 5dbd640..9a143d1 100644 --- a/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs +++ b/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs @@ -41,6 +41,7 @@ public static class EnrollmentParametersConstants { public const string ValidityPeriod = "ValidityPeriod"; public const string ValidityUnits = "ValidityUnits"; + public const string RenewalDays = "RenewalDays"; } public static Dictionary GetPluginAnnotations() @@ -88,6 +89,13 @@ public static Dictionary GetTemplateParameterAnnotat Hidden = false, DefaultValue = 1, Type = "Number" + }, + [EnrollmentParametersConstants.RenewalDays] = new PropertyConfigInfo() + { + Comments = $"The window that determines whether it is a renewal vs a re-issue.", + Hidden = false, + DefaultValue = 30, + Type = "Number" } }; } From cc91d15b820eb31801c1767d0f25dfb7f1d8e031 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 18 Apr 2025 09:19:25 -0400 Subject: [PATCH 10/25] checkpoint --- src/HydrantCAProxy/HydrantIdCAPlugin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs index 24562e1..d7b7b9f 100644 --- a/src/HydrantCAProxy/HydrantIdCAPlugin.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -310,12 +310,12 @@ public async Task Revoke(string caRequestID, string hexSerialNumber, uint r var revokeResponse = await client.GetSubmitRevokeCertificateAsync(hydrantId, revokeReason); _logger.LogTrace($"Revoke Response JSON: {JsonConvert.SerializeObject(revokeResponse)}"); - return 1; + return (int)EndEntityStatus.REVOKED; } catch (Exception e) { _logger.LogError($"Error during revoke process: {e.Message}"); - return -1; + return (int)EndEntityStatus.FAILED; } finally { From d58c37e764cbbec3ee1b2b06a5e0f4c50967fff6 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 18 Apr 2025 10:16:00 -0400 Subject: [PATCH 11/25] checkpoint --- src/HydrantCAProxy/RequestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HydrantCAProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs index eaae9d6..3cd7559 100644 --- a/src/HydrantCAProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -152,7 +152,7 @@ public CertRequestBody GetEnrollmentRequest(Guid? policyId, EnrollmentProductInf Validity = GetValidity(productInfo.ProductParameters["ValidityPeriod"], Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) }; - if (san.ContainsKey("dns")) + if (san.ContainsKey("dnsname")) { request.SubjectAltNames = GetSansRequest(san); } @@ -214,7 +214,7 @@ public CertRequestBodySubjectAltNames GetSansRequest(Dictionary dnsNames = new List(); - foreach (var v in sans["dns"]) + foreach (var v in sans["dnsname"]) { dnsNames.Add(v); } From c6a2fe035e72b54fe97427735b0e47c15ed212a4 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 18 Apr 2025 12:59:23 -0400 Subject: [PATCH 12/25] Fixes for Bug 69048 --- .../Models/CertRequestBodyDnComponents.cs | 8 +++- .../Models/PolicyDetailsDnComponents.cs | 6 ++- .../Models/PolicyDetailsSubjectAltNames.cs | 4 +- .../Client/Models/TagEnumConverter.cs | 39 +++++++++++++++++++ .../ICertRequestBodyDnComponents.cs | 4 +- 5 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 src/HydrantCAProxy/Client/Models/TagEnumConverter.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs b/src/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs index cac1f3a..33e19c3 100644 --- a/src/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs +++ b/src/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs @@ -34,7 +34,13 @@ public class CertRequestBodyDnComponents : ICertRequestBodyDnComponents public string C { get; set; } [JsonProperty("DC", NullValueHandling = NullValueHandling.Ignore)] - public List Dc { get; set; } + public List Dc { get; set; } + + [JsonProperty("E", NullValueHandling = NullValueHandling.Ignore)] + public List Email { get; set; } + + [JsonProperty("AEID", NullValueHandling = NullValueHandling.Ignore)] + public List Aeid { get; set; } } } \ No newline at end of file diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs b/src/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs index c6f2986..f5eb6af 100644 --- a/src/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs +++ b/src/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs @@ -31,7 +31,11 @@ public enum TagEnum [EnumMember(Value = "C")] C = 6, - [EnumMember(Value = "DC")] Dc = 7 + [EnumMember(Value = "DC")] Dc = 7, + + [EnumMember(Value = "E")] Email = 8, + + [EnumMember(Value = "AEID")] Aeid = 9 } [JsonProperty("tag", NullValueHandling = NullValueHandling.Ignore)] diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs b/src/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs index c2d5aae..bf25d52 100644 --- a/src/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs +++ b/src/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs @@ -16,14 +16,14 @@ namespace Keyfactor.HydrantId.Client.Models { public class PolicyDetailsSubjectAltNames : IPolicyDetailsSubjectAltNames { - [JsonConverter(typeof(StringEnumConverter))] + [JsonConverter(typeof(TagEnumConverter))] public enum TagEnum { [EnumMember(Value = "DNSNAME")] DnsName = 1, [EnumMember(Value = "IPADDRESS")] IpAddress = 2, - [EnumMember(Value = "RFS822NAME")] Rfs822Name = 3, + [EnumMember(Value = "RFC822NAME")] Rfc822Name = 3, [EnumMember(Value = "UPN")] Upn = 4 } diff --git a/src/HydrantCAProxy/Client/Models/TagEnumConverter.cs b/src/HydrantCAProxy/Client/Models/TagEnumConverter.cs new file mode 100644 index 0000000..58ade6d --- /dev/null +++ b/src/HydrantCAProxy/Client/Models/TagEnumConverter.cs @@ -0,0 +1,39 @@ +using System; +using Keyfactor.HydrantId.Client.Models; +using Newtonsoft.Json; + +public class TagEnumConverter : JsonConverter +{ + public override bool CanConvert(Type objectType) => objectType == typeof(PolicyDetailsSubjectAltNames.TagEnum) || objectType == typeof(PolicyDetailsSubjectAltNames.TagEnum?); + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + var strValue = (reader.Value as string)?.ToUpperInvariant(); + + return strValue switch + { + "DNSNAME" => PolicyDetailsSubjectAltNames.TagEnum.DnsName, + "IPADDRESS" => PolicyDetailsSubjectAltNames.TagEnum.IpAddress, + "RFC822NAME" => PolicyDetailsSubjectAltNames.TagEnum.Rfc822Name, + "RFS822NAME" => PolicyDetailsSubjectAltNames.TagEnum.Rfc822Name, // typo fallback + "UPN" => PolicyDetailsSubjectAltNames.TagEnum.Upn, + _ => throw new JsonSerializationException($"Unknown TagEnum value: {strValue}") + }; + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var enumVal = (PolicyDetailsSubjectAltNames.TagEnum)value; + + var strVal = enumVal switch + { + PolicyDetailsSubjectAltNames.TagEnum.DnsName => "DNSNAME", + PolicyDetailsSubjectAltNames.TagEnum.IpAddress => "IPADDRESS", + PolicyDetailsSubjectAltNames.TagEnum.Rfc822Name => "RFC822NAME", + PolicyDetailsSubjectAltNames.TagEnum.Upn => "UPN", + _ => throw new JsonSerializationException($"Cannot write TagEnum value: {value}") + }; + + writer.WriteValue(strVal); + } +} diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs b/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs index 829e7ce..68cd385 100644 --- a/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs +++ b/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs @@ -19,7 +19,9 @@ public interface ICertRequestBodyDnComponents string L { get;set; } string St { get;set; } string C { get;set; } - List Dc { get;set; } + List Dc { get;set; } + List Email { get; set; } + List Aeid { get; set; } } } \ No newline at end of file From 1932bc6f7f58b2833d30fe390f75a6d6e7e1c319 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Fri, 18 Apr 2025 13:28:12 -0400 Subject: [PATCH 13/25] all sans types support --- src/HydrantCAProxy/RequestManager.cs | 53 ++++++++++++++++------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/HydrantCAProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs index 3cd7559..178f629 100644 --- a/src/HydrantCAProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -22,6 +22,7 @@ using Keyfactor.AnyGateway.Extensions; using Keyfactor.PKI; using Keyfactor.PKI.Enums.EJBCA; +using System.Linq; namespace Keyfactor.HydrantId { @@ -152,7 +153,7 @@ public CertRequestBody GetEnrollmentRequest(Guid? policyId, EnrollmentProductInf Validity = GetValidity(productInfo.ProductParameters["ValidityPeriod"], Convert.ToInt16(productInfo.ProductParameters["ValidityUnits"])) }; - if (san.ContainsKey("dnsname")) + if (san!= null && san?.Count>0) { request.SubjectAltNames = GetSansRequest(san); } @@ -205,28 +206,36 @@ private CertRequestBodyValidity GetValidity(string period, int units) Log.LogError($"Error Occured in RequestManager.GetValidity: {e.Message}"); throw; } - } + } + + public CertRequestBodySubjectAltNames GetSansRequest(Dictionary sans) + { + try + { + Log.MethodEntry(); + var san = new CertRequestBodySubjectAltNames(); + + if (sans.TryGetValue("dnsname", out var dnsNames)) + san.Dnsname = dnsNames.ToList(); + + if (sans.TryGetValue("ipaddress", out var ipAddresses)) + san.Ipaddress = ipAddresses.ToList(); + + if (sans.TryGetValue("rfc822name", out var rfcNames)) + san.Rfc822Name = rfcNames.ToList(); + + if (sans.TryGetValue("upn", out var upns)) + san.Upn = upns.ToList(); + + return san; + } + catch (Exception e) + { + Log.LogError($"Error occurred in RequestManager.GetSansRequest: {e.Message}"); + throw; + } + } - public CertRequestBodySubjectAltNames GetSansRequest(Dictionary sans) - { - try - { - Log.MethodEntry(); - var san = new CertRequestBodySubjectAltNames(); - List dnsNames = new List(); - foreach (var v in sans["dnsname"]) - { - dnsNames.Add(v); - } - san.Dnsname = dnsNames; - return san; - } - catch (Exception e) - { - Log.LogError($"Error Occured in RequestManager.GetSansRequest: {e.Message}"); - throw; - } - } public EnrollmentResult GetEnrollmentResult( From 62c67f7fc4b90627f1c4545ae0b189f9e111fbd3 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 09:18:24 -0400 Subject: [PATCH 14/25] removed un-needed code --- src/HydrantCAProxy/Client/HydrantIdClient.cs | 1 - src/HydrantCAProxy/ExtensionMethods.cs | 25 ----------- .../Extensions/HttpClientExtensions.cs | 41 ------------------- src/HydrantCAProxy/HydrantIdCAPlugin.cs | 2 - src/HydrantCAProxy/RequestManager.cs | 1 - 5 files changed, 70 deletions(-) delete mode 100644 src/HydrantCAProxy/ExtensionMethods.cs delete mode 100644 src/HydrantCAProxy/Extensions/HttpClientExtensions.cs diff --git a/src/HydrantCAProxy/Client/HydrantIdClient.cs b/src/HydrantCAProxy/Client/HydrantIdClient.cs index 516591c..fcd0840 100644 --- a/src/HydrantCAProxy/Client/HydrantIdClient.cs +++ b/src/HydrantCAProxy/Client/HydrantIdClient.cs @@ -28,7 +28,6 @@ using Keyfactor.Extensions.CAPlugin.HydrantId; using Keyfactor.AnyGateway.Extensions; using HawkNet; -using Microsoft.VisualBasic; using System.Globalization; namespace Keyfactor.HydrantId.Client diff --git a/src/HydrantCAProxy/ExtensionMethods.cs b/src/HydrantCAProxy/ExtensionMethods.cs deleted file mode 100644 index b1f193b..0000000 --- a/src/HydrantCAProxy/ExtensionMethods.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Keyfactor.Extensions.CAPlugin.HydrantId -{ public static class ExtensionMethods - { - public static bool IsFullPathReadable(this string filePath) - { - try - { - byte[] fileContent = File.ReadAllBytes(filePath); - - return true; - } - catch (Exception) - { - return false; - } - } - } -} diff --git a/src/HydrantCAProxy/Extensions/HttpClientExtensions.cs b/src/HydrantCAProxy/Extensions/HttpClientExtensions.cs deleted file mode 100644 index c804b0f..0000000 --- a/src/HydrantCAProxy/Extensions/HttpClientExtensions.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2025 Keyfactor -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain a -// copy of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless -// required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES -// OR CONDITIONS OF ANY KIND, either express or implied. See the License for -// thespecific language governing permissions and limitations under the -// License. -using System; -using System.Diagnostics; -using System.Net.Http; -using System.Threading.Tasks; - -namespace Keyfactor.HydrantId.Extensions -{ - public static class HttpClientExtensions - { - // ReSharper disable once InconsistentNaming - public static async Task PatchAsync(this HttpClient client, Uri requestUri, HttpContent iContent) - { - var method = new HttpMethod("PATCH"); - var request = new HttpRequestMessage(method, requestUri) - { - Content = iContent - }; - - HttpResponseMessage response = new HttpResponseMessage(); - try - { - response = await client.SendAsync(request); - } - catch (TaskCanceledException e) - { - Debug.WriteLine("ERROR: " + e.ToString()); - } - - return response; - } - } -} diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/src/HydrantCAProxy/HydrantIdCAPlugin.cs index d7b7b9f..3ea7a80 100644 --- a/src/HydrantCAProxy/HydrantIdCAPlugin.cs +++ b/src/HydrantCAProxy/HydrantIdCAPlugin.cs @@ -16,9 +16,7 @@ using Keyfactor.HydrantId.Client.Models; using System.Diagnostics; using Keyfactor.AnyGateway.Extensions; -using Keyfactor.PKI; using System.Data; -using System.Drawing; using Keyfactor.PKI.Enums.EJBCA; namespace Keyfactor.Extensions.CAPlugin.HydrantId diff --git a/src/HydrantCAProxy/RequestManager.cs b/src/HydrantCAProxy/RequestManager.cs index 178f629..38b89fe 100644 --- a/src/HydrantCAProxy/RequestManager.cs +++ b/src/HydrantCAProxy/RequestManager.cs @@ -20,7 +20,6 @@ using Keyfactor.Logging; using LogHandler = Keyfactor.Logging.LogHandler; using Keyfactor.AnyGateway.Extensions; -using Keyfactor.PKI; using Keyfactor.PKI.Enums.EJBCA; using System.Linq; From 615f75d3910857923081c29eab2000dfc565a220 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 14:50:13 -0400 Subject: [PATCH 15/25] readme updates --- docsource/configuration.md | 102 +++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 docsource/configuration.md diff --git a/docsource/configuration.md b/docsource/configuration.md new file mode 100644 index 0000000..558ab3b --- /dev/null +++ b/docsource/configuration.md @@ -0,0 +1,102 @@ +## Overview + +HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command: + +* CA Sync: + * Download all certificates issued by connected Enterprise tier CAs in HydrantId (full sync). +* Certificate enrollment for all published HydrantId Certificate SKUs: + * Support certificate enrollment (new keys/certificate). +* Certificate revocation: + * Request revocation of a previously issued certificate. + + +## Requirements + +### 🔐 HydrantID API Key Setup Guide + +This guide explains how to generate and use an API Key ID and Secret in HydrantID for authenticated API access. + +--- + +#### 📍 Where to Find API Key Management + +1. **Log in** to your HydrantID instance. + - Example: https://acm-stage.hydrantid.com + +2. Click your **user profile icon** (top right) and select **"Profile"**. + +3. In the **Profile** page, scroll to the section labeled `API Keys`. + +--- + +#### ➕ Add a New API Key + +1. Click **"ADD API KEY"** (top right of the API Keys section). +2. A new API Key will be generated with: + - A unique **API ID** + - A **Secret API Key** — copy it immediately as it is only shown once. + +--- + +#### 🧾 Notes on API Keys + +- **ID** = what you'll pass in the HAWK `id` field +- **Key** = secret used to generate HAWK signature +- Each key shows `Created` and `Last Used` timestamps for traceability + +--- + +#### 🔐 Using the API ID and Key with HAWK + +HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secure its API. + +##### Required Fields in Authorization Header: +```text +Hawk id="API_ID", ts="TIMESTAMP", nonce="RANDOM", mac="HMAC_SIGNATURE" + + +### Root CA Configuration + +Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from HydrantId, and import them into the appropriate certificate store on the AnyCA Gateway REST server. + +* **Windows** - If the AnyCA Gateway REST is running on a Windows host, the root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. +* **Linux** - If the AnyCA Gateway REST is running on a Linux host, the root CA and applicable subordinate CAs must be present in the root CA certificate store. The location of this store varies per distribution, but is most commonly `/etc/ssl/certs/ca-certificates.crt`. The following is documentation on some popular distributions. + * [Ubuntu - Managing CA certificates](https://ubuntu.com/server/docs/install-a-root-ca-certificate-in-the-trust-store) + * [RHEL 9 - Using shared system certificates](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/securing_networks/using-shared-system-certificates_securing-networks#using-shared-system-certificates_securing-networks) + * [Fedora - Using Shared System Certificates](https://docs.fedoraproject.org/en-US/quick-docs/using-shared-system-certificates/) + +> The root CA and intermediate CAs must be trusted by both the Command server _and_ AnyCA Gateway REST server. + +## Gateway Registration + +The Gateway Registration tab configures the root or issuing CA certificate for the respective CA in GCP CAS. The certificate selected here should be the issuing CA identified in the [Root CA Configuration](#root-ca-configuration) step. + + +## Certificate Template Creation Step + +Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. + +The GCP CAS AnyCA Gateway REST plugin downloads all Certificate Templates in the configured GCP Region/Project and interprets them as 'Product IDs' in the Gateway Portal. + +> For example, if the connected GCP project has the following Certificate Templates: +> +> * `ServerAuth` +> * `ClientAuth` +> +> The `Edit Templates` > `Product ID` dialog dropdown will show the following available 'ProductIDs': +> +> * `Default` -> Don't use a certificate template when enrolling certificates with this Template. +> * `ServerAuth` -> Use the `ServerAuth` certificate template in GCP when enrolling certificates with this Template. +> * `ClientAuth` -> Use the `ClientAuth` certificate template in GCP when enrolling certificates with this Template. + +## Mechanics + +### Enrollment/Renewal/Reissuance + +The GCP CAS AnyCA Gateway REST plugin treats _all_ certificate enrollment as a new enrollment. + +### Synchronization + +The GCP CAS AnyCA Gateway REST plugin uses the [`ListCertificatesRequest` RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.ListCertificatesRequest) when synchronizing certificates from GCP. At the time the latest release, this RPC does not enable granularity to list certificates issued by a particular CA. As such, the CA Synchronization job implemented by the plugin will _always_ download all certificates issued by _any CA_ in the CA Pool. + +> Friendly reminder to always follow the [GCP CAS best practices](https://cloud.google.com/certificate-authority-service/docs/best-practices) From 0f82b9d401ae1d082e823c397bbb97b5854be640 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Mon, 21 Apr 2025 16:20:09 -0400 Subject: [PATCH 16/25] Update keyfactor-starter-workflow.yml --- .github/workflows/keyfactor-starter-workflow.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml index 6d8de53..64919a4 100644 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -11,9 +11,10 @@ on: jobs: call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v2 + uses: keyfactor/actions/.github/workflows/starter.yml@v3 secrets: token: ${{ secrets.V2BUILDTOKEN}} APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} + scan_token: ${{ secrets.SAST_TOKEN }} From 4d09ad4d756c480c95db88a23df314d5dd5459c8 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 16:51:37 -0400 Subject: [PATCH 17/25] updated manifest --- docsource/configuration.md | 102 ------------------------------------- integration-manifest.json | 45 +++++++++++++--- 2 files changed, 39 insertions(+), 108 deletions(-) delete mode 100644 docsource/configuration.md diff --git a/docsource/configuration.md b/docsource/configuration.md deleted file mode 100644 index 558ab3b..0000000 --- a/docsource/configuration.md +++ /dev/null @@ -1,102 +0,0 @@ -## Overview - -HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command: - -* CA Sync: - * Download all certificates issued by connected Enterprise tier CAs in HydrantId (full sync). -* Certificate enrollment for all published HydrantId Certificate SKUs: - * Support certificate enrollment (new keys/certificate). -* Certificate revocation: - * Request revocation of a previously issued certificate. - - -## Requirements - -### 🔐 HydrantID API Key Setup Guide - -This guide explains how to generate and use an API Key ID and Secret in HydrantID for authenticated API access. - ---- - -#### 📍 Where to Find API Key Management - -1. **Log in** to your HydrantID instance. - - Example: https://acm-stage.hydrantid.com - -2. Click your **user profile icon** (top right) and select **"Profile"**. - -3. In the **Profile** page, scroll to the section labeled `API Keys`. - ---- - -#### ➕ Add a New API Key - -1. Click **"ADD API KEY"** (top right of the API Keys section). -2. A new API Key will be generated with: - - A unique **API ID** - - A **Secret API Key** — copy it immediately as it is only shown once. - ---- - -#### 🧾 Notes on API Keys - -- **ID** = what you'll pass in the HAWK `id` field -- **Key** = secret used to generate HAWK signature -- Each key shows `Created` and `Last Used` timestamps for traceability - ---- - -#### 🔐 Using the API ID and Key with HAWK - -HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secure its API. - -##### Required Fields in Authorization Header: -```text -Hawk id="API_ID", ts="TIMESTAMP", nonce="RANDOM", mac="HMAC_SIGNATURE" - - -### Root CA Configuration - -Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from HydrantId, and import them into the appropriate certificate store on the AnyCA Gateway REST server. - -* **Windows** - If the AnyCA Gateway REST is running on a Windows host, the root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. -* **Linux** - If the AnyCA Gateway REST is running on a Linux host, the root CA and applicable subordinate CAs must be present in the root CA certificate store. The location of this store varies per distribution, but is most commonly `/etc/ssl/certs/ca-certificates.crt`. The following is documentation on some popular distributions. - * [Ubuntu - Managing CA certificates](https://ubuntu.com/server/docs/install-a-root-ca-certificate-in-the-trust-store) - * [RHEL 9 - Using shared system certificates](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/securing_networks/using-shared-system-certificates_securing-networks#using-shared-system-certificates_securing-networks) - * [Fedora - Using Shared System Certificates](https://docs.fedoraproject.org/en-US/quick-docs/using-shared-system-certificates/) - -> The root CA and intermediate CAs must be trusted by both the Command server _and_ AnyCA Gateway REST server. - -## Gateway Registration - -The Gateway Registration tab configures the root or issuing CA certificate for the respective CA in GCP CAS. The certificate selected here should be the issuing CA identified in the [Root CA Configuration](#root-ca-configuration) step. - - -## Certificate Template Creation Step - -Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. - -The GCP CAS AnyCA Gateway REST plugin downloads all Certificate Templates in the configured GCP Region/Project and interprets them as 'Product IDs' in the Gateway Portal. - -> For example, if the connected GCP project has the following Certificate Templates: -> -> * `ServerAuth` -> * `ClientAuth` -> -> The `Edit Templates` > `Product ID` dialog dropdown will show the following available 'ProductIDs': -> -> * `Default` -> Don't use a certificate template when enrolling certificates with this Template. -> * `ServerAuth` -> Use the `ServerAuth` certificate template in GCP when enrolling certificates with this Template. -> * `ClientAuth` -> Use the `ClientAuth` certificate template in GCP when enrolling certificates with this Template. - -## Mechanics - -### Enrollment/Renewal/Reissuance - -The GCP CAS AnyCA Gateway REST plugin treats _all_ certificate enrollment as a new enrollment. - -### Synchronization - -The GCP CAS AnyCA Gateway REST plugin uses the [`ListCertificatesRequest` RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.ListCertificatesRequest) when synchronizing certificates from GCP. At the time the latest release, this RPC does not enable granularity to list certificates issued by a particular CA. As such, the CA Synchronization job implemented by the plugin will _always_ download all certificates issued by _any CA_ in the CA Pool. - -> Friendly reminder to always follow the [GCP CAS best practices](https://cloud.google.com/certificate-authority-service/docs/best-practices) diff --git a/integration-manifest.json b/integration-manifest.json index 4cd0beb..fe04bb6 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,11 +1,44 @@ { "$schema": "https://keyfactor.github.io/v2/integration-manifest-schema.json", - "integration_type": "ca-gateway", - "name": "GCP CAS AnyCA Gateway DCOM plugin", + "name": "HydrantId AnyCA REST plugin", + "release_dir": "HydrantCAProxy/bin/Release/net6.0", + "description": "AnyCA Gateway REST plugin that extends HydrantId Certificate Authority Service to Keyfactor Command", "status": "production", - "description": "AnyCA Gateway DCOM plugin that extends Google Cloud Platform Certificate Authority Service to Keyfactor Command", + "integration_type": "anyca-plugin", + "support_level": "kf-supported", "link_github": true, "update_catalog": true, - "support_level": "kf-community", - "release_dir": "src\\GoogleCAProxy\\bin\\Release" -} + "gateway_framework": "24.2", + "about": { + "carest": { + "ca_plugin_config": [ + { + "name": "HydrantIdBaseUrl", + "description": "The Base URL For the HydrantId Endpoint similar to https://acm-stage.hydrantid.com. Get this from HydrantId." + }, + { + "name": "HydrantIdAuthId", + "description": "The AuthId Obtained from HydrantId." + }, + { + "name": "HydrantIdAuthKey", + "description": "The AuthKey Obtained from HydrantId." + } + ], + "enrollment_config": [ + { + "name": "ValidityPeriod", + "description": "The desired lifetime time period could be Days, Months or Years." + }, + { + "name": "ValidityUnits", + "description": "The desired lifetime time value some number indicating days, months or years." + }, + { + "name": "RenewalDays", + "description": "The window that determines whether it is a renewal vs a re-issue." + } + ] + } + } +} \ No newline at end of file From 6855035d07ccc2b0637067ad76e25658817e4d2b Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 16:56:11 -0400 Subject: [PATCH 18/25] readme updates --- integration-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-manifest.json b/integration-manifest.json index fe04bb6..3585c60 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,7 +1,7 @@ { "$schema": "https://keyfactor.github.io/v2/integration-manifest-schema.json", "name": "HydrantId AnyCA REST plugin", - "release_dir": "HydrantCAProxy/bin/Release/net6.0", + "release_dir": "src/HydrantCAProxy/bin/Release/net6.0", "description": "AnyCA Gateway REST plugin that extends HydrantId Certificate Authority Service to Keyfactor Command", "status": "production", "integration_type": "anyca-plugin", From bcea909f0d8eec00bf4c16da7b47cf7b8695bcbc Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 17:01:23 -0400 Subject: [PATCH 19/25] readme updates --- .../workflows/keyfactor-starter-workflow.yml | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 .github/workflows/keyfactor-starter-workflow.yml diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml deleted file mode 100644 index 64919a4..0000000 --- a/.github/workflows/keyfactor-starter-workflow.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Keyfactor Bootstrap Workflow - -on: - workflow_dispatch: - pull_request: - types: [opened, closed, synchronize, edited, reopened] - push: - create: - branches: - - 'release-*.*' - -jobs: - call-starter-workflow: - uses: keyfactor/actions/.github/workflows/starter.yml@v3 - secrets: - token: ${{ secrets.V2BUILDTOKEN}} - APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} - gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} - gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} - scan_token: ${{ secrets.SAST_TOKEN }} From bf6072e38198fdf5311923d8b9590bc868a60862 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 17:02:15 -0400 Subject: [PATCH 20/25] readme updates --- .../workflows/keyfactor-starter-workflow.yml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/keyfactor-starter-workflow.yml diff --git a/.github/workflows/keyfactor-starter-workflow.yml b/.github/workflows/keyfactor-starter-workflow.yml new file mode 100644 index 0000000..64919a4 --- /dev/null +++ b/.github/workflows/keyfactor-starter-workflow.yml @@ -0,0 +1,20 @@ +name: Keyfactor Bootstrap Workflow + +on: + workflow_dispatch: + pull_request: + types: [opened, closed, synchronize, edited, reopened] + push: + create: + branches: + - 'release-*.*' + +jobs: + call-starter-workflow: + uses: keyfactor/actions/.github/workflows/starter.yml@v3 + secrets: + token: ${{ secrets.V2BUILDTOKEN}} + APPROVE_README_PUSH: ${{ secrets.APPROVE_README_PUSH}} + gpg_key: ${{ secrets.KF_GPG_PRIVATE_KEY }} + gpg_pass: ${{ secrets.KF_GPG_PASSPHRASE }} + scan_token: ${{ secrets.SAST_TOKEN }} From 0576cb0eb2158e5b39fac5170f312e0056d09694 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Mon, 21 Apr 2025 17:09:02 -0400 Subject: [PATCH 21/25] readme updates --- docsource/configuration.md | 102 +++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 docsource/configuration.md diff --git a/docsource/configuration.md b/docsource/configuration.md new file mode 100644 index 0000000..b38978a --- /dev/null +++ b/docsource/configuration.md @@ -0,0 +1,102 @@ +## Overview + +HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command: + +* CA Sync: + * Download all certificates issued by connected Enterprise tier CAs in HydrantId (full sync). +* Certificate enrollment for all published HydrantId Certificate SKUs: + * Support certificate enrollment (new keys/certificate). +* Certificate revocation: + * Request revocation of a previously issued certificate. + + +## Requirements + +### 🔐 HydrantID API Key Setup Guide + +This guide explains how to generate and use an API Key ID and Secret in HydrantID for authenticated API access. + +--- + +#### 📍 Where to Find API Key Management + +1. **Log in** to your HydrantID instance. + - Example: https://acm-stage.hydrantid.com + +2. Click your **user profile icon** (top right) and select **"Profile"**. + +3. In the **Profile** page, scroll to the section labeled `API Keys`. + +--- + +#### ➕ Add a New API Key + +1. Click **"ADD API KEY"** (top right of the API Keys section). +2. A new API Key will be generated with: + - A unique **API ID** + - A **Secret API Key** — copy it immediately as it is only shown once. + +--- + +#### 🧾 Notes on API Keys + +- **ID** = what you'll pass in the HAWK `id` field +- **Key** = secret used to generate HAWK signature +- Each key shows `Created` and `Last Used` timestamps for traceability + +--- + +#### 🔐 Using the API ID and Key with HAWK + +HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secure its API. + +##### Required Fields in Authorization Header: +```text +Hawk id="API_ID", ts="TIMESTAMP", nonce="RANDOM", mac="HMAC_SIGNATURE" + + +### Root CA Configuration + +Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from HydrantId, and import them into the appropriate certificate store on the AnyCA Gateway REST server. + +* **Windows** - If the AnyCA Gateway REST is running on a Windows host, the root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. +* **Linux** - If the AnyCA Gateway REST is running on a Linux host, the root CA and applicable subordinate CAs must be present in the root CA certificate store. The location of this store varies per distribution, but is most commonly `/etc/ssl/certs/ca-certificates.crt`. The following is documentation on some popular distributions. + * [Ubuntu - Managing CA certificates](https://ubuntu.com/server/docs/install-a-root-ca-certificate-in-the-trust-store) + * [RHEL 9 - Using shared system certificates](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/securing_networks/using-shared-system-certificates_securing-networks#using-shared-system-certificates_securing-networks) + * [Fedora - Using Shared System Certificates](https://docs.fedoraproject.org/en-US/quick-docs/using-shared-system-certificates/) + +> The root CA and intermediate CAs must be trusted by both the Command server _and_ AnyCA Gateway REST server. + +## Gateway Registration + +The Gateway Registration tab configures the root or issuing CA certificate for the respective CA in HydrantId. The certificate selected here should be the issuing CA identified in the [Root CA Configuration](#root-ca-configuration) step. + + +## Certificate Template Creation Step + +Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. + +The GCP CAS AnyCA Gateway REST plugin downloads all Certificate Templates in the configured GCP Region/Project and interprets them as 'Product IDs' in the Gateway Portal. + +> For example, if the connected GCP project has the following Certificate Templates: +> +> * `ServerAuth` +> * `ClientAuth` +> +> The `Edit Templates` > `Product ID` dialog dropdown will show the following available 'ProductIDs': +> +> * `Default` -> Don't use a certificate template when enrolling certificates with this Template. +> * `ServerAuth` -> Use the `ServerAuth` certificate template in GCP when enrolling certificates with this Template. +> * `ClientAuth` -> Use the `ClientAuth` certificate template in GCP when enrolling certificates with this Template. + +## Mechanics + +### Enrollment/Renewal/Reissuance + +The GCP CAS AnyCA Gateway REST plugin treats _all_ certificate enrollment as a new enrollment. + +### Synchronization + +The GCP CAS AnyCA Gateway REST plugin uses the [`ListCertificatesRequest` RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.ListCertificatesRequest) when synchronizing certificates from GCP. At the time the latest release, this RPC does not enable granularity to list certificates issued by a particular CA. As such, the CA Synchronization job implemented by the plugin will _always_ download all certificates issued by _any CA_ in the CA Pool. + +> Friendly reminder to always follow the [GCP CAS best practices](https://cloud.google.com/certificate-authority-service/docs/best-practices) From 53bdd00b66f772d5f1667de03c2c714e72424a15 Mon Sep 17 00:00:00 2001 From: Brian Hill Date: Tue, 22 Apr 2025 09:17:59 -0400 Subject: [PATCH 22/25] checkpoint --- {src/HydrantCAProxy => HydrantCAProxy}/App.config | 0 .../Client/Authentication/Hawk.cs | 0 .../Client/Authentication/HawkCredential.cs | 0 .../Client/Authentication/HttpWebRequestExtensions.cs | 0 .../Client/Authentication/LICENSE | 0 .../HydrantCAProxy => HydrantCAProxy}/Client/HydrantIdClient.cs | 0 .../Client/Models/CertRequest.cs | 0 .../Client/Models/CertRequestBody.cs | 0 .../Client/Models/CertRequestBodyDnComponents.cs | 0 .../Client/Models/CertRequestBodySubjectAltNames.cs | 0 .../Client/Models/CertRequestBodyValidity.cs | 0 .../Client/Models/CertRequestPolicy.cs | 0 .../Client/Models/CertRequestResult.cs | 0 .../Client/Models/CertRequestStatus.cs | 0 .../Client/Models/CertRequestUser.cs | 0 .../Client/Models/Certificate.cs | 0 .../Client/Models/CertificateStatus.cs | 0 .../Client/Models/CertificateUser.cs | 0 .../Client/Models/Enums/IssuanceStatus.cs | 0 .../Client/Models/Enums/RevocationReasons.cs | 0 .../Client/Models/Enums/RevocationStatusEnum.cs | 0 .../Client/Models/Enums/SortDirectionEnum.cs | 0 .../Client/Models/ErrorReturn.cs | 0 .../Client/Models/GetCertificatesPayload.cs | 0 .../Client/Models/GetCertificatesResponse.cs | 0 .../Client/Models/GetCertificatesResponseItem.cs | 0 .../Client/Models/NameObject.cs | 0 {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Policy.cs | 0 .../Client/Models/PolicyDetails.cs | 0 .../Client/Models/PolicyDetailsCustomExtensions.cs | 0 .../Client/Models/PolicyDetailsCustomFields.cs | 0 .../Client/Models/PolicyDetailsDnComponents.cs | 0 .../Client/Models/PolicyDetailsExpiryEmails.cs | 0 .../Client/Models/PolicyDetailsSubjectAltNames.cs | 0 .../Client/Models/PolicyDetailsValidity.cs | 0 .../Client/Models/PolicyEnabled.cs | 0 .../Client/Models/RenewalRequest.cs | 0 .../Client/Models/RevokeCertificateReason.cs | 0 .../Client/Models/RevokeCertificateReasonIssuerDN.cs | 0 .../Client/Models/TagEnumConverter.cs | 0 .../Exceptions/RetryCountExceededException.cs | 0 .../Exceptions/RevokeReasonNotSupportedException.cs | 0 {src/HydrantCAProxy => HydrantCAProxy}/HydrantIdCAPlugin.cs | 0 {src/HydrantCAProxy => HydrantCAProxy}/HydrantIdCAPlugin.csproj | 0 .../HydrantIdCAPluginConfig.cs | 0 .../Interfaces/ICertRequest.cs | 0 .../Interfaces/ICertRequestBody.cs | 0 .../Interfaces/ICertRequestBodyDnComponents.cs | 0 .../Interfaces/ICertRequestBodySubjectAltNames.cs | 0 .../Interfaces/ICertRequestBodyValidity.cs | 0 .../Interfaces/ICertRequestPolicy.cs | 0 .../Interfaces/ICertRequestResult.cs | 0 .../Interfaces/ICertRequestStatus.cs | 0 .../Interfaces/ICertRequestUser.cs | 0 .../Interfaces/ICertificate.cs | 0 .../Interfaces/ICertificateStatus.cs | 0 .../Interfaces/ICertificateUser.cs | 0 .../Interfaces/ICertificatesPayload.cs | 0 .../Interfaces/ICertificatesResponse.cs | 0 .../Interfaces/ICertificatesResponseItem.cs | 0 .../Interfaces/IErrorReturn.cs | 0 .../Interfaces/IHawkCredential.cs | 0 .../Interfaces/IHawkCredentialComment.cs | 0 .../Interfaces/IHawkCredentialComments.cs | 0 .../Interfaces/IHawkCredentialDeleteResults.cs | 0 .../HydrantCAProxy => HydrantCAProxy}/Interfaces/INameObject.cs | 0 {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicy.cs | 0 .../Interfaces/IPolicyDetails.cs | 0 .../Interfaces/IPolicyDetailsCustomExtensions.cs | 0 .../Interfaces/IPolicyDetailsCustomFields.cs | 0 .../Interfaces/IPolicyDetailsDnComponents.cs | 0 .../Interfaces/IPolicyDetailsExpiryEmails.cs | 0 .../Interfaces/IPolicyDetailsSubjectAltNames.cs | 0 .../Interfaces/IPolicyDetailsValidity.cs | 0 .../Interfaces/IPolicyEnabled.cs | 0 .../Interfaces/IRenewalRequest.cs | 0 .../Interfaces/IRenewalResponse.cs | 0 .../Interfaces/IRevokeCertificateReason.cs | 0 .../Interfaces/IRevokeCertificateReasonIssuerDn.cs | 0 .../Properties/AssemblyInfo.cs | 0 {src/HydrantCAProxy => HydrantCAProxy}/RequestManager.cs | 0 {src/HydrantCAProxy => HydrantCAProxy}/manifest.json | 0 src/HydrantCAProxy/HydrantIdCAProxy.sln => HydrantIdCAProxy.sln | 2 +- integration-manifest.json | 2 +- 84 files changed, 2 insertions(+), 2 deletions(-) rename {src/HydrantCAProxy => HydrantCAProxy}/App.config (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Authentication/Hawk.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Authentication/HawkCredential.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Authentication/HttpWebRequestExtensions.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Authentication/LICENSE (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/HydrantIdClient.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequest.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestBody.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestBodyDnComponents.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestBodySubjectAltNames.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestBodyValidity.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestPolicy.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestResult.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestStatus.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertRequestUser.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Certificate.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertificateStatus.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/CertificateUser.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Enums/IssuanceStatus.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Enums/RevocationReasons.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Enums/RevocationStatusEnum.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Enums/SortDirectionEnum.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/ErrorReturn.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/GetCertificatesPayload.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/GetCertificatesResponse.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/GetCertificatesResponseItem.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/NameObject.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/Policy.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetails.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetailsCustomExtensions.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetailsCustomFields.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetailsDnComponents.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetailsExpiryEmails.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetailsSubjectAltNames.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyDetailsValidity.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/PolicyEnabled.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/RenewalRequest.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/RevokeCertificateReason.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/RevokeCertificateReasonIssuerDN.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Client/Models/TagEnumConverter.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Exceptions/RetryCountExceededException.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Exceptions/RevokeReasonNotSupportedException.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/HydrantIdCAPlugin.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/HydrantIdCAPlugin.csproj (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/HydrantIdCAPluginConfig.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequest.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestBody.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestBodyDnComponents.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestBodySubjectAltNames.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestBodyValidity.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestPolicy.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestResult.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestStatus.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertRequestUser.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertificate.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertificateStatus.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertificateUser.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertificatesPayload.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertificatesResponse.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/ICertificatesResponseItem.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IErrorReturn.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IHawkCredential.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IHawkCredentialComment.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IHawkCredentialComments.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IHawkCredentialDeleteResults.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/INameObject.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicy.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetails.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetailsCustomExtensions.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetailsCustomFields.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetailsDnComponents.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetailsExpiryEmails.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetailsSubjectAltNames.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyDetailsValidity.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IPolicyEnabled.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IRenewalRequest.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IRenewalResponse.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IRevokeCertificateReason.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Interfaces/IRevokeCertificateReasonIssuerDn.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/Properties/AssemblyInfo.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/RequestManager.cs (100%) rename {src/HydrantCAProxy => HydrantCAProxy}/manifest.json (100%) rename src/HydrantCAProxy/HydrantIdCAProxy.sln => HydrantIdCAProxy.sln (93%) diff --git a/src/HydrantCAProxy/App.config b/HydrantCAProxy/App.config similarity index 100% rename from src/HydrantCAProxy/App.config rename to HydrantCAProxy/App.config diff --git a/src/HydrantCAProxy/Client/Authentication/Hawk.cs b/HydrantCAProxy/Client/Authentication/Hawk.cs similarity index 100% rename from src/HydrantCAProxy/Client/Authentication/Hawk.cs rename to HydrantCAProxy/Client/Authentication/Hawk.cs diff --git a/src/HydrantCAProxy/Client/Authentication/HawkCredential.cs b/HydrantCAProxy/Client/Authentication/HawkCredential.cs similarity index 100% rename from src/HydrantCAProxy/Client/Authentication/HawkCredential.cs rename to HydrantCAProxy/Client/Authentication/HawkCredential.cs diff --git a/src/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs b/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs similarity index 100% rename from src/HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs rename to HydrantCAProxy/Client/Authentication/HttpWebRequestExtensions.cs diff --git a/src/HydrantCAProxy/Client/Authentication/LICENSE b/HydrantCAProxy/Client/Authentication/LICENSE similarity index 100% rename from src/HydrantCAProxy/Client/Authentication/LICENSE rename to HydrantCAProxy/Client/Authentication/LICENSE diff --git a/src/HydrantCAProxy/Client/HydrantIdClient.cs b/HydrantCAProxy/Client/HydrantIdClient.cs similarity index 100% rename from src/HydrantCAProxy/Client/HydrantIdClient.cs rename to HydrantCAProxy/Client/HydrantIdClient.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequest.cs b/HydrantCAProxy/Client/Models/CertRequest.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequest.cs rename to HydrantCAProxy/Client/Models/CertRequest.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestBody.cs b/HydrantCAProxy/Client/Models/CertRequestBody.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestBody.cs rename to HydrantCAProxy/Client/Models/CertRequestBody.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs b/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs rename to HydrantCAProxy/Client/Models/CertRequestBodyDnComponents.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestBodySubjectAltNames.cs b/HydrantCAProxy/Client/Models/CertRequestBodySubjectAltNames.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestBodySubjectAltNames.cs rename to HydrantCAProxy/Client/Models/CertRequestBodySubjectAltNames.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestBodyValidity.cs b/HydrantCAProxy/Client/Models/CertRequestBodyValidity.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestBodyValidity.cs rename to HydrantCAProxy/Client/Models/CertRequestBodyValidity.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestPolicy.cs b/HydrantCAProxy/Client/Models/CertRequestPolicy.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestPolicy.cs rename to HydrantCAProxy/Client/Models/CertRequestPolicy.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestResult.cs b/HydrantCAProxy/Client/Models/CertRequestResult.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestResult.cs rename to HydrantCAProxy/Client/Models/CertRequestResult.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestStatus.cs b/HydrantCAProxy/Client/Models/CertRequestStatus.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestStatus.cs rename to HydrantCAProxy/Client/Models/CertRequestStatus.cs diff --git a/src/HydrantCAProxy/Client/Models/CertRequestUser.cs b/HydrantCAProxy/Client/Models/CertRequestUser.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertRequestUser.cs rename to HydrantCAProxy/Client/Models/CertRequestUser.cs diff --git a/src/HydrantCAProxy/Client/Models/Certificate.cs b/HydrantCAProxy/Client/Models/Certificate.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/Certificate.cs rename to HydrantCAProxy/Client/Models/Certificate.cs diff --git a/src/HydrantCAProxy/Client/Models/CertificateStatus.cs b/HydrantCAProxy/Client/Models/CertificateStatus.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertificateStatus.cs rename to HydrantCAProxy/Client/Models/CertificateStatus.cs diff --git a/src/HydrantCAProxy/Client/Models/CertificateUser.cs b/HydrantCAProxy/Client/Models/CertificateUser.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/CertificateUser.cs rename to HydrantCAProxy/Client/Models/CertificateUser.cs diff --git a/src/HydrantCAProxy/Client/Models/Enums/IssuanceStatus.cs b/HydrantCAProxy/Client/Models/Enums/IssuanceStatus.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/Enums/IssuanceStatus.cs rename to HydrantCAProxy/Client/Models/Enums/IssuanceStatus.cs diff --git a/src/HydrantCAProxy/Client/Models/Enums/RevocationReasons.cs b/HydrantCAProxy/Client/Models/Enums/RevocationReasons.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/Enums/RevocationReasons.cs rename to HydrantCAProxy/Client/Models/Enums/RevocationReasons.cs diff --git a/src/HydrantCAProxy/Client/Models/Enums/RevocationStatusEnum.cs b/HydrantCAProxy/Client/Models/Enums/RevocationStatusEnum.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/Enums/RevocationStatusEnum.cs rename to HydrantCAProxy/Client/Models/Enums/RevocationStatusEnum.cs diff --git a/src/HydrantCAProxy/Client/Models/Enums/SortDirectionEnum.cs b/HydrantCAProxy/Client/Models/Enums/SortDirectionEnum.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/Enums/SortDirectionEnum.cs rename to HydrantCAProxy/Client/Models/Enums/SortDirectionEnum.cs diff --git a/src/HydrantCAProxy/Client/Models/ErrorReturn.cs b/HydrantCAProxy/Client/Models/ErrorReturn.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/ErrorReturn.cs rename to HydrantCAProxy/Client/Models/ErrorReturn.cs diff --git a/src/HydrantCAProxy/Client/Models/GetCertificatesPayload.cs b/HydrantCAProxy/Client/Models/GetCertificatesPayload.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/GetCertificatesPayload.cs rename to HydrantCAProxy/Client/Models/GetCertificatesPayload.cs diff --git a/src/HydrantCAProxy/Client/Models/GetCertificatesResponse.cs b/HydrantCAProxy/Client/Models/GetCertificatesResponse.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/GetCertificatesResponse.cs rename to HydrantCAProxy/Client/Models/GetCertificatesResponse.cs diff --git a/src/HydrantCAProxy/Client/Models/GetCertificatesResponseItem.cs b/HydrantCAProxy/Client/Models/GetCertificatesResponseItem.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/GetCertificatesResponseItem.cs rename to HydrantCAProxy/Client/Models/GetCertificatesResponseItem.cs diff --git a/src/HydrantCAProxy/Client/Models/NameObject.cs b/HydrantCAProxy/Client/Models/NameObject.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/NameObject.cs rename to HydrantCAProxy/Client/Models/NameObject.cs diff --git a/src/HydrantCAProxy/Client/Models/Policy.cs b/HydrantCAProxy/Client/Models/Policy.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/Policy.cs rename to HydrantCAProxy/Client/Models/Policy.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetails.cs b/HydrantCAProxy/Client/Models/PolicyDetails.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetails.cs rename to HydrantCAProxy/Client/Models/PolicyDetails.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsCustomExtensions.cs b/HydrantCAProxy/Client/Models/PolicyDetailsCustomExtensions.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetailsCustomExtensions.cs rename to HydrantCAProxy/Client/Models/PolicyDetailsCustomExtensions.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsCustomFields.cs b/HydrantCAProxy/Client/Models/PolicyDetailsCustomFields.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetailsCustomFields.cs rename to HydrantCAProxy/Client/Models/PolicyDetailsCustomFields.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs b/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs rename to HydrantCAProxy/Client/Models/PolicyDetailsDnComponents.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsExpiryEmails.cs b/HydrantCAProxy/Client/Models/PolicyDetailsExpiryEmails.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetailsExpiryEmails.cs rename to HydrantCAProxy/Client/Models/PolicyDetailsExpiryEmails.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs b/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs rename to HydrantCAProxy/Client/Models/PolicyDetailsSubjectAltNames.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyDetailsValidity.cs b/HydrantCAProxy/Client/Models/PolicyDetailsValidity.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyDetailsValidity.cs rename to HydrantCAProxy/Client/Models/PolicyDetailsValidity.cs diff --git a/src/HydrantCAProxy/Client/Models/PolicyEnabled.cs b/HydrantCAProxy/Client/Models/PolicyEnabled.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/PolicyEnabled.cs rename to HydrantCAProxy/Client/Models/PolicyEnabled.cs diff --git a/src/HydrantCAProxy/Client/Models/RenewalRequest.cs b/HydrantCAProxy/Client/Models/RenewalRequest.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/RenewalRequest.cs rename to HydrantCAProxy/Client/Models/RenewalRequest.cs diff --git a/src/HydrantCAProxy/Client/Models/RevokeCertificateReason.cs b/HydrantCAProxy/Client/Models/RevokeCertificateReason.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/RevokeCertificateReason.cs rename to HydrantCAProxy/Client/Models/RevokeCertificateReason.cs diff --git a/src/HydrantCAProxy/Client/Models/RevokeCertificateReasonIssuerDN.cs b/HydrantCAProxy/Client/Models/RevokeCertificateReasonIssuerDN.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/RevokeCertificateReasonIssuerDN.cs rename to HydrantCAProxy/Client/Models/RevokeCertificateReasonIssuerDN.cs diff --git a/src/HydrantCAProxy/Client/Models/TagEnumConverter.cs b/HydrantCAProxy/Client/Models/TagEnumConverter.cs similarity index 100% rename from src/HydrantCAProxy/Client/Models/TagEnumConverter.cs rename to HydrantCAProxy/Client/Models/TagEnumConverter.cs diff --git a/src/HydrantCAProxy/Exceptions/RetryCountExceededException.cs b/HydrantCAProxy/Exceptions/RetryCountExceededException.cs similarity index 100% rename from src/HydrantCAProxy/Exceptions/RetryCountExceededException.cs rename to HydrantCAProxy/Exceptions/RetryCountExceededException.cs diff --git a/src/HydrantCAProxy/Exceptions/RevokeReasonNotSupportedException.cs b/HydrantCAProxy/Exceptions/RevokeReasonNotSupportedException.cs similarity index 100% rename from src/HydrantCAProxy/Exceptions/RevokeReasonNotSupportedException.cs rename to HydrantCAProxy/Exceptions/RevokeReasonNotSupportedException.cs diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.cs b/HydrantCAProxy/HydrantIdCAPlugin.cs similarity index 100% rename from src/HydrantCAProxy/HydrantIdCAPlugin.cs rename to HydrantCAProxy/HydrantIdCAPlugin.cs diff --git a/src/HydrantCAProxy/HydrantIdCAPlugin.csproj b/HydrantCAProxy/HydrantIdCAPlugin.csproj similarity index 100% rename from src/HydrantCAProxy/HydrantIdCAPlugin.csproj rename to HydrantCAProxy/HydrantIdCAPlugin.csproj diff --git a/src/HydrantCAProxy/HydrantIdCAPluginConfig.cs b/HydrantCAProxy/HydrantIdCAPluginConfig.cs similarity index 100% rename from src/HydrantCAProxy/HydrantIdCAPluginConfig.cs rename to HydrantCAProxy/HydrantIdCAPluginConfig.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequest.cs b/HydrantCAProxy/Interfaces/ICertRequest.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequest.cs rename to HydrantCAProxy/Interfaces/ICertRequest.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestBody.cs b/HydrantCAProxy/Interfaces/ICertRequestBody.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestBody.cs rename to HydrantCAProxy/Interfaces/ICertRequestBody.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs b/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs rename to HydrantCAProxy/Interfaces/ICertRequestBodyDnComponents.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs b/HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs rename to HydrantCAProxy/Interfaces/ICertRequestBodySubjectAltNames.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs b/HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs rename to HydrantCAProxy/Interfaces/ICertRequestBodyValidity.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestPolicy.cs b/HydrantCAProxy/Interfaces/ICertRequestPolicy.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestPolicy.cs rename to HydrantCAProxy/Interfaces/ICertRequestPolicy.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestResult.cs b/HydrantCAProxy/Interfaces/ICertRequestResult.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestResult.cs rename to HydrantCAProxy/Interfaces/ICertRequestResult.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestStatus.cs b/HydrantCAProxy/Interfaces/ICertRequestStatus.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestStatus.cs rename to HydrantCAProxy/Interfaces/ICertRequestStatus.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertRequestUser.cs b/HydrantCAProxy/Interfaces/ICertRequestUser.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertRequestUser.cs rename to HydrantCAProxy/Interfaces/ICertRequestUser.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertificate.cs b/HydrantCAProxy/Interfaces/ICertificate.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertificate.cs rename to HydrantCAProxy/Interfaces/ICertificate.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertificateStatus.cs b/HydrantCAProxy/Interfaces/ICertificateStatus.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertificateStatus.cs rename to HydrantCAProxy/Interfaces/ICertificateStatus.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertificateUser.cs b/HydrantCAProxy/Interfaces/ICertificateUser.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertificateUser.cs rename to HydrantCAProxy/Interfaces/ICertificateUser.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertificatesPayload.cs b/HydrantCAProxy/Interfaces/ICertificatesPayload.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertificatesPayload.cs rename to HydrantCAProxy/Interfaces/ICertificatesPayload.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertificatesResponse.cs b/HydrantCAProxy/Interfaces/ICertificatesResponse.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertificatesResponse.cs rename to HydrantCAProxy/Interfaces/ICertificatesResponse.cs diff --git a/src/HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs b/HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs rename to HydrantCAProxy/Interfaces/ICertificatesResponseItem.cs diff --git a/src/HydrantCAProxy/Interfaces/IErrorReturn.cs b/HydrantCAProxy/Interfaces/IErrorReturn.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IErrorReturn.cs rename to HydrantCAProxy/Interfaces/IErrorReturn.cs diff --git a/src/HydrantCAProxy/Interfaces/IHawkCredential.cs b/HydrantCAProxy/Interfaces/IHawkCredential.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IHawkCredential.cs rename to HydrantCAProxy/Interfaces/IHawkCredential.cs diff --git a/src/HydrantCAProxy/Interfaces/IHawkCredentialComment.cs b/HydrantCAProxy/Interfaces/IHawkCredentialComment.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IHawkCredentialComment.cs rename to HydrantCAProxy/Interfaces/IHawkCredentialComment.cs diff --git a/src/HydrantCAProxy/Interfaces/IHawkCredentialComments.cs b/HydrantCAProxy/Interfaces/IHawkCredentialComments.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IHawkCredentialComments.cs rename to HydrantCAProxy/Interfaces/IHawkCredentialComments.cs diff --git a/src/HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs b/HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs rename to HydrantCAProxy/Interfaces/IHawkCredentialDeleteResults.cs diff --git a/src/HydrantCAProxy/Interfaces/INameObject.cs b/HydrantCAProxy/Interfaces/INameObject.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/INameObject.cs rename to HydrantCAProxy/Interfaces/INameObject.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicy.cs b/HydrantCAProxy/Interfaces/IPolicy.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicy.cs rename to HydrantCAProxy/Interfaces/IPolicy.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetails.cs b/HydrantCAProxy/Interfaces/IPolicyDetails.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetails.cs rename to HydrantCAProxy/Interfaces/IPolicyDetails.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs b/HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs rename to HydrantCAProxy/Interfaces/IPolicyDetailsCustomExtensions.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs b/HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs rename to HydrantCAProxy/Interfaces/IPolicyDetailsCustomFields.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs b/HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs rename to HydrantCAProxy/Interfaces/IPolicyDetailsDnComponents.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs b/HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs rename to HydrantCAProxy/Interfaces/IPolicyDetailsExpiryEmails.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs b/HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs rename to HydrantCAProxy/Interfaces/IPolicyDetailsSubjectAltNames.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs b/HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs rename to HydrantCAProxy/Interfaces/IPolicyDetailsValidity.cs diff --git a/src/HydrantCAProxy/Interfaces/IPolicyEnabled.cs b/HydrantCAProxy/Interfaces/IPolicyEnabled.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IPolicyEnabled.cs rename to HydrantCAProxy/Interfaces/IPolicyEnabled.cs diff --git a/src/HydrantCAProxy/Interfaces/IRenewalRequest.cs b/HydrantCAProxy/Interfaces/IRenewalRequest.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IRenewalRequest.cs rename to HydrantCAProxy/Interfaces/IRenewalRequest.cs diff --git a/src/HydrantCAProxy/Interfaces/IRenewalResponse.cs b/HydrantCAProxy/Interfaces/IRenewalResponse.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IRenewalResponse.cs rename to HydrantCAProxy/Interfaces/IRenewalResponse.cs diff --git a/src/HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs b/HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs rename to HydrantCAProxy/Interfaces/IRevokeCertificateReason.cs diff --git a/src/HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs b/HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs similarity index 100% rename from src/HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs rename to HydrantCAProxy/Interfaces/IRevokeCertificateReasonIssuerDn.cs diff --git a/src/HydrantCAProxy/Properties/AssemblyInfo.cs b/HydrantCAProxy/Properties/AssemblyInfo.cs similarity index 100% rename from src/HydrantCAProxy/Properties/AssemblyInfo.cs rename to HydrantCAProxy/Properties/AssemblyInfo.cs diff --git a/src/HydrantCAProxy/RequestManager.cs b/HydrantCAProxy/RequestManager.cs similarity index 100% rename from src/HydrantCAProxy/RequestManager.cs rename to HydrantCAProxy/RequestManager.cs diff --git a/src/HydrantCAProxy/manifest.json b/HydrantCAProxy/manifest.json similarity index 100% rename from src/HydrantCAProxy/manifest.json rename to HydrantCAProxy/manifest.json diff --git a/src/HydrantCAProxy/HydrantIdCAProxy.sln b/HydrantIdCAProxy.sln similarity index 93% rename from src/HydrantCAProxy/HydrantIdCAProxy.sln rename to HydrantIdCAProxy.sln index cb0f624..46f79f6 100644 --- a/src/HydrantCAProxy/HydrantIdCAProxy.sln +++ b/HydrantIdCAProxy.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.10.35027.167 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HydrantIdCAPlugin", "HydrantIdCAPlugin.csproj", "{011DC646-BEF9-4D3B-9D20-CA444A26B355}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HydrantIdCAPlugin", "HydrantCAProxy\HydrantIdCAPlugin.csproj", "{011DC646-BEF9-4D3B-9D20-CA444A26B355}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5505EA55-BEBD-4DBC-9ED2-448CFB9BCD37}" ProjectSection(SolutionItems) = preProject diff --git a/integration-manifest.json b/integration-manifest.json index 3585c60..fe04bb6 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -1,7 +1,7 @@ { "$schema": "https://keyfactor.github.io/v2/integration-manifest-schema.json", "name": "HydrantId AnyCA REST plugin", - "release_dir": "src/HydrantCAProxy/bin/Release/net6.0", + "release_dir": "HydrantCAProxy/bin/Release/net6.0", "description": "AnyCA Gateway REST plugin that extends HydrantId Certificate Authority Service to Keyfactor Command", "status": "production", "integration_type": "anyca-plugin", From bd4e137ad58bdbe7f2d7c03b364f5e97656ef632 Mon Sep 17 00:00:00 2001 From: Keyfactor Date: Tue, 22 Apr 2025 13:19:29 +0000 Subject: [PATCH 23/25] Update generated docs --- README.md | 329 ++++++++++++++------------------------ integration-manifest.json | 6 +- 2 files changed, 123 insertions(+), 212 deletions(-) diff --git a/README.md b/README.md index 43a49cc..58e4ac1 100644 --- a/README.md +++ b/README.md @@ -1,265 +1,176 @@ +

+ HydrantId AnyCA Gateway REST Plugin +

+ +

+ +Integration Status: production +Release +Issues +GitHub Downloads (all assets, all releases) +

+ +

+ + + Support + + · + + Requirements + + · + + Installation + + · + + License + + · + + Related Integrations + +

+ + +HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command: -# GCP CAS AnyCA Gateway DCOM plugin +* CA Sync: + * Download all certificates issued by connected Enterprise tier CAs in HydrantId (full sync). +* Certificate enrollment for all published HydrantId Certificate SKUs: + * Support certificate enrollment (new keys/certificate). +* Certificate revocation: + * Request revocation of a previously issued certificate. -AnyCA Gateway DCOM plugin that extends Google Cloud Platform Certificate Authority Service to Keyfactor Command +## Compatibility -#### Integration status: Production - Ready for use in production environments. +The HydrantId AnyCA Gateway REST plugin is compatible with the Keyfactor AnyCA Gateway REST 24.2 and later. -## About the Keyfactor AnyCA Gateway DCOM Connector +## Support +The HydrantId AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor customers. If you have a support issue, please open a support ticket with your Keyfactor representative. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com. -This repository contains an AnyCA Gateway Connector, which is a plugin to the Keyfactor AnyGateway. AnyCA Gateway Connectors allow Keyfactor Command to be used for inventory, issuance, and revocation of certificates from a third-party certificate authority. +> To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. -## Support for GCP CAS AnyCA Gateway DCOM plugin +## Requirements -GCP CAS AnyCA Gateway DCOM plugin is open source and supported on best effort level for this tool/library/client. This means customers can report Bugs, Feature Requests, Documentation amendment or questions as well as requests for customer information required for setup that needs Keyfactor access to obtain. Such requests do not follow normal SLA commitments for response or resolution. If you have a support issue, please open a support ticket via the Keyfactor Support Portal at https://support.keyfactor.com/ +### 🔐 HydrantID API Key Setup Guide -###### To report a problem or suggest a new feature, use the **[Issues](../../issues)** tab. If you want to contribute actual bug fixes or proposed enhancements, use the **[Pull requests](../../pulls)** tab. +This guide explains how to generate and use an API Key ID and Secret in HydrantID for authenticated API access. --- +#### 📍 Where to Find API Key Management ---- - - - - - -## Keyfactor AnyCA Gateway Framework Supported -The Keyfactor gateway framework implements common logic shared across various gateway implementations and handles communication with Keyfactor Command. The gateway framework hosts gateway implementations or plugins that understand how to communicate with specific CAs. This allows you to integrate your third-party CAs with Keyfactor Command such that they behave in a manner similar to the CAs natively supported by Keyfactor Command. - - - +1. **Log in** to your HydrantID instance. + - Example: https://acm-stage.hydrantid.com -This gateway extension was compiled against version of the AnyCA Gateway DCOM Framework. You will need at least this version of the framework Installed. If you have a later AnyGateway Framework Installed you will probably need to add binding redirects in the CAProxyServer.exe.config file to make things work properly. +2. Click your **user profile icon** (top right) and select **"Profile"**. +3. In the **Profile** page, scroll to the section labeled `API Keys`. -[Keyfactor CAGateway Install Guide](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm) +--- +#### ➕ Add a New API Key +1. Click **"ADD API KEY"** (top right of the API Keys section). +2. A new API Key will be generated with: + - A unique **API ID** + - A **Secret API Key** — copy it immediately as it is only shown once. --- +#### 🧾 Notes on API Keys -## Overview - -The [Google Cloud Platform (GCP) CA Services (CAS)](https://cloud.google.com/security/products/certificate-authority-service) AnyCA Gateway DCOM plugin extends the capabilities of connected GCP CAS CAs to [Keyfactor Command](https://www.keyfactor.com/products/command/) via the Keyfactor AnyCA Gateway DCOM. The plugin represents a fully featured AnyCA DCOM Plugin with the following capabilies: +- **ID** = what you'll pass in the HAWK `id` field +- **Key** = secret used to generate HAWK signature +- Each key shows `Created` and `Last Used` timestamps for traceability -* CA Sync: - * Download all certificates issued by connected Enterprise tier CAs in GCP CAS (full sync). - * Download all certificates issued by connected Enterprise tier CAs in GCP CAS issued after a specified time (incremental sync). -* Certificate enrollment for all published GoDaddy Certificate SKUs: - * Support certificate enrollment (new keys/certificate). -* Certificate revocation: - * Request revocation of a previously issued certificate. +--- -> The GCP CAS AnyCA Gateway DCOM plugin is **not** supported for [DevOps Tier](https://cloud.google.com/certificate-authority-service/docs/tiers) Certificate Authority Pools. -> -> DevOps tier CA Pools don't offer listing, describing, or revoking certificates. +#### 🔐 Using the API ID and Key with HAWK -## Compatibility +HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secure its API. -This AnyGateway is designed to be used with version 24.2 of the Keyfactor AnyCA Gateway DCOM Framework. +##### Required Fields in Authorization Header: +```text +Hawk id="API_ID", ts="TIMESTAMP", nonce="RANDOM", mac="HMAC_SIGNATURE" -## Requirements +### Root CA Configuration -### Application Default Credentials +Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from HydrantId, and import them into the appropriate certificate store on the AnyCA Gateway REST server. -The GCP CAS AnyCA Gateway DCOM plugin connects to and authenticates with GCP CAS implicitly using [Application Default Credentials](https://cloud.google.com/docs/authentication/application-default-credentials). This means that all authentication-related configuration of the GCP CAS AnyCA Gateway REST plugin is implied by the environment where the AnyCA Gateway REST itself is running. +* **Windows** - If the AnyCA Gateway REST is running on a Windows host, the root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. +* **Linux** - If the AnyCA Gateway REST is running on a Linux host, the root CA and applicable subordinate CAs must be present in the root CA certificate store. The location of this store varies per distribution, but is most commonly `/etc/ssl/certs/ca-certificates.crt`. The following is documentation on some popular distributions. + * [Ubuntu - Managing CA certificates](https://ubuntu.com/server/docs/install-a-root-ca-certificate-in-the-trust-store) + * [RHEL 9 - Using shared system certificates](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/securing_networks/using-shared-system-certificates_securing-networks#using-shared-system-certificates_securing-networks) + * [Fedora - Using Shared System Certificates](https://docs.fedoraproject.org/en-US/quick-docs/using-shared-system-certificates/) -Please refer to [Google's documentation](https://cloud.google.com/docs/authentication/provide-credentials-adc) to configure ADC on the server running the AnyCA Gateway REST. +> The root CA and intermediate CAs must be trusted by both the Command server _and_ AnyCA Gateway REST server. -> The easiest way to configure ADC for non-production environments is to use [User Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc#local-dev). -> -> For production environments that use an ADC method requiring the `GOOGLE_APPLICATION_CREDENTIALS` environment variable, you must ensure the following: -> -> 1. The service account that the AnyCA Gateway REST runs under must have read permission to the GCP credential JSON file. -> 2. You must set the `GOOGLE_APPLICATION_CREDENTIALS` environment variable for the Windows Service running the AnyCA Gateway REST using the [Windows registry editor](https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/windows-registry-advanced-users). -> * Refer to the [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment](https://learn.microsoft.com/en-us/windows/win32/procthread/environment-variables) docs. +## Installation -If the selected ADC mechanism is [Service Account Key](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif-key), it's recommended that a [custom role is created](https://cloud.google.com/iam/docs/creating-custom-roles) that has the following minimum permissions: +1. Install the AnyCA Gateway REST per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/InstallIntroduction.htm). -* `privateca.certificateTemplates.list` -* `privateca.certificateTemplates.use` -* `privateca.certificateAuthorities.get` -* `privateca.certificates.create` -* `privateca.certificates.get` -* `privateca.certificates.list` -* `privateca.certificates.update` -* `privateca.caPools.get` +2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [HydrantId AnyCA Gateway REST plugin](https://github.com/Keyfactor/hydrantid-cagateway/releases/latest) from GitHub. -> The built-in CA Service Operation Manager `roles/privateca.caManager` role can also be used, but is more permissive than a custom role with the above permissions. +3. Copy the unzipped directory (usually called `net6.0`) to the Extensions directory: -### Root CA Configuration + ```shell + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + ``` -Both the Keyfactor Command and AnyCA Gateway DCOM servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from GCP [CAS](https://console.cloud.google.com/security/cas), and import them into the appropriate certificate store on the AnyCA Gateway DCOM server. + > The directory containing the HydrantId AnyCA Gateway REST plugin DLLs (`net6.0`) can be named anything, as long as it is unique within the `Extensions` directory. -* **Windows** - The root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. - * Certificates can be imported in MMC by "File" -> "Add/Remove Snap-in" -> "Certificates" -> "Add >" -> "Computer account" -> "Local computer". - * Root CAs must go in the `Trusted Root Certification Authorities` certificate store. - * Subordinate CAs must go in the `Intermediate Certification Authorities` certificate store. +4. Restart the AnyCA Gateway REST service. -> If the Root CA and chain are not known by the server hosting the AnyCA Gateway DCOM, the certificate chain _may not_ be returned to Command in certificate enrollment requests. +5. Navigate to the AnyCA Gateway REST portal and verify that the Gateway recognizes the HydrantId plugin by hovering over the ⓘ symbol to the right of the Gateway on the top left of the portal. -### Template Identification +## Configuration -The GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). Certificate Templates exist at the Project level in GCP. Before installing the plugin, identify the [Certificate Templates](https://console.cloud.google.com/security/cas) that you want to make available to Keyfactor Command and [create Certificate Templates in AD](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Preparing_Templates.htm). +1. Follow the [official AnyCA Gateway REST documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) to define a new Certificate Authority, and use the notes below to configure the **Gateway Registration** and **CA Connection** tabs: -> Certificate Templates in GCP are not required. The plugin will not specify a template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate) if the `ProductId` (discussed later) is set to `Default`. + * **Gateway Registration** -## Installation + The Gateway Registration tab configures the root or issuing CA certificate for the respective CA in HydrantId. The certificate selected here should be the issuing CA identified in the [Root CA Configuration](#root-ca-configuration) step. -1. Install AnyCA Gateway DCOM v24.2 per the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/Introduction.htm). + * **CA Connection** -2. Download the [latest GCP CAS AnyCA Gateway DCOM plugin assemblies](https://github.com/Keyfactor/gcp-cloud-cagateway/releases/latest). + Populate using the configuration fields collected in the [requirements](#requirements) section. -3. Copy `*.dll` to the `C:\Program Files\Keyfactor\Keyfactor AnyGateway` directory. + * **HydrantIdBaseUrl** - The Base URL For the HydrantId Endpoint similar to https://acm-stage.hydrantid.com. Get this from HydrantId. + * **HydrantIdAuthId** - The AuthId Obtained from HydrantId. + * **HydrantIdAuthKey** - The AuthKey Obtained from HydrantId. -4. Update the `CAProxyServer.config` file. - 1. Update the `$.configuration.unity.CAConnector` section to point at the `GoogleCAProxy` class. +2. Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. - ```xml - - ``` + The GCP CAS AnyCA Gateway REST plugin downloads all Certificate Templates in the configured GCP Region/Project and interprets them as 'Product IDs' in the Gateway Portal. - 2. Modify the `Newtonsoft.Json` `bindingRedirect` to redirect versions from `0.0.0.0-13.0.0.0` to `12.0.0.0`. + > For example, if the connected GCP project has the following Certificate Templates: + > + > * `ServerAuth` + > * `ClientAuth` + > + > The `Edit Templates` > `Product ID` dialog dropdown will show the following available 'ProductIDs': + > + > * `Default` -> Don't use a certificate template when enrolling certificates with this Template. + > * `ServerAuth` -> Use the `ServerAuth` certificate template in GCP when enrolling certificates with this Template. + > * `ClientAuth` -> Use the `ClientAuth` certificate template in GCP when enrolling certificates with this Template. - ```xml - - - - - ``` +3. Follow the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Keyfactor.htm) to add each defined Certificate Authority to Keyfactor Command and import the newly defined Certificate Templates. - 3. Add a `bindingRedirect` for `Google.Apis.Auth` to redirect versions from `0.0.0.0-1.67.0.0` to `1.67.0.0`. +4. In Keyfactor Command (v12.3+), for each imported Certificate Template, follow the [official documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm) to define enrollment fields for each of the following parameters: - ```xml - - - - - ``` + * **ValidityPeriod** - The desired lifetime time period could be Days, Months or Years. + * **ValidityUnits** - The desired lifetime time value some number indicating days, months or years. + * **RenewalDays** - The window that determines whether it is a renewal vs a re-issue. - 4. Add a `bindingRedirect` for `System.Memory` to redirect versions from `0.0.0.0-4.0.1.2` to `4.0.1.1`. - ```xml - - - - - ``` - > Depending on additional environment-specific factors, additional binding redirects may need to be applied to `CAProxyServer.config`. +## License -## Configuration -The following sections will breakdown the required configurations for the AnyGatewayConfig.json file that will be imported to configure the Google CA. - -### Templates - -As discussed in the [Template Identification](#template-identification), the GCP CAS AnyCA Gateway DCOM plugin supports [GCP CAS Certificate Templates](https://cloud.google.com/certificate-authority-service/docs/policy-controls). The Keyfactor AnyCA Gateway DCOM maps [AD Certificate Templates](https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/certificate-template-concepts) to GCP Certificate Templates via the `ProductID` property in the `Templates` section of configuration files. - -_At least one_ Certificate Template must be defined in this section with the `ProductID` set to `Default`. This Product ID corresponds to no Certificate Template for the [CreateCertificate RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.CertificateAuthorityService.CreateCertificate). - -Subsequent Certificate Templates should set the `ProductID` to the Certificate Template ID in GCP CAS. - -```json -"Templates": { - "GCPCASDefault": { - "ProductID": "Default", - "Parameters": { - "Lifetime": "300", /* Certificate validity in days */ - } - } -} -``` - -> The `Lifetime` key should be added as a Custom Enrollment Parameter/Field for each Certificate Template in Keyfactor Command per the [official Keyfactor documentation](https://software.keyfactor.com/Core-OnPrem/Current/Content/ReferenceGuide/Configuring%20Template%20Options.htm). - -## Security - -Refer to the [official Keyfactor documentation](https://software.keyfactor.com/Guides/AnyGateway_Generic/Content/AnyGateway/cmdlets.htm) to configure the `Security` section. The following is provided as an example. - -```json -/* Grant permissions on the CA to users or groups in the local domain. - READ: Enumerate and read contents of certificates. - ENROLL: Request certificates from the CA. - OFFICER: Perform certificate functions such as issuance and revocation. This is equivalent to "Issue and Manage" permission on the Microsoft CA. - ADMINISTRATOR: Configure/reconfigure the gateway. - - Valid permission settings are "Allow", "None", and "Deny". -*/ -"Security": { - "Keyfactor\\Administrator": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "Keyfactor\\gateway_test": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - }, - "Keyfactor\\SVC_TimerService": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "None" - }, - "Keyfactor\\SVC_AppPool": { - "READ": "Allow", - "ENROLL": "Allow", - "OFFICER": "Allow", - "ADMINISTRATOR": "Allow" - } -} -``` - -## CAConnection - -The `CAConnection` section selects the GCP Project/CA Pool/CA whose certificate operations will be extended to Keyfactor. There are three required fields. - -* `ProjectId` - The Resource ID of the project that contains the Google CA Service. -* `LocationId` - The GCP location ID where the project containing the target GCP CAS CA is located. For example, 'us-central1'. -* `CAPoolId` - The CA Pool ID in GCP CAS to use for certificate operations. If the CA Pool has resource name `projects/my-project/locations/us-central1/caPools/my-pool`, this field should be set to `my-pool`. -* `CAId` (optional) - The CA ID of a CA in the same CA Pool as CAPool. For example, to issue certificates from a CA with resource name `projects/my-project/locations/us-central1/caPools/my-pool/certificateAuthorities/my-ca`, this field should be set to `my-ca`. - -```json -"CAConnection": { - "LocationId": "us-east1", - "ProjectId": "concise-frame-296019", - "CAPoolId":"gcp-test-pool", - "CAId":"ca-enterprise-subordinate-sandbox-tls" -} -``` - -> If `CAId` is not specified, CA selection will defer to GCP CAS - a CA in the CA Pool identified by `CAPoolId` will be selected automatically. - -## GatewayRegistration - -There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway - -```json - "GatewayRegistration": { - "LogicalName": "GoogleCASandbox", - "GatewayCertificate": { - "StoreName": "CA", - "StoreLocation": "LocalMachine", - "Thumbprint": "bc6d6b168ce5c08a690c15e03be596bbaa095ebf" - } - } -``` - -## ServiceSettings - -There are no Google Specific Changes for the GatewayRegistration section. Refer to the Keyfactor AnyGateway Documentation for more detail on required changed to support the AnyCA Gateway - -```json - "ServiceSettings": { - "ViewIdleMinutes": 8, - "FullScanPeriodHours": 1, - "PartialScanPeriodMinutes": 60 - } -``` +Apache License 2.0, see [LICENSE](LICENSE). +## Related Integrations +See all [Keyfactor Any CA Gateways (REST)](https://github.com/orgs/Keyfactor/repositories?q=anycagateway). \ No newline at end of file diff --git a/integration-manifest.json b/integration-manifest.json index fe04bb6..156497f 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -29,15 +29,15 @@ { "name": "ValidityPeriod", "description": "The desired lifetime time period could be Days, Months or Years." - }, - { + }, + { "name": "ValidityUnits", "description": "The desired lifetime time value some number indicating days, months or years." }, { "name": "RenewalDays", "description": "The window that determines whether it is a renewal vs a re-issue." - } + } ] } } From a29afbf275f5742f329eefc489f59b1fd2028476 Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:24:15 -0400 Subject: [PATCH 24/25] Update configuration.md --- docsource/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsource/configuration.md b/docsource/configuration.md index b38978a..3dfe6c8 100644 --- a/docsource/configuration.md +++ b/docsource/configuration.md @@ -53,7 +53,7 @@ HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secu ##### Required Fields in Authorization Header: ```text Hawk id="API_ID", ts="TIMESTAMP", nonce="RANDOM", mac="HMAC_SIGNATURE" - +``` ### Root CA Configuration From 4ac69433decbba63a90426a8acad096cff7004eb Mon Sep 17 00:00:00 2001 From: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com> Date: Tue, 29 Apr 2025 13:43:01 -0400 Subject: [PATCH 25/25] Update configuration.md --- docsource/configuration.md | 155 +++++++++++++++++++++++++++---------- 1 file changed, 112 insertions(+), 43 deletions(-) diff --git a/docsource/configuration.md b/docsource/configuration.md index 3dfe6c8..41a0756 100644 --- a/docsource/configuration.md +++ b/docsource/configuration.md @@ -1,14 +1,16 @@ ## Overview -HydrantId operates a PKI as a service platform for customers around the globe. The AnyGateway solution for HydrantId is designed to allow Keyfactor Command: +HydrantId operates a PKI-as-a-service platform for customers around the globe. The AnyGateway solution for HydrantId allows Keyfactor Command to perform: -* CA Sync: - * Download all certificates issued by connected Enterprise tier CAs in HydrantId (full sync). -* Certificate enrollment for all published HydrantId Certificate SKUs: - * Support certificate enrollment (new keys/certificate). -* Certificate revocation: - * Request revocation of a previously issued certificate. +- **CA Sync**: + - Download all certificates issued by connected Enterprise-tier CAs in HydrantId (full sync). +- **Certificate Enrollment**: + - Support certificate enrollment (new keys/certificate). + - Intelligent handling of Renewal vs Reissue based on certificate expiration. +- **Certificate Revocation**: + - Request revocation of previously issued certificates with mapped revocation reasons. +--- ## Requirements @@ -16,19 +18,13 @@ HydrantId operates a PKI as a service platform for customers around the globe. T This guide explains how to generate and use an API Key ID and Secret in HydrantID for authenticated API access. ---- - #### 📍 Where to Find API Key Management 1. **Log in** to your HydrantID instance. - Example: https://acm-stage.hydrantid.com - 2. Click your **user profile icon** (top right) and select **"Profile"**. - 3. In the **Profile** page, scroll to the section labeled `API Keys`. ---- - #### ➕ Add a New API Key 1. Click **"ADD API KEY"** (top right of the API Keys section). @@ -36,16 +32,12 @@ This guide explains how to generate and use an API Key ID and Secret in HydrantI - A unique **API ID** - A **Secret API Key** — copy it immediately as it is only shown once. ---- - #### 🧾 Notes on API Keys - **ID** = what you'll pass in the HAWK `id` field - **Key** = secret used to generate HAWK signature - Each key shows `Created` and `Last Used` timestamps for traceability ---- - #### 🔐 Using the API ID and Key with HAWK HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secure its API. @@ -55,48 +47,125 @@ HydrantID uses [HAWK Authentication](https://github.com/hueniverse/hawk) to secu Hawk id="API_ID", ts="TIMESTAMP", nonce="RANDOM", mac="HMAC_SIGNATURE" ``` +Each HTTP request dynamically constructs a HAWK header using: +- API ID +- Secret API Key +- Current timestamp +- Cryptographically random nonce +- SHA-256 algorithm + ### Root CA Configuration -Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA, and if applicable, any subordinate CAs for all features to work as intended. Download the CA Certificate (and chain, if applicable) from HydrantId, and import them into the appropriate certificate store on the AnyCA Gateway REST server. +Both the Keyfactor Command and AnyCA Gateway REST servers must trust the root CA, and any applicable intermediate CAs for HydrantID. -* **Windows** - If the AnyCA Gateway REST is running on a Windows host, the root CA and applicable subordinate CAs must be imported into the Windows certificate store. The certificates can be imported using the Microsoft Management Console (MMC) or PowerShell. -* **Linux** - If the AnyCA Gateway REST is running on a Linux host, the root CA and applicable subordinate CAs must be present in the root CA certificate store. The location of this store varies per distribution, but is most commonly `/etc/ssl/certs/ca-certificates.crt`. The following is documentation on some popular distributions. - * [Ubuntu - Managing CA certificates](https://ubuntu.com/server/docs/install-a-root-ca-certificate-in-the-trust-store) - * [RHEL 9 - Using shared system certificates](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/securing_networks/using-shared-system-certificates_securing-networks#using-shared-system-certificates_securing-networks) - * [Fedora - Using Shared System Certificates](https://docs.fedoraproject.org/en-US/quick-docs/using-shared-system-certificates/) +Refer to: +- [Ubuntu - Managing CA certificates](https://ubuntu.com/server/docs/install-a-root-ca-certificate-in-the-trust-store) +- [RHEL 9 - Using shared system certificates](https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/securing_networks/using-shared-system-certificates_securing-networks#using-shared-system-certificates_securing-networks) +- [Fedora - Using Shared System Certificates](https://docs.fedoraproject.org/en-US/quick-docs/using-shared-system-certificates/) -> The root CA and intermediate CAs must be trusted by both the Command server _and_ AnyCA Gateway REST server. +--- ## Gateway Registration -The Gateway Registration tab configures the root or issuing CA certificate for the respective CA in HydrantId. The certificate selected here should be the issuing CA identified in the [Root CA Configuration](#root-ca-configuration) step. +The Gateway Registration tab configures the root or issuing CA certificate for the respective CA in HydrantId. +The certificate selected here should match the issuing CA identified in the [Root CA Configuration](#root-ca-configuration) step. +--- ## Certificate Template Creation Step -Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. One Certificate Profile must be defined per Certificate Template. It's recommended that each Certificate Profile be named after the Product ID. +Define [Certificate Profiles](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCP-Gateway.htm) and [Certificate Templates](https://software.keyfactor.com/Guides/AnyCAGatewayREST/Content/AnyCAGatewayREST/AddCA-Gateway.htm) for the Certificate Authority as required. -The GCP CAS AnyCA Gateway REST plugin downloads all Certificate Templates in the configured GCP Region/Project and interprets them as 'Product IDs' in the Gateway Portal. +Naming Recommendations: +- Each Certificate Profile should be named after its Product ID. -> For example, if the connected GCP project has the following Certificate Templates: -> -> * `ServerAuth` -> * `ClientAuth` -> -> The `Edit Templates` > `Product ID` dialog dropdown will show the following available 'ProductIDs': -> -> * `Default` -> Don't use a certificate template when enrolling certificates with this Template. -> * `ServerAuth` -> Use the `ServerAuth` certificate template in GCP when enrolling certificates with this Template. -> * `ClientAuth` -> Use the `ClientAuth` certificate template in GCP when enrolling certificates with this Template. +Behavior: +- The plugin maps HydrantID Policy Names directly to Product IDs in the Gateway Portal. + +Example: +| GCP CAS Template | Product ID | +|:------------------|:-----------| +| `ServerAuth` | ServerAuth | +| `ClientAuth` | ClientAuth | + +Selecting "Default" bypasses specifying a template. + +--- -## Mechanics +# Mechanics -### Enrollment/Renewal/Reissuance +## Enrollment/Renewal/Reissuance + +All certificate enrollment operations are submitted as "new" requests. However, the plugin supports intelligent handling: + +- **New Enrollment**: + - Submits a new CSR against the selected HydrantId Policy. +- **Renewal vs Reissue**: + - Uses the prior certificate's serial number (`PriorCertSN`) to retrieve the existing certificate. + - Compares the expiration date against the current time. + - If expiration is **within** `RenewalDays` (default 30 days): Submit a **Renewal** request. + - If expiration is **outside** `RenewalDays`: Submit a **Reissue** request (new CSR, same policy). + +Template parameters: +| Parameter | Purpose | +|:---|:---| +| `RenewalDays` | Number of days before expiration considered a renewal window | +| `ValidityPeriod` | Period length (Days/Months/Years) | +| `ValidityUnits` | Value for the chosen period type | + +## Certificate Synchronization + +The plugin uses the `/api/v2/certificates` endpoint to perform full synchronization: + +- **Paging**: + - Fetches certificates in batches of 100 (default page size). +- **Filtering**: + - Only certificates with statuses `Generated` or `Revoked` are processed. +- **Retry Logic**: + - Up to **5 retry attempts** are made on API failures during synchronization before failing the job. +- **Certificate Parsing**: + - PEM chains are split into individual certificates. + +> Note: HydrantId's API does not allow filtering certificates by CA, so all certificates from the tenant are synced. + +## Certificate Revocation + +Revocation requests are sent via a PATCH to the `/api/v2/certificates/{id}` endpoint. + +**Mapped Revocation Reasons**: + +| Keyfactor Reason (RFC 5280) | HydrantID Reason | +|:---|:---| +| 0 (Unspecified) | Unspecified | +| 1 (KeyCompromise) | KeyCompromise | +| 2 (CACompromise) | CACompromise | +| 3 (AffiliationChanged) | AffiliationChanged | +| 4 (Superseded) | Superseded | +| 5 (CessationOfOperation) | CessationOfOperation | +| 6 (CertificateHold) | CertificateHold | +| 8 (RemoveFromCRL) | RemoveFromCRL | +| 9 (PrivilegeWithdrawn) | PrivilegeWithdrawn | +| 10 (AACompromise) | AACompromise | + +## Connection Information Validation + +The following fields are required when connecting the Gateway to HydrantId: + +- `HydrantIdBaseUrl` +- `HydrantIdAuthId` +- `HydrantIdAuthKey` + +Missing or empty fields will cause the plugin initialization to fail. + +--- -The GCP CAS AnyCA Gateway REST plugin treats _all_ certificate enrollment as a new enrollment. +# Additional Notes -### Synchronization +- After enrollment, the plugin polls HydrantId's `/csr/{id}/certificate` endpoint for up to **30 seconds** to retrieve the newly issued certificate. +- If the certificate is still unavailable, the enrollment will be marked **Pending** in Command and should be retried. +- The plugin uses the Keyfactor standard logging infrastructure (`Keyfactor.Logging`). -The GCP CAS AnyCA Gateway REST plugin uses the [`ListCertificatesRequest` RPC](https://cloud.google.com/certificate-authority-service/docs/reference/rpc/google.cloud.security.privateca.v1#google.cloud.security.privateca.v1.ListCertificatesRequest) when synchronizing certificates from GCP. At the time the latest release, this RPC does not enable granularity to list certificates issued by a particular CA. As such, the CA Synchronization job implemented by the plugin will _always_ download all certificates issued by _any CA_ in the CA Pool. +# 📌 Related Documentation -> Friendly reminder to always follow the [GCP CAS best practices](https://cloud.google.com/certificate-authority-service/docs/best-practices) +- [HAWK Authentication Specification](https://github.com/hueniverse/hawk) +- [HydrantID API Documentation](https://support.hydrantid.com/hc/en-us)