Skip to content

Commit

Permalink
Validation of OIDC claims via JSON schema validator
Browse files Browse the repository at this point in the history
Related: actions/runner#2417 (comment)
Signed-off-by: John Andersen <johnandersenpdx@gmail.com>
  • Loading branch information
pdxjohnny committed Sep 13, 2023
1 parent 7bd5668 commit 35eb44b
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 5 deletions.
30 changes: 29 additions & 1 deletion .github/workflows/notarize.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,38 @@ jobs:
- name: Submit claim
env:
OIDC_TOKEN: '${{ steps.github-oidc.outputs.token }}'
WORKFLOW_REF: '${{ github.workflow_ref }}'
# Use of job_workflow_sha blocked by
# https://github.com/actions/runner/issues/2417#issuecomment-1718369460
JOB_WORKFLOW_SHA: '${{ github.sha }}'
run: |
# Create the middleware config file
cat > oidc-middleware-config.json <<EOF
tee oidc-middleware-config.json <<EOF
{
"issuers": ["https://token.actions.githubusercontent.com"],
"claim_schema": {
"https://token.actions.githubusercontent.com": {
"\$schema": "https://json-schema.org/draft/2020-12/schema",
"required": [
"job_workflow_ref",
"job_workflow_sha"
],
"properties": {
"job_workflow_ref": {
"type": "string",
"enum": [
"${WORKFLOW_REF}"
]
},
"job_workflow_sha": {
"type": "string",
"enum": [
"${JOB_WORKFLOW_SHA}"
]
}
}
}
},
"audience": "${SCITT_URL}"
}
EOF
Expand All @@ -79,6 +106,7 @@ jobs:
scitt-emulator server --port 8080 --workspace workspace/ --tree-alg CCF \
--middleware scitt_emulator.oidc:OIDCAuthMiddleware \
--middleware-config-path oidc-middleware-config.json &
sleep 1s
fi
# Submit the claim using OIDC token as auth
scitt-emulator client submit-claim --token "${OIDC_TOKEN}" --url "${SCITT_URL}" --claim claim.cose --out claim.receipt.cbor
5 changes: 4 additions & 1 deletion scitt_emulator/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jwt
import json
import jwcrypto.jwk
import jsonschema
from flask import jsonify
from werkzeug.wrappers import Request
from scitt_emulator.client import HttpClient
Expand All @@ -27,7 +28,9 @@ def __init__(self, app, config_path):

def __call__(self, environ, start_response):
request = Request(environ)
self.validate_token(request.headers["Authorization"].replace("Bearer ", ""))
claims = self.validate_token(request.headers["Authorization"].replace("Bearer ", ""))
if "claim_schema" in self.config and claims["iss"] in self.config["claim_schema"]:
jsonschema.validate(claims, schema=self.config["claim_schema"][claims["iss"]])
return self.app(environ, start_response)

def validate_token(self, token):
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"oidc": [
"PyJWT",
"jwcrypto",
"jsonschema",
]
},
)
39 changes: 36 additions & 3 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def test_client_cli_token(tmp_path):
key = jwcrypto.jwk.JWK.generate(kty="RSA", size=2048)
algorithm = "RS256"
audience = "scitt.example.org"
subject = "repo:scitt-community/scitt-api-emulator:ref:refs/heads/main"

with Service(
{"key": key, "algorithms": [algorithm]},
Expand All @@ -213,7 +214,21 @@ def test_client_cli_token(tmp_path):
)
middleware_config_path = tmp_path / "oidc-middleware-config.json"
middleware_config_path.write_text(
json.dumps({"issuers": [oidc_service.url], "audience": audience})
json.dumps(
{
"issuers": [oidc_service.url],
"audience": audience,
"claim_schema": {
oidc_service.url: {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"required": ["sub"],
"properties": {
"sub": {"type": "string", "enum": [subject]},
},
}
},
}
)
)
with Service(
{
Expand Down Expand Up @@ -263,18 +278,36 @@ def test_client_cli_token(tmp_path):
assert not os.path.exists(receipt_path)
assert not os.path.exists(entry_id_path)

# create token
# create token without subject
token = jwt.encode(
{"iss": oidc_service.url, "aud": audience},
key.export_to_pem(private_key=True, password=None),
algorithm=algorithm,
headers={"kid": key.thumbprint()},
)
# submit claim with token
# submit claim with token lacking subject
command += [
"--token",
token,
]
check_error = None
try:
execute_cli(command)
except Exception as error:
check_error = error
assert check_error
assert not os.path.exists(receipt_path)
assert not os.path.exists(entry_id_path)

# create token with subject
token = jwt.encode(
{"iss": oidc_service.url, "aud": audience, "sub": subject},
key.export_to_pem(private_key=True, password=None),
algorithm=algorithm,
headers={"kid": key.thumbprint()},
)
# submit claim with token containing subject
command[-1] = token
execute_cli(command)
assert os.path.exists(receipt_path)
assert os.path.exists(entry_id_path)

1 comment on commit 35eb44b

@pdxjohnny
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ gh -R pdxjohnny/scitt-api-emulator workflow run notarize.yml -F scitt-url=$(cat public-url.txt)
$ ssh -nT -R 80:localhost:8080 nokey@localhost.run 2>/dev/null | grep --line-buffered 'tunneled with tls' | python -c 'import sys; print(sys.stdin.readline().split()[-1])' | tee public-url.txt &
$ docker run --rm -ti -p 8080:8080 -e PORT=8080 -e SCITT_URL=$(cat public-url.txt) -v "${PWD}/oidc-middleware-config.json:oidc-middleware-config.json:ro" ghcr.io/scitt-community/scitt-api-emulator bash -xec 'sed -i -e "s#SCITT_URL#${SCITT_URL}#g" -e "s#WORKFLOW_REF#pdxjohnny/scitt-api-emulator/.github/workflows/notarize.yml@refs/heads/auth#g" -e "s#JOB_WORKFLOW_SHA#35eb44b527a0e4a9d35f2e887b2621b0a327cbe0#g" -e "s#REPOSITORY_OWNER_ID#5950433#g" -e "s#REPOSITORY_ID#621131680#g" oidc-middleware-config.json && rm -rf workspace/ && mkdir -p workspace/storage/operations && set +e && timeout 3s scitt-emulator server --workspace workspace/ --tree-alg CCF --use-lro; set -e && echo "$(cat workspace/service_parameters.json)" | jq ".insertPolicy = \"\*\"" | tee workspace/service_parameters.json.new && mv workspace/service_parameters.json.new workspace/service_parameters.json && bash -x run_policy_engine.sh & scitt-emulator server --workspace workspace/ --tree-alg CCF --port "${PORT}" --use-lro --middleware scitt_emulator.oidc:OIDCAuthMiddleware --middleware-config-path oidc-middleware-config.json'

Please sign in to comment.