-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(jans-cedarling): update python example and docs (#10183)
* chore(jans-cedarling): update examples Signed-off-by: SafinWasi <[email protected]> * docs(jans-cedarling): update doc for python Signed-off-by: SafinWasi <[email protected]> * docs(jans-cedarling): fix typos and adjust schema Signed-off-by: SafinWasi <[email protected]> --------- Signed-off-by: SafinWasi <[email protected]> Co-authored-by: Mohammad Abudayyeh <[email protected]>
- Loading branch information
Showing
7 changed files
with
617 additions
and
552 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,232 +7,103 @@ tags: | |
|
||
# Python usage | ||
|
||
In this example, we will show an example Python script that calls the `cedarling_python` module and calls the `authz` function. Before beginning, ensure that you have completed the [building steps](./README.md#building) and are currently in a virtual Python environment that has the `cedarling_python` module installed. | ||
In this example, we will show an example Python script that calls the `cedarling_python` module and calls the `authorize()` function. | ||
|
||
## Demo script | ||
- Before beginning, ensure that you have completed the [building steps](./README.md#building) and are currently in a virtual Python environment that has the `cedarling_python` module installed. You can confirm this with `pip list`. | ||
- Run the script `jans/jans-cedarling/bindings/cedarling_python/example.py` from within the virtual environment. | ||
|
||
```python | ||
from cedarling_python import MemoryLogConfig, DisabledLoggingConfig, StdOutLogConfig | ||
from cedarling_python import PolicyStoreSource, PolicyStoreConfig, BootstrapConfig, JwtConfig | ||
from cedarling_python import Cedarling, ResourceData, Request | ||
|
||
# use MemoryLogConfig to store logs in memory with a time-to-live of 120 seconds | ||
# by default it is 60 seconds | ||
log_config = MemoryLogConfig(log_ttl=100) | ||
# we can also set value to as property | ||
# log_config.log_ttl = 120 | ||
|
||
# use DisabledLoggingConfig to ignore all logging | ||
# log_config = DisabledLoggingConfig() | ||
|
||
# use StdOutLogConfig to print logs to stdout | ||
log_config = StdOutLogConfig() | ||
|
||
# Create policy source configuration | ||
with open("policy-store.json", | ||
mode="r", encoding="utf8") as f: | ||
policy_raw_json = f.read() | ||
""" | ||
This policy store contains 2 policy as such: | ||
## Output | ||
``` | ||
(venv) $ python example.py | ||
Policy store location not provided, use 'CEDARLING_LOCAL_POLICY_STORE' environment variable | ||
Used default policy store path: example_files/policy-store.json | ||
{"id":"0193414e-9672-786a-986c-57f48d41c4e4","time":1731967489,"log_kind":"System","pdp_id":"c0ec33ff-9482-4bdc-83f6-2925a41a3280","msg":"configuration parsed successfully"} | ||
{"id":"0193414e-9672-786a-986c-57f5379086c3","time":1731967489,"log_kind":"System","pdp_id":"c0ec33ff-9482-4bdc-83f6-2925a41a3280","msg":"Cedarling Authz initialized successfully","application_id":"TestApp"} | ||
{"id":"0193414e-9676-7d8a-b55b-3f0097355851","time":1731967489,"log_kind":"Decision","pdp_id":"c0ec33ff-9482-4bdc-83f6-2925a41a3280","msg":"Result of authorize.","application_id":"TestApp","action":"Jans::Action::\"Read\"","resource":"Jans::Application::\"some_id\"","context":{"user_agent":"Linux","operating_system":"Linux","network_type":"Local","network":"127.0.0.1","geolocation":["America"],"fraud_indicators":["Allowed"],"device_health":["Healthy"],"current_time":1731967489},"person_principal":"Jans::User::\"qzxn1Scrb9lWtGxVedMCky-Ql_ILspZaQA6fyuYktw0\"","person_diagnostics":{"reason":["840da5d85403f35ea76519ed1a18a33989f855bf1cf8"],"errors":[]},"person_decision":"ALLOW","workload_principal":"Jans::Workload::\"d7f71bea-c38d-4caf-a1ba-e43c74a11a62\"","workload_diagnostics":{"reason":["444da5d85403f35ea76519ed1a18a33989f855bf1cf8"],"errors":[]},"workload_decision":"ALLOW","role_authorize_info":[{"role_principal":"Jans::Role::\"CasaAdmin\"","role_diagnostics":{"reason":[],"errors":[]},"role_decision":"DENY"}],"authorized":true} | ||
Result of workload authorization: ALLOW | ||
Policy ID used: | ||
444da5d85403f35ea76519ed1a18a33989f855bf1cf8 | ||
Errors during authorization: 0 | ||
Result of person authorization: ALLOW | ||
Policy ID used: | ||
840da5d85403f35ea76519ed1a18a33989f855bf1cf8 | ||
Errors during authorization: 0 | ||
Role authorization present | ||
Role authorization result: DENY | ||
Errors during authorization: 0 | ||
``` | ||
|
||
## Explanation | ||
Cedarling creates principal entities from the access, ID and userinfo tokens. The action, resource and context entities are declared in code. These four entities together form the `PARC` format that cedarling evaluates against policies provided in the policy store. The principal entities can be either User, Workload or Role. After forming the entities, cedarling evaluates them against the policies provided in the policy store. If entity is explicitly permitted by a policy, the result of the evaluation is `ALLOW`, otherwise it is `DENY`. | ||
|
||
In this case there are two policies in the store, one for User entities and one for Workload entities: | ||
|
||
``` | ||
@444da5d85403f35ea76519ed1a18a33989f855bf1cf8 | ||
permit( | ||
principal is Jans::Workload, | ||
action in [Jans::Action::"Update"], | ||
resource is Jans::Issue | ||
action in [Jans::Action::"Read"], | ||
resource is Jans::Application | ||
)when{ | ||
principal.org_id == resource.org_id | ||
resource.name == "Some Application" | ||
}; | ||
@840da5d85403f35ea76519ed1a18a33989f855bf1cf8 | ||
permit( | ||
principal is Jans::User, | ||
action in [Jans::Action::"Update"], | ||
resource is Jans::Issue | ||
action in [Jans::Action::"Read"], | ||
resource is Jans::Application | ||
)when{ | ||
principal.country == resource.country | ||
resource.name == "Some Application" | ||
}; | ||
""" | ||
# for now we support only json source | ||
policy_source = PolicyStoreSource(json=policy_raw_json) | ||
|
||
policy_store_config = PolicyStoreConfig(source=policy_source) | ||
|
||
|
||
# Create jwt configuration | ||
# do not validate JWT tokens | ||
jwt_config = JwtConfig(enabled=False) | ||
|
||
# collect all in the BootstrapConfig | ||
bootstrap_config = BootstrapConfig( | ||
application_name="TestApp", | ||
log_config=log_config, | ||
policy_store_config=policy_store_config, | ||
jwt_config=jwt_config | ||
) | ||
|
||
# initialize cedarling instance | ||
# all values in the bootstrap_config is parsed and validated at this step. | ||
instance = Cedarling(bootstrap_config) | ||
|
||
# returns a list of all active log ids | ||
# active_log_ids = instance.get_log_ids() | ||
|
||
# get log entry by id | ||
# log_entry = instance.get_log_by_id(active_log_ids[0]) | ||
``` | ||
|
||
These two policies say that a Principal entity (User or Workload) is allowed to execute a `Read` action on an Application resource when the resource is named "Some Application". As there are no policies for Role entities, the result of the evaluation for the Role entity is `DENY`. | ||
|
||
# show logs | ||
print("Logs stored in memory:") | ||
print(*instance.pop_logs(), sep="\n\n") | ||
In the script, the action, resource and context entities are used to create the request and execute the `authorize()` call: | ||
|
||
```python | ||
|
||
# //// Execute authentication request //// | ||
action = 'Jans::Action::"Read"' | ||
|
||
# Creating cedar resource object. | ||
# field resource_type and id is mandatory | ||
# other fields are attributes of the resource. | ||
resource = ResourceData(resource_type="Jans::Issue", | ||
id="random_id", org_id="some_long_id", country="US") | ||
# or we can init resource using dict | ||
resource = ResourceData.from_dict({ | ||
"type": "Jans::Issue", | ||
"id": "random_id", | ||
"org_id": "some_long_id", | ||
"country": "US" | ||
"type": "Jans::Application", | ||
"id": "some_id", | ||
"app_id": "application_id", | ||
"name": "Some Application", | ||
"url": { | ||
"host": "jans.test", | ||
"path": "/protected-endpoint", | ||
"protocol": "http" | ||
} | ||
}) | ||
|
||
|
||
action_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJib0c4ZGZjNU1LVG4zN283Z3NkQ2V5cUw4THBXUXRnb080MW0xS1p3ZHEwIiwiY29kZSI6ImJmMTkzNGY2LTM5MDUtNDIwYS04Mjk5LTZiMmUzZmZkZGQ2ZSIsImlzcyI6Imh0dHBzOi8vYWRtaW4tdWktdGVzdC5nbHV1Lm9yZyIsInRva2VuX3R5cGUiOiJCZWFyZXIiLCJjbGllbnRfaWQiOiI1YjQ0ODdjNC04ZGIxLTQwOWQtYTY1My1mOTA3YjgwOTQwMzkiLCJhdWQiOiI1YjQ0ODdjNC04ZGIxLTQwOWQtYTY1My1mOTA3YjgwOTQwMzkiLCJhY3IiOiJiYXNpYyIsIng1dCNTMjU2IjoiIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSJdLCJvcmdfaWQiOiJzb21lX2xvbmdfaWQiLCJhdXRoX3RpbWUiOjE3MjQ4MzA3NDYsImV4cCI6MTcyNDk0NTk3OCwiaWF0IjoxNzI0ODMyMjU5LCJqdGkiOiJseFRtQ1ZSRlR4T2pKZ3ZFRXBvek1RIiwibmFtZSI6IkRlZmF1bHQgQWRtaW4gVXNlciIsInN0YXR1cyI6eyJzdGF0dXNfbGlzdCI6eyJpZHgiOjIwMSwidXJpIjoiaHR0cHM6Ly9hZG1pbi11aS10ZXN0LmdsdXUub3JnL2phbnMtYXV0aC9yZXN0djEvc3RhdHVzX2xpc3QifX19._eQT-DsfE_kgdhA0YOyFxxPEMNw44iwoelWa5iU1n9s" | ||
""" | ||
JSON payload of access token | ||
{ | ||
"sub": "boG8dfc5MKTn37o7gsdCeyqL8LpWQtgoO41m1KZwdq0", | ||
"code": "bf1934f6-3905-420a-8299-6b2e3ffddd6e", | ||
"iss": "https://admin-ui-test.gluu.org", | ||
"token_type": "Bearer", | ||
"client_id": "5b4487c4-8db1-409d-a653-f907b8094039", | ||
"aud": "5b4487c4-8db1-409d-a653-f907b8094039", | ||
"acr": "basic", | ||
"x5t#S256": "", | ||
"scope": [ | ||
"openid", | ||
"profile" | ||
], | ||
"org_id": "some_long_id", | ||
"auth_time": 1724830746, | ||
"exp": 1724945978, | ||
"iat": 1724832259, | ||
"jti": "lxTmCVRFTxOjJgvEEpozMQ", | ||
"name": "Default Admin User", | ||
"status": { | ||
"status_list": { | ||
"idx": 201, | ||
"uri": "https://admin-ui-test.gluu.org/jans-auth/restv1/status_list" | ||
} | ||
} | ||
context = { | ||
"current_time": int(time.time()), | ||
"device_health": ["Healthy"], | ||
"fraud_indicators": ["Allowed"], | ||
"geolocation": ["America"], | ||
"network": "127.0.0.1", | ||
"network_type": "Local", | ||
"operating_system": "Linux", | ||
"user_agent": "Linux" | ||
} | ||
""" | ||
|
||
id_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY3IiOiJiYXNpYyIsImFtciI6IjEwIiwiYXVkIjoiNWI0NDg3YzQtOGRiMS00MDlkLWE2NTMtZjkwN2I4MDk0MDM5IiwiZXhwIjoxNzI0ODM1ODU5LCJpYXQiOjE3MjQ4MzIyNTksInN1YiI6ImJvRzhkZmM1TUtUbjM3bzdnc2RDZXlxTDhMcFdRdGdvTzQxbTFLWndkcTAiLCJpc3MiOiJodHRwczovL2FkbWluLXVpLXRlc3QuZ2x1dS5vcmciLCJqdGkiOiJzazNUNDBOWVNZdWs1c2FIWk5wa1p3Iiwibm9uY2UiOiJjMzg3MmFmOS1hMGY1LTRjM2YtYTFhZi1mOWQwZTg4NDZlODEiLCJzaWQiOiI2YTdmZTUwYS1kODEwLTQ1NGQtYmU1ZC01NDlkMjk1OTVhMDkiLCJqYW5zT3BlbklEQ29ubmVjdFZlcnNpb24iOiJvcGVuaWRjb25uZWN0LTEuMCIsImNfaGFzaCI6InBHb0s2WV9SS2NXSGtVZWNNOXV3NlEiLCJhdXRoX3RpbWUiOjE3MjQ4MzA3NDYsImdyYW50IjoiYXV0aG9yaXphdGlvbl9jb2RlIiwic3RhdHVzIjp7InN0YXR1c19saXN0Ijp7ImlkeCI6MjAyLCJ1cmkiOiJodHRwczovL2FkbWluLXVpLXRlc3QuZ2x1dS5vcmcvamFucy1hdXRoL3Jlc3R2MS9zdGF0dXNfbGlzdCJ9fX0.8BwLLGkFpWGx8wGpvVmNk_Ao8nZrP_WT-zoo-MY4zqY" | ||
""" | ||
JSON payload of id token | ||
{ | ||
"acr": "basic", | ||
"amr": "10", | ||
"aud": "5b4487c4-8db1-409d-a653-f907b8094039", | ||
"exp": 1724835859, | ||
"iat": 1724832259, | ||
"sub": "boG8dfc5MKTn37o7gsdCeyqL8LpWQtgoO41m1KZwdq0", | ||
"iss": "https://admin-ui-test.gluu.org", | ||
"jti": "sk3T40NYSYuk5saHZNpkZw", | ||
"nonce": "c3872af9-a0f5-4c3f-a1af-f9d0e8846e81", | ||
"sid": "6a7fe50a-d810-454d-be5d-549d29595a09", | ||
"jansOpenIDConnectVersion": "openidconnect-1.0", | ||
"c_hash": "pGoK6Y_RKcWHkUecM9uw6Q", | ||
"auth_time": 1724830746, | ||
"grant": "authorization_code", | ||
"status": { | ||
"status_list": { | ||
"idx": 202, | ||
"uri": "https://admin-ui-test.gluu.org/jans-auth/restv1/status_list" | ||
} | ||
} | ||
} | ||
""" | ||
|
||
userinfo_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb3VudHJ5IjoiVVMiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJ1c2VybmFtZSI6IlVzZXJOYW1lRXhhbXBsZSIsInN1YiI6ImJvRzhkZmM1TUtUbjM3bzdnc2RDZXlxTDhMcFdRdGdvTzQxbTFLWndkcTAiLCJpc3MiOiJodHRwczovL2FkbWluLXVpLXRlc3QuZ2x1dS5vcmciLCJnaXZlbl9uYW1lIjoiQWRtaW4iLCJtaWRkbGVfbmFtZSI6IkFkbWluIiwiaW51bSI6IjhkMWNkZTZhLTE0NDctNDc2Ni1iM2M4LTE2NjYzZTEzYjQ1OCIsImNsaWVudF9pZCI6IjViNDQ4N2M0LThkYjEtNDA5ZC1hNjUzLWY5MDdiODA5NDAzOSIsImF1ZCI6IjViNDQ4N2M0LThkYjEtNDA5ZC1hNjUzLWY5MDdiODA5NDAzOSIsInVwZGF0ZWRfYXQiOjE3MjQ3Nzg1OTEsIm5hbWUiOiJEZWZhdWx0IEFkbWluIFVzZXIiLCJuaWNrbmFtZSI6IkFkbWluIiwiZmFtaWx5X25hbWUiOiJVc2VyIiwianRpIjoiZmFpWXZhWUlUMGNEQVQ3Rm93MHBRdyIsImphbnNBZG1pblVJUm9sZSI6WyJhcGktYWRtaW4iXSwiZXhwIjoxNzI0OTQ1OTc4fQ.3LTc8YLvEeb7ONZp_FKA7yPP7S6e_VTzwhvAWUJrL4M" | ||
""" | ||
JSON payload of userinfo token | ||
{ | ||
"country": "US", | ||
"email": "[email protected]", | ||
"username": "UserNameExample", | ||
"sub": "boG8dfc5MKTn37o7gsdCeyqL8LpWQtgoO41m1KZwdq0", | ||
"iss": "https://admin-ui-test.gluu.org", | ||
"given_name": "Admin", | ||
"middle_name": "Admin", | ||
"inum": "8d1cde6a-1447-4766-b3c8-16663e13b458", | ||
"client_id": "5b4487c4-8db1-409d-a653-f907b8094039", | ||
"aud": "5b4487c4-8db1-409d-a653-f907b8094039", | ||
"updated_at": 1724778591, | ||
"name": "Default Admin User", | ||
"nickname": "Admin", | ||
"family_name": "User", | ||
"jti": "faiYvaYIT0cDAT7Fow0pQw", | ||
"jansAdminUIRole": [ | ||
"api-admin" | ||
], | ||
"exp": 1724945978 | ||
} | ||
""" | ||
|
||
|
||
# Creating cedarling request | ||
request = Request( | ||
action_token, | ||
access_token, | ||
id_token, | ||
userinfo_token, | ||
action='Jans::Action::"Update"', | ||
context={}, resource=resource) | ||
action=action, | ||
resource=resource, context=context) | ||
|
||
# Authorize call | ||
authorize_result = instance.authorize(request) | ||
print(*instance.pop_logs(), sep="\n\n") | ||
|
||
# if you change org_id result will be false | ||
assert authorize_result.is_allowed() | ||
|
||
# watch on the decision for workload | ||
workload_result = authorize_result.workload() | ||
print(workload_result.decision) | ||
|
||
# show diagnostic information | ||
workload_diagnostic = workload_result.diagnostics | ||
for i, reason in enumerate(workload_diagnostic.reason): | ||
if i == 0: | ||
print("reason policies:") | ||
print(reason) | ||
|
||
for i, error in enumerate(workload_diagnostic.errors): | ||
if i == 0: | ||
print("errors:") | ||
print("id:", error.id, "error:", error.error) | ||
``` | ||
|
||
- Save the script in a file called `example.py` | ||
- Save [this](https://github.com/JanssenProject/jans/blob/main/jans-cedarling/bindings/cedarling_python/example_files/policy-store.json) demo policy store file to `policy-store.json` in the same location | ||
- Run the example script: | ||
|
||
``` | ||
(venv) $ python example.py | ||
Logs stored in memory: | ||
{"id":"01929b39-b7d9-7e58-8abb-329c19c3d821","time":1729181104,"log_kind":"System","pdp_id":"1039a067-88de-4e8b-8d5f-421fc912b94f","msg":"PolicyStore loaded successfully","application_id":"TestApp"} | ||
{"id":"01929b39-b7d9-7e58-8abb-329dfb797de1","time":1729181104,"log_kind":"System","pdp_id":"1039a067-88de-4e8b-8d5f-421fc912b94f","msg":"JWT service loaded successfully","application_id":"TestApp"} | ||
{"id":"01929b39-b7d9-7e58-8abb-329e91d2b37f","time":1729181104,"log_kind":"System","pdp_id":"1039a067-88de-4e8b-8d5f-421fc912b94f","msg":"Cedarling Authz initialized successfully","application_id":"TestApp"} | ||
Logs stored in memory: | ||
{"id":"01929b39-b7db-766c-95a8-4790ff90532d","time":1729181104,"log_kind":"Decision","pdp_id":"1039a067-88de-4e8b-8d5f-421fc912b94f","msg":"Result of authorize with resource as workload entity","application_id":"TestApp","principal":"Jans::Workload::\"5b4487c4-8db1-409d-a653-f907b8094039\"","action":"Jans::Action::\"Update\"","resource":"Jans::Issue::\"random_id\"","context":{},"decision":"ALLOW","diagnostics":{"reason":["840da5d85403f35ea76519ed1a18a33989f855bf1cf8"],"errors":[]}} | ||
``` | ||
Cedarling will return `is_allowed()` as `True` only if both the User and Workload entity evaluations are `ALLOW`. | ||
|
||
As you can see, the logs from cedarling's initialization and the result of the authorize call is printed to the console. | ||
|
||
## Exposed functions | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.