From 2381a09cd7a51f2582c041bcab4941d7c5138696 Mon Sep 17 00:00:00 2001
From: Jose Gonzalez
Date: Wed, 15 Jan 2025 14:34:36 -0500
Subject: [PATCH 01/10] fix: implement missing method from interface (#10646)
---
.../AgamaChallenge.java | 27 ++++++++++++++++---
1 file changed, 24 insertions(+), 3 deletions(-)
diff --git a/docs/script-catalog/authorization_challenge/AgamaChallenge.java b/docs/script-catalog/authorization_challenge/AgamaChallenge.java
index 89fdade3277..6c272dff776 100644
--- a/docs/script-catalog/authorization_challenge/AgamaChallenge.java
+++ b/docs/script-catalog/authorization_challenge/AgamaChallenge.java
@@ -20,6 +20,7 @@
import io.jans.agama.engine.client.MiniBrowser;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.util.Base64Util;
+import io.jans.as.server.authorize.ws.rs.AuthzRequest;
import io.jans.util.*;
import jakarta.servlet.ServletRequest;
@@ -141,12 +142,14 @@ public boolean authorize(Object scriptContext) {
if (!CdiUtil.bean(FlowUtils.class).serviceEnabled())
return makeUnexpectedError(context, null, "Agama engine is disabled");
+
+ AuthzRequest authRequest = context.getAuthzRequest();
- if (!context.getAuthzRequest().isUseAuthorizationChallengeSession())
+ if (!authRequest.isUseAuthorizationChallengeSession())
return makeMissingParamError(context, "Please set 'use_auth_session=true' in your request");
ServletRequest servletRequest = context.getHttpRequest();
- AuthorizationChallengeSession deviceSessionObject = context.getAuthzRequest().getAuthorizationChallengeSessionObject();
+ AuthorizationChallengeSession deviceSessionObject = authRequest.getAuthorizationChallengeSessionObject();
boolean noSO = deviceSessionObject == null;
scriptLogger.debug("There IS{} device session object", noSO ? " NO" : "");
@@ -313,5 +316,23 @@ public int getApiVersion() {
public Map getAuthenticationMethodClaims(Object context) {
return Map.of();
}
-
+
+ @Override
+ public void prepareAuthzRequest(Object scriptContext) {
+
+ ExternalScriptContext context = (ExternalScriptContext) scriptContext;
+ AuthzRequest authRequest = context.getAuthzRequest();
+
+ AuthorizationChallengeSession sessionObject = authRequest.getAuthorizationChallengeSessionObject();
+ if (sessionObject != null) {
+ Map sessionAttributes = sessionObject.getAttributes().getAttributes();
+
+ // set scope from session into request object
+ String scopeFromSession = sessionAttributes.get("scope");
+ if (StringUtils.isNotBlank(scopeFromSession) && StringUtils.isBlank(authRequest.getScope())) {
+ authRequest.setScope(scopeFromSession);
+ }
+ }
+ }
+
}
From 5a53d53b50dd0b559254a7008b5db69e08e64f1b Mon Sep 17 00:00:00 2001
From: Yuriy Movchan
Date: Thu, 16 Jan 2025 13:54:14 +0300
Subject: [PATCH 02/10] feat(jans-auth): Show valid client name or id in
consent form (#10649)
Signed-off-by: Yuriy Movchan
---
.../sample-script/ConsentGatheringSample.py | 2 +-
.../server/authorize/ws/rs/AuthorizeAction.java | 16 +++++++++++++++-
.../layout/authorize-extended-template.xhtml | 2 +-
.../consent_gathering/ConsentGatheringSample.py | 2 +-
4 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/docs/script-catalog/consent_gathering/sample-script/ConsentGatheringSample.py b/docs/script-catalog/consent_gathering/sample-script/ConsentGatheringSample.py
index 40576be19b1..f0a48a0a49d 100644
--- a/docs/script-catalog/consent_gathering/sample-script/ConsentGatheringSample.py
+++ b/docs/script-catalog/consent_gathering/sample-script/ConsentGatheringSample.py
@@ -30,7 +30,7 @@ def destroy(self, configurationAttributes):
return True
def getApiVersion(self):
- return 1
+ return 11
# Main consent-gather method. Must return True (if gathering performed successfully) or False (if fail).
# All user entered values can be access via Map context.getPageAttributes()
diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java
index a5a96ce2de4..35384a724db 100644
--- a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java
+++ b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeAction.java
@@ -989,6 +989,20 @@ public String getClientDisplayName() {
}
final Client client = clientService.getClient(clientId);
+ return getCheckedClientDisplayName(client);
+ }
+
+ public String getClientDisplayName(final Client client) {
+ log.trace("client {}", client);
+
+ if (client == null) {
+ getClientDisplayName();
+ }
+
+ return getCheckedClientDisplayName(client);
+ }
+
+ private String getCheckedClientDisplayName(final Client client) {
if (StringUtils.isNotBlank(client.getClientName())) {
return client.getClientName();
}
@@ -998,7 +1012,7 @@ public String getClientDisplayName() {
}
return "Unknown";
- }
+ }
public String getAuthReqId() {
return authReqId;
diff --git a/jans-auth-server/server/src/main/webapp/WEB-INF/incl/layout/authorize-extended-template.xhtml b/jans-auth-server/server/src/main/webapp/WEB-INF/incl/layout/authorize-extended-template.xhtml
index e8b03eafc30..37ca0a66712 100644
--- a/jans-auth-server/server/src/main/webapp/WEB-INF/incl/layout/authorize-extended-template.xhtml
+++ b/jans-auth-server/server/src/main/webapp/WEB-INF/incl/layout/authorize-extended-template.xhtml
@@ -46,7 +46,7 @@
+ value="#{authorizeAction.getClientDisplayName(client)}" />
diff --git a/jans-linux-setup/jans_setup/static/extension/consent_gathering/ConsentGatheringSample.py b/jans-linux-setup/jans_setup/static/extension/consent_gathering/ConsentGatheringSample.py
index 40576be19b1..f0a48a0a49d 100644
--- a/jans-linux-setup/jans_setup/static/extension/consent_gathering/ConsentGatheringSample.py
+++ b/jans-linux-setup/jans_setup/static/extension/consent_gathering/ConsentGatheringSample.py
@@ -30,7 +30,7 @@ def destroy(self, configurationAttributes):
return True
def getApiVersion(self):
- return 1
+ return 11
# Main consent-gather method. Must return True (if gathering performed successfully) or False (if fail).
# All user entered values can be access via Map context.getPageAttributes()
From d19e34f943a34cf7ed2fa5f5ece7e17c97eaa5a2 Mon Sep 17 00:00:00 2001
From: YuriyZ
Date: Thu, 16 Jan 2025 13:01:19 +0200
Subject: [PATCH 03/10] fix(jans-auth-server): failing test -
SelectAccountHttpTest selectAccountTest #10647
Signed-off-by: YuriyZ
---
.../java/io/jans/as/client/ws/rs/SelectAccountHttpTest.java | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SelectAccountHttpTest.java b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SelectAccountHttpTest.java
index 5f1788fb3d0..7e93a231e14 100644
--- a/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SelectAccountHttpTest.java
+++ b/jans-auth-server/client/src/test/java/io/jans/as/client/ws/rs/SelectAccountHttpTest.java
@@ -20,7 +20,6 @@
import io.jans.as.model.jwt.JwtHeaderName;
import org.apache.logging.log4j.util.Strings;
import org.json.JSONArray;
-import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
@@ -42,7 +41,7 @@ public class SelectAccountHttpTest extends BaseTest {
@BeforeTest
public void setUp() {
- driver = new HtmlUnitDriver(true);
+ startSelenium();
pageConfig = newPageConfig(driver);
}
From 80bdd2f4ff7f4868af8bfddb8b293f511e9979cb Mon Sep 17 00:00:00 2001
From: Safin Wasi <6601566+SafinWasi@users.noreply.github.com>
Date: Thu, 16 Jan 2025 05:45:24 -0600
Subject: [PATCH 04/10] refactor(jans-cedarling): make tokens optional (#10555)
* refactor(jans-cedarling): make tokens optional
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
* docs(jans-cedarling): update readme
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
* docs(jans-cedarling): update docs
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
* chore(jans-cedarling): add license information
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
* chore(jans-cedarling): minor fixes
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
* chore(jans-cedarling): upgrade gunicorn
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
---------
Signed-off-by: SafinWasi <6601566+SafinWasi@users.noreply.github.com>
Co-authored-by: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com>
---
docs/cedarling/cedarling-policy-store.md | 8 +-
docs/cedarling/python/sidecar.md | 14 +-
jans-cedarling/flask-sidecar/Dockerfile | 9 +-
jans-cedarling/flask-sidecar/README.md | 47 ++-
.../flask-sidecar/docker-compose.yml | 1 +
jans-cedarling/flask-sidecar/main/app.py | 16 +
.../main/base/cedarling/cedarling.py | 91 ++++--
jans-cedarling/flask-sidecar/main/config.py | 21 ++
jans-cedarling/flask-sidecar/main/core.py | 16 +
.../flask-sidecar/main/extensions/__init__.py | 16 +
.../main/extensions/routes_extension.py | 16 +
jans-cedarling/flask-sidecar/main/logger.py | 16 +
.../flask-sidecar/main/v1/resource.py | 16 +
.../flask-sidecar/main/v1/schema.py | 18 +-
jans-cedarling/flask-sidecar/poetry.lock | 274 +++++++++++++++---
jans-cedarling/flask-sidecar/pyproject.toml | 7 +-
.../flask-sidecar/tests/conftest.py | 33 +++
.../flask-sidecar/tests/test_app.py | 60 ++++
.../flask-sidecar/tests/test_core.py | 26 ++
.../test_secrets/cedarling_test_config.json | 41 +++
jans-cedarling/flask-sidecar/tox.ini | 20 ++
21 files changed, 685 insertions(+), 81 deletions(-)
create mode 100644 jans-cedarling/flask-sidecar/tests/conftest.py
create mode 100644 jans-cedarling/flask-sidecar/tests/test_app.py
create mode 100644 jans-cedarling/flask-sidecar/tests/test_core.py
create mode 100644 jans-cedarling/flask-sidecar/tests/test_secrets/cedarling_test_config.json
diff --git a/docs/cedarling/cedarling-policy-store.md b/docs/cedarling/cedarling-policy-store.md
index 55bdf64de8c..504f9cf69ca 100644
--- a/docs/cedarling/cedarling-policy-store.md
+++ b/docs/cedarling/cedarling-policy-store.md
@@ -178,7 +178,11 @@ This record contains the information needed to validate tokens from this issuer:
- **description** : (*String*) A brief description of the trusted issuer, providing context for administrators.
- **openid_configuration_endpoint** : (*String*) The HTTPS URL for the OpenID Connect configuration endpoint (usually found at `/.well-known/openid-configuration`).
- **identity_source** : (*Object*, *optional*) Metadata related to the tokens issued by this issuer.
-- **`access_tokens`, `id_tokens`, `userinfo_tokens`, and `tx_tokens`**: See: [Token Metadata Schema](#token-metadata-schema).
+
+**Notes**:
+
+- The `access_tokens`, `id_tokens`, `userinfo_tokens`, and `tx_tokens` fields will follow the [Token Metadata Schema](#token-metadata-schema).
+- The `access_tokens` will contain a `trusted` and `principal_identifier` field in addition to the fields from the `Token Metadata Schema`.
### Token Metadata Schema
@@ -186,8 +190,6 @@ The Token Entity Metadata Schema defines how tokens are mapped, parsed, and tran
```json
{
- "trusted": bool,
- "principal_identifier": "str",
"user_id": "",
"role_mapping": "",
"claim_mapping": {
diff --git a/docs/cedarling/python/sidecar.md b/docs/cedarling/python/sidecar.md
index 9febea1c8a4..0ba9f5f9289 100644
--- a/docs/cedarling/python/sidecar.md
+++ b/docs/cedarling/python/sidecar.md
@@ -14,7 +14,7 @@ The sidecar is a containerized Flask project that uses the `cedarling_python` bi
- Ensure that you have installed [docker](https://docs.docker.com/engine/install/) and [docker compose](https://docs.docker.com/compose/install/).
- Clone the [Janssen](https://github.com/JanssenProject/jans) repository
- Navigate to `jans/jans-cedarling/flask-sidecar`
-- Edit the provided `secrets/bootstrap.json` file to your specifications. The configuration keys are described [here](https://github.com/JanssenProject/jans/blob/ffe9f493e4a5c6b05f2adeeb8a6eba7eb83b103e/jans-cedarling/bindings/cedarling_python/cedarling_python.pyi#L9).
+- Edit the provided `secrets/bootstrap.json` file to your specifications. The configuration keys are described [here](https://github.com/JanssenProject/jans/blob/main/jans-cedarling/bindings/cedarling_python/cedarling_python.pyi#L10).
- Run `docker compose up`
- For cloud deployments, please use the provided Dockerfile and pass your bootstrap configuration via the environment variable `CEDARLING_BOOTSTRAP_CONFIG_FILE`.
- The sidecar runs on port 5000. OpenAPI documentation is available at `http://0.0.0.0:5000/swagger-ui`
@@ -28,8 +28,13 @@ Example request to the evaluation endpoint:
```
{
"subject": {
- "type": "string",
- "id": "string"
+ "type": "JWT",
+ "id": "cedarling",
+ "properties": {
+ "access_token": "",
+ "id_token": "",
+ "userinfo_token": ""
+ }
},
"resource": {
"type": "Jans::Application",
@@ -48,9 +53,6 @@ Example request to the evaluation endpoint:
"name": "Jans::Action::\"Read\""
},
"context": {
- "access_token": "...",
- "id_token": "...",
- "userinfo_token": "...",
"device_health": [
"Healthy"
],
diff --git a/jans-cedarling/flask-sidecar/Dockerfile b/jans-cedarling/flask-sidecar/Dockerfile
index 3504f1e31da..53a6ea677d6 100644
--- a/jans-cedarling/flask-sidecar/Dockerfile
+++ b/jans-cedarling/flask-sidecar/Dockerfile
@@ -51,11 +51,11 @@ RUN git clone --filter blob:none --no-checkout https://github.com/JanssenProject
&& git sparse-checkout set jans-cedarling \
&& cd jans-cedarling/bindings/cedarling_python \
&& cp -r ../../flask-sidecar/* /api \
- && version=$(sed -n 's/.*version = "\(.*\)"/\1/p' pyproject.toml) \
+ && version=$(sed -n 's/.*version = "\([0-9].[0-9].[0-9]\)"/\1/p' Cargo.toml) \
&& echo "${version}" > /api/cedarling_version \
&& release_version="${version}" \
&& if [ "$version" = "0.0.0" ]; then release_version="nightly"; fi \
- && wget -q https://github.com/JanssenProject/jans/releases/download/"${release_version}"/cedarling_python-"${version}"-cp310-cp310-manylinux_2_34_x86_64.whl -O /api/cedarling_python-"${version}"-cp310-cp310-manylinux_2_34_x86_64.whl \
+ && wget -q https://github.com/JanssenProject/jans/releases/download/"${release_version}"/cedarling_python-"${version}"-cp310-cp310-manylinux_2_31_x86_64.whl -O /api/cedarling_python-"${version}"-cp310-cp310-manylinux_2_31_x86_64.whl \
&& rm -rf /tmp/jans
# Setting up proper permissions:
@@ -63,14 +63,15 @@ RUN chmod -R g=u /api \
&& chown -R 1000:1000 /api
# Project initialization:
-RUN poetry add /api/cedarling_python-$(cat /api/cedarling_version)-cp310-cp310-manylinux_2_34_x86_64.whl \
+RUN poetry add /api/cedarling_python-$(cat /api/cedarling_version)-cp310-cp310-manylinux_2_31_x86_64.whl \
&& poetry install --no-dev --no-root --no-interaction --no-ansi \
# Cleaning poetry installation's cache for production:
&& rm -rf "$POETRY_CACHE_DIR"
ENV FLASK_APP=main.core:app \
GUNICORN_LOG_LEVEL=${GUNICORN_LOG_LEVEL:-debug} \
- CEDARLING_BOOTSTRAP_CONFIG_FILE=${CEDARLING_BOOTSTRAP_CONFIG_FILE:-/api/bootstrap.json}
+ CEDARLING_BOOTSTRAP_CONFIG_FILE=${CEDARLING_BOOTSTRAP_CONFIG_FILE:-/api/bootstrap.json} \
+ SIDECAR_DEBUG_RESPOSE=${SIDECAR_DEBUG_RESPONSE:-False}
EXPOSE 5000
LABEL org.opencontainers.image.url="ghcr.io/janssenproject/jans/cedarling-flask-sidecar" \
diff --git a/jans-cedarling/flask-sidecar/README.md b/jans-cedarling/flask-sidecar/README.md
index f373e5d3377..f24d70f70ac 100644
--- a/jans-cedarling/flask-sidecar/README.md
+++ b/jans-cedarling/flask-sidecar/README.md
@@ -7,18 +7,44 @@ This is a Flask API that implements the [AuthZen](https://openid.github.io/authz
To run the API:
- Install [poetry](https://python-poetry.org/docs/#installation)
-- Clone the [Janssen](https://github.com/JanssenProject/jans) repository
+- Clone the [Janssen](https://github.com/JanssenProject/jans) repository:
+ ```
+ git clone --filter blob:none --no-checkout https://github.com/JanssenProject/jans
+ ```
+ ```
+ cd jans
+ ```
```
- git clone --filter blob:none --no-checkout https://github.com/JanssenProject/jans /tmp/jans \
- && cd /tmp/jans \
- && git sparse-checkout init --cone \
- && git checkout main \
- && git sparse-checkout set jans-cedarling
+ git sparse-checkout init --cone
+ ```
+ ```
+ git checkout main
+ ```
+
```
-- Navigate to `jans/jans-cedarling/flask-sidecar/main`
+ git sparse-checkout set jans-cedarling
+ ```
+- Navigate to `jans-cedarling/flask-sidecar`
- Run `poetry install` to install dependencies
+- Navigate to `main/`
- Run `poetry run flask run` to run the API on `http://127.0.0.1:5000`
+## Configuration
+
+For running via poetry, the sidecar supports the following environment variables:
+
+| Variable name | Default value | Supported value(s) |
+| ------------- | ------------- | ------------------ |
+| APP_MODE | testing | development, testing, production |
+| CEDARLING_BOOTSTRAP_CONFIG_FILE | None | Path to your configuration |
+| SIDECAR_DEBUG_RESPONSE | False | True, False |
+
+- Navigate to `jans/jans-cedarling/flask-sidecar/main` and create a file named `.env`
+- Set environment variables like so:
+```
+APP_MODE=development
+```
+
## Tests
Not yet implemented
@@ -28,6 +54,13 @@ Not yet implemented
- Clone the [Janssen](https://github.com/JanssenProject/jans) repository
- Navigate to `jans/jans-cedarling/flask-sidecar/`
- Modify the `secrets/bootstrap.json` file to your specifications. Configuration values are described [here](https://github.com/JanssenProject/jans/blob/main/jans-cedarling/bindings/cedarling_python/cedarling_python.pyi).
+ - The default configuration expects you to provide a URL to a policy store file via `CEDARLING_POLICY_STORE_URI`. If you want to use a local policy store via `CEDARLING_POLICY_STORE_FN`, you need to mount it inside the docker image. Place your policy store file in the `secrets` folder and edit the Dockerfile at line 46 to add this line:
+
+ ```
+ ...
+ COPY --chown=1000:1000 ./secrets/.json /api/
+ ...
+ ```
- Run `docker compose up`
- The service is running on `http://0.0.0.0:5000`. OpenAPI documentation is available at `/swagger-ui`
diff --git a/jans-cedarling/flask-sidecar/docker-compose.yml b/jans-cedarling/flask-sidecar/docker-compose.yml
index aa5040ca56c..6c93d08202c 100644
--- a/jans-cedarling/flask-sidecar/docker-compose.yml
+++ b/jans-cedarling/flask-sidecar/docker-compose.yml
@@ -9,6 +9,7 @@ services:
- FLASK_APP=main.core:app
- APP_MODE=${APP_MODE:-development}
- CEDARLING_BOOTSTRAP_CONFIG_FILE=/run/secrets/cedarling_bootstrap_config_file
+ - SIDECAR_DEBUG_RESPOSE={SIDECAR_DEBUG_RESPOSE:-False}
secrets:
- cedarling_bootstrap_config_file
secrets:
diff --git a/jans-cedarling/flask-sidecar/main/app.py b/jans-cedarling/flask-sidecar/main/app.py
index 42b61c0bd56..7343d508d09 100644
--- a/jans-cedarling/flask-sidecar/main/app.py
+++ b/jans-cedarling/flask-sidecar/main/app.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from flask import Flask
from main.config import ConfigLoader, get_instance_path
from main.extensions import api, cors, cedarling
diff --git a/jans-cedarling/flask-sidecar/main/base/cedarling/cedarling.py b/jans-cedarling/flask-sidecar/main/base/cedarling/cedarling.py
index 554fa02357d..7e15f38b113 100644
--- a/jans-cedarling/flask-sidecar/main/base/cedarling/cedarling.py
+++ b/jans-cedarling/flask-sidecar/main/base/cedarling/cedarling.py
@@ -1,6 +1,27 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from cedarling_python import BootstrapConfig
from cedarling_python import Cedarling
-from cedarling_python import ResourceData, Request, AuthorizeResult, AuthorizeResultResponse
+from cedarling_python import (
+ ResourceData,
+ Request,
+ AuthorizeResultResponse,
+ Tokens
+)
from main.logger import logger
from flask import Flask
import json
@@ -19,6 +40,7 @@ def __init__(self, app=None):
def init_app(self, app: Flask):
self._bootstrap_config = app.config.get("CEDARLING_BOOTSTRAP_CONFIG", "{}")
+ self.debug_response: bool = app.config.get("SIDECAR_DEBUG_RESPONSE", False)
app.extensions = getattr(app, "extensions", {})
app.extensions["cedarling_client"] = self
self.initialize_cedarling()
@@ -42,11 +64,17 @@ def generate_resource(self, resource: DictType) -> ResourceData:
resource_entity = ResourceData.from_dict(resource_entity_dict)
return resource_entity
- def validate_context(self, context: DictType) -> bool:
- for key in KEYS_LIST:
- if context.get(key, None) is None:
- return False
- return True
+ def validate_subject(self, subject: DictType) -> bool:
+ if "properties" not in subject:
+ return False
+ count = 0
+ i = 0
+ while count == 0 and i < len(KEYS_LIST):
+ key = KEYS_LIST[i]
+ if subject["properties"].get(key, None) is not None:
+ count += 1
+ i += 1
+ return True if count > 0 else False
def generate_report(self, authorize_response: AuthorizeResultResponse | None, report: str) -> _t.List[str]:
result = []
@@ -59,6 +87,13 @@ def generate_report(self, authorize_response: AuthorizeResultResponse | None, re
for error in diagnostic.errors:
result.append(error.error)
return result
+
+ def get_reason(self, authorize_response: AuthorizeResultResponse | None) -> _t.List[str]:
+ result = []
+ if authorize_response is not None:
+ for reason in authorize_response.diagnostics.reason:
+ result.append(reason)
+ return result
def authorize(self,
subject: DictType,
@@ -68,7 +103,7 @@ def authorize(self,
result_dict = {}
action_entity = action.get("name", "")
resource_entity = self.generate_resource(resource)
- if not self.validate_context(context):
+ if not self.validate_subject(subject):
result_dict["decision"] = False
result_dict["context"] = {
"id": "-1",
@@ -77,13 +112,12 @@ def authorize(self,
}
}
return result_dict
- access_token = context.get("access_token", "")
- id_token = context.get("id_token", "")
- userinfo_token = context.get("userinfo_token", "")
- for key in KEYS_LIST:
- context.pop(key)
+ access_token = subject["properties"].get("access_token", None)
+ id_token = subject["properties"].get("id_token", None)
+ userinfo_token = subject["properties"].get("userinfo_token", None)
try:
- request = Request(access_token, id_token, userinfo_token, action_entity, resource_entity, context)
+ tokens = Tokens(access_token, id_token, userinfo_token)
+ request = Request(tokens, action_entity, resource_entity, context)
authorize_result = self._cedarling.authorize(request)
except Exception as e:
result_dict["decision"] = False
@@ -100,6 +134,7 @@ def authorize(self,
result_dict["decision"] = True
else:
result_dict["decision"] = False
+ if self.debug_response:
person_result = authorize_result.person()
workload_result = authorize_result.workload()
person_value = None
@@ -108,18 +143,22 @@ def authorize(self,
person_value = person_result.decision.value
if workload_result is not None:
workload_value = workload_result.decision.value
- person_diagnostic = self.generate_report(person_result, "reason")
- person_error = self.generate_report(person_result, "error")
- workload_diagnostic = self.generate_report(workload_result, "reason")
- workload_error = self.generate_report(workload_result, "error")
- result_dict["context"] = {
- "reason_admin": {
- "person evaluation": person_value,
- "person diagnostics": person_diagnostic,
- "person error": person_error,
- "workload evaluation": workload_value,
- "workload diagnostics": workload_diagnostic,
- "workload_error": workload_error
+ person_diagnostic = self.generate_report(person_result, "reason")
+ person_error = self.generate_report(person_result, "error")
+ person_reason = self.get_reason(person_result)
+ workload_diagnostic = self.generate_report(workload_result, "reason")
+ workload_error = self.generate_report(workload_result, "error")
+ workload_reason = self.get_reason(workload_result)
+ result_dict["context"] = {
+ "reason_admin": {
+ "person evaluation": person_value,
+ "person diagnostics": person_diagnostic,
+ "person error": person_error,
+ "person reason": person_reason,
+ "workload evaluation": workload_value,
+ "workload diagnostics": workload_diagnostic,
+ "workload error": workload_error,
+ "workload reason": workload_reason
+ }
}
- }
return result_dict
diff --git a/jans-cedarling/flask-sidecar/main/config.py b/jans-cedarling/flask-sidecar/main/config.py
index d6a4cc23dc2..8c578fc502e 100644
--- a/jans-cedarling/flask-sidecar/main/config.py
+++ b/jans-cedarling/flask-sidecar/main/config.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
import os
from pathlib import Path
from main.logger import logger
@@ -25,6 +41,11 @@ class BaseConfig:
exit()
with open(CEDARLING_BOOTSTRAP_CONFIG_FILE, "r") as f:
CEDARLING_BOOTSTRAP_CONFIG = f.read()
+ SIDECAR_DEBUG_RESPONSE = os.getenv("SIDECAR_DEBUG_RESPONSE", "False")
+ if SIDECAR_DEBUG_RESPONSE == "True":
+ SIDECAR_DEBUG_RESPONSE = True
+ else:
+ SIDECAR_DEBUG_RESPONSE = False
class TestingConfig(BaseConfig):
TESTING = True
diff --git a/jans-cedarling/flask-sidecar/main/core.py b/jans-cedarling/flask-sidecar/main/core.py
index ed940548dda..e26857ecaa8 100644
--- a/jans-cedarling/flask-sidecar/main/core.py
+++ b/jans-cedarling/flask-sidecar/main/core.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from main.app import create_app
app = create_app()
diff --git a/jans-cedarling/flask-sidecar/main/extensions/__init__.py b/jans-cedarling/flask-sidecar/main/extensions/__init__.py
index cae351c3c70..db04fdf2c9a 100644
--- a/jans-cedarling/flask-sidecar/main/extensions/__init__.py
+++ b/jans-cedarling/flask-sidecar/main/extensions/__init__.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from flask_smorest import Api, Blueprint
from flask_cors import CORS
from main.base.cedarling.cedarling import CedarlingInstance
diff --git a/jans-cedarling/flask-sidecar/main/extensions/routes_extension.py b/jans-cedarling/flask-sidecar/main/extensions/routes_extension.py
index 707a4298383..b3a2793c298 100644
--- a/jans-cedarling/flask-sidecar/main/extensions/routes_extension.py
+++ b/jans-cedarling/flask-sidecar/main/extensions/routes_extension.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from main.v1.resource import blp as evaluation_routes
def register_routes(app):
diff --git a/jans-cedarling/flask-sidecar/main/logger.py b/jans-cedarling/flask-sidecar/main/logger.py
index 325696b40eb..73aceaa6bc6 100644
--- a/jans-cedarling/flask-sidecar/main/logger.py
+++ b/jans-cedarling/flask-sidecar/main/logger.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from datetime import datetime
from structlog import configure, stdlib, processors, get_logger
diff --git a/jans-cedarling/flask-sidecar/main/v1/resource.py b/jans-cedarling/flask-sidecar/main/v1/resource.py
index 402047f571a..d35a6a6b362 100644
--- a/jans-cedarling/flask-sidecar/main/v1/resource.py
+++ b/jans-cedarling/flask-sidecar/main/v1/resource.py
@@ -1,3 +1,19 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
from main.extensions import BlueprintApi
from main.v1.schema import EvaluationRequestSchema, DecisionSchema, WellKnownSchema
from flask.views import MethodView
diff --git a/jans-cedarling/flask-sidecar/main/v1/schema.py b/jans-cedarling/flask-sidecar/main/v1/schema.py
index cb59030e69c..c79812b1635 100644
--- a/jans-cedarling/flask-sidecar/main/v1/schema.py
+++ b/jans-cedarling/flask-sidecar/main/v1/schema.py
@@ -1,5 +1,21 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
import marshmallow as ma
-from marshmallow import EXCLUDE, RAISE, ValidationError, validate, validates_schema
+from marshmallow import EXCLUDE
class BaseSchema(ma.Schema):
class Meta(ma.Schema.Meta):
diff --git a/jans-cedarling/flask-sidecar/poetry.lock b/jans-cedarling/flask-sidecar/poetry.lock
index 58ed84d8303..b0508c6f1e4 100644
--- a/jans-cedarling/flask-sidecar/poetry.lock
+++ b/jans-cedarling/flask-sidecar/poetry.lock
@@ -1,14 +1,14 @@
-# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
+# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "apispec"
-version = "6.7.1"
+version = "6.8.1"
description = "A pluggable API specification generator. Currently supports the OpenAPI Specification (f.k.a. the Swagger specification)."
optional = false
python-versions = ">=3.9"
files = [
- {file = "apispec-6.7.1-py3-none-any.whl", hash = "sha256:d99e7a564f3871327c17b3e43726cc1e6ade2c97aa05706644a48818fc37999e"},
- {file = "apispec-6.7.1.tar.gz", hash = "sha256:c01b8b6ff40ffedf55b79a67f9dd920e9b2fc3909aae116facf6c8372a08b933"},
+ {file = "apispec-6.8.1-py3-none-any.whl", hash = "sha256:eacba00df745efc9adb2a45cf992300e87938582077e101fb26b78ecf4320beb"},
+ {file = "apispec-6.8.1.tar.gz", hash = "sha256:f4916cbb7be156963b18f5929a0e42bd2349135834b680a81b12432bcfaa9a39"},
]
[package.dependencies]
@@ -17,7 +17,7 @@ packaging = ">=21.3"
[package.extras]
dev = ["apispec[tests]", "pre-commit (>=3.5,<5.0)", "tox"]
-docs = ["apispec[marshmallow]", "pyyaml (==6.0.2)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-rtd-theme (==3.0.1)"]
+docs = ["apispec[marshmallow]", "pyyaml (==6.0.2)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-rtd-theme (==3.0.2)"]
marshmallow = ["marshmallow (>=3.18.0)"]
tests = ["apispec[marshmallow,yaml]", "openapi-spec-validator (==0.7.1)", "pytest"]
yaml = ["PyYAML (>=3.10)"]
@@ -35,13 +35,13 @@ files = [
[[package]]
name = "click"
-version = "8.1.7"
+version = "8.1.8"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
- {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
- {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+ {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
+ {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
]
[package.dependencies]
@@ -58,6 +58,97 @@ files = [
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
+[[package]]
+name = "coverage"
+version = "7.6.10"
+description = "Code coverage measurement for Python"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78"},
+ {file = "coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c"},
+ {file = "coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a"},
+ {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165"},
+ {file = "coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988"},
+ {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5"},
+ {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3"},
+ {file = "coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5"},
+ {file = "coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244"},
+ {file = "coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e"},
+ {file = "coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3"},
+ {file = "coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43"},
+ {file = "coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132"},
+ {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f"},
+ {file = "coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994"},
+ {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99"},
+ {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd"},
+ {file = "coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377"},
+ {file = "coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8"},
+ {file = "coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609"},
+ {file = "coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853"},
+ {file = "coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078"},
+ {file = "coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0"},
+ {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50"},
+ {file = "coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022"},
+ {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b"},
+ {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0"},
+ {file = "coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852"},
+ {file = "coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359"},
+ {file = "coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247"},
+ {file = "coverage-7.6.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05fca8ba6a87aabdd2d30d0b6c838b50510b56cdcfc604d40760dae7153b73d9"},
+ {file = "coverage-7.6.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9e80eba8801c386f72e0712a0453431259c45c3249f0009aff537a517b52942b"},
+ {file = "coverage-7.6.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a372c89c939d57abe09e08c0578c1d212e7a678135d53aa16eec4430adc5e690"},
+ {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ec22b5e7fe7a0fa8509181c4aac1db48f3dd4d3a566131b313d1efc102892c18"},
+ {file = "coverage-7.6.10-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26bcf5c4df41cad1b19c84af71c22cbc9ea9a547fc973f1f2cc9a290002c8b3c"},
+ {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4e4630c26b6084c9b3cb53b15bd488f30ceb50b73c35c5ad7871b869cb7365fd"},
+ {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2396e8116db77789f819d2bc8a7e200232b7a282c66e0ae2d2cd84581a89757e"},
+ {file = "coverage-7.6.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:79109c70cc0882e4d2d002fe69a24aa504dec0cc17169b3c7f41a1d341a73694"},
+ {file = "coverage-7.6.10-cp313-cp313-win32.whl", hash = "sha256:9e1747bab246d6ff2c4f28b4d186b205adced9f7bd9dc362051cc37c4a0c7bd6"},
+ {file = "coverage-7.6.10-cp313-cp313-win_amd64.whl", hash = "sha256:254f1a3b1eef5f7ed23ef265eaa89c65c8c5b6b257327c149db1ca9d4a35f25e"},
+ {file = "coverage-7.6.10-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:2ccf240eb719789cedbb9fd1338055de2761088202a9a0b73032857e53f612fe"},
+ {file = "coverage-7.6.10-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0c807ca74d5a5e64427c8805de15b9ca140bba13572d6d74e262f46f50b13273"},
+ {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bcfa46d7709b5a7ffe089075799b902020b62e7ee56ebaed2f4bdac04c508d8"},
+ {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e0de1e902669dccbf80b0415fb6b43d27edca2fbd48c74da378923b05316098"},
+ {file = "coverage-7.6.10-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f7b444c42bbc533aaae6b5a2166fd1a797cdb5eb58ee51a92bee1eb94a1e1cb"},
+ {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b330368cb99ef72fcd2dc3ed260adf67b31499584dc8a20225e85bfe6f6cfed0"},
+ {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9a7cfb50515f87f7ed30bc882f68812fd98bc2852957df69f3003d22a2aa0abf"},
+ {file = "coverage-7.6.10-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6f93531882a5f68c28090f901b1d135de61b56331bba82028489bc51bdd818d2"},
+ {file = "coverage-7.6.10-cp313-cp313t-win32.whl", hash = "sha256:89d76815a26197c858f53c7f6a656686ec392b25991f9e409bcef020cd532312"},
+ {file = "coverage-7.6.10-cp313-cp313t-win_amd64.whl", hash = "sha256:54a5f0f43950a36312155dae55c505a76cd7f2b12d26abeebbe7a0b36dbc868d"},
+ {file = "coverage-7.6.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:656c82b8a0ead8bba147de9a89bda95064874c91a3ed43a00e687f23cc19d53a"},
+ {file = "coverage-7.6.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccc2b70a7ed475c68ceb548bf69cec1e27305c1c2606a5eb7c3afff56a1b3b27"},
+ {file = "coverage-7.6.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5e37dc41d57ceba70956fa2fc5b63c26dba863c946ace9705f8eca99daecdc4"},
+ {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0aa9692b4fdd83a4647eeb7db46410ea1322b5ed94cd1715ef09d1d5922ba87f"},
+ {file = "coverage-7.6.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa744da1820678b475e4ba3dfd994c321c5b13381d1041fe9c608620e6676e25"},
+ {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c0b1818063dc9e9d838c09e3a473c1422f517889436dd980f5d721899e66f315"},
+ {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:59af35558ba08b758aec4d56182b222976330ef8d2feacbb93964f576a7e7a90"},
+ {file = "coverage-7.6.10-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7ed2f37cfce1ce101e6dffdfd1c99e729dd2ffc291d02d3e2d0af8b53d13840d"},
+ {file = "coverage-7.6.10-cp39-cp39-win32.whl", hash = "sha256:4bcc276261505d82f0ad426870c3b12cb177752834a633e737ec5ee79bbdff18"},
+ {file = "coverage-7.6.10-cp39-cp39-win_amd64.whl", hash = "sha256:457574f4599d2b00f7f637a0700a6422243b3565509457b2dbd3f50703e11f59"},
+ {file = "coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f"},
+ {file = "coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23"},
+]
+
+[package.dependencies]
+tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
+
+[package.extras]
+toml = ["tomli"]
+
+[[package]]
+name = "exceptiongroup"
+version = "1.2.2"
+description = "Backport of PEP 654 (exception groups)"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
+ {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
+]
+
+[package.extras]
+test = ["pytest (>=6)"]
+
[[package]]
name = "flask"
version = "3.1.0"
@@ -117,6 +208,38 @@ dev = ["flask-smorest[tests]", "pre-commit (>=3.6,<5.0)", "tox"]
docs = ["alabaster (==1.0.0)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)"]
tests = ["PyYAML (==6.0.2)", "apispec (==6.7.0)", "coverage (==7.6.4)", "flask (==3.0.3)", "marshmallow (==3.23.0)", "pytest (==8.3.3)", "pytest-cov (==5.0.0)", "webargs (==8.6.0)", "werkzeug (==3.0.4)"]
+[[package]]
+name = "gunicorn"
+version = "22.0.0"
+description = "WSGI HTTP Server for UNIX"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "gunicorn-22.0.0-py3-none-any.whl", hash = "sha256:350679f91b24062c86e386e198a15438d53a7a8207235a78ba1b53df4c4378d9"},
+ {file = "gunicorn-22.0.0.tar.gz", hash = "sha256:4a0b436239ff76fb33f11c07a16482c521a7e09c1ce3cc293c2330afe01bec63"},
+]
+
+[package.dependencies]
+packaging = "*"
+
+[package.extras]
+eventlet = ["eventlet (>=0.24.1,!=0.36.0)"]
+gevent = ["gevent (>=1.4.0)"]
+setproctitle = ["setproctitle"]
+testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"]
+tornado = ["tornado (>=0.2)"]
+
+[[package]]
+name = "iniconfig"
+version = "2.0.0"
+description = "brain-dead simple config-ini parsing"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
+ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
+]
+
[[package]]
name = "itsdangerous"
version = "2.2.0"
@@ -130,13 +253,13 @@ files = [
[[package]]
name = "jinja2"
-version = "3.1.4"
+version = "3.1.5"
description = "A very fast and expressive template engine."
optional = false
python-versions = ">=3.7"
files = [
- {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
- {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
+ {file = "jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb"},
+ {file = "jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb"},
]
[package.dependencies]
@@ -217,13 +340,13 @@ files = [
[[package]]
name = "marshmallow"
-version = "3.23.1"
+version = "3.25.1"
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
optional = false
python-versions = ">=3.9"
files = [
- {file = "marshmallow-3.23.1-py3-none-any.whl", hash = "sha256:fece2eb2c941180ea1b7fcbd4a83c51bfdd50093fdd3ad2585ee5e1df2508491"},
- {file = "marshmallow-3.23.1.tar.gz", hash = "sha256:3a8dfda6edd8dcdbf216c0ede1d1e78d230a6dc9c5a088f58c4083b974a0d468"},
+ {file = "marshmallow-3.25.1-py3-none-any.whl", hash = "sha256:ec5d00d873ce473b7f2ffcb7104286a376c354cab0c2fa12f5573dab03e87210"},
+ {file = "marshmallow-3.25.1.tar.gz", hash = "sha256:f4debda3bb11153d81ac34b0d582bf23053055ee11e791b54b4b35493468040a"},
]
[package.dependencies]
@@ -231,29 +354,29 @@ packaging = ">=17.0"
[package.extras]
dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"]
-docs = ["alabaster (==1.0.0)", "autodocsumm (==0.2.14)", "sphinx (==8.1.3)", "sphinx-issues (==5.0.0)", "sphinx-version-warning (==1.1.2)"]
+docs = ["autodocsumm (==0.2.14)", "furo (==2024.8.6)", "sphinx (==8.1.3)", "sphinx-copybutton (==0.5.2)", "sphinx-issues (==5.0.0)", "sphinxext-opengraph (==0.9.1)"]
tests = ["pytest", "simplejson"]
[[package]]
name = "maturin"
-version = "1.7.4"
+version = "1.8.1"
description = "Build and publish crates with pyo3, cffi and uniffi bindings as well as rust binaries as python packages"
optional = false
python-versions = ">=3.7"
files = [
- {file = "maturin-1.7.4-py3-none-linux_armv6l.whl", hash = "sha256:eb7b7753b733ae302c08f80bca7b0c3fda1eea665c2b1922c58795f35a54c833"},
- {file = "maturin-1.7.4-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0182a9638399c8835afd39d2aeacf56908e37cba3f7abb15816b9df6774fab81"},
- {file = "maturin-1.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:41a29c5b23f3ebdfe7633637e3de256579a1b2700c04cd68c16ed46934440c5a"},
- {file = "maturin-1.7.4-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:23fae44e345a2da5cb391ae878726fb793394826e2f97febe41710bd4099460e"},
- {file = "maturin-1.7.4-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:8b441521c151f0dbe70ed06fb1feb29b855d787bda038ff4330ca962e5d56641"},
- {file = "maturin-1.7.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:7ccb66d0c5297cf06652c5f72cb398f447d3a332eccf5d1e73b3fe14dbc9498c"},
- {file = "maturin-1.7.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:71f668f19e719048605dbca6a1f4d0dc03b987c922ad9c4bf5be03b9b278e4c3"},
- {file = "maturin-1.7.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:c179fcb2b494f19186781b667320e43d95b3e71fcb1c98fffad9ef6bd6e276b3"},
- {file = "maturin-1.7.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd5b4b95286f2f376437340f8a4908f4761587212170263084455be8099099a7"},
- {file = "maturin-1.7.4-py3-none-win32.whl", hash = "sha256:35487a424467d1fda4567cbb02d21f09febb10eda22f5fd647b130bc0767dc61"},
- {file = "maturin-1.7.4-py3-none-win_amd64.whl", hash = "sha256:f70c1c8ec9bd4749a53c0f3ae8fdbb326ce45be4f1c5551985ee25a6d7150328"},
- {file = "maturin-1.7.4-py3-none-win_arm64.whl", hash = "sha256:f3d38a6d0c7fd7b04bec30dd470b2173cf9bd184ab6220c1acaf49df6b48faf5"},
- {file = "maturin-1.7.4.tar.gz", hash = "sha256:2b349d742a07527d236f0b4b6cab26f53ebecad0ceabfc09ec4c6a396e3176f9"},
+ {file = "maturin-1.8.1-py3-none-linux_armv6l.whl", hash = "sha256:7e590a23d9076b8a994f2e67bc63dc9a2d1c9a41b1e7b45ac354ba8275254e89"},
+ {file = "maturin-1.8.1-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d8251a95682c83ea60988c804b620c181911cd824aa107b4a49ac5333c92968"},
+ {file = "maturin-1.8.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b9fc1a4354cac5e32c190410208039812ea88c4a36bd2b6499268ec49ef5de00"},
+ {file = "maturin-1.8.1-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:621e171c6b39f95f1d0df69a118416034fbd59c0f89dcaea8c2ea62019deecba"},
+ {file = "maturin-1.8.1-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:98f638739a5132962347871b85c91f525c9246ef4d99796ae98a2031e3df029f"},
+ {file = "maturin-1.8.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:f9f5c47521924b6e515cbc652a042fe5f17f8747445be9d931048e5d8ddb50a4"},
+ {file = "maturin-1.8.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:0f4407c7353c31bfbb8cdeb82bc2170e474cbfb97b5ba27568f440c9d6c1fdd4"},
+ {file = "maturin-1.8.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:ec49cd70cad3c389946c6e2bc0bd50772a7fcb463040dd800720345897eec9bf"},
+ {file = "maturin-1.8.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c08767d794de8f8a11c5c8b1b47a4ff9fb6ae2d2d97679e27030f2f509c8c2a0"},
+ {file = "maturin-1.8.1-py3-none-win32.whl", hash = "sha256:d678407713f3e10df33c5b3d7a343ec0551eb7f14d8ad9ba6febeb96f4e4c75c"},
+ {file = "maturin-1.8.1-py3-none-win_amd64.whl", hash = "sha256:a526f90fe0e5cb59ffb81f4ff547ddc42e823bbdeae4a31012c0893ca6dcaf46"},
+ {file = "maturin-1.8.1-py3-none-win_arm64.whl", hash = "sha256:e95f077fd2ddd2f048182880eed458c308571a534be3eb2add4d3dac55bf57f4"},
+ {file = "maturin-1.8.1.tar.gz", hash = "sha256:49cd964aabf59f8b0a6969f9860d2cdf194ac331529caae14c884f5659568857"},
]
[package.dependencies]
@@ -274,6 +397,61 @@ files = [
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
]
+[[package]]
+name = "pluggy"
+version = "1.5.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
+ {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["pytest", "pytest-benchmark"]
+
+[[package]]
+name = "pytest"
+version = "8.3.4"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"},
+ {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
+iniconfig = "*"
+packaging = "*"
+pluggy = ">=1.5,<2"
+tomli = {version = ">=1", markers = "python_version < \"3.11\""}
+
+[package.extras]
+dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
+
+[[package]]
+name = "pytest-cov"
+version = "6.0.0"
+description = "Pytest plugin for measuring coverage."
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0"},
+ {file = "pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35"},
+]
+
+[package.dependencies]
+coverage = {version = ">=7.5", extras = ["toml"]}
+pytest = ">=4.6"
+
+[package.extras]
+testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"]
+
[[package]]
name = "python-dotenv"
version = "1.0.1"
@@ -380,13 +558,43 @@ typing = ["mypy (>=1.4)", "rich", "twisted"]
[[package]]
name = "tomli"
-version = "2.1.0"
+version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
files = [
- {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"},
- {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"},
+ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
+ {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
+ {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
+ {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
+ {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
+ {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
+ {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
+ {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
+ {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
+ {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
+ {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
+ {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
+ {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
+ {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
]
[[package]]
@@ -430,4 +638,4 @@ watchdog = ["watchdog (>=2.3)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
-content-hash = "0675d7de7297345d80644938832646b44bb54db5f19b1932c1272f96c77e680d"
+content-hash = "e2d07778e7aa9b1e8e5e3c76bb0ef0b9f9af86249da8655d985a7b5848f5180d"
diff --git a/jans-cedarling/flask-sidecar/pyproject.toml b/jans-cedarling/flask-sidecar/pyproject.toml
index 0c30b0be9ea..153c565f69f 100644
--- a/jans-cedarling/flask-sidecar/pyproject.toml
+++ b/jans-cedarling/flask-sidecar/pyproject.toml
@@ -5,6 +5,7 @@ description = "Sidecar for cedarling"
authors = ["SafinWasi <6601566+SafinWasi@users.noreply.github.com>"]
license = "Apache-2.0"
readme = "README.md"
+packages = [{ include = "main" }]
[tool.poetry.dependencies]
python = "^3.10"
@@ -16,9 +17,13 @@ flask-cors = "^5.0.0"
python-dotenv = "^1.0.1"
structlog = "^24.4.0"
python-json-logger = "^2.0.7"
-gunicorn = "^20.1.0"
+gunicorn = "^22.0.0"
+[tool.poetry.group.test.dependencies]
+pytest = "^8.3.4"
+pytest-cov = "^6.0.0"
+
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
diff --git a/jans-cedarling/flask-sidecar/tests/conftest.py b/jans-cedarling/flask-sidecar/tests/conftest.py
new file mode 100644
index 00000000000..c2f9f9db2d8
--- /dev/null
+++ b/jans-cedarling/flask-sidecar/tests/conftest.py
@@ -0,0 +1,33 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import os
+
+import pytest
+from main.extensions import cedarling
+
+current_path = os.path.dirname(os.path.realpath(__file__))
+
+
+@pytest.fixture(autouse=True)
+def env_setup(monkeypatch):
+ monkeypatch.setenv("APP_MODE", "testing")
+ monkeypatch.setenv("CEDARLING_BOOTSTRAP_CONFIG_FILE", os.path.join(current_path, "test_secrets", "cedarling_test_config.json"))
+ monkeypatch.setattr(cedarling, "initialize_cedarling", lambda: None)
+
+@pytest.fixture(scope="function")
+def mock_cedarling(monkeypatch):
+ pass
diff --git a/jans-cedarling/flask-sidecar/tests/test_app.py b/jans-cedarling/flask-sidecar/tests/test_app.py
new file mode 100644
index 00000000000..867c9d7477f
--- /dev/null
+++ b/jans-cedarling/flask-sidecar/tests/test_app.py
@@ -0,0 +1,60 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+test_app
+~~~~~~~~
+This module consists of testcases for :module:`main.app` module.
+"""
+import os
+
+import pytest
+
+
+@pytest.mark.parametrize(
+ "mode",
+ [
+ ("development"),
+ ("testing"),
+ ("production"),
+ ("dummy"),
+ ],
+)
+def test_create_app(mode):
+ """Test factory function that creates Flask's app."""
+ from main.app import create_app
+ os.environ["APP_MODE"] = mode
+ config = {
+ "testing": {
+ "debug": True,
+ "testing": True
+ },
+ "development": {
+ "debug": True,
+ "testing": False
+ },
+ "production": {
+ "debug": False,
+ "testing": False
+ }
+ }
+ loaded_config = config.get(mode, config.get("testing"))
+ app = create_app()
+ assert loaded_config is not None
+ assert loaded_config.get("debug", None) is not None
+ assert loaded_config.get("testing", None) is not None
+ assert app.config["DEBUG"] is loaded_config["debug"]
+ assert app.config["TESTING"] is loaded_config["testing"]
+ # Flask app has ``app_context`` attr
+ assert hasattr(app, "app_context")
diff --git a/jans-cedarling/flask-sidecar/tests/test_core.py b/jans-cedarling/flask-sidecar/tests/test_core.py
new file mode 100644
index 00000000000..ec41bf68100
--- /dev/null
+++ b/jans-cedarling/flask-sidecar/tests/test_core.py
@@ -0,0 +1,26 @@
+"""
+Copyright (c) 2025, Gluu, Inc.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+test_core
+~~~~~~~~~
+This module consists of testcases for :module:`core` module.
+"""
+
+
+def test_core_app():
+ """Test core app is a Flask app."""
+ from main.core import app
+
+ assert hasattr(app, "app_context")
diff --git a/jans-cedarling/flask-sidecar/tests/test_secrets/cedarling_test_config.json b/jans-cedarling/flask-sidecar/tests/test_secrets/cedarling_test_config.json
new file mode 100644
index 00000000000..fb5d711a0fa
--- /dev/null
+++ b/jans-cedarling/flask-sidecar/tests/test_secrets/cedarling_test_config.json
@@ -0,0 +1,41 @@
+{
+ "CEDARLING_APPLICATION_NAME": "My App",
+ "CEDARLING_POLICY_STORE_URI": "https://gluu.org",
+ "CEDARLING_POLICY_STORE_ID": "gICAgcHJpbmNpcGFsIGlz",
+ "CEDARLING_LOG_TYPE": "std_out",
+ "CEDARLING_LOG_LEVEL": "INFO",
+ "CEDARLING_LOG_TTL": null,
+ "CEDARLING_USER_AUTHZ": "enabled",
+ "CEDARLING_WORKLOAD_AUTHZ": "enabled",
+ "CEDARLING_USER_WORKLOAD_BOOLEAN_OPERATION": "AND",
+ "CEDARLING_LOCAL_JWKS": null,
+ "CEDARLING_LOCAL_POLICY_STORE": null,
+ "CEDARLING_POLICY_STORE_LOCAL_FN": null,
+ "CEDARLING_JWT_SIG_VALIDATION": "disabled",
+ "CEDARLING_JWT_STATUS_VALIDATION": "disabled",
+ "CEDARLING_JWT_SIGNATURE_ALGORITHMS_SUPPORTED": [
+ "HS256",
+ "RS256"
+ ],
+ "CEDARLING_AT_ISS_VALIDATION": "disabled",
+ "CEDARLING_AT_JTI_VALIDATION": "disabled",
+ "CEDARLING_AT_NBF_VALIDATION": "disabled",
+ "CEDARLING_AT_EXP_VALIDATION": "disabled",
+ "CEDARLING_IDT_ISS_VALIDATION": "disabled",
+ "CEDARLING_IDT_SUB_VALIDATION": "disabled",
+ "CEDARLING_IDT_EXP_VALIDATION": "disabled",
+ "CEDARLING_IDT_IAT_VALIDATION": "disabled",
+ "CEDARLING_IDT_AUD_VALIDATION": "disabled",
+ "CEDARLING_USERINFO_ISS_VALIDATION": "disabled",
+ "CEDARLING_USERINFO_SUB_VALIDATION": "disabled",
+ "CEDARLING_USERINFO_AUD_VALIDATION": "disabled",
+ "CEDARLING_USERINFO_EXP_VALIDATION": "disabled",
+ "CEDARLING_ID_TOKEN_TRUST_MODE": "strict",
+ "CEDARLING_LOCK": "disabled",
+ "CEDARLING_LOCK_MASTER_CONFIGURATION_URI": null,
+ "CEDARLING_DYNAMIC_CONFIGURATION": "disabled",
+ "CEDARLING_LOCK_SSA_JWT": "",
+ "CEDARLING_AUDIT_HEALTH_INTERVAL": 0,
+ "CEDARLING_AUDIT_TELEMETRY_INTERVAL": 0,
+ "CEDARLING_LISTEN_SSE": "disabled"
+}
diff --git a/jans-cedarling/flask-sidecar/tox.ini b/jans-cedarling/flask-sidecar/tox.ini
index e69de29bb2d..343b7139804 100644
--- a/jans-cedarling/flask-sidecar/tox.ini
+++ b/jans-cedarling/flask-sidecar/tox.ini
@@ -0,0 +1,20 @@
+[tox]
+envlist = py310
+skip_missing_interpreters = true
+# align with pyproject.toml
+isolated_build = true
+
+[testenv]
+passenv = *
+deps =
+ pytest
+ pytest-cov
+ pytest-env
+ pytest-structlog
+allowlist_externals = poetry
+skip_install = true
+commands_pre =
+ poetry install
+commands =
+ poetry install -v
+ poetry run pytest -v --cov-config=.coveragerc --cov=main --cov-report=term-missing:skip-covered --cov-report=xml tests/
From 519c64469eb0725dac88851b15fa51203c4ee583 Mon Sep 17 00:00:00 2001
From: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com>
Date: Thu, 16 Jan 2025 11:46:54 +0000
Subject: [PATCH 05/10] ci: add cedarling wasm build (#10656)
* ci: add cedarling wasm
Signed-off-by: moabu <47318409+moabu@users.noreply.github.com>
* ci: build and sign
Signed-off-by: moabu <47318409+moabu@users.noreply.github.com>
* ci: remove .gitignore file from package
Signed-off-by: moabu <47318409+moabu@users.noreply.github.com>
* ci: add cedarling wasm build to jans-tarp
Signed-off-by: moabu <47318409+moabu@users.noreply.github.com>
---------
Signed-off-by: moabu <47318409+moabu@users.noreply.github.com>
---
.github/workflows/build-packages.yml | 57 +++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml
index c9b886d4c24..e725f0851c0 100644
--- a/.github/workflows/build-packages.yml
+++ b/.github/workflows/build-packages.yml
@@ -307,6 +307,8 @@ jobs:
overwrite: true
build_demo_packages:
if: github.repository == 'JanssenProject/jans'
+ # Needs cedarling wasm as jans-tarp uses the wasm package
+ needs: build_cedarling_wasm
runs-on: ubuntu-latest
steps:
- name: Harden Runner
@@ -326,6 +328,15 @@ jobs:
for i in $(ls -d */); do zip -r demo-${i%/}-$VER-source.zip $i && sha256sum demo-${i%/}-$VER-source.zip > demo-${i%/}-$VER-source.zip.sha256sum; done
sudo rm demo-jans-tarp-$VER-source.zip demo-jans-tarp-$VER-source.zip.sha256sum
cd jans-tarp
+ # Get the latest cedarling wasm package
+ TAG=$(echo ${{ github.event.ref }} | cut -d '/' -f 3 | sed 's/^v//')
+ if [ "${TAG}" == "nightly" ]; then
+ TAG="0.0.0"
+ fi
+ wget https://github.com/${{ github.repository }}/releases/download/"${VER}"/cedarling_wasm_"${TAG}"_pkg.tar.gz -O cedarling_wasm.tar.gz
+ mkdir wasm
+ tar -xvf cedarling_wasm.tar.gz -C wasm
+ # END Get the latest cedarling wasm package
npm install
npm run build
npm run pack
@@ -380,4 +391,48 @@ jobs:
gpg --armor --detach-sign cedarling_python-"${TAG}"-cp311-cp311-manylinux_2_31_x86_64.whl || echo "Failed to sign"
gpg --armor --detach-sign cedarling_python-"${TAG}"-cp310-cp310-manylinux_2_31_x86_64.whl || echo "Failed to sign"
echo "${{ secrets.MOAUTO_WORKFLOW_TOKEN }}" | gh auth login --with-token
- gh release upload "${VERSION}" *.whl *.sha256sum *.asc
\ No newline at end of file
+ gh release upload "${VERSION}" *.whl *.sha256sum *.asc
+ build_cedarling_wasm:
+ if: github.repository == 'JanssenProject/jans'
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Harden Runner
+ uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
+ with:
+ egress-policy: audit
+
+ - name: Checkout
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ - name: Import GPG key
+ id: import_gpg
+ continue-on-error: true
+ uses: crazy-max/ghaction-import-gpg@01dd5d3ca463c7f10f7f4f7b4f177225ac661ee4 # v6.1.0
+ with:
+ gpg_private_key: ${{ secrets.MOAUTO_GPG_PRIVATE_KEY }}
+ passphrase: ${{ secrets.MOAUTO_GPG_PRIVATE_KEY_PASSPHRASE }}
+ git_user_signingkey: true
+ git_commit_gpgsign: true
+ - name: Build WASM build
+ id: sign-cedarling
+ working-directory: ${{ github.workspace }}/jans-cedarling/bindings/cedarling_wasm
+ run: |
+ rustup update stable && rustup default stable
+ cargo install wasm-pack
+ wasm-pack build --release --target web
+ ls pkg
+ - name: Archive and sign pkg contents
+ id: archive_pkg
+ working-directory: ${{ github.workspace }}/jans-cedarling/bindings/cedarling_wasm
+ run: |
+ TAG=$(echo ${{ github.event.ref }} | cut -d '/' -f 3 | sed 's/^v//')
+ VERSION="$(echo ${{ github.event.ref }} | cut -d '/' -f 3)"
+ if [ "${TAG}" == "nightly" ]; then
+ VERSION=nightly
+ TAG="0.0.0"
+ fi
+ rm -rf pkg/.gitignore || echo "Failed to remove gitignore"
+ tar -czvf cedarling_wasm_"${TAG}"_pkg.tar.gz -C pkg .
+ sha256sum cedarling_wasm_"${TAG}"_pkg.tar.gz > cedarling_wasm_"${TAG}"_pkg.tar.gz.sha256sum
+ gpg --armor --detach-sign cedarling_wasm_"${TAG}"_pkg.tar.gz || echo "Failed to sign"
+ echo "${{ secrets.MOAUTO_WORKFLOW_TOKEN }}" | gh auth login --with-token
+ gh release upload "${VERSION}" *.tar.gz *.sha256sum *.asc
\ No newline at end of file
From 6c06ade0dcfc8530d85f9949a604acf77fe1e6be Mon Sep 17 00:00:00 2001
From: Richard Marin <34529290+rmarinn@users.noreply.github.com>
Date: Thu, 16 Jan 2025 22:27:55 +0800
Subject: [PATCH 06/10] refactor(jans-cedarling): enhance schema parser and
entity creation implementation (#10549)
* feat(jans-cedarling): implement new CedarRecordAttr struct
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement struct for CedarEntityType
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): remove `Cedar` prefix in struct names
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement Action type struct
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): rename RecordAttr to AttributeKind
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): change type aliases to newtype definitions
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement new CedarSchemaJson struct
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): implement EntityShape newtype for AttributeKind::Record
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): remove newtypes for string types
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): initial entity builder implementation
- implement an entity builder can can make workload entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): add user entity creation to the EntityBuilder
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): improve entity builder code readability
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement EntityBuilder token entity creation
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement EntityBuilder resource entity creation
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): replace infallible unwrap with expect
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement EntityBuilder role entity creation
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): implement EntityBuilder::build_entities
- implement EntityBuilder::build_entities which builds all the
cedarling-specific entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): replace old implementation
- start using the new CedarJsonSchema
- start using EntityBuilder to build entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): loading unknown attribute variant
- make the default type "EntityOrCommon" for unknown variants instead of
failing desrialization.
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): multiple access_token entities being created
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): using access_token to create all token entities
- fix the bug where the access_token is being used to create all token
entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): handle common type context
- fix CommonType contexts not being handled properly
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): entity references not being fully qualified
- fix entity references within entities not being qualified; i.e. the
namespace is not included in the reference... which causes problems
down the line
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): role entities creation
- refactor role entities creation to not fail if no role entities were
created but just return an empty Vec
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): broken test: test_failed_workload_mapping
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): broken test: test_failed_id_token_mapping
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): remove outdated test errors_on_invalid_type
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): silently fail non-required attr creation errors
- silently fail non-required attr creation errors since it was making an
existing test fail: "check_mapping_tokens_data"
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): move build_context to it's own file
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): remove outdated commens
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): move EntityBuilder into the Authz struct
- move EntityBuilder into the Authz struct from AuthzConfig
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* docs(jans-cedarling): update auto adding references to context docs
- remove the now obsolete naming convention needed to automatically map
entity references to the context from the docs
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): check resource schema before creating the entity
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): improve error message for entity resouce
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): resolve clippy issues
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): remove panics in build_context func
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): remove testing println!
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* test(jans-cedarling): cover building resource entity with record attr
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): non-required record attr getting required
- fix non required record attributes getting required if the record is
also required.
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): improve code readability
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): return str instead of String for value_type_name
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): replace unwrap_or with unwrap_or_else
- replace unwrap_or with unwrap_or_else for laziness
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): improve code readability
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): map infallible error to BuildEntityError
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): reduce lookups in merge_json_values
- reduce the amount of lookups done in merge_json_values to improve
performance
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): delete unused file
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): remove outdated comment
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): rename try_join_namespace to join_namespace
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* docs(jans-cedarling): update PYTHON_TYPES.md
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): swap params when calling merge_json_values
- when calling merge_json_values, use the original context as the first
param
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): implement ClaimAliasMap struct
- implement a struct to describe claim aliases for better readability
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): return an error instead of panicking
- return an error instead of panicking in try_build_role_entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): remove extra impl block
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): do not create duplicate role entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* test(jans-cedarling): add test for creating roles from different tokens
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): return an error when given a wrong token kind
- return an error when given a wrong kind of token when building token
entities
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* test(jans-cedarling): add test for creating token entities
- add test for creating id_token entity
- add test for creating userinfo_token entity
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* test(jans-cedarling): added more comprehensive tests for entity builder
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* chore(jans-cedarling): resolve clippy issues
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* feat(jans-cedarling): unify cases in build_role_entities
Signed-off-by: John Anderson
* fix(jans-cedarling): misspelling in error message
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): test intermittently failing
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): remove unwrap and improve error messages
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* fix(jans-cedarling): python test error msg assert
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): remove deserialize_to_string fn
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
* refactor(jans-cedarling): replace if-else with then_some
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
---------
Signed-off-by: rmarinn <34529290+rmarinn@users.noreply.github.com>
Signed-off-by: John Anderson
Co-authored-by: John Anderson
Co-authored-by: Oleh
---
docs/cedarling/cedarling-authz.md | 16 +-
.../bindings/cedarling_python/PYTHON_TYPES.md | 28 +-
.../cedarling_python/src/authorize/errors.rs | 63 +-
.../cedarling_python/tests/test_authorize.py | 6 +-
jans-cedarling/cedarling/Cargo.toml | 2 +-
.../cedarling/src/authz/build_ctx.rs | 191 ++++++
.../cedarling/src/authz/entities/create.rs | 440 -------------
.../cedarling/src/authz/entities/mod.rs | 278 ---------
.../src/authz/entities/test_create.rs | 587 ------------------
.../successful_scenario.schema | 26 -
.../successful_scenario_schema.json | 87 ---
.../test_create_data/type_error_schema.json | 36 --
.../src/authz/entities/trait_as_expression.rs | 29 -
.../cedarling/src/authz/entities/user.rs | 257 --------
.../cedarling/src/authz/entities/workload.rs | 249 --------
.../cedarling/src/authz/entity_builder.rs | 471 ++++++++++++++
.../src/authz/entity_builder/build_attrs.rs | 318 ++++++++++
.../src/authz/entity_builder/build_expr.rs | 586 +++++++++++++++++
.../entity_builder/build_resource_entity.rs | 331 ++++++++++
.../authz/entity_builder/build_role_entity.rs | 286 +++++++++
.../entity_builder/build_token_entities.rs | 368 +++++++++++
.../authz/entity_builder/build_user_entity.rs | 291 +++++++++
.../entity_builder/build_workload_entity.rs | 463 ++++++++++++++
.../src/authz/entity_builder/mapping.rs | 61 ++
.../cedarling/src/authz/merge_json.rs | 56 --
jans-cedarling/cedarling/src/authz/mod.rs | 228 ++-----
jans-cedarling/cedarling/src/authz/request.rs | 12 -
.../src/common/cedar_schema/cedar_json.rs | 442 ++++---------
.../common/cedar_schema/cedar_json/action.rs | 571 +++++------------
.../cedar_schema/cedar_json/attribute.rs | 283 +++++++++
.../cedar_schema/cedar_json/deserialize.rs | 36 ++
.../cedar_schema/cedar_json/entity_type.rs | 171 +++++
.../cedar_schema/cedar_json/entity_types.rs | 226 -------
.../cedarling/src/common/cedar_schema/mod.rs | 2 +-
.../cedarling/src/common/policy_store.rs | 2 +-
.../src/common/policy_store/claim_mapping.rs | 24 +-
.../cedarling/src/init/service_factory.rs | 10 +-
jans-cedarling/cedarling/src/jwt/mod.rs | 2 +-
jans-cedarling/cedarling/src/jwt/token.rs | 58 +-
jans-cedarling/cedarling/src/lib.rs | 6 +-
.../cedarling/src/tests/mapping_entities.rs | 105 ++--
.../src/tests/schema_type_mapping.rs | 2 +-
42 files changed, 4293 insertions(+), 3413 deletions(-)
create mode 100644 jans-cedarling/cedarling/src/authz/build_ctx.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/create.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/mod.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/test_create.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/test_create_data/successful_scenario.schema
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/test_create_data/successful_scenario_schema.json
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/test_create_data/type_error_schema.json
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/trait_as_expression.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/user.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/entities/workload.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_attrs.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_expr.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_resource_entity.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_role_entity.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_token_entities.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_user_entity.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/build_workload_entity.rs
create mode 100644 jans-cedarling/cedarling/src/authz/entity_builder/mapping.rs
delete mode 100644 jans-cedarling/cedarling/src/authz/merge_json.rs
create mode 100644 jans-cedarling/cedarling/src/common/cedar_schema/cedar_json/attribute.rs
create mode 100644 jans-cedarling/cedarling/src/common/cedar_schema/cedar_json/deserialize.rs
create mode 100644 jans-cedarling/cedarling/src/common/cedar_schema/cedar_json/entity_type.rs
delete mode 100644 jans-cedarling/cedarling/src/common/cedar_schema/cedar_json/entity_types.rs
diff --git a/docs/cedarling/cedarling-authz.md b/docs/cedarling/cedarling-authz.md
index 89f3a5c7619..70445076942 100644
--- a/docs/cedarling/cedarling-authz.md
+++ b/docs/cedarling/cedarling-authz.md
@@ -83,14 +83,14 @@ decision_result = await cedarling(input)
## Automatically Adding Entity References to the Context
-Cedarling simplifies context creation by automatically including certain entities. This means you don't need to manually pass their references when using them in your policies. The following entities are automatically added to the context, along with their naming conventions in `lower_snake_case` format:
-
-- **Workload Entity**: `workload`
-- **User Entity**: `user`
-- **Resource Entity**: `resource`
-- **Access Token Entity**: `access_token`
-- **ID Token Entity**: `id_token`
-- **Userinfo Token Entity**: `userinfo_token`
+Cedarling simplifies context creation by automatically including certain entities. This means you don't need to manually pass their references when using them in your policies. The following entities are automatically added to the context.
+
+- Workload Entity
+- User Entity
+- Resource Entity
+- Access Token Entity
+- ID Token Entity
+- Userinfo Token Entity
### Example Policy
diff --git a/jans-cedarling/bindings/cedarling_python/PYTHON_TYPES.md b/jans-cedarling/bindings/cedarling_python/PYTHON_TYPES.md
index f0875a6f06d..436c8f5d727 100644
--- a/jans-cedarling/bindings/cedarling_python/PYTHON_TYPES.md
+++ b/jans-cedarling/bindings/cedarling_python/PYTHON_TYPES.md
@@ -209,30 +209,14 @@ ___
Exception raised by authorize_errors
___
-# authorize_errors.CreateAccessTokenEntityError
-Error encountered while creating access_token entity
+# authorize_errors.BuildEntitiesError
+Error encountered while building entities into context
___
# authorize_errors.CreateContextError
Error encountered while validating context according to the schema
___
-# authorize_errors.CreateIdTokenEntityError
-Error encountered while creating id token entities
-___
-
-# authorize_errors.CreateUserEntityError
-Error encountered while creating User entity
-___
-
-# authorize_errors.CreateUserinfoTokenEntityError
-Error encountered while creating Userinfo_token entity
-___
-
-# authorize_errors.CreateWorkloadEntityError
-Error encountered while creating workload entity
-___
-
# authorize_errors.EntitiesError
Error encountered while collecting all entities
___
@@ -245,14 +229,6 @@ ___
Error encountered while processing JWT token data
___
-# authorize_errors.ResourceEntityError
-Error encountered while creating resource entity
-___
-
-# authorize_errors.RoleEntityError
-Error encountered while creating role entity
-___
-
# authorize_errors.UserRequestValidationError
Error encountered while creating cedar_policy::Request for user entity principal
___
diff --git a/jans-cedarling/bindings/cedarling_python/src/authorize/errors.rs b/jans-cedarling/bindings/cedarling_python/src/authorize/errors.rs
index 89ad49ba9a9..feda288a4ad 100644
--- a/jans-cedarling/bindings/cedarling_python/src/authorize/errors.rs
+++ b/jans-cedarling/bindings/cedarling_python/src/authorize/errors.rs
@@ -30,54 +30,6 @@ create_exception!(
"Error encountered while processing JWT token data"
);
-create_exception!(
- authorize_errors,
- CreateIdTokenEntityError,
- AuthorizeError,
- "Error encountered while creating id token entities"
-);
-
-create_exception!(
- authorize_errors,
- CreateUserinfoTokenEntityError,
- AuthorizeError,
- "Error encountered while creating Userinfo_token entity"
-);
-create_exception!(
- authorize_errors,
- CreateAccessTokenEntityError,
- AuthorizeError,
- "Error encountered while creating access_token entity"
-);
-
-create_exception!(
- authorize_errors,
- CreateUserEntityError,
- AuthorizeError,
- "Error encountered while creating User entity"
-);
-
-create_exception!(
- authorize_errors,
- CreateWorkloadEntityError,
- AuthorizeError,
- "Error encountered while creating workload entity"
-);
-
-create_exception!(
- authorize_errors,
- ResourceEntityError,
- AuthorizeError,
- "Error encountered while creating resource entity"
-);
-
-create_exception!(
- authorize_errors,
- RoleEntityError,
- AuthorizeError,
- "Error encountered while creating role entity"
-);
-
create_exception!(
authorize_errors,
ActionError,
@@ -120,6 +72,13 @@ create_exception!(
"Error encountered while parsing all entities to json for logging"
);
+create_exception!(
+ authorize_errors,
+ BuildEntitiesError,
+ AuthorizeError,
+ "Error encountered while building entities into context"
+);
+
create_exception!(
authorize_errors,
AddEntitiesIntoContextError,
@@ -166,17 +125,11 @@ macro_rules! errors_functions {
// For each possible case of `AuthorizeError`, we have created a corresponding Python exception that inherits from `cedarling::AuthorizeError`.
errors_functions! {
ProcessTokens => ProcessTokens,
- CreateIdTokenEntity => CreateIdTokenEntityError,
- CreateUserinfoTokenEntity => CreateUserinfoTokenEntityError,
- CreateAccessTokenEntity => CreateAccessTokenEntityError,
- CreateUserEntity => CreateUserEntityError,
- CreateWorkloadEntity => CreateWorkloadEntityError,
- ResourceEntity => ResourceEntityError,
- RoleEntity => RoleEntityError,
Action => ActionError,
CreateContext => CreateContextError,
WorkloadRequestValidation => WorkloadRequestValidationError,
UserRequestValidation => UserRequestValidationError,
+ BuildEntity => BuildEntitiesError,
BuildContext => AddEntitiesIntoContextError,
Entities => EntitiesError,
EntitiesToJson => EntitiesToJsonError
diff --git a/jans-cedarling/bindings/cedarling_python/tests/test_authorize.py b/jans-cedarling/bindings/cedarling_python/tests/test_authorize.py
index 92926ccfccd..b1e8971f1ce 100644
--- a/jans-cedarling/bindings/cedarling_python/tests/test_authorize.py
+++ b/jans-cedarling/bindings/cedarling_python/tests/test_authorize.py
@@ -186,8 +186,8 @@ def test_resource_entity_error():
'''
try:
raise_authorize_error(load_bootstrap_config())
- except authorize_errors.ResourceEntityError as e:
- assert str(e) == "could not create resource entity: could not get attribute value from payload: type mismatch for key 'org_id'. expected: 'String', but found: 'number'"
+ except authorize_errors.BuildEntitiesError as e:
+ assert str(e) == "failed to build resource entity: failed to build `org_id` attribute: failed to build restricted expression: type mismatch for key 'org_id'. expected: 'string', but found: 'number'"
def test_authorize_error():
@@ -199,4 +199,4 @@ def test_authorize_error():
try:
raise_authorize_error(load_bootstrap_config())
except authorize_errors.AuthorizeError as e:
- assert str(e) == "could not create resource entity: could not get attribute value from payload: type mismatch for key 'org_id'. expected: 'String', but found: 'number'"
+ assert str(e) == "failed to build resource entity: failed to build `org_id` attribute: failed to build restricted expression: type mismatch for key 'org_id'. expected: 'string', but found: 'number'"
diff --git a/jans-cedarling/cedarling/Cargo.toml b/jans-cedarling/cedarling/Cargo.toml
index 689991b1919..2e924cad531 100644
--- a/jans-cedarling/cedarling/Cargo.toml
+++ b/jans-cedarling/cedarling/Cargo.toml
@@ -16,7 +16,7 @@ serde_yml = "0.0.12"
thiserror = { workspace = true }
sparkv = { workspace = true }
uuid7 = { version = "1.1.0", features = ["serde", "uuid"] }
-cedar-policy = "4.2"
+cedar-policy = { version = "4.2", features = ["partial-eval"] }
base64 = "0.22.1"
url = "2.5.2"
lazy_static = "1.5.0"
diff --git a/jans-cedarling/cedarling/src/authz/build_ctx.rs b/jans-cedarling/cedarling/src/authz/build_ctx.rs
new file mode 100644
index 00000000000..265a4f7e7aa
--- /dev/null
+++ b/jans-cedarling/cedarling/src/authz/build_ctx.rs
@@ -0,0 +1,191 @@
+// This software is available under the Apache-2.0 license.
+// See https://www.apache.org/licenses/LICENSE-2.0.txt for full text.
+//
+// Copyright (c) 2024, Gluu, Inc.
+
+use std::collections::HashMap;
+
+use super::{AuthorizeEntitiesData, AuthzConfig};
+use crate::common::cedar_schema::cedar_json::attribute::Attribute;
+use crate::common::cedar_schema::cedar_json::CedarSchemaJson;
+use crate::common::cedar_schema::CEDAR_NAMESPACE_SEPARATOR;
+use cedar_policy::ContextJsonError;
+use serde_json::{json, map::Entry, Value};
+
+/// Constructs the authorization context by adding the built entities from the tokens
+pub fn build_context(
+ config: &AuthzConfig,
+ request_context: Value,
+ entities_data: &AuthorizeEntitiesData,
+ schema: &cedar_policy::Schema,
+ action: &cedar_policy::EntityUid,
+) -> Result {
+ let namespace = config.policy_store.namespace();
+ let action_name = &action.id().escaped();
+ let json_schema = &config.policy_store.schema.json;
+ let action_schema = json_schema
+ .get_action(namespace, action_name)
+ .ok_or(BuildContextError::UnknownAction(action_name.to_string()))?;
+
+ // Get the entities required for the context
+ let mut ctx_entity_refs = json!({});
+ let type_ids = entities_data.type_ids();
+ if let Some(ctx) = action_schema.applies_to.context.as_ref() {
+ match ctx {
+ Attribute::Record { attrs, .. } => {
+ for (key, attr) in attrs.iter() {
+ if let Some(entity_ref) =
+ build_entity_refs_from_attr(namespace, attr, &type_ids, json_schema)?
+ {
+ ctx_entity_refs[key] = entity_ref;
+ }
+ }
+ },
+ Attribute::EntityOrCommon { name, .. } => {
+ // TODO: handle potential namespace collisions when Cedarling starts
+ // supporting multiple namespaces
+ if let Some((_namespace, attr)) = json_schema.get_common_type(name) {
+ match attr {
+ Attribute::Record { attrs, .. } => {
+ for (key, attr) in attrs.iter() {
+ if let Some(entity_ref) = build_entity_refs_from_attr(
+ namespace,
+ attr,
+ &type_ids,
+ json_schema,
+ )? {
+ ctx_entity_refs[key] = entity_ref;
+ }
+ }
+ },
+ attr => {
+ return Err(BuildContextError::InvalidKind(
+ attr.kind_str().to_string(),
+ "record".to_string(),
+ ))
+ },
+ }
+ }
+ },
+ attr => {
+ return Err(BuildContextError::InvalidKind(
+ attr.kind_str().to_string(),
+ "record or common".to_string(),
+ ))
+ },
+ }
+ }
+
+ let context = merge_json_values(request_context, ctx_entity_refs)?;
+ let context: cedar_policy::Context =
+ cedar_policy::Context::from_json_value(context, Some((schema, action)))?;
+
+ Ok(context)
+}
+
+/// Builds the JSON entity references from a given attribute.
+///
+/// Returns `Ok(None)` if the attr is not an Entity Reference
+fn build_entity_refs_from_attr(
+ namespace: &str,
+ attr: &Attribute,
+ type_ids: &HashMap,
+ schema: &CedarSchemaJson,
+) -> Result