Skip to content

Commit

Permalink
(PE-37345) Create new bulk signing endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
artlawson committed Dec 20, 2023
1 parent 83f6be3 commit f7db793
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
-----BEGIN X509 CRL-----
MIICnDCBhQIBATANBgkqhkiG9w0BAQUFADAfMR0wGwYDVQQDDBRQdXBwZXQgQ0E6
IGxvY2FsaG9zdBcNMTQwNDI5MjExNTI3WhcNMTkwNDI4MjExNTI4WjAiMCACAQQX
DTE0MDQyOTIxMTUyOFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0UBAMCAQEwDQYJ
KoZIhvcNAQEFBQADggIBAEHP3m5UA+lz1mjF2K+2jZ9bgZE15POftI9peXNILia3
AHE7OQtyxju/Mt/o5OpPW+0RJso9OrXhEE6T65BgOovBi1VkfxXILIui8n1oF1UK
9npunKXwgjP6Y8QbuaLv584QdwjfEFlFp/nJW5IQRKVIgsLsSGIBlZvmELiosR/W
er3Ba7Cy/Y8cfMx0t/4QCU63l/Sr/8mgvp3P5RwhljN9ekp5Y3Yz4jdRycJsrq8J
aQss8N4BrE/ppbvCdmf5UdkXgivd6cl04aSg1f25yYtEY12fyD8C8VySGOfZrnlh
aOhJapWTuKVU/PxdCZfeL+RVufrRWBo4iJCRARKddDeqDWtI62pysjy/2PRvzMRW
qudj9gJC3JnsWzvZqTGK6LNwDyH65Uc7cXjq+xxMgDpCYKZrpSmwlKUmpfnzZK/o
ckJKFaQzXvF/RJF2Ai5W3HEl4CjRp5y2yqpORsl+FDVBl2hi5n7rCqJ4RibbdtTC
pFFUP+na3zv0Z49uFLGQ/a/WHI2KuryMlDTkqltr9xncSpKafyT1UCciRdct3Q01
EWmuRcsawSg+nLB7VcLRgcnbbRuHJS2Pn2AZxYAg0SshGeZpl0zIiVzadb1/IY1d
MlXJjO6RAj87/yUMC7/xC6IJh3sQymC1Yw8nYOGjnGiMCV68e5izd3eQTj8arTZj
MIICvTCBpgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBwZXQgQ0E6
IGxvY2FsaG9zdBcNMjMxMjIwMDAyODQ2WhcNMjgxMjIwMDAyODQ3WjAiMCACAQQX
DTIzMTIyMDAwMjg0N1owDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQIwHwYD
VR0jBBgwFoAUWctw9L0Bogbt5p4IKvI4hGREaF8wDQYJKoZIhvcNAQELBQADggIB
AIdohytD45AnfqwTflcoon/QpQkTqS1DyvknfxrhQjAiMhlRnfTei0cDHeuRJ7G/
52gKICEcPsFa59NtA0DABdl8Nq5feTMIjhJN5AIZXO2wGN2D1PWTPAdMHFy0J3eG
5M1avmppFfQRuprMD3Ve+p8eFpwCfk7tJz2ddK7IDNrUGekrTLxKmJfB1m/fBGXl
BXVZdxi7sXF4Jrb2pnFZvwg1WjsoVCeiWkPJ1Tf3T3rGZo4Ud/PMf2QTWsB9rXLD
mT90f+pPGOGcmTvFvKvvtho2wOXQA+QvfUOnnUng1cXkCKsyjtBKxAxvmBlQxzSB
YZpOx33bpnuHcBELJa29fcV35JXocI7/NgAe5g1NaPzvh5qdO9s9ruq+vhPIC/Zz
H+alQU/x1us9PMj2YawTTE0zILyW4ppX0An0sqN82XUt84Erh2dJEhiouNzuTnnw
SpKEyon0hL60tlDyIUIDkdS+vwrwio8J5+mx4lMlB7N0LQXXg6odvkHaN5m9Mvbi
f/vIHktL/CfErAG2WvKS1KgfENORCtYapmbLZ7SU350Tzjp63vZOpejLmADr89K0
OrtEX85n3iNTxL7epEfbPLfNs+oT6Tl4FrzAAoIckjPF8qIaqPqnGhLXa+D86i8Z
qRAehYkFkQu1ctySh+Mi2dEcoh4kDtn6/LtcMNhMNZ5t
-----END X509 CRL-----
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
-----BEGIN X509 CRL-----
MIICnDCBhQIBATANBgkqhkiG9w0BAQUFADAfMR0wGwYDVQQDDBRQdXBwZXQgQ0E6
IGxvY2FsaG9zdBcNMTQwNDI5MjExNTI3WhcNMTkwNDI4MjExNTI4WjAiMCACAQQX
DTE0MDQyOTIxMTUyOFowDDAKBgNVHRUEAwoBAaAOMAwwCgYDVR0UBAMCAQEwDQYJ
KoZIhvcNAQEFBQADggIBAEHP3m5UA+lz1mjF2K+2jZ9bgZE15POftI9peXNILia3
AHE7OQtyxju/Mt/o5OpPW+0RJso9OrXhEE6T65BgOovBi1VkfxXILIui8n1oF1UK
9npunKXwgjP6Y8QbuaLv584QdwjfEFlFp/nJW5IQRKVIgsLsSGIBlZvmELiosR/W
er3Ba7Cy/Y8cfMx0t/4QCU63l/Sr/8mgvp3P5RwhljN9ekp5Y3Yz4jdRycJsrq8J
aQss8N4BrE/ppbvCdmf5UdkXgivd6cl04aSg1f25yYtEY12fyD8C8VySGOfZrnlh
aOhJapWTuKVU/PxdCZfeL+RVufrRWBo4iJCRARKddDeqDWtI62pysjy/2PRvzMRW
qudj9gJC3JnsWzvZqTGK6LNwDyH65Uc7cXjq+xxMgDpCYKZrpSmwlKUmpfnzZK/o
ckJKFaQzXvF/RJF2Ai5W3HEl4CjRp5y2yqpORsl+FDVBl2hi5n7rCqJ4RibbdtTC
pFFUP+na3zv0Z49uFLGQ/a/WHI2KuryMlDTkqltr9xncSpKafyT1UCciRdct3Q01
EWmuRcsawSg+nLB7VcLRgcnbbRuHJS2Pn2AZxYAg0SshGeZpl0zIiVzadb1/IY1d
MlXJjO6RAj87/yUMC7/xC6IJh3sQymC1Yw8nYOGjnGiMCV68e5izd3eQTj8arTZj
MIICvTCBpgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBwZXQgQ0E6
IGxvY2FsaG9zdBcNMjMxMjIwMDAyODQ2WhcNMjgxMjIwMDAyODQ3WjAiMCACAQQX
DTIzMTIyMDAwMjg0N1owDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQIwHwYD
VR0jBBgwFoAUWctw9L0Bogbt5p4IKvI4hGREaF8wDQYJKoZIhvcNAQELBQADggIB
AIdohytD45AnfqwTflcoon/QpQkTqS1DyvknfxrhQjAiMhlRnfTei0cDHeuRJ7G/
52gKICEcPsFa59NtA0DABdl8Nq5feTMIjhJN5AIZXO2wGN2D1PWTPAdMHFy0J3eG
5M1avmppFfQRuprMD3Ve+p8eFpwCfk7tJz2ddK7IDNrUGekrTLxKmJfB1m/fBGXl
BXVZdxi7sXF4Jrb2pnFZvwg1WjsoVCeiWkPJ1Tf3T3rGZo4Ud/PMf2QTWsB9rXLD
mT90f+pPGOGcmTvFvKvvtho2wOXQA+QvfUOnnUng1cXkCKsyjtBKxAxvmBlQxzSB
YZpOx33bpnuHcBELJa29fcV35JXocI7/NgAe5g1NaPzvh5qdO9s9ruq+vhPIC/Zz
H+alQU/x1us9PMj2YawTTE0zILyW4ppX0An0sqN82XUt84Erh2dJEhiouNzuTnnw
SpKEyon0hL60tlDyIUIDkdS+vwrwio8J5+mx4lMlB7N0LQXXg6odvkHaN5m9Mvbi
f/vIHktL/CfErAG2WvKS1KgfENORCtYapmbLZ7SU350Tzjp63vZOpejLmADr89K0
OrtEX85n3iNTxL7epEfbPLfNs+oT6Tl4FrzAAoIckjPF8qIaqPqnGhLXa+D86i8Z
qRAehYkFkQu1ctySh+Mi2dEcoh4kDtn6/LtcMNhMNZ5t
-----END X509 CRL-----
41 changes: 38 additions & 3 deletions src/clj/puppetlabs/services/ca/certificate_authority_core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
[ring.util.request :as request]
[ring.util.response :as rr]
[schema.core :as schema]
[slingshot.slingshot :as sling])
[slingshot.slingshot :refer [try+ throw+]])
(:import (clojure.lang IFn)
(java.io ByteArrayInputStream InputStream StringWriter)
(java.security.cert X509Certificate)
Expand Down Expand Up @@ -77,7 +77,7 @@
[ca-settings :- ca/CaSettings
report-activity
{:keys [body] {:keys [subject]} :route-params :as request}]
(sling/try+
(try+
(let [report-activity-fn (ca/create-report-activity-fn report-activity request)]
(ca/process-csr-submission! subject body ca-settings report-activity-fn)
(rr/content-type (rr/response nil) "text/plain"))
Expand Down Expand Up @@ -257,6 +257,37 @@
request-cert)
(log/warn (i18n/trs "Request is missing a certificate for an endpoint that requires a certificate."))))))

(schema/def Certnames [schema/Str])

(defn validate-schema!
"This wraps schema/check and throws a custom slingshot stone instead of the
generic exception that schema/validate would throw."
[schema body]
(when-let [schema-error (schema/check schema body)]
(-> (rr/response (cheshire/generate-string {:kind :schema-violation
:schema schema
:submitted body
:error schema-error})
(rr/status 422)
(rr/content-type "application/json")))))

(schema/defn handle-bulk-cert-signing
[request
_ca-settings :- ca/CaSettings]
(let [json-body (try-to-parse (:body request))
certnames (:certnames json-body)]
(validate-schema! Certnames certnames)
(-> (rr/response (cheshire/generate-string {}))
(rr/status 200)
(rr/content-type "application/json"))))

(schema/defn handle-bulk-cert-signing-all
[_request
_ca-settings :- ca/CaSettings]
(-> (rr/response (cheshire/generate-string {}))
(rr/status 200)
(rr/content-type "application/json")))

(schema/defn ^:always-validate
handle-cert-renewal
"Given a request and the CA settings, if there is a cert present in the request
Expand Down Expand Up @@ -540,7 +571,11 @@
(PUT ["/clean"] request
(handle-cert-clean request ca-settings report-activity))
(POST ["/certificate_renewal"] request
(handle-cert-renewal request ca-settings report-activity)))
(handle-cert-renewal request ca-settings report-activity))
(POST ["/sign"] request
(handle-bulk-cert-signing request ca-settings))
(POST ["/sign/all"] request
(handle-bulk-cert-signing-all request ca-settings)))
(comidi/not-found "Not Found")))

(schema/defn ^:always-validate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,65 @@
:body "Bad data"})]
(is (= 400 (:status response)))))))

(deftest ca-bulk-signing-endpoint-test
(testing "ca bulk signing endpoint "
(bootstrap/with-puppetserver-running-with-mock-jrubies
"JRuby mocking is safe here because all of the requests are to the CA
endpoints, which are implemented in Clojure."
app
{:jruby-puppet
{:gem-path [(ks/absolute-path jruby-testutils/gem-path)]}
:webserver
{:ssl-cert (str bootstrap/server-conf-dir "/ssl/certs/localhost.pem")
:ssl-key (str bootstrap/server-conf-dir "/ssl/private_keys/localhost.pem")
:ssl-ca-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:ssl-crl-path (str bootstrap/server-conf-dir "/ssl/crl.pem")}}

(testing "returns 200 with valid payload"
(let [random-certname (ks/rand-str :alpha-lower 16)
response (http-client/post
"https://localhost:8140/puppet-ca/v1/sign"
{:body (json/encode {:certnames [random-certname]})
:ssl-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:ssl-key (str bootstrap/server-conf-dir "/ca/ca_key.pem")
:ssl-ca-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:as :text
:headers {"Accept" "application/json"}})]
(is (= 200 (:status response)))))
(testing "throws schema violation for invalid certname"
(let [response (http-client/post
"https://localhost:8140/puppet-ca/v1/sign"
{:body (json/encode {:certnames [1 2 3]})
:ssl-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:ssl-key (str bootstrap/server-conf-dir "/ca/ca_key.pem")
:ssl-ca-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:as :text
:headers {"Accept" "application/json"}})]
(clojure.pprint/pprint (:body response))
(is (= 422 (:status response))))))))

(deftest ca-bulk-signing-all-endpoint-test
(testing "returns 200 response"
(bootstrap/with-puppetserver-running-with-mock-jrubies
"JRuby mocking is safe here because all of the requests are to the CA
endpoints, which are implemented in Clojure."
app
{:jruby-puppet
{:gem-path [(ks/absolute-path jruby-testutils/gem-path)]}
:webserver
{:ssl-cert (str bootstrap/server-conf-dir "/ssl/certs/localhost.pem")
:ssl-key (str bootstrap/server-conf-dir "/ssl/private_keys/localhost.pem")
:ssl-ca-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:ssl-crl-path (str bootstrap/server-conf-dir "/ssl/crl.pem")}}
(let [response (http-client/post
"https://localhost:8140/puppet-ca/v1/sign/all"
{:ssl-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:ssl-key (str bootstrap/server-conf-dir "/ca/ca_key.pem")
:ssl-ca-cert (str bootstrap/server-conf-dir "/ca/ca_crt.pem")
:as :text
:headers {"Accept" "application/json"}})]
(is (= 200 (:status response)))))))

(deftest ca-certificate-renew-endpoint-test
(testing "with the feature enabled"
(testing "with allow-header-cert-info = false (default)"
Expand Down

0 comments on commit f7db793

Please sign in to comment.