Skip to content

Commit 335b1a2

Browse files
committed
Cherry-pick and squash #908
1 parent caa01f5 commit 335b1a2

15 files changed

+729
-142
lines changed

bin/run_integration_tests.sh

+1-6
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,9 @@ while test "true" != "$(docker inspect -f {{.State.Running}} autograph-app-hsm)"
2424
sleep 1 # wait before checking again
2525
done
2626

27-
# fetch the updated root hash from the app-hsm service
28-
docker cp autograph-app-hsm:/tmp/normandy_dev_root_hash.txt .
29-
APP_HSM_NORMANDY_ROOT_HASH=$(grep '[0-9A-F]' normandy_dev_root_hash.txt | tr -d '\r\n')
30-
3127
# start the monitor lambda emulators
3228
docker compose up -d monitor-lambda-emulator
33-
AUTOGRAPH_ROOT_HASH=$APP_HSM_NORMANDY_ROOT_HASH docker compose up -d monitor-hsm-lambda-emulator
29+
docker compose up -d monitor-hsm-lambda-emulator
3430

3531
echo "waiting for monitor-lambda-emulator to start"
3632
while test "true" != "$(docker inspect -f {{.State.Running}} autograph-monitor-lambda-emulator)"; do
@@ -43,7 +39,6 @@ while test "true" != "$(docker inspect -f {{.State.Running}} autograph-monitor-h
4339
sleep 1 # wait before checking again
4440
done
4541

46-
echo "checking monitoring using hsm root hash:" "$APP_HSM_NORMANDY_ROOT_HASH"
4742
# exec in containers to workaround https://circleci.com/docs/2.0/building-docker-images/#accessing-services
4843
docker compose exec monitor-lambda-emulator "/usr/local/bin/test_monitor.sh"
4944
docker compose logs monitor-lambda-emulator

bin/test_monitor.sh

100644100755
File mode changed.

docker-compose.yml

-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,6 @@ services:
8282
- AUTOGRAPH_KEY=19zd4w3xirb5syjgdx8atq6g91m03bdsmzjifs2oddivswlu9qs
8383
# set a non-empty value to use the lambda handler
8484
- LAMBDA_TASK_ROOT=/usr/local/bin/
85-
- AUTOGRAPH_ROOT_HASH
8685
ports:
8786
- "9000:8080"
8887
links:
@@ -103,7 +102,6 @@ services:
103102
- AUTOGRAPH_KEY=19zd4w3xirb5syjgdx8atq6g91m03bdsmzjifs2oddivswlu9qs
104103
# set a non-empty value to use the lambda handler
105104
- LAMBDA_TASK_ROOT=/usr/local/bin/
106-
- AUTOGRAPH_ROOT_HASH
107105
ports:
108106
- "9001:8080"
109107
links:

docs/endpoints.md

+39
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,42 @@ Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="som
380380
"webextensions-rsa-with-recommendation"
381381
]
382382
```
383+
384+
## /config/:keyid
385+
386+
### Request
387+
388+
Get the sanitized configuration of a signer. For example:
389+
390+
```bash
391+
GET /config/dummyrsa
392+
Host: autograph.example.net
393+
Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="some-app-ext-data", mac="6R4rV5iE+NPoym+WwjeHzjAGXUtLNIxmo1vpMofpLAE="
394+
```
395+
396+
### Response
397+
398+
400 Bad Request when the request includes a non-empty body
399+
401 Unauthorized when the Authorization header is missing or HAWK authorization fails
400+
404 Not Found when the keyid does not exist, or an authorization does not have permission to access the signer.
401+
405 Method Not Allowed when the request method is not GET
402+
200 OK when the authorization is valid and path and signer ID is found. Example response body with Content-Type application/json:
403+
404+
```json
405+
{
406+
"id": "dummyrsa",
407+
"type": "genericrsa",
408+
"mode": "pss",
409+
"publickey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtEM/Vdfd4Vl9wmeVdCYuWYnQl0Zc9RW5hLE4hFA+c277qanE8XCK+ap/c5so87XngLLfacB3zZhGxIOut/4SlEBOAUmVNCfnTO+YkRk3A8OyJ4XNqdn+/ov78ZbssGf+0zws2BcwZYwhtuTvro3yi62FQ7T1TpT5VjljH7sHW/iZnS/RKiY4DwqAN799gkB+Gwovtroabh2w5OX0P+PYyUbJLFQeo5uiAQ8cAXTlHqCkj11GYgU4ttVDuFGotKRyaRn1F+yKxE4LQcAULx7s0KzvS35mNU+MoywLWjy9a4TcjK0nq+BjspKX4UkNwVstvH18hQWun7E+dxTi59cRmwIDAQAB",
410+
"hash": "sha256"
411+
}
412+
```
413+
414+
The returned configuration should be a subset of the internal configuration with the following differences:
415+
- Public values, such as the `id`, `publickey` and `certificate` are copied verbatim.
416+
- Private keys are hashed, and return only the SHA256 checksum of the secret value.
417+
- The `certificate`, if present is parsed and the following additional fields are added:
418+
+ `cert_sha1`: Contains the SHA1 fingerprint of the DER certificate.
419+
+ `cert_sha256`: Contains the SHA256 fingerprint of the DER certificate.
420+
+ `cert_start`: Contains the certificate `NotBefore` time in RFC 3339 format.
421+
+ `cert_end`: Contains the certificate `NotAfter` time in RFC 3339 format.

handlers.go

+53
Original file line numberDiff line numberDiff line change
@@ -495,3 +495,56 @@ func (a *autographer) handleGetAuthKeyIDs(w http.ResponseWriter, r *http.Request
495495
w.WriteHeader(http.StatusOK)
496496
w.Write(signerIDsJSON)
497497
}
498+
499+
// handleGetConfig returns the public signer configuration (keyID param for the API)
500+
func (a *autographer) handleGetConfig(w http.ResponseWriter, r *http.Request) {
501+
if r.Method != "GET" {
502+
httpError(w, r, http.StatusMethodNotAllowed, "%s method not allowed; endpoint accepts GET only", r.Method)
503+
return
504+
}
505+
if r.Body != nil {
506+
body, err := ioutil.ReadAll(r.Body)
507+
if err != nil {
508+
httpError(w, r, http.StatusBadRequest, "failed to read request body: %s", err)
509+
return
510+
}
511+
if len(body) > 0 {
512+
httpError(w, r, http.StatusBadRequest, "endpoint received unexpected request body")
513+
return
514+
}
515+
}
516+
517+
pathKeyID, ok := mux.Vars(r)["keyid"]
518+
if !ok {
519+
httpError(w, r, http.StatusInternalServerError, "route is improperly configured")
520+
return
521+
}
522+
if !signer.IDFormatRegexp.MatchString(pathKeyID) {
523+
httpError(w, r, http.StatusBadRequest, "keyid in URL path '%s' is invalid, it must match %s", pathKeyID, signer.IDFormat)
524+
return
525+
}
526+
_, headerAuthID, err := a.authorizeHeader(r)
527+
if err != nil {
528+
httpError(w, r, http.StatusUnauthorized, "authorization verification failed: %v", err)
529+
return
530+
}
531+
532+
requestedSigner, err := a.authBackend.getSignerForUser(headerAuthID, pathKeyID)
533+
if err != nil {
534+
log.Infof("user authorization failed: %s", err)
535+
httpError(w, r, http.StatusNotFound, "keyid %s was not found for user %s", pathKeyID, headerAuthID)
536+
return
537+
}
538+
539+
requestedConfig := requestedSigner.Config()
540+
signerConfigJSON, err := json.Marshal(requestedConfig.Sanitize())
541+
if err != nil {
542+
log.Errorf("handleGetConfig failed to marshal JSON with error: %s", err)
543+
httpError(w, r, http.StatusInternalServerError, "error marshaling response JSON")
544+
return
545+
}
546+
547+
w.Header().Set("Content-Type", "application/json")
548+
w.WriteHeader(http.StatusOK)
549+
w.Write(signerConfigJSON)
550+
}

0 commit comments

Comments
 (0)