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

Feature/#281 remove dependency with sd jwt python (#297) #306

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
335bece
Feature/#281 remove dependency with sd jwt python (#297)
LadyCodesItBetter Nov 14, 2024
6bcfaa3
fix: CI and code alignemnt [wip]
peppelinux Nov 14, 2024
3214c67
fix: kid not found issue [wip]
LadyCodesItBetter Nov 15, 2024
c22efcc
Merge pull request #308 from LadyCodesItBetter/pr-306
peppelinux Nov 18, 2024
1ea832a
Apply suggestions from code review
peppelinux Nov 19, 2024
34c27fc
fix: all reference for sym key removed
LadyCodesItBetter Nov 20, 2024
e02393b
feat: add license, documentation and fork disclaimer
LadyCodesItBetter Nov 20, 2024
8431fa8
feat: dynamic MongoDB config via PYEUDIW_MONGO_TEST_AUTH_INLINE
LadyCodesItBetter Nov 20, 2024
47def07
fix: some reference of unused key type
LadyCodesItBetter Nov 20, 2024
01057d9
fix: old methods references
LadyCodesItBetter Nov 20, 2024
daa9d74
fix: wrong connection string
LadyCodesItBetter Nov 20, 2024
07d2e87
fix: last tests kid issue and removed old test in order to use the ne…
LadyCodesItBetter Nov 20, 2024
37c39ba
feat: added logger
LadyCodesItBetter Nov 20, 2024
8bbc0a0
feat: unprotected header management and claims on headers
LadyCodesItBetter Nov 20, 2024
16df309
feat: added json serialization format verifier
LadyCodesItBetter Nov 20, 2024
16cea56
feat: empty authentication settings for tests can be set with custom …
LadyCodesItBetter Nov 20, 2024
b319f97
Apply suggestions from code review
peppelinux Nov 21, 2024
d209ec0
Apply suggestions from code review
peppelinux Nov 21, 2024
2d7cd0f
feat: mongo storage get ttl and remove non deterministic test about t…
peppelinux Nov 21, 2024
87efb37
ci: mongodb upgraded to 8.0 and working dir for unit test configured
peppelinux Nov 21, 2024
04a6242
fix: mongodb in CI set to 7.0
peppelinux Nov 21, 2024
d3466dc
fix: sd-jwt removed from setup.py and pydantic updated
peppelinux Nov 21, 2024
b72d1be
ci: fix bandit
peppelinux Nov 21, 2024
1c54446
fix: import secrets in sd-jwt
peppelinux Nov 21, 2024
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
139 changes: 68 additions & 71 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ name: pyeudiw

on:
push:
branches: [ "*" ]
branches: ["*"]
pull_request:
branches: [ "*" ]
branches: ["*"]

jobs:

pre_job:
runs-on: ubuntu-latest
outputs:
Expand All @@ -19,11 +18,10 @@ jobs:
- id: skip_check
uses: fkirc/[email protected]
with:
skip_after_successful_duplicate: 'true'
same_content_newer: 'true'
skip_after_successful_duplicate: "true"
same_content_newer: "true"

main_job:

needs: pre_job
if: needs.pre_job.outputs.should_skip != 'true'

Expand All @@ -33,72 +31,71 @@ jobs:
fail-fast: false
matrix:
python-version:
- '3.10'
- '3.11'
- '3.12'
- "3.10"
- "3.11"
- "3.12"

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install system package
run: |
sudo apt update
sudo apt install python3-dev python3-pip
- name: Install MongoDB
run: |
sudo apt-get install -y gnupg wget
sudo wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
sudo echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.4 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update
sudo apt-get install -y mongodb-org
- name: Start MongoDB
run: sudo systemctl start mongod
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements-customizations.txt ]; then pip install -r requirements-customizations.txt; fi
python -m pip install -U setuptools
python -m pip install -e .
python -m pip install "Pillow>=10.0.0,<10.1" "device_detector>=5.0,<6" "satosa>=8.4,<8.6" "jinja2>=3.0,<4" "pymongo>=4.4.1,<4.5" aiohttp
python -m pip install git+https://github.com/openwallet-foundation-labs/sd-jwt-python.git
python -m pip install git+https://github.com/peppelinux/pyMDOC-CBOR.git
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install system package
run: |
sudo apt update
sudo apt install python3-dev python3-pip
- name: Install MongoDB
run: |
sudo apt-get install -y gnupg wget
sudo wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -
sudo echo "deb http://repo.mongodb.org/apt/debian buster/mongodb-org/4.4 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list
sudo apt-get update
sudo apt-get install -y mongodb-org
- name: Start MongoDB
run: sudo systemctl start mongod
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f requirements-customizations.txt ]; then pip install -r requirements-customizations.txt; fi
python -m pip install -U setuptools
python -m pip install -e .
python -m pip install "Pillow>=10.0.0,<10.1" "device_detector>=5.0,<6" "satosa>=8.4,<8.6" "jinja2>=3.0,<4" "pymongo>=4.4.1,<4.5" aiohttp
python -m pip install git+https://github.com/peppelinux/pyMDOC-CBOR.git

- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 pyeudiw --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 pyeudiw --count --exit-zero --statistics --max-line-length 160
- name: Tests
run: |
# pytest --cov=pyeudiw --cov-fail-under=90 pyeudiw
pytest --cov=pyeudiw pyeudiw
coverage report -m --skip-covered
- name: Bandit Security Scan
run: |
bandit -r -x pyeudiw/tests* pyeudiw/*
- name: Lint with html linter
run: |
echo -e '\nHTML:'
readarray -d '' array < <(find $SRC example -name "*.html" -print0)
echo "Running linter on (${#array[@]}): "
printf '\t- %s\n' "${array[@]}"
echo "Linter output:"

- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
flake8 pyeudiw --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 pyeudiw --count --exit-zero --statistics --max-line-length 160
- name: Tests
run: |
# pytest --cov=pyeudiw --cov-fail-under=90 pyeudiw
pytest --cov=pyeudiw pyeudiw
coverage report -m --skip-covered
- name: Bandit Security Scan
run: |
bandit -r -x pyeudiw/tests* pyeudiw/*
- name: Lint with html linter
run: |
echo -e '\nHTML:'
readarray -d '' array < <(find $SRC example -name "*.html" -print0)
echo "Running linter on (${#array[@]}): "
printf '\t- %s\n' "${array[@]}"
echo "Linter output:"
for file in "${array[@]}"
do
echo -e "\n$file:"
html_lint.py "$file" | awk -v path="file://$PWD/$file:" '$0=path$0' | sed -e 's/: /:\n\t/';
done

for file in "${array[@]}"
do
echo -e "\n$file:"
html_lint.py "$file" | awk -v path="file://$PWD/$file:" '$0=path$0' | sed -e 's/: /:\n\t/';
done

# block if the html linter fails
#for file in "${array[@]}"
#do
#errors=$(html_lint.py "$file" | grep -c 'Error')
#if [ "$errors" -gt 0 ]; then exit 1; fi;
#done
# block if the html linter fails
#for file in "${array[@]}"
#do
#errors=$(html_lint.py "$file" | grep -c 'Error')
#if [ "$errors" -gt 0 ]; then exit 1; fi;
#done
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,8 @@ env

.DS_Store

docs/source
docs/source

# VSCode
# VSCode specific settings
.vscode/
171 changes: 171 additions & 0 deletions docs/SD-JWT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# sd-jwt-python Fork with cryptojwt

## Introduction

This module is a fork of the original [sd-jwt-python](https://github.com/openwallet-foundation-labs/sd-jwt-python) project. It has been adapted to use the [`cryptojwt`](https://github.com/IdentityPython/JWTConnect-Python-CryptoJWT) library as the core JWT implementation.
peppelinux marked this conversation as resolved.
Show resolved Hide resolved

The purpose of this fork is to:
1. Leverage the robustness and extended features provided by the `cryptojwt` library.
2. Maintain compatibility with existing SD-JWT specifications.
3. Provide a more modular and extensible codebase for advanced use cases.
peppelinux marked this conversation as resolved.
Show resolved Hide resolved

If you're familiar with the original `sd-jwt-python` library, this fork retains similar functionality with minimal API changes, if needed.

---

## Features

- **SD-JWT Support**: Implements the Selective Disclosure JWT standard.
- **`cryptojwt` Integration**: Leverages a mature and feature-rich library for JWT operations.
- **Backward Compatibility**: Minimal changes required for existing users of `sd-jwt-python`.
- **Improved Flexibility**: Extensible for custom SD-JWT use cases.

---

# SD-JWT Library Usage Documentation

## Introduction

This library provides an implementation of the SD-JWT (Selective Disclosure for JWT) standard. This document explains how to create and verify a Selected-Disclosure JWT (SD-JWT) using the EUDI Wallet IT Python library. It also covers how to validate proof of possession enabling three key operations:
peppelinux marked this conversation as resolved.
Show resolved Hide resolved
1. **Issuer**: Generate an SD-JWT with selective disclosure capabilities.
2. **Holder**: Select claims to disclose and create a presentation.
3. **Verifier**: Validate the SD-JWT and verify the disclosed claims.

### Requirements
- Python 3.7 or later.
peppelinux marked this conversation as resolved.
Show resolved Hide resolved
- Install the library via `pip`:
```bash
pip install pyeudiw
```

- **Key Requirements**:
- All keys must be in JWK (JSON Web Key) format, conforming to [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517).
- You can use a library like `cryptojwt` to generate or manage JWKs. Example:

```bash
from cryptojwt.jwk.ec import new_ec_key

# Generate an EC key pair
issuer_private_key = new_ec_key('P-256')

# Serialize the keys
issuer_keys = [issuer_private_key.serialize(private=True)] # List of private keys
public_key = issuer_private_key.serialize() # Public key
```
---

## 1. Issuer: Generating an SD-JWT

The Issuer creates an SD-JWT using the user's claims (`user_claims`) and a private key in JWK format to sign the token.

### Example

```bash
from pyeudiw.sd_jwt.issuer import SDJWTIssuer

# User claims
user_claims = {
"sub": "john_doe_42",
"given_name": "John",
"family_name": "Doe",
"email": "[email protected]",
}

# Generate private keys
issuer_private_key = new_ec_key('P-256')
issuer_keys = [issuer_private_key.serialize(private=True)] # List of private JWKs
holder_key = new_ec_key('P-256').serialize(private=True) # Holder private key (optional)

# Create SD-JWT
sdjwt_issuer = SDJWTIssuer(
user_claims=user_claims,
issuer_keys=issuer_keys, # List of private JWKs
holder_key=holder_key, # Holder key (optional)
add_decoy_claims=True, # Add decoy claims for privacy
serialization_format="compact" # Compact JWS format
)

# Output SD-JWT and disclosures
print("SD-JWT Issuance:", sdjwt_issuer.sd_jwt_issuance)
```

---

## 2. Holder: Creating a Selective Disclosure Presentation

The Holder receives the SD-JWT from the Issuer and selects which claims to disclose to the Verifier.

### Example

```bash
from pyeudiw.sd_jwt.holder import SDJWTHolder

# Claims to disclose
holder_disclosed_claims = {
"given_name": True,
"family_name": True
}

# Initialize Holder
sdjwt_holder = SDJWTHolder(sdjwt_issuer.sd_jwt_issuance)

# Create presentation with selected claims
sdjwt_holder.create_presentation(
disclosed_claims=holder_disclosed_claims,
nonce=None, # Optional: Used for key binding
verifier=None, # Optional: Verifier identifier for key binding
holder_key=holder_key # Optional: Holder private key for key binding
)

# Output the presentation
print("SD-JWT Presentation:", sdjwt_holder.sd_jwt_presentation)
```

---
peppelinux marked this conversation as resolved.
Show resolved Hide resolved

## 3. Verifier: Verifying an SD-JWT

The Verifier validates the SD-JWT and checks the disclosed claims.

### Example

```bash
peppelinux marked this conversation as resolved.
Show resolved Hide resolved
from pyeudiw.sd_jwt.verifier import SDJWTVerifier

# Callback to retrieve Issuer's public key
def get_issuer_public_key(issuer, header_parameters):
# Return the public key(s) in JWK format
return [issuer_private_key.serialize()]

# Initialize Verifier
sdjwt_verifier = SDJWTVerifier(
sdjwt_presentation=sdjwt_holder.sd_jwt_presentation,
cb_get_issuer_key=get_issuer_public_key
)

# Verify and retrieve payload
verified_payload = sdjwt_verifier.get_verified_payload()

# Verified claims
print("Verified Claims:", verified_payload)
```

---
peppelinux marked this conversation as resolved.
Show resolved Hide resolved

## Key Considerations

1. **JWK Format**: All keys (private and public) must conform to the JWK standard (RFC 7517).
2. **Generating Keys**: Use a library like `cryptojwt` to generate or manage JWKs.
3. **Custom Keys**: If you already have keys, ensure they are in the correct JWK format before use.

peppelinux marked this conversation as resolved.
Show resolved Hide resolved
---

## Conclusion

This documentation demonstrates how to:
- Create SD-JWTs with selective disclosure capabilities.
- Allow Holders to share only necessary claims.
- Validate SD-JWTs and verify disclosed claims securely.

For further details, consult the library's source code and examples.
peppelinux marked this conversation as resolved.
Show resolved Hide resolved
```
32 changes: 29 additions & 3 deletions example/satosa/integration_test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,41 @@ This integration test will verify a full authentication flow of a simulated IT-W
### Environment

An up an running Openid4VP Relying Party is a requirement of this project.
The intended Relying Party of this integration test is the example one provided in the repostiory [https://github.com/italia/Satosa-Saml2Spid](https://github.com/italia/Satosa-Saml2Spid).
The intended Relying Party of this integration test is the example one provided in the repository [https://github.com/italia/Satosa-Saml2Spid](https://github.com/italia/Satosa-Saml2Spid).
That project will provide full instruction on how to setup such an environment with Docker.

Before starting, make sure that the `pyeudiw_backend.yaml` is properly configured and included in the file `proxy_conf.yaml` that is running in your Docker environemnt.
Before starting, make sure that the `pyeudiw_backend.yaml` is properly configured and included in the file `proxy_conf.yaml` that is running in your Docker environment.
This project folder always provide up to date example of the pyeudiw plugin configuration in the file [pyeudiw_backend.yaml](./pyeudiw_backend.yaml), as well as other configuration file of the module in [static](./static/) and [template](./template/) folders.

#### MongoDB Configuration for Tests

The MongoDB connection is configured dynamically using the environment variable `PYEUDIW_MONGO_TEST_AUTH_INLINE`.

#### How It Works
- The value of `PYEUDIW_MONGO_TEST_AUTH_INLINE` should be in the format `username:password@`.
- If the variable is not set, the configuration defaults to:
- **Authentication**: Defaults to empty string.
- **MongoDB URL**: `mongodb://satosa:localhost:27017/?timeoutMS=2000`.
peppelinux marked this conversation as resolved.
Show resolved Hide resolved

#### Example Usage
1. **With Authentication**:
Set the environment variable:
```bash
export PYEUDIW_MONGO_TEST_AUTH_INLINE="satosa:thatpassword@"
```

or just using `.env` file

#### Custom Behavior
You can override the default credentials by setting the environment variable:

```bash
export PYEUDIW_MONGO_TEST_AUTH_INLINE="customuser:custompassword@"
```

### Dependencies

Requirements eexclusive to the integration test can be installed with
Requirements exclusive to the integration test can be installed with

pip install -r requirements_test.txt

Expand Down
Loading
Loading