Skip to content

Commit

Permalink
feat: create consent challenge verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
cowan-macady committed Apr 17, 2023
1 parent dd8a109 commit 299d867
Show file tree
Hide file tree
Showing 7 changed files with 298 additions and 18 deletions.
103 changes: 91 additions & 12 deletions indykite_sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,7 @@ positional arguments:
tenant_id String
```
74. Is Digital Twin identified by token Authorized to perform an Action on a Resource
76. Is Digital Twin identified by token Authorized to perform an Action on a Resource
```shell
python3 api.py is_authorized_token ACCESS_TOKEN
Expand All @@ -1230,7 +1230,7 @@ positional arguments:
access_token User Token
```
75. Is Digital Twin identified by property Authorized to perform an Action on a Resource
77. Is Digital Twin identified by property Authorized to perform an Action on a Resource
```shell
python3 api.py is_authorized_property PROPERTY_TYPE PROPERTY_VALUE
Expand All @@ -1242,7 +1242,42 @@ positional arguments:
property_value String #e.g test@example.com
```
76. Create Consent for OAuth2 application for a given Digital Twin
78. What actions are authorized to be performed on a Resource by a subject identified by id
```shell
python3 api.py what_authorized_dt DIGITAL_TWIN_ID TENANT_ID
```
```shell
positional arguments:
digital_twin_id String
tenant_id String
```
79. What actions are authorized to be performed on a Resource by a subject identified by token
```shell
python3 api.py what_authorized_token ACCESS_TOKEN
```
```shell
positional arguments:
access_token User Token
```
80. What actions are authorized to be performed on a Resource by a subject identified by properties
```shell
python3 api.py what_authorized_property PROPERTY_TYPE PROPERTY_VALUE
```
```shell
positional arguments:
property_type String #e.g "email"
property_value String #e.g test@example.com
```
81. Create Consent for OAuth2 application for a given Digital Twin
```shell
python3 api.py create_consent PII_PROCESSOR_ID PII_PRINCIPAL_ID
Expand All @@ -1255,7 +1290,7 @@ positional arguments:
```
77. List Consents for Digital Twin for OAuth2 application
82. List Consents for Digital Twin for OAuth2 application
```shell
python3 api.py list_consents PII_PRINCIPAL_ID
Expand All @@ -1266,10 +1301,10 @@ positional arguments:
pii_principal_id String
```
78. Revoke Consents for Digital Twin for OAuth2 application
83. Revoke Consents for Digital Twin for OAuth2 application
```shell
python3 api.py revoke_consent APPLICATION_AGENT_CREDENTIAL_ID
python3 api.py revoke_consent PII_PRINCIPAL_ID CONSENT_IDS
```
```shell
Expand All @@ -1278,13 +1313,57 @@ positional arguments:
consent_ids List of consent ids separated by space
```
79. Start forgotten password flow
84. Check OAuth2 Consent challenge
```shell
python3 api.py check_oauth2_consent_challenge CHALLENGE
```
```shell
positional arguments:
challenge String
```
85. Create OAuth2 Consent Verifier with Approval
```shell
python3 api.py create_oauth2_consent_verifier_approval CONSENT_CHALLENGE GRANT_SCOPES GRANTED_AUDIENCE
```
```shell
positional arguments:
consent_challenge String
grant_scopes List
granted_audiences List
access_token Dict
id_token Dict
userinfo Dict
remember bool
remember_for int
```
86. Create OAuth2 Consent Verifier with Denial
```shell
python3 api.py create_oauth2_consent_verifier_denial CONSENT_CHALLENGE
```
```shell
positional arguments:
consent_challenge String
error String
error_description String
error_hint String
status_code int
```
87. Start forgotten password flow
```shell
python3 api.py start_forgotten_password DIGITAL_TWIN_ID TENANT_ID
```
80. Create email invitation (invite a user)
88. Create email invitation (invite a user)
```shell
python3 api.py create_email_invitation TENANT_ID EMAIL
Expand All @@ -1296,7 +1375,7 @@ positional arguments:
email String
```
81. Check invitation state : check if invitation invalid, in future, pending, accepted, expired, cancelled, processing
89. Check invitation state : check if invitation invalid, in future, pending, accepted, expired, cancelled, processing
```shell
python3 api.py check_invitation_state REFERENCE_ID
Expand All @@ -1308,7 +1387,7 @@ positional arguments: one of:
invitation_token token used in the invitation email
```
82. Resend an invitation
90. Resend an invitation
```shell
python3 api.py resend_invitation REFERENCE_ID
Expand All @@ -1319,7 +1398,7 @@ positional arguments:
reference_id id used to create the invitation
```
83. Cancel an invitation
91. Cancel an invitation
```shell
python3 api.py cancel_invitation REFERENCE_ID
Expand All @@ -1330,7 +1409,7 @@ positional arguments:
reference_id id used to create the invitation
```
84. Register a DigitalTwin without credential
92. Register a DigitalTwin without credential
```shell
python3 api.py register_digital_twin_without_credential TENANT_ID
Expand Down
41 changes: 41 additions & 0 deletions indykite_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,17 @@ def main():
check_oauth2_consent_challenge_parser.add_argument("challenge",
help="Consent challenge extracted from consent URL")

# create_oauth2_consent_verifier_approval
create_oauth2_consent_verifier_approval_parser = subparsers.add_parser("create_oauth2_consent_verifier_approval")
create_oauth2_consent_verifier_approval_parser.add_argument("consent_challenge",
help="Consent challenge extracted from consent URL")
create_oauth2_consent_verifier_approval_parser.add_argument("access_token")

# create_oauth2_consent_verifier_denial
create_oauth2_consent_verifier_denial_parser = subparsers.add_parser("create_oauth2_consent_verifier_denial")
create_oauth2_consent_verifier_denial_parser.add_argument("consent_challenge",
help="Consent challenge extracted from consent URL")

# FORGOTTEN_PASSWORD
start_forgotten_password = subparsers.add_parser("start_forgotten_password")
start_forgotten_password.add_argument("digital_twin_id", help="gid ID of the digital twin with forgotten password")
Expand Down Expand Up @@ -1928,6 +1939,36 @@ def main():
print("Invalid consent response")
return consent_response

elif command == "create_oauth2_consent_verifier_approval":
consent_challenge = args.consent_challenge
grant_scopes = ["openid", "email", "profile"]
granted_audiences = []
# custom claims for jwk (map values to enrich token)
access_token = json.loads(args.access_token)
consent_response = client.create_oauth2_consent_verifier_approval(consent_challenge, grant_scopes,
granted_audiences, access_token, {}, {},
False, None)
if consent_response:
print_response(consent_response)
else:
print("Invalid consent response")
return consent_response

elif command == "create_oauth2_consent_verifier_denial":
consent_challenge = args.consent_challenge
error = "access_denied"
error_description = "Access is denied"
error_hint = "Ask someone else"
status_code = 403
consent_response = client.create_oauth2_consent_verifier_denial(consent_challenge, error,
error_description,
error_hint, status_code)
if consent_response:
print_response(consent_response)
else:
print("Invalid consent response")
return consent_response

elif command == "start_forgotten_password":
digital_twin_id = args.digital_twin_id
tenant_id = args.tenant_id
Expand Down
3 changes: 2 additions & 1 deletion indykite_sdk/identity/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ def __init__(self, local=False):
from .delete import del_digital_twin, del_digital_twin_by_token
from .enrich_token import enrich_token
from .import_digital_twins import import_digital_twins
from .consent import create_consent, list_consents, revoke_consent, check_oauth2_consent_challenge
from .consent import create_consent, list_consents, revoke_consent, check_oauth2_consent_challenge, \
create_oauth2_consent_verifier_approval, create_oauth2_consent_verifier_denial
from .forgotten_password import start_forgotten_password_flow
from .invitation import create_email_invitation, create_mobile_invitation, check_invitation_state, resend_invitation, cancel_invitation
from .register_digital_twins_no_cred import register_digital_twin_without_credential
53 changes: 52 additions & 1 deletion indykite_sdk/identity/consent.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from indykite_sdk.indykite.identity.v1beta2 import identity_management_api_pb2 as pb2
from indykite_sdk.model.consent import CreateConsentResponse, CheckOAuth2ConsentChallengeResponse
from indykite_sdk.indykite.objects.v1beta1 import struct_pb2 as struct
from indykite_sdk.model.consent import CreateConsentResponse, CheckOAuth2ConsentChallengeResponse, CreateOAuth2ConsentVerifierResponse, ConsentRequestSessionData
import sys
import indykite_sdk.utils.logger as logger
from indykite_sdk.utils.message_to_value import arg_to_value


def create_consent(self, pii_processor_id, pii_principal_id, properties=[]):
Expand Down Expand Up @@ -80,5 +82,54 @@ def check_oauth2_consent_challenge(self, challenge):
return CheckOAuth2ConsentChallengeResponse.deserialize(response)


def create_oauth2_consent_verifier_approval(self, consent_challenge, grant_scopes=[], granted_audiences=[],
access_token={}, id_token={}, userinfo={}, remember=False,
remember_for=None):
sys.excepthook = logger.handle_excepthook
try:
response = self.stub.CreateOAuth2ConsentVerifier(
pb2.CreateOAuth2ConsentVerifierRequest(
consent_challenge=consent_challenge,
approval=pb2.ConsentApproval(
grant_scopes=grant_scopes,
granted_audiences=granted_audiences,
session=pb2.ConsentRequestSessionData(
access_token=arg_to_value(access_token) if access_token else {},
id_token=arg_to_value(id_token) if id_token else {},
userinfo=arg_to_value(userinfo) if userinfo else {}
),
remember=remember,
remember_for=remember_for
)
)
)
except Exception as exception:
return logger.logger_error(exception)
if not response:
return None

return response


def create_oauth2_consent_verifier_denial(self, consent_challenge, error=None,
error_description=None,
error_hint=None, status_code=None,):
sys.excepthook = logger.handle_excepthook
try:
response = self.stub.CreateOAuth2ConsentVerifier(
pb2.CreateOAuth2ConsentVerifierRequest(
consent_challenge=consent_challenge,
denial=pb2.DenialResponse(
error=error,
error_description=error_description,
error_hint=error_hint,
status_code=status_code
)
)
)
except Exception as exception:
return logger.logger_error(exception)
if not response:
return None

return response
16 changes: 16 additions & 0 deletions indykite_sdk/model/consent.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,19 @@ def __init__(self, client_id, app_space_id):
self.requested_at = None
self.context = None


class CreateOAuth2ConsentVerifierResponse:
@classmethod
def deserialize(cls, message):
if message is None:
return None
fields = [desc.name for desc, val in message.ListFields()]
consent_verifier = CreateOAuth2ConsentVerifierResponse(
str(message.verifier) if message.verifier else None,
str(message.authorization_endpoint) if message.authorization_endpoint else None
)
return consent_verifier

def __init__(self, verifier=None, authorization_endpoint=None):
self.verifier = verifier
self.authorization_endpoint = authorization_endpoint
7 changes: 7 additions & 0 deletions indykite_sdk/utils/message_to_value.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,11 @@ def arg_to_value(value):
if isinstance(value, bytes):
return struct.Value(bytes_value=value)

if isinstance(value, dict):
keys = value.keys()
mapped = {}
for key in keys:
mapped[key] = arg_to_value(value[key])
return struct.MapValue(fields=mapped)

return None

0 comments on commit 299d867

Please sign in to comment.