-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* update docstrings * formatting * lines too long * update docstrings * update model to enforce payload and enforce one of did/verification method * formatting * update docstrings * fix typo * updated docstrings sd-jws/jws * formatting * add example payload * formatting move string around * add example payload * shorten string * fix typo * some minor edits * minor edits to sd_jws * typo * jes unit tests * add sd_jwt unit tests * 🎨 * 🎨 * 🎨 * test jws model * 🎨 * edits * 🎨 * 🎨 Updated docstrings * 🎨 --------- Co-authored-by: ff137 <[email protected]>
- Loading branch information
Showing
8 changed files
with
729 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,16 +23,91 @@ | |
"/sign", | ||
response_model=SDJWSCreateResponse, | ||
summary="Sign SD-JWS", | ||
description=""" | ||
Sign Select Disclosure for JWS (SD-JWS) | ||
See https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html for the SD-JWT / SD-JWS spec. | ||
""", | ||
) | ||
async def sign_sd_jws( | ||
body: SDJWSCreateRequest, | ||
auth: AcaPyAuth = Depends(acapy_auth_from_header), | ||
) -> SDJWSCreateResponse: | ||
""" | ||
Sign a Selective Disclosure JSON Web Signature (SD-JWS). | ||
--- | ||
This endpoint allows users to create a Selective Disclosure JSON Web Signature (SD-JWS). | ||
The SD-JWS enables the selective disclosure of specific attributes to a verifier while keeping others confidential. | ||
**Usage:** | ||
- **DID-Based Signing:** Provide the `did` field with a valid DID. | ||
The Aries agent will automatically select the appropriate verification key associated with the DID. | ||
- **Verification Method-Based Signing:** Provide the `verification_method` field with a specific verification method | ||
(DID with verkey) to explicitly specify which key to use for signing. | ||
**Notes:** | ||
- If the issuer uses a `did:sov` DID, ensure that the DID is public. | ||
- The `headers` field is optional. Custom headers can be specified, but the `typ`, `alg`, | ||
and `kid` fields are automatically populated by the Aries agent based on the signing method. | ||
- The `non_sd_list` field specifies attributes that are **not** selectively disclosed. | ||
Attributes listed here will always be included in the SD-JWS. | ||
**Non-Selective Disclosure (`non_sd_list`):** | ||
- To exclude list elements: | ||
- Use the format `"<attribute_name>[start:end]"` where `start` and `end` define the range | ||
(e.g., `"nationalities[1:3]"`). | ||
- To exclude specific dictionary attributes: | ||
- Use the format `"<dictionary_name>.<attribute_name>"` (e.g., `"address.street_address"`). | ||
**Example Request Body:** | ||
```json | ||
{ | ||
"did": "did:sov:39TXHazGAYif5FUFCjQhYX", | ||
"payload": { | ||
"credential_subject": "reference_to_holder", | ||
"given_name": "John", | ||
"family_name": "Doe", | ||
"email": "[email protected]", | ||
"phone_number": "+27-123-4567", | ||
"nationalities": ["a","b","c","d"], | ||
"address": { | ||
"street_address": "123 Main St", | ||
"locality": "Anytown", | ||
"region": "Anywhere", | ||
"country": "ZA" | ||
}, | ||
"birthdate": "1940-01-01" | ||
}, | ||
"non_sd_list": [ | ||
"given_name", | ||
"address", | ||
"address.street_address", | ||
"nationalities", | ||
"nationalities[1:3]" | ||
] | ||
} | ||
``` | ||
Request Body: | ||
--- | ||
SDJWSCreateRequest: | ||
`did` (str, optional): The DID to sign the SD-JWS with. | ||
`verification_method` (str, optional): The verification method (DID with verkey) to use for signing. | ||
`payload` (dict): The JSON payload to be signed. | ||
`headers` (dict, optional): Custom headers for the SD-JWS. | ||
`non_sd_list` (List[str], optional): List of attributes excluded from selective disclosure. | ||
Response: | ||
--- | ||
SDJWSCreateResponse: | ||
`sd_jws` (str): The resulting SD-JWS string concatenated with the necessary disclosures in the format | ||
`<Issuer-signed JWS>~<Disclosure 1>~<Disclosure 2>~...~<Disclosure N>`. | ||
**References:** | ||
- [Selective Disclosure JSON Web Token (SD-JWT) | ||
Specification](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html) | ||
""" | ||
bound_logger = logger.bind( | ||
# Do not log payload: | ||
body=body.model_dump(exclude="payload") | ||
|
@@ -65,16 +140,57 @@ async def sign_sd_jws( | |
"/verify", | ||
response_model=SDJWSVerifyResponse, | ||
summary="Verify SD-JWS", | ||
description=""" | ||
Verify Select Disclosure for JWS (SD-JWS) | ||
See https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html for the SD-JWT / SD-JWS spec. | ||
""", | ||
) | ||
async def verify_sd_jws( | ||
body: SDJWSVerifyRequest, | ||
auth: AcaPyAuth = Depends(acapy_auth_from_header), | ||
) -> SDJWSVerifyResponse: | ||
""" | ||
Verify a Selective Disclosure JSON Web Signature (SD-JWS). | ||
--- | ||
This endpoint allows users to verify the authenticity and integrity of a Selective Disclosure | ||
JSON Web Signature (SD-JWS). It decodes the SD-JWS to retrieve the payload and headers, | ||
assesses its validity, and processes the disclosures. | ||
**Usage:** | ||
- Submit the SD-JWS string concatenated with the necessary disclosures to this endpoint. | ||
- The format should be: `<Issuer-signed JWS>~<Disclosure 1>~<Disclosure 2>~...~<Disclosure N>`. | ||
- The holder provides the SD-JWS along with the required disclosures based on the verifier's request. | ||
**Notes:** | ||
- Only the disclosures relevant to the verifier's request needs to be provided. | ||
Other disclosures can remain confidential. | ||
**Example Request Body:** | ||
```json | ||
{ | ||
"sd_jws": "<Issuer-signed JWS>~<Disclosure 1>~<Disclosure 2>~...~<Disclosure N>" | ||
} | ||
``` | ||
Request Body: | ||
--- | ||
SDJWSVerifyRequest: | ||
`sd_jws` (str): The concatenated SD-JWS and disclosures to verify and reveal. | ||
Response: | ||
--- | ||
SDJWSVerifyResponse: | ||
`valid` (bool): Indicates whether the SD-JWS is valid. | ||
`payload` (dict): The decoded payload of the SD-JWS. | ||
`headers` (dict): The headers extracted from the SD-JWS. | ||
`kid` (str): The Key ID of the signer. | ||
`disclosed_attributes` (dict): The selectively disclosed attributes based on the provided disclosures. | ||
`error` (str, optional): Error message if the SD-JWS verification fails. | ||
**References:** | ||
- [Selective Disclosure JSON Web Token (SD-JWT) | ||
Specification](https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-07.html) | ||
""" | ||
bound_logger = logger.bind(body=body) | ||
bound_logger.debug("POST request received: Verify SD-JWS") | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import pytest | ||
|
||
from app.models.jws import JWSCreateRequest | ||
from shared.exceptions.cloudapi_value_error import CloudApiValueError | ||
|
||
|
||
def test_jws_create_request(): | ||
# no did or verification_method | ||
with pytest.raises(CloudApiValueError) as exc: | ||
JWSCreateRequest(payload={"test": "test_value"}) | ||
|
||
assert exc.value.detail == ( | ||
"One of `did` or `verification_method` must be populated." | ||
) | ||
|
||
# did and verification_method | ||
with pytest.raises(CloudApiValueError) as exc: | ||
JWSCreateRequest( | ||
did="did:sov:AGguR4mc186Tw11KeWd4qq", | ||
payload={"test": "test_value"}, | ||
verification_method="did:sov:AGguR4mc186Tw11KeWd4qq", | ||
) | ||
|
||
assert exc.value.detail == ( | ||
"Only one of `did` or `verification_method` can be populated." | ||
) | ||
|
||
# no payload | ||
with pytest.raises(CloudApiValueError) as exc: | ||
JWSCreateRequest(did="did:sov:AGguR4mc186Tw11KeWd4qq") | ||
|
||
assert exc.value.detail == ("`payload` must be populated.") |
Oops, something went wrong.