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

Tenant Issuer Config Related Fixes #737

Closed
wants to merge 10 commits into from
8 changes: 8 additions & 0 deletions charts/traction/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,17 @@ acapy:
wallet_name: traction_innkeeper
print_key: false
print_token: false
connect_to_endorser: [
{
"endorser_alias": "endorser",
"ledger_id": "bcovrin-test",
}
]
create_public_did: ["bcovrin-test"]
reservation:
expiry_minutes: 2880
auto_approve: false
self_issuer_permission: false
## Acapy resource requests and limits
## ref: https://kubernetes.io/docs/user-guide/compute-resources/
## @param acapy.resources.limits.memory The memory limit for the Acapy containers
Expand Down
8 changes: 8 additions & 0 deletions deploy/traction/values-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ acapy:
innkeeper_wallet:
print_key: true
print_token: true
connect_to_endorser: [
{
"endorser_alias": "endorser",
"ledger_id": "bcovrin-test",
}
]
create_public_did: ["bcovrin-test"]
reservation:
expiry_minutes: 2880
auto_approve: false
self_issuer_permission: false
resources:
limits:
cpu: 200m
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

from .endorser_connection_service import EndorserConnectionService
from ..tenant.routes import SWAGGER_CATEGORY
from ..innkeeper.tenant_manager import TenantManager
from ..innkeeper.models import TenantRecord

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -68,10 +70,28 @@ async def endorser_connection_set(request: web.BaseRequest):

"""
context: AdminRequestContext = request["context"]
tenant_wallet_id = context.profile.settings.get("wallet.id")
tenant_mgr = context.inject(TenantManager)
root_profile = tenant_mgr.profile
profile = context.profile
# TODO use when multi ledger support is implemented
endorser_config = profile.settings.get("tenant.endorser_config", [])
public_did_config = profile.settings.get("tenant.public_did_config", [])
async with root_profile.session() as session:
tenant_record = await TenantRecord.query_by_wallet_id(session, tenant_wallet_id)
# issuer check
if (
not tenant_record.connected_to_endorsers
or not tenant_record.created_public_did
or (
tenant_record.connected_to_endorsers
and tenant_record.connected_to_endorsers == []
)
or (tenant_record.created_public_did and tenant_record.created_public_did == [])
):
raise web.HTTPBadRequest(
reason=(
"Tenant is not configured as an issuer, cannot "
"connect with endorser or create public did"
)
)
endorser_srv = context.inject(EndorserConnectionService)
info = endorser_srv.endorser_info(profile)
if not info:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ class Config:
alias_generator = _alias_generator
allow_population_by_field_name = True

def serialize(self) -> dict:
"""Serialize the EndorserLedgerConfig to a mapping."""
ret = {}
if self.endorser_alias:
ret["endorser_alias"] = self.endorser_alias
if self.ledger_id:
ret["ledger_id"] = self.ledger_id
return ret


class InnkeeperWalletConfig(BaseModel):
tenant_id: Optional[str] # real world, this is a UUID
Expand Down Expand Up @@ -50,14 +59,15 @@ def default(cls):
class ReservationConfig(BaseModel):
expiry_minutes: int
auto_approve: bool
self_issuer_permission: bool = False

class Config:
alias_generator = _alias_generator
allow_population_by_field_name = True

@classmethod
def default(cls):
return cls(expiry_minutes=60, auto_approve=False)
return cls(expiry_minutes=60, auto_approve=False, self_issuer_permission=False)


class TractionInnkeeperConfig(BaseModel):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ def __init__(
wallet_id: str = None,
connected_to_endorsers: List = [],
created_public_did: List = [],
self_issuer_permission: bool = False,
**kwargs,
):
"""Construct record."""
Expand All @@ -271,6 +272,7 @@ def __init__(
self.wallet_id = wallet_id
self.connected_to_endorsers = connected_to_endorsers
self.created_public_did = created_public_did
self.self_issuer_permission = self_issuer_permission

@property
def tenant_id(self) -> Optional[str]:
Expand All @@ -287,6 +289,7 @@ def record_value(self) -> dict:
"wallet_id",
"connected_to_endorsers",
"created_public_did",
"self_issuer_permission",
)
}

Expand Down Expand Up @@ -371,6 +374,12 @@ class Meta:
required=False,
)

self_issuer_permission = fields.Bool(
required=False,
description="True if tenant can make itself issuer, false if only innkeeper can",
default=False,
)


class TenantAuthenticationApiRecord(BaseRecord):
"""Innkeeper Tenant Authentication - API Record Schema"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,9 +460,9 @@ async def tenant_config_update(request: web.BaseRequest):
tenant_id = request.match_info["tenant_id"]
async with profile.session() as session:
tenant_record = await TenantRecord.retrieve_by_id(session, tenant_id)
if connect_to_endorser:
if connect_to_endorser or connect_to_endorser == []:
tenant_record.connected_to_endorsers = connect_to_endorser
if create_public_did:
if create_public_did or create_public_did == []:
tenant_record.created_public_did = create_public_did
await tenant_record.save(session)
return web.json_response(tenant_record.serialize())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from aries_cloudagent.storage.error import StorageError, StorageNotFoundError
from aries_cloudagent.wallet.models.wallet_record import WalletRecord

from .config import TractionInnkeeperConfig, InnkeeperWalletConfig
from .config import TractionInnkeeperConfig, InnkeeperWalletConfig, ReservationConfig
from .models import TenantRecord, ReservationRecord


Expand Down Expand Up @@ -54,6 +54,23 @@ async def create_wallet(
# (mostly) duplicate code.

try:
if "tenant.endorser_config" in extra_settings:
connect_to_endorsers = extra_settings.get("tenant.endorser_config")
del extra_settings["tenant.endorser_config"]
else:
connect_to_endorsers = self._config.innkeeper_wallet.connect_to_endorser
if "tenant.public_did_config" in extra_settings:
created_public_did = extra_settings.get("tenant.public_did_config")
del extra_settings["tenant.public_did_config"]
else:
created_public_did = self._config.innkeeper_wallet.create_public_did
if "tenant.self_issuer_permission" in extra_settings:
self_issuer_permission = extra_settings.get(
"tenant.self_issuer_permission"
)
del extra_settings["tenant.self_issuer_permission"]
else:
self_issuer_permission = self._config.reservation.self_issuer_permission
# we must stick with managed until AcaPy has full support for unmanaged.
# transport/inbound/session.py only deals with managed.
key_management_mode = WalletRecord.MODE_MANAGED
Expand Down Expand Up @@ -87,13 +104,18 @@ async def create_wallet(
except BaseError as err:
self._logger.error(f"Error creating wallet ('{wallet_name}').", err)
raise err

# self_issuer_permission check
innkeeper_tenant_id = self._config.innkeeper_wallet.tenant_id
if not self_issuer_permission or tenant_id == innkeeper_tenant_id:
connect_to_endorsers = []
created_public_did = []
# ok, all is good, then create a tenant record
tenant = await self.create_tenant(
wallet_id=wallet_record.wallet_id,
tenant_id=tenant_id,
connected_to_endorsers=extra_settings.get("tenant.endorser_config"),
created_public_did=extra_settings.get("tenant.public_did_config"),
connected_to_endorsers=connect_to_endorsers,
created_public_did=created_public_did,
self_issuer_permission=self_issuer_permission,
)

return tenant, wallet_record, token
Expand All @@ -114,6 +136,7 @@ async def create_tenant(
wallet_id: str,
connected_to_endorsers: List = [],
created_public_did: List = [],
self_issuer_permission: bool = False,
tenant_id: str = None,
):
try:
Expand All @@ -129,8 +152,12 @@ async def create_tenant(
tenant_name=tenant_name,
wallet_id=wallet_record.wallet_id,
new_with_id=tenant_id is not None,
connected_to_endorsers=connected_to_endorsers,
connected_to_endorsers=list(
endorser_config.serialize()
for endorser_config in connected_to_endorsers
),
created_public_did=created_public_did,
self_issuer_permission=self_issuer_permission,
)
await tenant.save(session, reason="New tenant")
# self._logger.info(tenant)
Expand All @@ -142,6 +169,7 @@ async def create_tenant(

async def create_innkeeper(self):
config: InnkeeperWalletConfig = self._config.innkeeper_wallet
reservation_config: ReservationConfig = self._config.reservation
tenant_id = config.tenant_id
wallet_name = config.wallet_name
wallet_key = config.wallet_key
Expand All @@ -163,14 +191,14 @@ async def create_innkeeper(self):
self._logger.info(f"'{wallet_name}' wallet exists.")
token = await self.get_token(wallet_record, wallet_key)
else:
self._logger.info(f"creating '{wallet_name}' wallet...")
tenant_record, wallet_record, token = await self.create_wallet(
wallet_name,
wallet_key,
{
"wallet.innkeeper": True,
"tenant.endorser_config": config.connect_to_endorser,
"tenant.public_did_config": config.create_public_did,
"tenant.self_issuer_permission": reservation_config.self_issuer_permission,
},
tenant_id,
)
Expand All @@ -183,6 +211,9 @@ async def create_innkeeper(self):
print(f"wallet.wallet_id = {wallet_record.wallet_id}")
print(f"tenant.endorser_config = {tenant_record.connected_to_endorsers}")
print(f"tenant.public_did_config = {tenant_record.created_public_did}")
print(
f"tenant.self_issuer_permission = {str(tenant_record.self_issuer_permission)}"
)
_key = wallet_record.wallet_key if config.print_key else "********"
print(f"wallet.wallet_key = {_key}\n")
if config.print_token:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class TenantConfigSchema(OpenAPISchema):
),
description="Public DID config",
)
self_issuer_permission = fields.Bool(
required=False,
description="True if tenant can make itself issuer, false if only innkeeper can",
default=False,
Comment on lines +47 to +48
Copy link
Member

Choose a reason for hiding this comment

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

Might be better described as True if tenants are automatically allowed to be issuers, False if innkeeper approval is required". Maybe the flag needs to be renamed as well to something more consistent to the behaviour, like auto_issuer_permission`?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to auto_issuer to be consistent with other flags in reservation config like auto_approve.

)


def generate_reservation_token_data(expiry_minutes: int):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,12 @@ async def tenant_config_get(request: web.BaseRequest):
tenant_record = await TenantRecord.query_by_wallet_id(session, wallet_id)
endorser_config = tenant_record.connected_to_endorsers
public_did_config = tenant_record.created_public_did
tenant_issuer_flag = tenant_record.self_issuer_permission
return web.json_response(
{
"connect_to_endorser": endorser_config,
"create_public_did": public_did_config,
"self_issuer_permission": tenant_issuer_flag,
}
)

Expand Down
8 changes: 8 additions & 0 deletions scripts/plugin-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ traction_innkeeper:
wallet_key: change-me
print_key: true
print_token: true
connect_to_endorser: [
{
"endorser_alias": "endorser",
"ledger_id": "bcovrin-test",
}
]
create_public_did: ["bcovrin-test"]
reservation:
auto_approve: true
expiry_minutes: 2880
self_issuer_permission: false
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ const { loading } = storeToRefs(useInnkeeperTenantsStore());
const innkeeperTenantsStore = useInnkeeperTenantsStore();
// For the innkeeper tenant, reuse here for getting configured endorser
const tenantStore = useTenantStore();
const { endorserInfo, loading: loadingEndorser } = storeToRefs(
useTenantStore()
);
const {
endorserInfo,
tenantConfig,
loading: loadingEndorser,
} = storeToRefs(useTenantStore());

// Props
const props = defineProps<{
Expand All @@ -92,19 +94,32 @@ const handleSubmit = async (isFormValid: boolean) => {
if (!isFormValid) {
return;
}

let connect_to_endorser_payload = [];
let create_public_did_payload = [];
if (tenantConfig.value?.connect_to_endorser?.length) {
connect_to_endorser_payload = tenantConfig.value.connect_to_endorser;
} else {
connect_to_endorser_payload = [
{
endorser_alias: endorserInfo.value?.endorser_name || '',
ledger_id: config.value.frontend?.ariesDetails?.ledgerName,
},
];
}
if (tenantConfig.value?.create_public_did?.length) {
create_public_did_payload = tenantConfig.value.create_public_did;
} else {
create_public_did_payload = [
config.value.frontend?.ariesDetails?.ledgerName,
];
}
try {
await innkeeperTenantsStore.updateTenantConfig(props.tenant.tenant_id, {
connect_to_endorser: formFields.canConnectEndorser
? [
{
endorser_alias: endorserInfo.value?.endorser_name || '',
ledger_id: config.value.frontend?.ariesDetails?.ledgerName,
},
]
? connect_to_endorser_payload
: [],
create_public_did: formFields.canRegisterDid
? [config.value.frontend?.ariesDetails?.ledgerName]
? create_public_did_payload
: [],
});
toast.success('Tenant Settings Updated');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3418,6 +3418,8 @@ export interface TenantConfig {
connect_to_endorser?: EndorserLedgerConfig[];
/** Public DID config */
create_public_did?: string[];
/** self issuer permission flag */
self_issuer_permission?: boolean;
}

export interface TenantList {
Expand Down
Loading