Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
132 changes: 132 additions & 0 deletions docker/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
############################################
# Controller Database (Mongo)
############################################
MONGODB_HOST=controller-db
MONGODB_PORT=27017
MONGODB_NAME=oidccontroller
OIDC_CONTROLLER_DB_USER=changeme
OIDC_CONTROLLER_DB_USER_PWD=changeme


############################################
# Controller Core Settings
############################################
DEBUGGER=false
LOG_LEVEL=DEBUG
CONTROLLER_SERVICE_PORT=5000

# Public URLs
CONTROLLER_URL=https://your-public-url.example.com
CONTROLLER_WEB_HOOK_URL=https://your-public-url.example.com/webhooks
CONTROLLER_API_KEY=

# Session & presentation settings
CONTROLLER_CAMERA_REDIRECT_URL=wallet_howto
CONTROLLER_PRESENTATION_EXPIRE_TIME=300
CONTROLLER_PRESENTATION_CLEANUP_TIME=86400
CONTROLLER_SESSION_TIMEOUT_CONFIG_FILE=/etc/controller-config/sessiontimeout.json
CONTROLLER_VARIABLE_SUBSTITUTION_OVERRIDE=/etc/controller-config/user_variable_substitution.py

# Templates and cleanup limits
CONTROLLER_TEMPLATE_DIR=/app/controller-config/templates
CONTROLLER_PRESENTATION_RECORD_RETENTION_HOURS=1
CONTROLLER_CLEANUP_MAX_PRESENTATION_RECORDS=1000
CONTROLLER_CLEANUP_MAX_CONNECTIONS=2000

INVITATION_LABEL="VC-AuthN"
SET_NON_REVOKED=true
ACAPY_PROOF_FORMAT=anoncreds


############################################
# Controller Feature Flags
############################################
USE_REDIS_ADAPTER=false
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_DB=0

USE_CONNECTION_BASED_VERIFICATION=true
USE_OOB_PRESENT_PROOF=true
USE_OOB_LOCAL_DID_SERVICE=true
USE_URL_DEEP_LINK=false
WALLET_DEEP_LINK_PREFIX=bcwallet://aries_proof-request


############################################
# ACA-Py Agent
############################################
AGENT_TENANT_MODE=traction
AGENT_HOST=localhost
AGENT_NAME="VC-AuthN Agent"

AGENT_HTTP_PORT=8030
AGENT_ADMIN_PORT=8077

# Traction / ACA-Py admin endpoints
AGENT_ADMIN_URL=https://traction-admin.example.com
AGENT_ENDPOINT=https://traction-acapy-endpoint.example.com

AGENT_ADMIN_API_KEY=changeme
AGENT_GENESIS_URL=https://test.bcovrin.vonx.io/genesis
AGENT_WALLET_SEED=your-32-char-seed-here-00000000000000


############################################
# ACA-Py Wallet / Tenant Identity
#
# When AGENT_TENANT_MODE=multi:
# ACAPY_TENANT_WALLET_ID = Wallet ID
# ACAPY_TENANT_WALLET_KEY = Wallet Key
#
# When AGENT_TENANT_MODE=traction:
# ACAPY_TENANT_WALLET_ID = Traction Tenant ID
# ACAPY_TENANT_WALLET_KEY = Traction Tenant API Key
############################################
ACAPY_TENANT_WALLET_ID=your-tenant-id-here
ACAPY_TENANT_WALLET_KEY=your-tenant-key-here

# Legacy (ignored when ACAPY_TENANT_* is set)
MT_ACAPY_WALLET_ID=legacy-wallet-id
MT_ACAPY_WALLET_KEY=legacy-wallet-key


############################################
# ACA-Py Single-Tenant Settings (Unused)
############################################
ST_ACAPY_ADMIN_API_KEY_NAME=
ST_ACAPY_ADMIN_API_KEY=


############################################
# OIDC Client
############################################
OIDC_CLIENT_ID=your-client-id
OIDC_CLIENT_NAME="Your Application Name"
OIDC_CLIENT_REDIRECT_URI=https://your-redirect-url.example.com
OIDC_CLIENT_SECRET=your-client-secret


############################################
# Keycloak Database
############################################
KEYCLOAK_DB_NAME=keycloak
KEYCLOAK_DB_USER=keycloak
KEYCLOAK_DB_PASSWORD=changeme


############################################
# Keycloak Service
############################################
KEYCLOAK_DB_VENDOR=postgres
KEYCLOAK_DB_ADDR=keycloak-db
KEYCLOAK_USER=admin
KEYCLOAK_PASSWORD=admin
KEYCLOAK_LOGLEVEL=WARN
KEYCLOAK_ROOT_LOGLEVEL=WARN


############################################
# Logging
############################################
LOG_WITH_JSON=false
4 changes: 4 additions & 0 deletions docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ services:
- ACAPY_TENANCY=${AGENT_TENANT_MODE}
- ACAPY_AGENT_URL=${AGENT_ENDPOINT}
- ACAPY_ADMIN_URL=${AGENT_ADMIN_URL}
# Unified Tenant / Wallet Configuration
- ACAPY_TENANT_WALLET_ID=${ACAPY_TENANT_WALLET_ID}
- ACAPY_TENANT_WALLET_KEY=${ACAPY_TENANT_WALLET_KEY}
# Legacy variables (passed for backward compatibility)
- MT_ACAPY_WALLET_ID=${MT_ACAPY_WALLET_ID}
- MT_ACAPY_WALLET_KEY=${MT_ACAPY_WALLET_KEY}
- ST_ACAPY_ADMIN_API_KEY=${AGENT_ADMIN_API_KEY}
Expand Down
4 changes: 4 additions & 0 deletions docker/manage
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ configureEnvironment() {
AGENT_ADMIN_MODE="admin-api-key ${AGENT_ADMIN_API_KEY}"
fi
export AGENT_WALLET_SEED=${AGENT_WALLET_SEED}
# Unified Tenant / Wallet Config
export ACAPY_TENANT_WALLET_ID=${ACAPY_TENANT_WALLET_ID}
export ACAPY_TENANT_WALLET_KEY=${ACAPY_TENANT_WALLET_KEY}
# Legacy Config
export MT_ACAPY_WALLET_ID=${MT_ACAPY_WALLET_ID}
export MT_ACAPY_WALLET_KEY=${MT_ACAPY_WALLET_KEY}

Expand Down
51 changes: 48 additions & 3 deletions docs/ConfigurationGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ Several functions in ACAPy VC-AuthN can be tweaked by using the following enviro
| Variable | Type | What it does | NOTES |
| ------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| ACAPY_PROOF_FORMAT | string ("indy" or "anoncreds") | Sets the proof format for ACA-Py presentation requests. Use `anoncreds` for modern AnonCreds support or `indy` for legacy Indy-based ecosystems. | Defaults to `indy` for backward compatibility with existing deployments. |
| AGENT_TENANT_MODE | string ("single", "multi", "traction") | **single**: Standard single-tenant agent. <br> **multi**: Standard ACA-Py Multi-tenancy (authenticates via Admin API using Wallet ID/Key). <br> **traction**: Traction Multi-tenancy (authenticates via Tenant API using Tenant ID/API Key). |
| ACAPY_TENANT_WALLET_ID | string | **If Mode=multi**: The `wallet_id` of the sub-wallet. <br> **If Mode=traction**: The `tenant_id` provided by Traction. |
| ACAPY_TENANT_WALLET_KEY | string | **If Mode=multi**: The `wallet_key` used to unlock the sub-wallet. <br> **If Mode=traction**: The Tenant `api_key` provided by Traction. |
| CONTROLLER_WEB_HOOK_URL | string (URL) | **Required for Multi-Tenant Mode.** The public or internal URL where the ACA-Py Agent can reach this Controller to send webhooks (e.g. `http://controller:5000/webhooks`). | The controller will automatically register this URL with the specific tenant wallet on startup. |
| SET_NON_REVOKED | bool | if True, the `non_revoked` attributed will be added to each of the present-proof request `requested_attribute` and `requested_predicate` with 'from=0' and'to=`int(time.time())` | |
| USE_OOB_LOCAL_DID_SERVICE | bool | Instructs ACAPy VC-AuthN to use a local DID, it must be used when the agent service is not registered on the ledger with a public DID | Use this when `ACAPY_WALLET_LOCAL_DID` is set to `true` in the agent. |
Expand All @@ -85,15 +88,57 @@ Several functions in ACAPy VC-AuthN can be tweaked by using the following enviro
| LOG_TIMESTAMP_FORMAT | string | determines the timestamp formatting used in logs | Default is "iso" |
| LOG_LEVEL | "DEBUG", "INFO", "WARNING", or "ERROR" | sets the minimum log level that will be printed to standard out | Defaults to DEBUG |

### Multi-Tenant Webhook Registration
### Legacy Variable Support

When running in Multi-Tenant mode (`ACAPY_TENANCY="multi"`), the ACA-Py Agent may not automatically know where to send verification success notifications for specific tenant wallets.
For backward compatibility with version 2.x deployments, the legacy `MT_` variables are still supported in `multi` mode. However, `ACAPY_TENANT_` variables take precedence if both are set.

| Legacy Variable | Mapped to | Status |
| -------------------- | ------------------------ | ---------- |
| MT_ACAPY_WALLET_ID | ACAPY_TENANT_WALLET_ID | Deprecated |
| MT_ACAPY_WALLET_KEY | ACAPY_TENANT_WALLET_KEY | Deprecated |

### Deployment Examples

**Standard Multi-Tenant (ACA-Py):**
```yaml
environment:
- AGENT_TENANT_MODE=multi
- ACAPY_TENANT_WALLET_ID=3ffd2cf2-5fee-434a-859b-c84f1677e647
- ACAPY_TENANT_WALLET_KEY=my-secure-wallet-key
- CONTROLLER_WEB_HOOK_URL=http://controller:5000/webhooks
```

### Traction Tenancy Mode

The `traction` mode (`AGENT_TENANT_MODE="traction"`) is designed specifically for environments where the ACA-Py Admin API endpoints (e.g., `/multitenancy/wallet/...`) are restricted or blocked for security reasons, which is true of many `traction` environments.

In this mode:
1. **Authentication:** The controller authenticates directly as the tenant using `ACAPY_TENANT_WALLET_ID` (as the Tenant ID) and `ACAPY_TENANT_WALLET_KEY` (as the Tenant API Key) to obtain a Bearer token.
2. **Fallback:** If these keys are not provided, it falls back to trying to authenticate using the legacy `MT_ACAPY_WALLET_ID` and `MT_ACAPY_WALLET_KEY` via the wallet token endpoint (though this may fail if that endpoint is also blocked).
3. **Webhook Registration:** The controller bypasses the Admin API and uses the authenticated Tenant API (`PUT /tenant/wallet`) to register the `CONTROLLER_WEB_HOOK_URL`.

**Example Docker Configuration for Traction:**

```yaml
environment:
- AGENT_TENANT_MODE=traction
- ACAPY_TENANT_WALLET_ID=00000000-0000-0000-0000-000000000000
- ACAPY_TENANT_WALLET_KEY=your-traction-api-key
- CONTROLLER_WEB_HOOK_URL=https://your-controller-url.com/webhooks
- ACAPY_ADMIN_URL=https://traction-tenant-proxy-url
```

### Multi-Tenant and Traction Webhook Registration

When running in Multi-Tenant (`AGENT_TENANT_MODE="multi"`) or Traction (`AGENT_TENANT_MODE="traction"`) modes, the ACA-Py Agent may not automatically know where to send verification success notifications for specific tenant wallets.

To address this, the VC-AuthN Controller performs an automatic handshake on startup:

1. It checks if `CONTROLLER_WEB_HOOK_URL` is defined.
2. If the Controller is protected by `CONTROLLER_API_KEY`, it appends the key to the URL using the `#<key>` syntax. This instructs ACA-Py to parse the hash and send it as an `x-api-key` header in the webhook request.
3. It attempts to connect to the ACA-Py Admin API using the `ST_ACAPY_ADMIN_API_KEY` to update the specific Tenant Wallet configuration.
3. It attempts to connect to the ACA-Py Agent to update the specific Tenant Wallet configuration.
- **Multi Mode:** Uses the Admin API (`/multitenancy/wallet/{id}`) authenticated with `ST_ACAPY_ADMIN_API_KEY`.
- **Traction Mode:** Uses the Tenant API (`/tenant/wallet`) authenticated with the Tenant Token acquired via `ACAPY_TENANT_WALLET_KEY`.
4. If the Agent is not yet ready, the Controller will retry the registration up to 5 times before logging an error.

This ensures that even in complex Docker/Kubernetes network topologies, the Agent sends verification signals to the correct Controller instance.
Expand Down
27 changes: 24 additions & 3 deletions docs/MigrationGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,33 @@ The functionality has mostly remained unchanged, however there are some details

## For versions after 2.3.2

### Multi-Tenant Webhook Configuration
If you are running in Multi-Tenant mode (`ACAPY_TENANCY="multi"`), you **must** now define the `CONTROLLER_WEB_HOOK_URL` environment variable.
### Configuration Unification (Multi-Tenant & Traction)

To simplify configuration and support new integration patterns, the environment variables for multi-tenant identification have been unified.

**New Variables:**
* `ACAPY_TENANT_WALLET_ID`: Replaces `MT_ACAPY_WALLET_ID`.
* `ACAPY_TENANT_WALLET_KEY`: Replaces `MT_ACAPY_WALLET_KEY`.

**Impact on Existing Deployments:**
* **No Action Required:** Existing deployments using `MT_ACAPY_WALLET_ID` and `MT_ACAPY_WALLET_KEY` will continue to work. The system automatically falls back to these variables if the new ones are not present.
* **Recommended Action:** We recommend updating your `docker-compose` or Kubernetes configuration to use the new `ACAPY_TENANT_` variables to ensure future compatibility.

### Multi-Tenant and Traction Webhook Configuration

If you are running in Multi-Tenant (`AGENT_TENANT_MODE="multi"`) or Traction (`AGENT_TENANT_MODE="traction"`) mode, you **must** now define the `CONTROLLER_WEB_HOOK_URL` environment variable.

* **Why:** The controller now explicitly registers this URL with the specific ACA-Py tenant wallet on startup. This fixes issues where OIDC authentication flows would hang because the agent sent verifications to the wrong location or failed authentication.
* **Action Required:** Update your `docker-compose` or Kubernetes config:
```yaml
environment:
- CONTROLLER_WEB_HOOK_URL=https://<your-controller-domain>/webhooks
```
```

### New Tenancy Mode: Traction

A new mode has been added for integrating with Traction (or secured multi-tenant agents where Admin APIs are blocked).

* **Setting:** `AGENT_TENANT_MODE="traction"`
* **Requirements:** Requires `ACAPY_TENANT_WALLET_ID` (as the Traction Tenant ID) and `ACAPY_TENANT_WALLET_KEY` (as the Traction Tenant API Key).
* **Behavior:** Authenticates directly with the Tenant API (`/multitenancy/tenant/{id}/token`) using the provided API Key and bypasses `multitenancy/wallet` Admin endpoints used in standard multi-tenant mode.
9 changes: 8 additions & 1 deletion oidc-controller/api/core/acapy/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
import structlog

from ..config import settings
from .config import AgentConfig, MultiTenantAcapy, SingleTenantAcapy
from .config import (
AgentConfig,
MultiTenantAcapy,
SingleTenantAcapy,
TractionTenantAcapy,
)
from .models import CreatePresentationResponse, OobCreateInvitationResponse, WalletDid

# HTTP timeout for all ACA-Py API calls (seconds)
Expand Down Expand Up @@ -36,6 +41,8 @@ class AcapyClient:
def __init__(self):
if settings.ACAPY_TENANCY == "multi":
self.agent_config = MultiTenantAcapy()
elif settings.ACAPY_TENANCY == "traction":
self.agent_config = TractionTenantAcapy()
elif settings.ACAPY_TENANCY == "single":
self.agent_config = SingleTenantAcapy()
else:
Expand Down
Loading