Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(jans-cedarling): custom tokens and putting tokens in principal attrs #10706

Open
wants to merge 23 commits into
base: main
Choose a base branch
from

Conversation

rmarinn
Copy link
Contributor

@rmarinn rmarinn commented Jan 21, 2025

Prepare


Description

This PR implements:

  • automatically adding token entity references to the principal entities' attributes if it is defined in the schema
  • custom token support

Target issue

Target issue: #10591

closes #10591

Implementation Details

Updated bootstrap config

The following properties that are related to the JWTs are removed from the bootstrap config:

  • CEDARLING_MAPPING_ID_TOKEN
  • CEDARLING_MAPPING_ACCESS_TOKEN
  • CEDARLING_MAPPING_USERINFO_TOKEN
  • CEDARLING_AT_ISS_VALIDATION
  • CEDARLING_AT_JTI_VALIDATION
  • CEDARLING_AT_NBF_VALIDATION
  • CEDARLING_AT_EXP_VALIDATION
  • CEDARLING_IDT_ISS_VALIDATION
  • CEDARLING_IDT_SUB_VALIDATION
  • CEDARLING_IDT_EXP_VALIDATION
  • CEDARLING_IDT_IAT_VALIDATION
  • CEDARLING_IDT_AUD_VALIDATION
  • CEDARLING_USERINFO_ISS_VALIDATION
  • CEDARLING_USERINFO_SUB_VALIDATION
  • CEDARLING_USERINFO_AUD_VALIDATION
  • CEDARLING_USERINFO_EXP_VALIDATION

To configure the token validation settings and mappings, the new CEDARLING_TOKEN_CONFIGS will now be used.

CEDARLING_TOKEN_CONFIGS = {
  "access_token": {
    "entity_type_name": "Access_token",
    "iss": "enabled",
    "aud": "enabled",
    "sub": "enabled",
    "jti": "enabled",
    "nbf": "enabled",
    "iat": "enabled",
    "exp": "enabled",
  },
  "id_token": {
    "entity_type_name": "id_token",
    "exp": "enabled",
  },
  "userinfo_token": {
    "entity_type_name": "Userinfo_token",
    "exp": "enabled",
  },
  "custom_token1": {
    "entity_type_name": "SomeCustom_token",
    "exp": "enabled",
  },
  "custom_token2": {
    "entity_type_name": "AnotherCustom_token",
    "exp": "enabled",
  },
  // more custom tokens can be added here
}

Note that tokens that are not in the CEDARLING_TOKEN_CONFIGS will be ignored and fields that are not defined will default to "disabled". Furthermore, if the boostrap property is not set, a default containing the access_token, id_token, and userinfo_token with some validation enabled will be used.

The shape of the input to authz will remain the same, though the user can now add their custom tokens in the "tokens" field:

input = {
  "tokens": {
    "access_token": "...",
    "id_token": "...",
    "userinfo_token": "...",
    "custom_token1": "...",
    "custom_token2": "...",
  },
  // ...the rest of the input
}

Additionally, the a new bootstrap config, CEDARLING_MAPPING_ROLE, was added. This bootrap property tells Cedarling what the entity type name of the Role is in the schema.

Automatically adding token entities to the principal entity attributes

To automatically add the token entities to the principal entity attributes, two conditions must be met:

  1. The entity type name of the token should be defined via the CEDARLING_TOKEN_CONFIGS bootstrap property:
CEDARLING_TOKEN_CONFIGS = {
  "access_token": {
    "entity_type_name": "Access_token",
    "exp": "enabled",
  },
  "custom_token": {
    "entity_type_name": "Custom_token",
    "exp": "enabled",
  },
}
  1. In the Cedar schema, an entity should require an attribute with the same type as the token entity:
namespace Jans {
  entity Workload = {
    access_token: Access_token,
    custom_token: Custom_token,
  };
  entity Access_token = { exp: Long };
  entity Custom_token = { exp: Long };
}

If these two conditions are met, the built entity will have a token entity reference in it's attributes which it can access when defining policies

permit (
  principal is Jans::Workload,
  action in [Jans::Action::GET, Jans::Action::POST],
  resource is Jans::HTTP_Request
) when {
  principal.access_token.exp < 1234567890 &&
  principal.custom_token.exp < 1234567890
};
Updated Policy Store

To be able to support custom tokens, the "trusted_issuers" field in the policy store has been updated. The "access_tokens", "id_tokens", "userinfo_tokens", and "tx_tokens" have been replaced with "tokens_metadata". The "claim_mapping" field is a map of token_name -> token_metadata.

{
  // ...
  "tokens_metadata": {
    "access_token": {"trusted": true, "principal_identifier": "jti"},
    "id_token": {},
    "userinfo_token": {
      "user_id": "sub", 
      "role_mapping": "role", 
      "claim_mapping": {
        "email": {
          "parser": "regex",
          "type": "Jans::email_address",
          "regex_expression": "^(?P<UID>[^@]+)@(?P<DOMAIN>.+)$",
          "UID": {
              "attr": "uid",
              "type": "String"
          },
          "DOMAIN": {
              "attr": "domain",
              "type": "String"
          }
        },
      }, 
    },
    // users can add as many tokens they want here
    "custom_token": {
      // ...
    }
  }
}

Test and Document the changes

  • Static code analysis has been run locally and issues have been fixed
  • Relevant unit and integration tests have been added/updated
  • Relevant documentation has been updated if any (i.e. user guides, installation and configuration guides, technical design docs etc)

Please check the below before submitting your PR. The PR will not be merged if there are no commits that start with docs: to indicate documentation changes or if the below checklist is not selected.

  • I confirm that there is no impact on the docs due to the code changes in this PR.

- automatically add token entity references to the principal entities if
  they are required in the principal's schema

Signed-off-by: rmarinn <[email protected]>
- implement support for custom tokens
- implement `CEDARLING_TOKEN_ENTITY_MAPPER` bootstrap property to
  support putting token entities into principal entities
- implement `CEDARLING_MAPPING_TOKENS` bootstrap property to support
  having custom tokens
- implement `CEDARLING_MAPPING_ROLE` bootstrap property to set the
  entity name of the role entity
- implement `CEDARLING_TOKEN_VALIDATION_SETTINGS` bootstrap property to
  support having custom tokens
- add support for custom token entity metatdata

Signed-off-by: rmarinn <[email protected]>
- remove token entity mapping in entity builder. the token entity
  mapping is enforced in the jwt module. if the token isn't in the
  mapper, the token isn't decoded or validated.

Signed-off-by: rmarinn <[email protected]>
- add docstring for token entity mapper
- add docstring for token entity mapping

Signed-off-by: rmarinn <[email protected]>
Implement CEDARLING_TOKEN_CONFIGS which replaces
CEDARLING_TOKEN_VALIDATION_SETTINGS and CEDARLING_MAPPING_TOKENS

Signed-off-by: rmarinn <[email protected]>
@rmarinn rmarinn self-assigned this Jan 21, 2025
@rmarinn rmarinn marked this pull request as draft January 21, 2025 03:55
@rmarinn rmarinn changed the title feat(jans-cedarling): custom tokens and tokens in principal attrs feat(jans-cedarling): custom tokens and putting tokens in principal attrs Jan 21, 2025
@mo-auto mo-auto added comp-jans-cedarling Touching folder /jans-cedarling kind-feature Issue or PR is a new feature request labels Jan 21, 2025
@rmarinn rmarinn requested a review from nynymike January 21, 2025 15:02
@mo-auto mo-auto added area-documentation Documentation needs to change as part of issue or PR comp-docs Touching folder /docs labels Jan 21, 2025
@rmarinn rmarinn marked this pull request as ready for review January 22, 2025 04:57
@@ -25,14 +23,14 @@ use crate::{
/// - if a Userinfo token is present:
/// - `userinfo_token.aud` == `access_token.client_id`
/// - `userinfo_token.sub` == `id_token.sub`
pub fn validate_id_tkn_trust_mode(tokens: &DecodedTokens) -> Result<(), IdTokenTrustModeError> {
pub fn validate_id_tkn_trust_mode(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check other tokens?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I don't think so since this is just for checking the tokens defined in openid connect core.

Though users want to add additional checks for their custom tokens, they can just do so via the Cedar policies since token entities get created.

// we just ignore input tokens that are not defined
// in the token entity mapper bootstrap config
//
// TODO: should we log that we skip some tokens?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be helpful to log this, at least in debug level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will add logging in issue #10730 after this merges

@@ -484,3 +485,17 @@ pub struct LogTokensInfo<'a> {
pub userinfo: Option<HashMap<&'a str, &'a serde_json::Value>>,
pub access: Option<HashMap<&'a str, &'a serde_json::Value>>,
}

#[derive(Debug, Clone, PartialEq, serde::Serialize)]
pub struct NewLogTokensInfo<'a>(pub HashMap<&'a str, HashMap<&'a str, &'a serde_json::Value>>);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we need to stay LogTokensInfo structure? maybe we can remove LogTokensInfo and rename current to the LogTokensInfo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to remove that since rustanalyzer wasn't complaining that it was unused.

Removed here 673ded1.

olehbozhok
olehbozhok previously approved these changes Jan 23, 2025
Copy link
Contributor

@olehbozhok olehbozhok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine for me, but I would appreciate it if you could reply to the comments above.

Copy link
Contributor

@olehbozhok olehbozhok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK for me. It would be great to define how to correctly validate all tokens that present in request

@rmarinn
Copy link
Contributor Author

rmarinn commented Jan 24, 2025

OK for me. It would be great to define how to correctly validate all tokens that present in request

The validation was not changed. Validation settings are set via the CEDARLING_TOKEN_CONFIGS bootstrap config. See: cedarling-properties.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-documentation Documentation needs to change as part of issue or PR comp-docs Touching folder /docs comp-jans-cedarling Touching folder /jans-cedarling kind-feature Issue or PR is a new feature request
Projects
None yet
4 participants