Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and test adding new issuers #260

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3659f05
fix add issuer and new tests
beejones Dec 11, 2024
e2539f4
fixing auth tests
beejones Dec 11, 2024
37618bc
fix test_auth
beejones Dec 12, 2024
a2359f2
remove user certs
beejones Dec 13, 2024
92020eb
Fixing env vars
beejones Dec 13, 2024
9497639
Try to fix aci failing
beejones Dec 13, 2024
9c2cf3e
fix aci failing
beejones Dec 13, 2024
fa65601
Adding env to jwt_issuer up
beejones Dec 13, 2024
ab9f92b
add env vars back into aci script
beejones Dec 13, 2024
d039514
add unset
beejones Dec 13, 2024
824775c
Merge remote-tracking branch 'origin/main' into beejones/fix-jwt-issuers
DomAyre Dec 17, 2024
d3a2843
Minor layout changes
DomAyre Dec 17, 2024
e7cd184
Recreate the JWT Issuer for each test
DomAyre Dec 17, 2024
4252e2f
.
DomAyre Dec 17, 2024
685aad3
Merge branch 'main' into beejones/fix-jwt-issuers
beejones Jan 7, 2025
a8192dc
Merge main
beejones Jan 8, 2025
3a79912
fix build error
beejones Jan 8, 2025
9c572f3
Fix system test failing
beejones Jan 8, 2025
08e69e9
Merge branch 'main' into beejones/fix-jwt-issuers
beejones Jan 8, 2025
d93bd4c
debug js_app_set.sh
beejones Jan 8, 2025
c78a9c6
Merge branch 'beejones/fix-jwt-issuers' of https://github.com/microso…
beejones Jan 8, 2025
e70301a
update yanked package
beejones Jan 8, 2025
68b9668
dummy change
beejones Jan 8, 2025
34b7d0b
sync aci cleanroom scripts with main
beejones Jan 9, 2025
d932624
temporary create directory to see if this fixes the aci cleanroom ci …
beejones Jan 9, 2025
d74e9b3
remove debugging flag in js_app_set.sh
beejones Jan 9, 2025
6bc2264
cleanup
beejones Jan 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ KMS_URL ?= https://127.0.0.1:8000
KEYS_DIR ?= ${KMS_WORKSPACE}/sandbox_common
RUN_BACK ?= true
CCF_PLATFORM ?= virtual
JWT_ISSUER_WORKSPACE ?= ${PWD}/jwt_issuer_workspace
JWT_ISSUER_WORKSPACE ?= ${PWD}/jwt_issuers_workspace

DEPLOYMENT_ENV ?= $(if $(shell echo $(KMS_URL) | grep -E '127.0.0.1|localhost'),local,cloud)

Expand Down
2 changes: 1 addition & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@
"openapi": {
"responses": {
"200": {
"description": "Generate a heartbeat response"
"description": "Generate an auth response"
}
}
}
Expand Down
64 changes: 32 additions & 32 deletions governance/proposals/set_jwt_issuer.json
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
{
"actions": [
{
"name": "set_jwt_issuer",
"args": {
"issuer": "http://Demo-jwt-issuer",
"key_filter": "all",
"jwks": {
"keys": [
${JWK}
]
}
"actions": [
{
"name": "set_jwt_issuer",
"args": {
"issuer": "${JWT_ISSUER}",
"key_filter": "all",
"jwks": {
"keys": [
${JWK}
]
}
},
{
"name": "set_jwt_validation_policy",
"args": {
"issuer": "http://Demo-jwt-issuer",
"validation_policy": {
"iss": "http://Demo-jwt-issuer",
"sub": "c0d8e9a7-6b8e-4e1f-9e4a-3b2c1d0f5a6b",
"name": "Cool caller"
}
}
},
{
"name": "set_jwt_validation_policy",
"args": {
"issuer": "${JWT_ISSUER}",
"validation_policy": {
"iss": "${JWT_ISSUER}",
"sub": "c0d8e9a7-6b8e-4e1f-9e4a-3b2c1d0f5a6b",
"name": "Cool caller"
}
},
{
"name": "set_jwt_public_signing_keys",
"args": {
"issuer": "http://Demo-jwt-issuer",
"jwks": {
"keys": [
${JWK}
]
}
}
},
{
"name": "set_jwt_public_signing_keys",
"args": {
"issuer": "${JWT_ISSUER}",
"jwks": {
"keys": [
${JWK}
]
}
}
]
}
]
}
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ paramiko==3.5.0
pyasn1==0.6.1
PyJWT==2.9.0
pre-commit==3.5.0
setuptools==72.0.0
setuptools==72.1.0
pytest==8.3.3
pytest-xdist==3.6.1
python-dotenv==1.0.1
1 change: 1 addition & 0 deletions scripts/jwt_issuer/down.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ docker compose -p ${UNIQUE_ID:-default} -f services/docker-compose.yml down jwt-

unset JWT_ISSUER_WORKSPACE
unset JWT_ISSUER
unset JWT_TOKEN_ISSUER_URL
Copy link
Collaborator

Choose a reason for hiding this comment

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

We will update this too when we combine JWT_ISSUER into one value

6 changes: 5 additions & 1 deletion scripts/jwt_issuer/up.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ jwt-issuer-up() {
REPO_ROOT="$(realpath "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/../..")"
export JWT_ISSUER_WORKSPACE=${JWT_ISSUER_WORKSPACE:-$REPO_ROOT/jwt_issuers_workspace/${UNIQUE_ID:-default}/}
mkdir -p $JWT_ISSUER_WORKSPACE
export JWT_TOKEN_ISSUER_URL="http://localhost:3000/token"
Copy link
Collaborator

Choose a reason for hiding this comment

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

We set it twice

export JWT_ISSUER="http://Demo-jwt-issuer"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

only use JWT_ISSUER


docker compose -p ${UNIQUE_ID:-default} -f services/docker-compose.yml up jwt-issuer --wait "$@"
sudo chown $USER:$USER -R $JWT_ISSUER_WORKSPACE

export JWT_ISSUER="$(cat $JWT_ISSUER_WORKSPACE/jwt_issuer_address)/token"
export JWT_TOKEN_ISSUER_URL="$(cat $JWT_ISSUER_WORKSPACE/jwt_issuer_address)/token"

set +e
}
Expand All @@ -22,5 +24,7 @@ jwt-issuer-up "$@"

jq -n '{
JWT_ISSUER_WORKSPACE: env.JWT_ISSUER_WORKSPACE,
JWT_TOKEN_ISSUER_URL: env.JWT_TOKEN_ISSUER_URL,
JWT_ISSUER: env.JWT_ISSUER,
DomAyre marked this conversation as resolved.
Show resolved Hide resolved

}'
50 changes: 50 additions & 0 deletions scripts/kms/endpoints/auth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

set -ex

Copy link
Contributor Author

Choose a reason for hiding this comment

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

remove +x

auth() {
params=()
auth="jwt"
jwtprops=""

# Parse command-line arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--auth)
auth="$2"
shift 2
;;
--jwtprops)
jwtprops="$2"
shift 2
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done

# Extract iss from jwtprops if present
if [[ "$jwtprops" == *"iss="* ]]; then
export JWT_ISSUER=$(echo "$jwtprops" | grep -oP '(?<=iss=)[^&]*')
fi

auth_arg=()
if [[ "$auth" == "member_cert" ]]; then
auth_arg=(--cert $KMS_MEMBER_CERT_PATH --key $KMS_MEMBER_PRIVK_PATH)
elif [[ "$auth" == "jwt" ]]; then
auth_arg=(-H "Authorization: Bearer $(curl -X POST $JWT_TOKEN_ISSUER_URL$jwtprops | jq -r '.access_token')")
fi

curl $KMS_URL/app/auth \
--cacert $KMS_SERVICE_CERT_PATH \
"${auth_arg[@]}" \
-H "Content-Type: application/json" \
-w '\n%{http_code}\n'
}

auth "$@"
2 changes: 1 addition & 1 deletion scripts/kms/endpoints/key.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ key() {
if [[ "$auth" == "member_cert" ]]; then
auth_arg=(--cert $KMS_MEMBER_CERT_PATH --key $KMS_MEMBER_PRIVK_PATH)
elif [[ "$auth" == "jwt" ]]; then
auth_arg=(-H "Authorization: Bearer $(curl -X POST $JWT_ISSUER | jq -r '.access_token')")
auth_arg=(-H "Authorization: Bearer $(curl -X POST $JWT_TOKEN_ISSUER_URL | jq -r '.access_token')")
fi

curl $KMS_URL/app/key${query_string} \
Expand Down
4 changes: 4 additions & 0 deletions scripts/kms/js_app_set.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ js-app-set() {
echo "$line" >> "$temp_file"
fi
done < $REPO_ROOT/governance/proposals/set_js_app.json

# Ensure the target directory exists
mkdir -p $WORKSPACE/proposals
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can revisit this when all other changes are addressed, this shouldn't be necessary and it might hide other issues


mv "$temp_file" $WORKSPACE/proposals/set_js_app.json

# Submit the proposal
Expand Down
18 changes: 18 additions & 0 deletions scripts/kms/jwt_issuer_trust.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@ jwt-issuer-trust() {

REPO_ROOT="$(realpath "$(dirname "$(realpath "${BASH_SOURCE[0]}")")/../..")"

# Check for new issuer
Copy link
Collaborator

Choose a reason for hiding this comment

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

For my own understanding, the scheme is:

  • If you call this without --iss it will use JWT_TOKEN_ISSUER_URL which will have been set if you bring up a local test JWT issuer
  • If you have some external JWT issuer you can just specify it with this --iss flag?

If my understanding is correct I really like this scheme!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For an external one we need to set JWT_TOKEN_ISSUER_URL to the token endpoint.
--iss will the name for the iss property in the token. CCF uses this to register the issuer.

Copy link
Collaborator

Choose a reason for hiding this comment

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

So is it equivalent to setting JWT_ISSUER? In which case why are we mixing methods? I think we either allow fully specifying which JWT issuer we're trusting via command line params or we just require the env variables to be changed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a test adding a new issuer implemented by our test token issuer.
For this case I needed to specify the issuer JWT_ISSUER and keep the url to the test token url.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure that addresses my point about mixed methods, for the test you could set both env variables for the test, or you could provider command line params for both and specify them for the test?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Now we've decided to unify JWT_ISSUER this goes away

while [[ $# -gt 0 ]]; do
case "$1" in
--iss)
JWT_ISSUER="$2"
shift 2
;;
--iss=*)
JWT_ISSUER="${1#*=}"
shift 1
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done

# Populate the JWK of the token issuer
PRIVATE_PEM="$JWT_ISSUER_WORKSPACE/private.pem"
CERT_PEM="$JWT_ISSUER_WORKSPACE/cert.pem"
Expand Down
41 changes: 0 additions & 41 deletions src/authorization/jwt/DemoJwtProvider.ts

This file was deleted.

14 changes: 7 additions & 7 deletions src/authorization/jwt/JwtValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { ServiceResult } from "../../utils/ServiceResult";
import { IValidatorService } from "../IValidationService";
import { JwtIdentityProviderEnum } from "./JwtIdentityProviderEnum";
import { IJwtIdentityProvider } from "./IJwtIdentityProvider";
import { DemoJwtProvider } from "./DemoJwtProvider";
import { MsJwtProvider } from "./MsJwtProvider";
import { Logger, LogContext } from "../../utils/Logger";

Expand All @@ -23,24 +22,25 @@ export class JwtValidator implements IValidatorService {
JwtIdentityProviderEnum.MS_AAD,
new MsJwtProvider("JwtProvider", this.logContext),
);
this.identityProviders.set(
JwtIdentityProviderEnum.Demo,
new DemoJwtProvider("DemoJwtProvider"),
);
}

/*
* Validate the request
* @param request request to validate with JWT
* */
validate(request: ccfapp.Request<any>): ServiceResult<string> {
const jwtCaller = request.caller as unknown as ccfapp.JwtAuthnIdentity;
Logger.debug(
`Authorization: JWT jwtCaller (JwtValidator)-> ${<JwtIdentityProviderEnum>jwtCaller.jwt.keyIssuer}`,
this.logContext
);
Logger.info(`JWT content: ${JSON.stringify(jwtCaller.jwt)}`, this.logContext);
const provider = this.identityProviders.get(
<JwtIdentityProviderEnum>jwtCaller.jwt.keyIssuer,
JwtIdentityProviderEnum.MS_AAD
);

if (!provider) {
const error = `Authorization: JWT validation provider is undefined (JwtValidator) for ${<JwtIdentityProviderEnum>jwtCaller.jwt.keyIssuer}`;
const error = `Authorization: JWT validation provider ${JwtIdentityProviderEnum.MS_AAD} is undefined (JwtValidator) for ${<JwtIdentityProviderEnum>jwtCaller.jwt.keyIssuer}`;
Logger.error(error, this.logContext);
return ServiceResult.Failed(
{ errorMessage: error, errorType: "caller error" },
Expand Down
2 changes: 1 addition & 1 deletion src/authorization/jwt/MsJwtProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const authorizeJwt = (
errorMessage,
errorType: "AuthenticationError",
},
500,
401,
logContext
);
}
Expand Down
2 changes: 1 addition & 1 deletion test/system-test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def setup_jwt_issuer():
["./scripts/jwt_issuer/up.sh", "--build"],
env={
**os.environ,
"JWT_ISSUER_WORKSPACE": f"{REPO_ROOT}/jwt_issuer_workspace",
"JWT_ISSUER_WORKSPACE": f"{REPO_ROOT}/jwt_issuers_workspace",
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can match the default in up.sh (/defualt/)

},
)
yield
Expand Down
4 changes: 4 additions & 0 deletions test/system-test/endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,7 @@ def keyReleasePolicy(**kwargs):

def settingsPolicy(**kwargs):
return call_endpoint("settingsPolicy", **kwargs)


def auth(**kwargs):
return call_endpoint("auth", **kwargs)
36 changes: 36 additions & 0 deletions test/system-test/test_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from endpoints import auth
from utils import apply_kms_constitution, trust_jwt_issuer


def test_auth_member_cert(setup_kms):
status_code, auth_json = auth(auth="member_cert")
assert status_code == 200
assert auth_json["auth"]["policy"] == "member_cert"


def test_auth_jwt(setup_kms, setup_jwt_issuer):
apply_kms_constitution()
trust_jwt_issuer()
status_code, auth_json = auth(auth="jwt")
assert status_code == 200
assert auth_json["auth"]["policy"] == "jwt"


def test_auth_jwt_new_issuer(setup_kms, setup_jwt_issuer):
issuer = "https://new-issuer"
apply_kms_constitution()
trust_jwt_issuer(iss=issuer)
status_code, auth_json = auth(auth="jwt", jwtprops=f"?iss={issuer}")
assert status_code == 200


def test_auth_jwt_wrong_iss(setup_kms, setup_jwt_issuer):
apply_kms_constitution()
trust_jwt_issuer()
status_code, auth_json = auth(auth="jwt", jwtprops="?iss=test")
assert status_code == 401


if __name__ == "__main__":
import pytest
pytest.main([__file__, "-s"])
7 changes: 5 additions & 2 deletions test/system-test/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,12 @@ def remove_key_release_policy():
)


def trust_jwt_issuer():
def trust_jwt_issuer(iss=""):
command = ["scripts/kms/jwt_issuer_trust.sh"]
if iss:
command.extend(["--iss", iss])
subprocess.run(
"scripts/kms/jwt_issuer_trust.sh",
command,
cwd=REPO_ROOT,
check=True,
)
Expand Down
9 changes: 9 additions & 0 deletions test/utils/jwt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Token issuer

## Request
```
curl -X POST ${AadEndpoint:-http://localhost:3000/token} \
Copy link
Collaborator

Choose a reason for hiding this comment

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

This needs updating since #266

-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=${ClientApplicationId:-}&client_secret=${ClientSecret:-}&scope=${ApiIdentifierUri:-}/.default&grant_type=client_credentials" \
-w "\n"
```
Loading
Loading