Skip to content

Commit

Permalink
refactor(jans-cedarling): make all tokens optional when calling Cedar…
Browse files Browse the repository at this point in the history
…ling::authorize (#10436)

* refactor(jans-cedarling): make process_tokens params optional

- make the `access_token` param for the JwtService::process_tokens
  optional
- make the `id_token` param for the JwtService::process_tokens
  optional
- return an `Unimplemented` error when any `None` is passed in for the
  tokens since the `authz` module doesn't support optional params yet.

Signed-off-by: rmarinn <[email protected]>

* feat(jans-cedarling): implement processing single tokens

- implement JwtService::process_token which decodes and optionally
  validates a single JWT.

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): replace jwt validation implementation

- replace the old jwt validation implementation that needs multiple
  tokens at once with the new implementation which validates the tokens
  one at a time.

Signed-off-by: rmarinn <[email protected]>

* feat(jans-cedarling): make tokens optional when calling authorize

- implement allowing passing `None` for some tokens when calling
  authorize.

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): make creation of workload entity optional

Signed-off-by: rmarinn <[email protected]>

* fix(jans-cedarling): user and role entity creation

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): make creation of user entity optional

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): use if-else instead of match for bool

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): improve functionality for decoded JWTs

implement convenience function for getting the following data from a
decoded JWT:
- metadata
- user_mapping
- claim_mapping
- role_mapping
- logging_info

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): removed unused functions for TrustedIssuer

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): improve create_workload_entity func implemenation

- change order for creating workload entities to: id_token then
  access_token
- improve `create_workload` error handling
- renamed `CedarPolicyCreateTypeError` to `CreateCedarEntityError`

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): improve create_user_entity func implemenation

- change order for creating workload entities to: id_token,
  access_token, then userinfo_token
- improve `create_user_entitiy` error handling

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): resolve clippy issues

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): error check when loading bootstrap config

- Error when both `CEDARLING_USER_AUTHZ` and
  `CEDARLING_WORKLOAD_AUTHZ` are disabled.

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): add new fields to TokenEntityMetadata

- add `trusted` and `principal_identifier` to the TokenEntityMetadata
  struct so all tokens have access to them.

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): remove some cloning when logging authz

Signed-off-by: rmarinn <[email protected]>

* test(jans-cedarling): add unit tests for entity creation

- add tests for creating user entity
- add tests for creating workload entity

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): improve error handling for entity creation

- errors that occur because no tokens were available should now be
  tracable when creating user and workload entities

Signed-off-by: rmarinn <[email protected]>

* test(jans-cedarling): update python tests expected error

Signed-off-by: rmarinn <[email protected]>

* feat(jans-cedarling): make tokens optional in the python binding

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): change error message to start with a lowercase letter

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): flattened `use` statements for readability

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): remove unused JwtProcessingError variant

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): simplify iterator creation

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): make workload entity creation optional

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): make user entity creation optional

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): remove outdated comment

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): convert Token into a struct from an enum

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): unify token entity creation logic

- combine `entities::create_<token_kind>_token` functions into a single,
  unified function.
- prevent incorrect token types from creating entities of the wrong kind (e.g.,
  using access_tokens to create id_token entities).
- simplify logic and enforce stricter type safety for token-to-entity mapping.

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): eliminate access_token from user entity creation

- remove the use of access_token in the create_user_entity function
- simplify the user entity creation process.

Signed-off-by: rmarinn <[email protected]>

* fix(jans-cedarling): field name conflict for serializing/deserializing

- fix field name conflict by using serde_rename for UserAuthorizeInfo
  and WorkloadAuthorizeInfo

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): remove unused commented code

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): token priority when creating userinfo entity

- change the token priority when creating the userinfo entity to be
  1. userinfo_token then 2. id_token

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): resolve clippy issues

Signed-off-by: rmarinn <[email protected]>

* test(jans-cedarling): update expected error in python bindings test

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): implement rename for logging info fields

- rename UserAuthorizeInfo.principal to user_principal
- rename UserAuthorizeInfo.diagnostics to user_diagnostics
- rename UserAuthorizeInfo.decision to user_decision
- rename WorkloadAuthorizeInfo.principal to workload_principal
- rename WorkloadAuthorizeInfo.diagnostics to workload_diagnostics
- rename WorkloadAuthorizeInfo.decision to workload_decision

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): run cargo fmt and add missing license headers

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): rename the Vec of role from `role` to `roles`

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): remove unused function

Signed-off-by: rmarinn <[email protected]>

* refactor(jans-cedarling): rename UserAuthorizeInfo fields

- change `user` to `person`

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): run cargo fmt

Signed-off-by: rmarinn <[email protected]>

* chore(jans-cedarling): refactor to avoid unnecessary cloning

Signed-off-by: Oleh Bohzok <[email protected]>

---------

Signed-off-by: rmarinn <[email protected]>
Signed-off-by: Oleh Bohzok <[email protected]>
Co-authored-by: Oleh Bohzok <[email protected]>
  • Loading branch information
rmarinn and olehbozhok authored Dec 24, 2024
1 parent e67a811 commit eacf1b3
Show file tree
Hide file tree
Showing 74 changed files with 2,227 additions and 1,685 deletions.
8 changes: 3 additions & 5 deletions docs/cedarling/cedarling-policy-store.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,18 +178,16 @@ 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.

**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`.
- **`access_tokens`, `id_tokens`, `userinfo_tokens`, and `tx_tokens`**: See: [Token Metadata Schema](#token-metadata-schema).

### Token Metadata Schema

The Token Entity Metadata Schema defines how tokens are mapped, parsed, and transformed within Cedarling. It allows you to specify how to extract user IDs, roles, and other claims from a token using customizable parsers.

```json
{
"trusted": bool,
"principal_identifier": "str",
"user_id": "<field name in token (e.g., 'email', 'sub', 'uid', etc.) or '' if not used>",
"role_mapping": "<field for role assignment (e.g., 'role', 'memberOf', etc.) or '' if not used>",
"claim_mapping": {
Expand Down
28 changes: 16 additions & 12 deletions jans-cedarling/bindings/cedarling_python/PYTHON_TYPES.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@ authorization data with access token, action, resource, and context.

Attributes
----------
:param access_token: The access token string.
:param id_token: The id token string.
:param userinfo_token: The userinfo token string.
:param action: The action to be authorized.
:param resource: Resource data (wrapped `ResourceData` object).
:param context: Python dictionary with additional context.
:param context: Python dictionary with additional context.
:param access_token: (Optional) The access token string.
:param id_token: (Optional) The id token string.
:param userinfo_token: (Optional) The userinfo token string.

Example
-------
Expand Down Expand Up @@ -203,6 +203,10 @@ ___
Error encountered while parsing Action to EntityUid
___

# authorize_errors.AddEntitiesIntoContextError
Error encountered while adding entities into context
___

# authorize_errors.AuthorizeError
Exception raised by authorize_errors
___
Expand All @@ -219,14 +223,6 @@ ___
Error encountered while creating id token entities
___

# authorize_errors.CreateRequestUserEntityError
Error encountered while creating cedar_policy::Request for user entity principal
___

# authorize_errors.CreateRequestWorkloadEntityError
Error encountered while creating cedar_policy::Request for workload entity principal
___

# authorize_errors.CreateUserEntityError
Error encountered while creating User entity
___
Expand Down Expand Up @@ -259,3 +255,11 @@ ___
Error encountered while creating role entity
___

# authorize_errors.UserRequestValidationError
Error encountered while creating cedar_policy::Request for user entity principal
___

# authorize_errors.WorkloadRequestValidationError
Error encountered while creating cedar_policy::Request for workload entity principal
___

6 changes: 3 additions & 3 deletions jans-cedarling/bindings/cedarling_python/cedarling_python.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,12 @@ class Cedarling:

@final
class Request:
access_token: str
id_token: str
userinfo_token: str
action: str
resource: ResourceData
context: Dict[str, Any]
access_token: str | None
id_token: str | None
userinfo_token: str | None

def __init__(self,
access_token: str,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,14 @@ create_exception!(

create_exception!(
authorize_errors,
CreateRequestWorkloadEntityError,
WorkloadRequestValidationError,
AuthorizeError,
"Error encountered while creating cedar_policy::Request for workload entity principal"
);

create_exception!(
authorize_errors,
CreateRequestUserEntityError,
UserRequestValidationError,
AuthorizeError,
"Error encountered while creating cedar_policy::Request for user entity principal"
);
Expand Down Expand Up @@ -175,8 +175,8 @@ errors_functions! {
RoleEntity => RoleEntityError,
Action => ActionError,
CreateContext => CreateContextError,
CreateRequestWorkloadEntity => CreateRequestWorkloadEntityError,
CreateRequestUserEntity => CreateRequestUserEntityError,
WorkloadRequestValidation => WorkloadRequestValidationError,
UserRequestValidation => UserRequestValidationError,
BuildContext => AddEntitiesIntoContextError,
Entities => EntitiesError,
EntitiesToJson => EntitiesToJsonError
Expand Down
19 changes: 10 additions & 9 deletions jans-cedarling/bindings/cedarling_python/src/authorize/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ use serde_pyobject::from_pyobject;
///
/// Attributes
/// ----------
/// :param access_token: The access token string.
/// :param id_token: The id token string.
/// :param userinfo_token: The userinfo token string.
/// :param action: The action to be authorized.
/// :param resource: Resource data (wrapped `ResourceData` object).
/// :param context: Python dictionary with additional context.
/// :param access_token: (Optional) The access token string.
/// :param id_token: (Optional) The id token string.
/// :param userinfo_token: (Optional) The userinfo token string.
///
/// Example
/// -------
Expand All @@ -36,11 +36,11 @@ use serde_pyobject::from_pyobject;
#[pyclass(get_all, set_all)]
pub struct Request {
/// Access token raw value
pub access_token: String,
pub access_token: Option<String>,
/// Id token raw value
pub id_token: String,
pub id_token: Option<String>,
/// Userinfo token raw value
pub userinfo_token: String,
pub userinfo_token: Option<String>,
/// cedar_policy action
pub action: String,
/// cedar_policy resource data
Expand All @@ -52,13 +52,14 @@ pub struct Request {
#[pymethods]
impl Request {
#[new]
#[pyo3(signature = (action, resource, context, access_token=None, id_token=None, userinfo_token=None))]
fn new(
access_token: String,
id_token: String,
userinfo_token: String,
action: String,
resource: ResourceData,
context: Py<PyDict>,
access_token: Option<String>,
id_token: Option<String>,
userinfo_token: Option<String>,
) -> Self {
Self {
access_token,
Expand Down
20 changes: 11 additions & 9 deletions jans-cedarling/bindings/cedarling_python/tests/test_authorize.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,13 @@ def test_authorize_ok():
})

request = Request(
ACCESS_TOKEN,
ID_TOKEN,
USERINFO_TOKEN,
access_token=ACCESS_TOKEN,
id_token=ID_TOKEN,
userinfo_token=USERINFO_TOKEN,
action='Jans::Action::"Update"',
context={}, resource=resource)
context={},
resource=resource,
)

authorize_result = instance.authorize(request)
assert authorize_result.is_allowed(), "request should be allowed"
Expand Down Expand Up @@ -170,9 +172,9 @@ def raise_authorize_error(bootstrap_config):
})

request = Request(
ACCESS_TOKEN,
ID_TOKEN,
USERINFO_TOKEN,
access_token=ACCESS_TOKEN,
id_token=ID_TOKEN,
userinfo_token=USERINFO_TOKEN,
action='Jans::Action::"Update"',
context={}, resource=resource)

Expand All @@ -189,7 +191,7 @@ 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: could not convert json field with key: org_id to: String, got: number"
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'"


def test_authorize_error():
Expand All @@ -201,4 +203,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: could not convert json field with key: org_id to: String, got: number"
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'"
19 changes: 9 additions & 10 deletions jans-cedarling/cedarling/examples/authorize_with_jwt_validation.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
/*
* 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.
*/
// 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, HashSet};

use cedarling::{
AuthorizationConfig, BootstrapConfig, Cedarling, IdTokenTrustMode, JwtConfig, LogConfig,
LogLevel, LogTypeConfig, PolicyStoreConfig, PolicyStoreSource, Request, ResourceData,
TokenValidationConfig, WorkloadBoolOp,
};
use jsonwebtoken::Algorithm;
use std::collections::{HashMap, HashSet};

static POLICY_STORE_RAW_YAML: &str =
include_str!("../../test_files/policy-store_with_trusted_issuers_ok.yaml");
Expand Down Expand Up @@ -62,9 +61,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// on a specific resource. Each token (access, ID, and userinfo) is required for the
// authorization process, alongside resource and action details.
let result = cedarling.authorize(Request {
access_token,
id_token,
userinfo_token,
access_token: Some(access_token),
id_token: Some(id_token),
userinfo_token: Some(userinfo_token),
action: "Jans::Action::\"Update\"".to_string(),
context: serde_json::json!({}),
resource: ResourceData {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
/*
* 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.
*/
// 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 cedarling::{
AuthorizationConfig, BootstrapConfig, Cedarling, JwtConfig, LogConfig, LogLevel, LogTypeConfig,
PolicyStoreConfig, PolicyStoreSource, Request, ResourceData, WorkloadBoolOp,
};
use std::collections::HashMap;

static POLICY_STORE_RAW: &str = include_str!("../../test_files/policy-store_ok.yaml");

Expand Down Expand Up @@ -113,9 +112,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let userinfo_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FkbWluLXVpLXRlc3QuZ2x1dS5vcmciLCJzdWIiOiJib0c4ZGZjNU1LVG4zN283Z3NkQ2V5cUw4THBXUXRnb080MW0xS1p3ZHEwIiwiY2xpZW50X2lkIjoiNWI0NDg3YzQtOGRiMS00MDlkLWE2NTMtZjkwN2I4MDk0MDM5IiwiYXVkIjoiNWI0NDg3YzQtOGRiMS00MDlkLWE2NTMtZjkwN2I4MDk0MDM5IiwidXNlcm5hbWUiOiJhZG1pbkBnbHV1Lm9yZyIsIm5hbWUiOiJEZWZhdWx0IEFkbWluIFVzZXIiLCJlbWFpbCI6ImFkbWluQGdsdXUub3JnIiwiY291bnRyeSI6IlVTIiwianRpIjoidXNyaW5mb190a25fanRpIn0.NoR53vPZFpfb4vFk85JH9RPx7CHsaJMZwrH3fnB-N60".to_string();

let result = cedarling.authorize(Request {
access_token,
id_token,
userinfo_token,
access_token: Some(access_token),
id_token: Some(id_token),
userinfo_token: Some(userinfo_token),
action: "Jans::Action::\"Update\"".to_string(),
context: serde_json::json!({}),
resource: ResourceData {
Expand Down
13 changes: 6 additions & 7 deletions jans-cedarling/cedarling/examples/log_init.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
/*
* 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.
*/
// 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.

// The following macro uses conditional compilation to include this file code
// only when the target platform is NOT WebAssembly. This is not required to
// use the library but is needed here since Cedarling compiles binding to WASM
// and `use std::env` prevents that compilation.
#![cfg(not(target_family = "wasm"))]

use std::env;

use cedarling::{
AuthorizationConfig, BootstrapConfig, Cedarling, JwtConfig, LogConfig, LogLevel, LogStorage,
LogTypeConfig, MemoryLogConfig, PolicyStoreConfig, PolicyStoreSource, WorkloadBoolOp,
};
use std::env;

// The human-readable policy and schema file is located in next folder:
// `test_files\policy-store_ok`
Expand Down
13 changes: 6 additions & 7 deletions jans-cedarling/cedarling/src/authz/authorize_result.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
/*
* 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.
*/
// 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::HashSet;

use cedar_policy::Decision;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer};
use std::collections::HashSet;

use crate::bootstrap_config::WorkloadBoolOp;

Expand Down
Loading

0 comments on commit eacf1b3

Please sign in to comment.