-
Notifications
You must be signed in to change notification settings - Fork 27
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
[INJICERT-642] add dev & integrator docs #145
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,31 @@ | ||
# Inji Stack Setup | ||
|
||
This guide provides instructions for setting up and running Inji Stack. | ||
This guide provides instructions for setting up and running Inji Stack for a custom use-case based on an existing configured foundational ID system. | ||
An example for this could be a use-case where Authentication is performed from a pre-existing registry such as a **National ID** being put to use to deliver services such as **Farmer Identity Card** to eligible farmers. | ||
|
||
## Prerequisites | ||
|
||
- Docker and Docker Compose installed on your system | ||
- Git (to clone the repository) | ||
- Basic understanding of Docker and container operations | ||
- Relevant Postman collections are [here](../../docs/postman-collections/), please add the `mock` ones and install the [pmlib library](https://joolfe.github.io/postman-util-lib/) as per the rules given under the heading `Postman Collection`. | ||
|
||
### Building inji-web-proxy | ||
Before running the docker-compose, you need to build the inji-web-proxy image: | ||
|
||
```bash | ||
# Clone the repository | ||
git clone https://github.com/mosip/inji-web.git -b release-0.11.x | ||
cd inji-web/inji-web-proxy | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. password config update step is missing for using the oidckeystore.p12 file of collab. |
||
|
||
```bash | ||
vharsh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# Build the Docker image | ||
docker build -t inji-web-proxy:local . | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use case in the docker compose is Farmer, but the mimoto config file below calls out as Mock which need to be changed correctly. |
||
``` | ||
|
||
## Directory Structure Setup | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Ensure all configuration files are properly updated in the config directory" - this is very level for someone to just try out a usecase using docker componse. |
||
Create the following directory structure before proceeding: | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Change the below property file, since we don't want to point default to hitesh github file for csv changes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Below changes in docker compose are required for this. |
||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have a CSV file along with photo, so the VC is created with photo |
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# Creating a DID Document | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see link in the docker compose readme file to this document There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a link to this file from the docker compose README.md |
||
|
||
A DID document is used to prove the existence and control of a DID(Decentralized Identifier). Besides other important functions it helps expose the public keys in a standards compliant way leading to interoperability. Thus, a Signed Document such as a Verifiable Credential can be assured of coming from the same source and without any unwanted tampering. | ||
|
||
# Steps | ||
|
||
The below steps have been written with for hosting a Ed25519VerificationKey2020 in a DID format. For other VerificationKeys please look through their specs and contribute back to this document. | ||
|
||
**Pre-requisites**: A running Certify setup with an initialized DataProviderPlugin implementation(CertifyIssuer configured) configured and enabled. | ||
Optional: An identity Holder, an identity Verifier | ||
|
||
1. Get the Certificate for the KeyPair which was used to sign the Verifiable Credential from Certify. For Ed25519 key the applicationId & referenceId pair are "CERTIFY_MOCK_ED25519" & "ED25519_SIGN" | ||
|
||
```bash | ||
# This example demonstrates it for an Ed25519 Key created using github.com/mosip/keymanager | ||
# If you've created a keypair with another applicationId & referenceId, do update it accordingly. | ||
|
||
$ curl "https://${CERTIFY_HOST}/v1/certify/system-info/certificate?applicationId=CERTIFY_MOCK_ED25519&referenceId=ED25519_SIGN" | ||
{ | ||
"responseTime": "2024-11-28T12:48:36.299Z", | ||
"response": { | ||
"certificate": "-----BEGIN CERTIFICATE-----[REDACTED]\n\[REDACTED]\n\[REDACTED]\n-----END CERTIFICATE-----\n", | ||
"certSignRequest": null, | ||
"issuedAt": "2024-11-04T04:12:39.000Z", | ||
"expiryAt": "2026-11-04T04:12:39.000Z", | ||
"timestamp": "2024-11-28T12:48:35.689Z" | ||
}, | ||
"errors": [] | ||
} | ||
``` | ||
|
||
2. Place the Certificate in a file and convert it into a public key after it's represented properly in a file. | ||
|
||
```bash | ||
$ echo "-----BEGIN CERTIFICATE-----[REDACTED]\n\[REDACTED]\n\[REDACTED]\n-----END CERTIFICATE-----\n" > cert.pem | ||
$ openssl x509 -pubkey -noout -in cert.pem > cert-pub.pem | ||
``` | ||
|
||
3. Get the public key and use the [multibase.py](../utils/multibase-script/multibase.py) and run this script. | ||
|
||
```bash | ||
# NOTE: You may have to do this in your own python virtual environment and install requisite dependencies | ||
# Please refer to your Python Virtual Env Manager's documentation for this to get started. | ||
|
||
$ python3 multibase.py cert-pub.pem | ||
Loaded PEM public key from: cert-pub.pem | ||
Multibase: [REDACTED] | ||
Raw key length: 32 | ||
Raw key hex: [REDACTED] | ||
Original key length: 32 | ||
Original key hex: [REDACTED] | ||
Keys match: True | ||
``` | ||
|
||
4. Copy the Multibase value and create a DID document. | ||
|
||
```bash | ||
# this example demonstrates using the an example DID hosted on https://example.github.io/DID/acme | ||
$ cat did.json | ||
{ | ||
"@context": [ | ||
"https://www.w3.org/ns/did/v1" | ||
], | ||
"id": "did:web:vharsh.github.io:DID:harsh", | ||
"alsoKnownAs": [ | ||
"[email protected]" | ||
], | ||
"service": [], | ||
"verificationMethod": [ | ||
{ | ||
"id": "did:web:example.github.io:DID:acme#key-0", | ||
"type": "Ed25519VerificationKey2020", | ||
"@context": "https://w3id.org/security/suites/ed25519-2020/v1", | ||
"controller": "did:web:example.github.io:DID:acme", | ||
"publicKeyMultibase": "[REDACTED]" | ||
|
||
} | ||
], | ||
"authentication": [ | ||
"did:web:example.github.io:DID:acme#key-0" | ||
], | ||
"assertionMethod": [ | ||
"did:web:example.github.io:DID:acme#key-0" | ||
] | ||
} | ||
$ | ||
``` | ||
|
||
5. Host the DID document on the matching HTTPS domain and verify if the `did.json` document is hosted correctly via a DID Resolver such as [Uniresolver](https://dev.uniresolver.io/). | ||
|
||
```bash | ||
$ curl https://example.github.io/DID/acme | ||
{ | ||
"@context": [ | ||
"https://www.w3.org/ns/did/v1" | ||
], | ||
"id": "did:web:example.github.io:DID:acme", | ||
"alsoKnownAs": [ | ||
"[email protected]" | ||
], | ||
"service": [], | ||
"verificationMethod": [ | ||
{ | ||
"id": "did:web:example.github.io:DID:acme#key-0", | ||
"type": "Ed25519VerificationKey2020", | ||
"@context": "https://w3id.org/security/suites/ed25519-2020/v1", | ||
"controller": "did:web:example.github.io:DID:acme", | ||
"publicKeyMultibase": "[REDACTED]" | ||
} | ||
], | ||
"authentication": [ | ||
"did:web:example.github.io:DID:acme#key-0" | ||
], | ||
"assertionMethod": [ | ||
"did:web:example.github.io:DID:acme#key-0" | ||
] | ||
} | ||
``` | ||
|
||
# Specifications(for Further reading & better understanding) | ||
|
||
For a more detailed understanding please go through the below specs | ||
|
||
- [Ed25519Signature2020Algorithm Spec](https://www.w3.org/community/reports/credentials/CG-FINAL-di-eddsa-2020-20220724/#ed25519verificationkey2020) | ||
- [did:web spec](https://w3c-ccg.github.io/did-method-web/) | ||
- [DID Core spec](https://www.w3.org/TR/did-core/) | ||
|
||
|
||
# Contributing | ||
|
||
Please feel free to raise PRs to improve the docs or raise issues on the [MOSIP Community](https://community.mosip.io/) if you have doubts. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Local Development of Inji Certify | ||
|
||
**Pre-requisites**: Java 21 installed, Postgres DB installed & configured | ||
|
||
1. Clone the repo, usually the active development happens on the `develop` branch but one can try out one of the `release-x.y.z` branches as well. | ||
2. Run the DB init scripts present in `db_scripts/mosip_certify` , running `deploy.sh deploy.properties` is a good way to init the DB. | ||
3. Decide on the issuance mode of Certify. Some plugins enable Certify to operate as a Proxy and others enable it to work as an Issuer, configure `mosip.certify.issuer` appropriately as `PluginIssuer` or `CertifyIssuer`. | ||
* If you don't have another Issuance module such as Sunbird, MOSIP Stack, you may want to set it up with CertifyIssuer and configure `mosip.certify.issuer.vc-sign-algo`, `mosip.certify.issuer.pub.key`, `mosip.certify.issuer.uri` appropriately. | ||
4. Decide on the VCI plugin for use locally and configure it, while running locally from an IDE such as Eclipse or IntelliJ one needs to add configuration to the `application-local.properties` and add the VCI plugin dependency to the pom.xml of Certify Service. | ||
5. Get an eSignet 1.4.1 setup running configured with the appropriate Authenticator plugin implementation matching the VCI plugin. | ||
* Configure `mosip.certify.authorization.url` to point to your Authorization service, this could be a working eSignet instance or another AuthZ provider configured with an [Authenticator plugin implementation](https://docs.esignet.io/integration/authenticator) | ||
* Update the well known configuration in `mosip.certify.key-values` to match the Credential type, scope and other fields to match your VerifiableCredential. | ||
* Appropriately configure the `mosip.certify.authn.allowed-audiences` to allowed audiences such that it matches with the AuthZ token when the Credential issue request is made to Certify. | ||
6. Perform Authentication & VC Issuance to see if the Certify & AuthZ stack is working apprpriately. Look out for the Postman collections referred to in the main README.md of this project. | ||
|
||
|
||
## Locally setting up CSV Plugin | ||
|
||
|
||
The above README can be used to setup the [CSV Plugin](https://github.com/mosip/digital-credential-plugins/tree/develop/mock-certify-plugin) and it'll help showcase how one can setup a custom authored plugin for local testing. | ||
|
||
Pre-requisites: | ||
|
||
* a working Authorization service which gives an identifiable information in the end-user's ID in the `sub` field | ||
* pre-populated CSV file configured with the matching identities to be authenticated against |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Developer READMEs | ||
|
||
- [Local Development](./Local-Development.md) | ||
- [How to decide b/w VCIssuance & DataProviderPlugin while writing your own](./VCIssuance-vs-DataProvider.md) | ||
|
||
# Integrator READMEs | ||
|
||
- [How to host a DID document](./Hosting-DID-Document.md) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# VCIssuance vs DataProvider | ||
|
||
|
||
Certify has a plugin model to issue VCs so that implementors can extend Inji Certify to issue various VCs and and the plugin can be of two types. | ||
|
||
1. VCIssuancePlugin | ||
2. DataProviderPlugin | ||
|
||
While they are two types of Issuing Plugins, both types are issuing VCs by connecting to a configured datasource. The two types of Plugins enable Inji Certify to operate differ in where VC Signing happens. | ||
|
||
## How to choose to implement either one? | ||
|
||
- An integrator can choose to implement VCIssuancePlugin interface if they want to implement the VC Signing by themselves. This gives more power to the VC Plugin authors in choosing to support their own formats, signing algorithms which may or may not be supported by Certify. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This has to come out little differently, we have to say if the implementor already has a VC generation system in place and wishes to use that and use the certify only for delivering the VC in OpenID4VCI way to the holder There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing it to...
|
||
- There may be a case, where an integrator might want Certify to deal with fewer aspects of VCIssuance or may not trust Certify with their unsigned data payload, in this case the implementors can choose to implement DataProviderPlugin interface and only implement the business logic required to fetch the data based on the claims object. | ||
vharsh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
- Both plugins can leave some aspects of the configuration to the Certify's configuration provider which can be a bunch of static config files or something such as Spring Config Server. | ||
|
||
# Summary | ||
|
||
| **Property** | VCIssuancePlugin | DataProviderPlugin | | ||
|-------------------|------------------------------------|--------------------| | ||
| VC Signing | managed by the plugin itself | done by Inji Certify itself | | ||
| Credential Creation | done by the plugin itself | done by plugin itself | | ||
| Signing key management | can be done by plugin or delegated to keymanager lib | done by Inji Certify end-to-end via keymanager | | ||
| VC Issuance | done by the plugin completely | data is given by the plugin, VC issuance is done by Inji Certify | | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this table to be little more simplified. what is the VC signing vs credential creation ? |
||
|
||
# Doubts? | ||
|
||
If you've further questions, do not hesitate to ask a question about the same in [MOSIP Community](cd ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import os | ||
vharsh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import argparse | ||
from cryptography.hazmat.primitives import serialization | ||
from cryptography.hazmat.primitives.asymmetric import ed25519 | ||
import base58 | ||
|
||
def pem_to_eddsa_multibase(pem_str, prefix='z'): | ||
""" | ||
Convert PEM to EdDSA and then to multibase | ||
""" | ||
try: | ||
# Load PEM public key | ||
public_key = serialization.load_pem_public_key(pem_str.encode()) | ||
|
||
# Convert to EdDSA raw bytes | ||
raw_bytes = public_key.public_bytes( | ||
encoding=serialization.Encoding.Raw, | ||
format=serialization.PublicFormat.Raw | ||
) | ||
|
||
# Prepend multicodec prefix for Ed25519 (0xed01) | ||
multicodec_bytes = bytes.fromhex('ed01') | ||
final_bytes = multicodec_bytes + raw_bytes | ||
|
||
# Convert to base58btc with prefix | ||
return prefix + base58.b58encode(final_bytes).decode('utf-8') | ||
except Exception as e: | ||
print(f"Error converting to multibase: {str(e)}") | ||
raise | ||
|
||
def multibase_to_eddsa_key(multibase_str): | ||
""" | ||
Convert multibase back to EdDSA public key | ||
""" | ||
try: | ||
# Remove prefix | ||
base58_str = multibase_str[1:] | ||
|
||
# Decode base58 to raw bytes | ||
decoded = base58.b58decode(base58_str) | ||
|
||
# Remove multicodec prefix (first 2 bytes) | ||
raw_bytes = decoded[2:] | ||
|
||
# Create EdDSA public key object | ||
return ed25519.Ed25519PublicKey.from_public_bytes(raw_bytes) | ||
except Exception as e: | ||
print(f"Error converting from multibase: {str(e)}") | ||
raise | ||
|
||
def load_pem_file(file_path): | ||
""" | ||
Load the PEM file containing the public key | ||
""" | ||
if not os.path.isfile(file_path): | ||
raise FileNotFoundError(f"The file {file_path} does not exist.") | ||
|
||
with open(file_path, 'r') as pem_file: | ||
return pem_file.read() | ||
|
||
def main(): | ||
# Parse command-line arguments | ||
parser = argparse.ArgumentParser(description="Convert a PEM public key to and from multibase encoding") | ||
parser.add_argument("pem_file", help="Path to the PEM file containing the public key") | ||
args = parser.parse_args() | ||
|
||
# Load the public key from the PEM file | ||
try: | ||
pem_str = load_pem_file(args.pem_file) | ||
print(f"Loaded PEM public key from: {args.pem_file}") | ||
|
||
# Convert to multibase | ||
multibase = pem_to_eddsa_multibase(pem_str) | ||
print("Multibase:", multibase) | ||
|
||
# Convert back and verify length | ||
recovered_key = multibase_to_eddsa_key(multibase) | ||
raw_bytes = recovered_key.public_bytes( | ||
encoding=serialization.Encoding.Raw, | ||
format=serialization.PublicFormat.Raw | ||
) | ||
print("Raw key length:", len(raw_bytes)) # Should be 32 bytes | ||
print("Raw key hex:", raw_bytes.hex()) | ||
|
||
# Verify the original key bytes | ||
original_key = serialization.load_pem_public_key(pem_str.encode()) | ||
original_bytes = original_key.public_bytes( | ||
encoding=serialization.Encoding.Raw, | ||
format=serialization.PublicFormat.Raw | ||
) | ||
print("Original key length:", len(original_bytes)) # Should be 32 bytes | ||
print("Original key hex:", original_bytes.hex()) | ||
|
||
# Verify they match | ||
print("Keys match:", raw_bytes == original_bytes) | ||
|
||
except Exception as e: | ||
print(f"Error: {str(e)}") | ||
|
||
if __name__ == "__main__": | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Setup instructions | ||
|
||
**Pre-requisites**: | ||
|
||
* Python interpreter | ||
* Virutal Environment manager | ||
* Required dependencies installed | ||
|
||
|
||
To use this script: | ||
|
||
Run | ||
|
||
```bash | ||
$ ls | ||
multibase.py public-key.pem | ||
$ python3 multibase.py public-key.pem | ||
... | ||
``` | ||
|
||
Detailed instructions available at [docs](../../docs/Hosting-DID-Document.md) for hosting an Ed25519VerificationKey2020. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check the status on this with Inji web team, since they may move away from using the proxy project to nginx config and this step might not work
https://mosip.atlassian.net/browse/INJIWEB-1213