Skip to content

Commit

Permalink
feat(jans-cedarling): Improve log searching and retrieval (#10772)
Browse files Browse the repository at this point in the history
* chore(jans-cedarling): extend trait `Loggable` with methods that important for the memory logger

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

* chore(jans-cedarling): update to new interface

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

* chore(jans-cedarling): generate one request_id per `authorize request`

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

* chore(jans-cedarling): remove `PartialEq, Eq` macros from `KvEntry`, it is unused

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

* chore(jans-cedarling): add import entities from std lib

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

* chore(jans-cedarling): remove using `unwrap`

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

* feat(jans-cedarling): add to sparkv API to push additional keys for existing key

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

* chore(jans-cedarling): update traits to work with additional index

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

* feat(jans-cedarling): add methods for getting logs by tag

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

* chore(jans-cedarling): remove default implementation for some method in trait `Indexed` to not forget implement them

It lead to less amount of the bugs, because of compiler highlight

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

* chore(jans-cedarling): fix `get_index_keys` to be more correct

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

* feat(jans-cedarling): add to `AuthorizeResult` field `request_id` that allows to load information from `memory` logger

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

* chore(jans-cedarling): rename method `LogStorage::get_logs_by_id_and_tag` to the `get_logs_by_id_and_tag`

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

* feat(jans-cedarling): add method `get_log_by_request_id`

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

* chore(jans-cedarling): update python bindings related to new memory logger API

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

* feat(jans-cedarling): update python `pyi` file

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

* test(jans-cedarling): add python tests to load data from memory logger

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

* chore(jans-cedarling): minor changes with naming

- rename `get_log_by_request_id` to `get_logs_by_request_id`
- remove in trait `LogWriter` method `log` and now use only `log_any`

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

* feat(jans-cedarling):update WASM bindings, add new fields and method related to getting logs from memory logger by `request_id` and tags

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

* chore(jans-cedarling): add clippy rule to not use standart `uuid7` generator

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

* chore(jans-cedarling): fix clippy issues

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

* chore(jans-cedarling): fix unit tests when compare id of log entry

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

* test(jans-cedarling): add test logs for memory logger index

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

* docs(jans-cedarling): update logger docs

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

* test(jans-cedarling): fix python tests

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

* docs(jans-cedarling): update python documentation

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

* test(jans-cedarling): add test cases for sparkv index

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

---------

Signed-off-by: Oleh Bohzok <[email protected]>
  • Loading branch information
olehbozhok authored Feb 4, 2025
1 parent d13bdbf commit 9286f82
Show file tree
Hide file tree
Showing 26 changed files with 956 additions and 200 deletions.
38 changes: 38 additions & 0 deletions docs/cedarling/cedarling-logs.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,44 @@ This is set by `CEDARLING_LOG_LEVEL`
* `DEBUG`: Designates fine-grained informational events useful for debugging the application.
* `TRACE`: Provides finer-grained informational events than DEBUG. It is often used for detailed tracing of program execution.

## Memory Log interface

This interface is used to interact with the memory log storage. It provides methods for getting logs and removing them from the storage.
Same interface is translated to other languages through bindings.

Tags are used to filter logs. It can be `log_kind` and `log_level` values from log entry data.

You can obtain the `request_id` from the result structure of the `authorize` method call.

```rust
/// Log Storage
/// interface for getting log entries from the storage
pub trait LogStorage {
/// Return logs and remove them from the storage
fn pop_logs(&self) -> Vec<serde_json::Value>;

/// Get specific log entry
fn get_log_by_id(&self, id: &str) -> Option<serde_json::Value>;

/// Returns a list of all log ids
fn get_log_ids(&self) -> Vec<String>;

/// Get logs by tag, like `log_kind` or `log level`.
/// Tag can be `log_kind`, `log_level`.
fn get_logs_by_tag(&self, tag: &str) -> Vec<serde_json::Value>;

/// Get logs by request_id.
/// Return log entries that match the given request_id.
fn get_logs_by_request_id(&self, request_id: &str) -> Vec<serde_json::Value>;

/// Get log by request_id and tag, like composite key `request_id` + `log_kind`.
/// Tag can be `log_kind`, `log_level`.
/// Return log entries that match the given request_id and tag.
fn get_logs_by_request_id_and_tag(&self, request_id: &str, tag: &str)
-> Vec<serde_json::Value>;
}
```

## Jans Lock Server

In enterprise deployments, [Janssen Lock Server](../janssen-server/lock/) collects Cedarling
Expand Down
158 changes: 90 additions & 68 deletions jans-cedarling/bindings/cedarling_python/PYTHON_TYPES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@
This document describes the Cedarling Python bindings types.
Documentation was generated from python types.

AuthorizeResult
===============

A Python wrapper for the Rust `cedarling::AuthorizeResult` struct.
Represents the result of an authorization request.

Methods
-------
.. method:: is_allowed(self) -> bool
Returns whether the request is allowed.

.. method:: workload(self) -> AuthorizeResultResponse
Returns the detailed response as an `AuthorizeResultResponse` object.

___

AuthorizeResultResponse
=======================

A Python wrapper for the Rust `cedar_policy::Response` struct.
Represents the result of an authorization request.

Attributes
----------
:param decision: The authorization decision (wrapped `Decision` object).
:param diagnostics: Additional information on the decision (wrapped `Diagnostics` object).
___

BootstrapConfig
=========

Expand Down Expand Up @@ -63,103 +91,53 @@ Methods

:param config: A `BootstrapConfig` object with startup settings.

.. method:: authorize(self, request: Request) -> AuthorizeResult

Execute authorize request
:param request: Request struct for authorize.

.. method:: pop_logs(self) -> List[dict]

Retrieves and removes all logs from storage.

:returns: A list of log entries as Python objects.

:raises ValueError: If an error occurs while fetching logs.

.. method:: get_log_by_id(self, id: str) -> dict|None

Gets a log entry by its ID.

:param id: The log entry ID.

:raises ValueError: If an error occurs while fetching the log.

.. method:: get_log_ids(self) -> List[str]

Retrieves all stored log IDs.

.. method:: authorize(self, request: Request) -> AuthorizeResult
.. method:: get_logs_by_tag(self, tag: str) -> List[dict]

Execute authorize request
:param request: Request struct for authorize.
Retrieves all logs matching a specific tag. Tags can be 'log_kind', 'log_level' params from log entries.

___
:param tag: A string specifying the tag type.

ResourceData
============
:returns: A list of log entries filtered by the tag, each converted to a Python dictionary.

A Python wrapper for the Rust `cedarling::ResourceData` struct. This class represents
a resource entity with a type, ID, and attributes. Attributes are stored as a payload
in a dictionary format.
.. method:: get_logs_by_request_id(self, id: str) -> List[dict]

Attributes
----------
:param resource_type: Type of the resource entity.
:param id: ID of the resource entity.
:param payload: Optional dictionary of attributes.
Retrieves log entries associated with a specific request ID. Each log entry is converted to a Python dictionary containing fields like 'id', 'timestamp', and 'message'.

Methods
-------
.. method:: __init__(self, resource_type: str, id: str, **kwargs: dict)
Initialize a new ResourceData. In kwargs the payload is a dictionary of entity attributes.
:param id: The unique identifier for the request.

.. method:: from_dict(cls, value: dict) -> ResourceData
Initialize a new ResourceData from a dictionary.
To pass `resource_type` you need to use `type` key.
___
:returns: A list of dictionaries, each representing a log entry related to the specified request ID.

Request
=======
.. method:: get_logs_by_request_id_and_tag(self, id: str, tag: str) -> List[dict]

A Python wrapper for the Rust `cedarling::Request` struct. Represents
authorization data with access token, action, resource, and context.
Retrieves all logs associated with a specific request ID and tag. The tag can be 'log_kind', 'log_level' params from log entries.

Attributes
----------
:param tokens: A class containing the JWTs what will be used for the request.
:param action: The action to be authorized.
:param resource: Resource data (wrapped `ResourceData` object).
:param context: Python dictionary with additional context.
:param id: The request ID as a string.

Example
-------
```python
# Create a request for authorization
request = Request(access_token="token123", action="read", resource=resource, context={})
```
___

AuthorizeResult
===============

A Python wrapper for the Rust `cedarling::AuthorizeResult` struct.
Represents the result of an authorization request.

Methods
-------
.. method:: is_allowed(self) -> bool
Returns whether the request is allowed.

.. method:: workload(self) -> AuthorizeResultResponse
Returns the detailed response as an `AuthorizeResultResponse` object.

___
:param tag: The tag type as a string.

AuthorizeResultResponse
=======================

A Python wrapper for the Rust `cedar_policy::Response` struct.
Represents the result of an authorization request.
:returns: A list of log entries matching both the request ID and tag, each converted to a Python dictionary.

Attributes
----------
:param decision: The authorization decision (wrapped `Decision` object).
:param diagnostics: Additional information on the decision (wrapped `Diagnostics` object).
___

Decision
Expand Down Expand Up @@ -205,6 +183,50 @@ error : str
The error message describing the evaluation failure.
___

Request
=======

A Python wrapper for the Rust `cedarling::Request` struct. Represents
authorization data with access token, action, resource, and context.

Attributes
----------
:param tokens: A class containing the JWTs what will be used for the request.
:param action: The action to be authorized.
:param resource: Resource data (wrapped `ResourceData` object).
:param context: Python dictionary with additional context.

Example
-------
```python
# Create a request for authorization
request = Request(access_token="token123", action="read", resource=resource, context={})
```
___

ResourceData
============

A Python wrapper for the Rust `cedarling::ResourceData` struct. This class represents
a resource entity with a type, ID, and attributes. Attributes are stored as a payload
in a dictionary format.

Attributes
----------
:param resource_type: Type of the resource entity.
:param id: ID of the resource entity.
:param payload: Optional dictionary of attributes.

Methods
-------
.. method:: __init__(self, resource_type: str, id: str, **kwargs: dict)
Initialize a new ResourceData. In kwargs the payload is a dictionary of entity attributes.

.. method:: from_dict(cls, value: dict) -> ResourceData
Initialize a new ResourceData from a dictionary.
To pass `resource_type` you need to use `type` key.
___

# authorize_errors.ActionError
Error encountered while parsing Action to EntityUid
___
Expand Down
11 changes: 10 additions & 1 deletion jans-cedarling/bindings/cedarling_python/cedarling_python.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,20 @@ class Cedarling:

def __init__(self, config: BootstrapConfig) -> None: ...

def authorize(self, request: Request) -> AuthorizeResult: ...

def pop_logs(self) -> List[Dict]: ...

def get_log_by_id(self, id: str) -> Optional[Dict]: ...

def get_log_ids(self) -> List[str]: ...

def authorize(self, request: Request) -> AuthorizeResult: ...
def get_logs_by_tag(self, tag: str) -> List[Dict]: ...

def get_logs_by_request_id(self, request_id: str) -> List[Dict]: ...

def get_logs_by_request_id_and_tag(
self, request_id: str, tag: str) -> List[Dict]: ...


@final
Expand Down Expand Up @@ -170,6 +177,8 @@ class AuthorizeResult:

def person(self) -> AuthorizeResultResponse | None: ...

def request_id(self) -> str: ...


@final
class AuthorizeResultResponse:
Expand Down
24 changes: 18 additions & 6 deletions jans-cedarling/bindings/cedarling_python/print_documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import inspect
from types import ModuleType
import cedarling_python
from cedarling_python import BootstrapConfig
from cedarling_python import Cedarling
from cedarling_python import ResourceData, Request, AuthorizeResult, AuthorizeResultResponse, Decision, Diagnostics, PolicyEvaluationError
Expand Down Expand Up @@ -95,12 +96,23 @@ def print_module_doc(module: ModuleType):
print_doc(getattr(module, attr), module.__name__)


types = [
BootstrapConfig,
Cedarling,
ResourceData, Request, AuthorizeResult, AuthorizeResultResponse, Decision, Diagnostics, PolicyEvaluationError,
authorize_errors
]
def filter(name):
"""
Filter attribute names of `cedarling_python` library.
"""
if name.startswith("_") or name is None:
return False

if name == "cedarling_python":
return False

return True


attr_names = [attr for attr in dir(cedarling_python) if filter(attr)]
attr_names.sort()

types = [getattr(cedarling_python, attr_name) for attr_name in attr_names]

if __name__ == "__main__":

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ impl AuthorizeResult {
fn person(&self) -> Option<AuthorizeResultResponse> {
self.inner.person.clone().map(|v| v.into())
}

fn request_id(&self) -> String {
self.inner.request_id.clone()
}
}

impl From<cedarling::AuthorizeResult> for AuthorizeResult {
Expand Down
Loading

0 comments on commit 9286f82

Please sign in to comment.