Skip to content

Commit

Permalink
feat: add authz policy config node
Browse files Browse the repository at this point in the history
  • Loading branch information
cowan-macady committed Apr 18, 2023
1 parent 02c21c1 commit 890c762
Show file tree
Hide file tree
Showing 10 changed files with 372 additions and 5 deletions.
81 changes: 78 additions & 3 deletions indykite_sdk/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from indykite_sdk.authorization import AuthorizationClient
from indykite_sdk.oauth2 import HttpClient
from indykite_sdk.indykite.config.v1beta1.model_pb2 import (SendGridProviderConfig, MailJetProviderConfig, AmazonSESProviderConfig, MailgunProviderConfig)
from indykite_sdk.indykite.config.v1beta1.model_pb2 import (EmailServiceConfig, AuthFlowConfig, OAuth2ClientConfig, IngestMappingConfig, WebAuthnProviderConfig)
from indykite_sdk.indykite.config.v1beta1.model_pb2 import (EmailServiceConfig, AuthFlowConfig, OAuth2ClientConfig, IngestMappingConfig, WebAuthnProviderConfig, AuthorizationPolicyConfig )
from indykite_sdk.indykite.config.v1beta1.model_pb2 import OAuth2ProviderConfig, OAuth2ApplicationConfig
from indykite_sdk.indykite.identity.v1beta2.import_pb2 import ImportDigitalTwinsRequest, ImportDigitalTwin
from indykite_sdk.indykite.identity.v1beta2.import_pb2 import PasswordCredential, PasswordHash, Bcrypt, SHA256
Expand Down Expand Up @@ -422,6 +422,20 @@ def main():
update_webauthn_provider_config_node_parser.add_argument("display_name", help="Display name")
update_webauthn_provider_config_node_parser.add_argument("description", help="Description")

# create_authorization_policy_config_node
create_authorization_policy_config_node_parser = subparsers.add_parser("create_authorization_policy_config_node")
create_authorization_policy_config_node_parser.add_argument("app_space_id", help="AppSpace (gid)")
create_authorization_policy_config_node_parser.add_argument("name", help="Name (not display name)")
create_authorization_policy_config_node_parser.add_argument("display_name", help="Display name")
create_authorization_policy_config_node_parser.add_argument("description", help="Description")

# update_authorization_policy_config_node
update_authorization_policy_config_node_parser = subparsers.add_parser("update_authorization_policy_config_node")
update_authorization_policy_config_node_parser.add_argument("config_node_id", help="Config node id (gid)")
update_authorization_policy_config_node_parser.add_argument("etag", help="Etag")
update_authorization_policy_config_node_parser.add_argument("display_name", help="Display name")
update_authorization_policy_config_node_parser.add_argument("description", help="Description")

# read_oauth2_provider
read_oauth2_provider_parser = subparsers.add_parser("read_oauth2_provider")
read_oauth2_provider_parser.add_argument("oauth2_provider_id", help="Oauth2 provider id (gid)")
Expand Down Expand Up @@ -1520,6 +1534,67 @@ def main():
print("Invalid update webauthn provider config node response")
return update_webauthn_provider_config_node_response

elif command == "create_authorization_policy_config_node":
location = args.app_space_id
name = args.name
display_name = args.display_name
description = args.description

with open("utils/sdk_policy_config.json") as f:
file_data = f.read()
policy_dict = json.loads(file_data)
policy_dict = json.dumps(policy_dict)
policy_config = AuthorizationPolicyConfig(
policy=str(policy_dict),
status="STATUS_ACTIVE",
tags=[]
)

create_authorization_policy_config_node_response = client_config.create_authorization_policy_config_node(
location,
name,
display_name,
description,
policy_config,
[]
)

if create_authorization_policy_config_node_response:
print_response(create_authorization_policy_config_node_response)
else:
print("Invalid create authorization policy config node response")
return create_authorization_policy_config_node_response

elif command == "update_authorization_policy_config_node":
config_node_id = args.config_node_id
etag = args.etag
display_name = args.display_name
description = args.description

with open("utils/sdk_policy_config.json") as f:
file_data = f.read()
policy_dict = json.loads(file_data)
policy_dict = json.dumps(policy_dict)

policy_config = AuthorizationPolicyConfig(
policy=str(policy_dict),
status="STATUS_ACTIVE",
tags=[]
)
update_authorization_policy_config_node_response = client_config.update_authorization_policy_config_node(
config_node_id,
etag,
display_name,
description,
policy_config,
[]
)
if update_authorization_policy_config_node_response:
print_response(update_authorization_policy_config_node_response)
else:
print("Invalid update authorization policy config node response")
return update_authorization_policy_config_node_response

elif command == "read_oauth2_provider":
oauth2_provider_id = args.oauth2_provider_id
config = client_config.read_oauth2_provider(oauth2_provider_id, [])
Expand Down Expand Up @@ -1958,10 +2033,10 @@ def main():
consent_challenge = args.consent_challenge
error = "access_denied"
error_description = "Access is denied"
error_hint = "Ask someone else"
error_hint = "Your consent challenge may be not valid: check your OAuth2 host and your clientID"
status_code = 403
consent_response = client.create_oauth2_consent_verifier_denial(consent_challenge, error,
error_description,
error_description,
error_hint, status_code)
if consent_response:
print_response(consent_response)
Expand Down
3 changes: 2 additions & 1 deletion indykite_sdk/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ def __init__(self, local=False):
from .service_account_credential import get_service_account_credential, register_service_account_credential_jwk, register_service_account_credential_pem, delete_service_account_credential
from .config_node import create_email_service_config_node, read_config_node, update_email_service_config_node, delete_config_node, create_auth_flow_config_node, update_auth_flow_config_node, \
create_oauth2_client_config_node, update_oauth2_client_config_node, create_ingest_mapping_config_node, update_ingest_mapping_config_node, \
create_webauthn_provider_config_node, update_webauthn_provider_config_node
create_webauthn_provider_config_node, update_webauthn_provider_config_node, \
create_authorization_policy_config_node, update_authorization_policy_config_node
from .oauth2_provider import create_oauth2_provider, read_oauth2_provider, update_oauth2_provider, delete_oauth2_provider
from .oauth2_application import create_oauth2_application, read_oauth2_application, update_oauth2_application, \
delete_oauth2_application
Expand Down
64 changes: 64 additions & 0 deletions indykite_sdk/config/config_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from indykite_sdk.model.conveyance_preference import ConveyancePreference
from indykite_sdk.model.user_verification_requirement import UserVerificationRequirement
from indykite_sdk.model.authenticator_attachment import AuthenticatorAttachment
from indykite_sdk.model.authorization_policy_config_status import Status
import sys
import indykite_sdk.utils.logger as logger

Expand Down Expand Up @@ -290,6 +291,59 @@ def update_webauthn_provider_config_node(self, config_node_id, etag, display_nam
return UpdateConfigNode.deserialize(response)


def create_authorization_policy_config_node(self, location, name, display_name, description,
authorization_policy_config, bookmarks=[]):
sys.excepthook = logger.handle_excepthook
try:
valid = True
if authorization_policy_config and authorization_policy_config.status:
valid = validate_authorization_policy_status(authorization_policy_config.status)
if valid:
response = self.stub.CreateConfigNode(
pb2.CreateConfigNodeRequest(
location=location,
name=name,
display_name=wrappers.StringValue(value=display_name),
description=wrappers.StringValue(value=description),
authorization_policy_config= authorization_policy_config,
bookmarks=bookmarks
)
)
except Exception as exception:
return logger.logger_error(exception)

if not response:
return None
return CreateConfigNode.deserialize(response)


def update_authorization_policy_config_node(self, config_node_id, etag, display_name, description,
authorization_policy_config,
bookmarks=[]):
sys.excepthook = logger.handle_excepthook
try:
valid = True
if authorization_policy_config and authorization_policy_config.status:
valid = validate_authorization_policy_status(authorization_policy_config.status)
if valid:
response = self.stub.UpdateConfigNode(
pb2.UpdateConfigNodeRequest(
id=config_node_id,
etag=wrappers.StringValue(value=etag),
display_name=wrappers.StringValue(value=display_name),
description=wrappers.StringValue(value=description),
authorization_policy_config= authorization_policy_config,
bookmarks=bookmarks
)
)
except Exception as exception:
return logger.logger_error(exception)

if not response:
return None
return UpdateConfigNode.deserialize(response)


def validate_conveyance(conveyance):
try:
conveyances = [c.value for c in ConveyancePreference]
Expand Down Expand Up @@ -318,3 +372,13 @@ def validate_authenticator_attachment(authenticator_attachment):
return True
except Exception as exception:
return logger.logger_error(exception)


def validate_authorization_policy_status(status):
try:
statuses = [s.name for s in Status]
if status not in statuses:
raise TypeError("status must be a member of AuthorizationPolicyConfig.Status")
return True
except Exception as exception:
return logger.logger_error(exception)
31 changes: 31 additions & 0 deletions indykite_sdk/model/authorization_policy_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import json
from indykite_sdk.model.authorization_policy_config_status import Status


class AuthorizationPolicyConfig:
@classmethod
def deserialize(cls, message_config):
if message_config is None:
return None
fields = [desc.name for desc, val in message_config.ListFields()]
authorization_policy_config = AuthorizationPolicyConfig(
policy=json.loads(message_config.policy)
)
if "status" in fields:
authorization_policy_config.status = \
Status[message_config.status].name
if "tags" in fields:
authorization_policy_config.tags = [
str(t)
for t in message_config.tags
]
return authorization_policy_config

def __init__(self, policy, status=None, tags=[]):

self.policy = policy
self.status = status
self.tags = tags



7 changes: 7 additions & 0 deletions indykite_sdk/model/authorization_policy_config_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from enum import Enum


class Status(Enum):
STATUS_INVALID = 0
STATUS_ACTIVE = 1
STATUS_INACTIVE = 2
6 changes: 6 additions & 0 deletions indykite_sdk/model/config_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from indykite_sdk.model.oauth2_client_config import OAuth2ClientConfig
from indykite_sdk.model.ingest_mapping_config import IngestMappingConfig
from indykite_sdk.model.webauthn_provider_config import WebAuthnProviderConfig
from indykite_sdk.model.authorization_policy_config import AuthorizationPolicyConfig


class ConfigNode:
Expand Down Expand Up @@ -52,6 +53,10 @@ def deserialize(cls, message):
if message.HasField('webauthn_provider_config'):
config_node.webauthn_provider_config = WebAuthnProviderConfig.deserialize(message.webauthn_provider_config)

if message.HasField('authorization_policy_config'):
config_node.authorization_policy_config = AuthorizationPolicyConfig.deserialize(
message.authorization_policy_config)

return config_node

def __init__(self, id, name, display_name, etag, customer_id, app_space_id, tenant_id):
Expand All @@ -72,5 +77,6 @@ def __init__(self, id, name, display_name, etag, customer_id, app_space_id, tena
self.oauth2_client_config = None
self.ingest_mapping_config = None
self.webauthn_provider_config = None
self.authorization_policy_config = None


17 changes: 17 additions & 0 deletions indykite_sdk/utils/sdk_policy_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"meta": {
"policyVersion": "1.0-indykite"
},
"subject": {
"type": "DigitalTwin"
},
"actions": [
"HAS_FREE_PARKING"
],
"resource": {
"type": "ParkingLot"
},
"condition": {
"cypher": "MATCH(subject:DigitalTwin{digital_twin_id:$subject_id}) MATCH(n1:Household) MATCH(n2:DigitalTwin) MATCH(n3:LoyaltyProgram) MATCH(n4:Mall) MATCH(resource:ParkingLot) MATCH(sub)-[:MEMBER_OF]->(n1) MATCH(n2)-[:MEMBER_OF]->(n1) MATCH(n2)-[:MEMBER_OF]->(n3) MATCH(n4)-[:OFFERS]->(n3) MATCH(resource)-[:OUTSIDE]->(n4)"
}
}
20 changes: 19 additions & 1 deletion tests/helpers/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
from indykite_sdk.indykite.config.v1beta1.model_pb2 import (UniqueNameIdentifier, SendGridProviderConfig, MailJetProviderConfig,
AmazonSESProviderConfig, MailgunProviderConfig,EmailServiceConfig,
AuthFlowConfig, OAuth2ClientConfig, IngestMappingConfig, WebAuthnProviderConfig)
AuthFlowConfig, OAuth2ClientConfig, IngestMappingConfig, WebAuthnProviderConfig, AuthorizationPolicyConfig)
from indykite_sdk.indykite.config.v1beta1.model_pb2 import EmailAttachment, Email, EmailMessage, EmailTemplate, EmailDefinition
from indykite_sdk.indykite.config.v1beta1.model_pb2 import OAuth2ProviderConfig, OAuth2ApplicationConfig
from indykite_sdk.indykite.config.v1beta1.model_pb2 import google_dot_protobuf_dot_wrappers__pb2 as wrappers
Expand Down Expand Up @@ -46,6 +46,7 @@
OAUTH2_CLIENT_CONFIG_NODE = "gid:AAAACtBSbo_Sf0XXpOzuoNfzMk8"
INGEST_MAPPING_CONFIG_NODE = "gid:AAAAFLk0_fECVENquHrfZUTjaic"
WEBAUTHN_PROVIDER_CONFIG_NODE = "gid:AAAADRcYFyi8IUUIv-P5IJwlXQ0"
AUTHZ_POLICY_CONFIG_NODE = "gid:AAAAFpurKX4qjEbFqNQd8L3wEqk"
OAUTH2_PROVIDER = "gid:AAAAEXX8LPjXo0bmvR1VWQEwrQI"
OAUTH2_APPLICATION = "gid:AAAAC8hPU8pCTEblkvWJ4et0PG4"
PASSWORD = "Password"
Expand Down Expand Up @@ -210,6 +211,10 @@ def get_webauthn_provider_config_node_id():
return WEBAUTHN_PROVIDER_CONFIG_NODE


def get_authz_policy_config_node_id():
return AUTHZ_POLICY_CONFIG_NODE


def get_oauth2_provider_id():
return OAUTH2_PROVIDER

Expand Down Expand Up @@ -354,3 +359,16 @@ def get_webauthn_provider_exception():
authentication_timeout=Duration(seconds=60)
)
return webauthn_provider_config


def get_authz_policy():
with open(os.path.dirname(__file__) + "/sdk_policy_config.json") as f:
file_data = f.read()
policy_dict = json.loads(file_data)
policy_dict = json.dumps(policy_dict)
policy_config = AuthorizationPolicyConfig(
policy=str(policy_dict),
status="STATUS_ACTIVE",
tags=[]
)
return policy_config
17 changes: 17 additions & 0 deletions tests/helpers/sdk_policy_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"meta": {
"policyVersion": "1.0-indykite"
},
"subject": {
"type": "DigitalTwin"
},
"actions": [
"HAS_FREE_PARKING"
],
"resource": {
"type": "ParkingLot"
},
"condition": {
"cypher": "MATCH(subject:DigitalTwin{digital_twin_id:$subject_id}) MATCH(n1:Household) MATCH(n2:DigitalTwin) MATCH(n3:LoyaltyProgram) MATCH(n4:Mall) MATCH(resource:ParkingLot) MATCH(sub)-[:MEMBER_OF]->(n1) MATCH(n2)-[:MEMBER_OF]->(n1) MATCH(n2)-[:MEMBER_OF]->(n3) MATCH(n4)-[:OFFERS]->(n3) MATCH(resource)-[:OUTSIDE]->(n4)"
}
}

0 comments on commit 890c762

Please sign in to comment.