Skip to content

Cedarling sample inputs

bootstrap.json#

{
    "CEDARLING_APPLICATION_NAME": "Cedarling-Test-In-Custom-Script",
    "CEDARLING_AUDIT_HEALTH_INTERVAL": 0,
    "CEDARLING_AUDIT_TELEMETRY_INTERVAL": 0,
    "CEDARLING_DYNAMIC_CONFIGURATION": "disabled",
    "CEDARLING_ID_TOKEN_TRUST_MODE": "never",
    "CEDARLING_JWT_SIGNATURE_ALGORITHMS_SUPPORTED": [
    "HS256",
    "RS256"
    ],
    "CEDARLING_JWT_SIG_VALIDATION": "disabled",
    "CEDARLING_JWT_STATUS_VALIDATION": "disabled",
    "CEDARLING_LISTEN_SSE": "disabled",
    "CEDARLING_LOCAL_JWKS": null,
    "CEDARLING_LOCK": "disabled",
    "CEDARLING_LOCK_SSA_JWT": null,
    "CEDARLING_LOG_LEVEL": "DEBUG",
    "CEDARLING_LOG_TYPE": "std_out",
    "CEDARLING_POLICY_STORE_ID": "cdeb4b635459898300a5893589a76b726e202dcb5a86",
    "CEDARLING_POLICY_STORE_URI": "./custom/static/policy-store.json",
    "CEDARLING_PRINCIPAL_BOOLEAN_OPERATION": {
    "===": [
            {
            "var": "Jans::Workload"
            },
            "ALLOW"
        ]
    },
    "CEDARLING_USER_AUTHZ": "enabled",
    "CEDARLING_WORKLOAD_AUTHZ": "enabled",
    "id": "7a962b6e-aa45-4418-a94a-ee382d20a723"
}

policy-store.json#

{
    "cedar_version": "4.4.0",
    "policy_stores": {
        "3cf98caf8e7fdb289c922ba9514118dcba716ce426ae": {
        "name": "admin_ui_store",
        "description": "Admin UI Policy Store\t",
        "policies": {
        "7c52efd895db799901d8590a2c5e3a76539d4a6de514": {
            "description": "Authorization policy",
            "creation_date": "2025-06-09T12:32:26.114299",
            "policy_content": "QGlkKCJBdXRob3JpemF0aW9uIHBvbGljeSIpCnBlcm1pdCAoCiAgcHJpbmNpcGFsIGlzIEphbnM6Oldvcmtsb2FkLAogIGFjdGlvbiA9PSBKYW5zOjpBY3Rpb246OiJFeGVjdXRlIiwKICByZXNvdXJjZSBpcyBKYW5zOjpBcHBsaWNhdGlvbgopCndoZW4gewogIHByaW5jaXBhbC5ncmFudFR5cGVzLmNvbnRhaW5zKCJhdXRob3JpemF0aW9uX2NvZGUiKQp9Ow=="
            }
        },
        "trusted_issuers": {},
        "schema": "eyJKYW5zIjp7ImNvbW1vblR5cGVzIjp7IkNvbnRleHQiOnsidHlwZSI6IlJlY29yZCIsImF0dHJpYnV0ZXMiOnsiY3VycmVudF90aW1lIjp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsInJlcXVpcmVkIjpmYWxzZSwibmFtZSI6IkxvbmcifSwiZGV2aWNlX2hlYWx0aCI6eyJ0eXBlIjoiU2V0IiwicmVxdWlyZWQiOmZhbHNlLCJlbGVtZW50Ijp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsIm5hbWUiOiJTdHJpbmcifX0sImZyYXVkX2luZGljYXRvcnMiOnsidHlwZSI6IlNldCIsInJlcXVpcmVkIjpmYWxzZSwiZWxlbWVudCI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJuYW1lIjoiU3RyaW5nIn19LCJnZW9sb2NhdGlvbiI6eyJ0eXBlIjoiU2V0IiwicmVxdWlyZWQiOmZhbHNlLCJlbGVtZW50Ijp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsIm5hbWUiOiJTdHJpbmcifX0sIm5ldHdvcmsiOnsidHlwZSI6IkVudGl0eU9yQ29tbW9uIiwicmVxdWlyZWQiOmZhbHNlLCJuYW1lIjoiU3RyaW5nIn0sIm5ldHdvcmtfdHlwZSI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJyZXF1aXJlZCI6ZmFsc2UsIm5hbWUiOiJTdHJpbmcifSwib3BlcmF0aW5nX3N5c3RlbSI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJyZXF1aXJlZCI6ZmFsc2UsIm5hbWUiOiJTdHJpbmcifSwidXNlcl9hZ2VudCI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJyZXF1aXJlZCI6ZmFsc2UsIm5hbWUiOiJTdHJpbmcifX19LCJlbWFpbF9hZGRyZXNzIjp7InR5cGUiOiJSZWNvcmQiLCJhdHRyaWJ1dGVzIjp7ImRvbWFpbiI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJuYW1lIjoiU3RyaW5nIn0sInVpZCI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJuYW1lIjoiU3RyaW5nIn19fSwiVXJsIjp7InR5cGUiOiJTdHJpbmcifX0sImVudGl0eVR5cGVzIjp7IkFwcGxpY2F0aW9uIjp7InNoYXBlIjp7InR5cGUiOiJSZWNvcmQiLCJhdHRyaWJ1dGVzIjp7ImdyYW50VHlwZXMiOnsidHlwZSI6IlNldCIsImVsZW1lbnQiOnsidHlwZSI6IkVudGl0eU9yQ29tbW9uIiwibmFtZSI6IlN0cmluZyJ9fX19fSwiUm9sZSI6eyJzaGFwZSI6eyJ0eXBlIjoiUmVjb3JkIiwiYXR0cmlidXRlcyI6e319fSwiVHJ1c3RlZElzc3VlciI6eyJzaGFwZSI6eyJ0eXBlIjoiUmVjb3JkIiwiYXR0cmlidXRlcyI6eyJpc3N1ZXJfZW50aXR5X2lkIjp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsIm5hbWUiOiJVcmwifX19fSwiVXNlciI6eyJzaGFwZSI6eyJ0eXBlIjoiUmVjb3JkIiwiYXR0cmlidXRlcyI6eyJlbWFpbCI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJyZXF1aXJlZCI6ZmFsc2UsIm5hbWUiOiJlbWFpbF9hZGRyZXNzIn0sInJvbGUiOnsidHlwZSI6IlNldCIsImVsZW1lbnQiOnsidHlwZSI6IkVudGl0eU9yQ29tbW9uIiwibmFtZSI6IlN0cmluZyJ9fSwic3ViIjp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsInJlcXVpcmVkIjpmYWxzZSwibmFtZSI6IlN0cmluZyJ9fX0sIm1lbWJlck9mVHlwZXMiOlsiUm9sZSJdfSwiV29ya2xvYWQiOnsic2hhcGUiOnsidHlwZSI6IlJlY29yZCIsImF0dHJpYnV0ZXMiOnsiY2xpZW50X2lkIjp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsIm5hbWUiOiJTdHJpbmcifSwiaXNzIjp7InR5cGUiOiJFbnRpdHlPckNvbW1vbiIsInJlcXVpcmVkIjpmYWxzZSwibmFtZSI6IlRydXN0ZWRJc3N1ZXIifSwibmFtZSI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJyZXF1aXJlZCI6ZmFsc2UsIm5hbWUiOiJTdHJpbmcifSwicnBfaWQiOnsidHlwZSI6IkVudGl0eU9yQ29tbW9uIiwicmVxdWlyZWQiOmZhbHNlLCJuYW1lIjoiU3RyaW5nIn0sInNwaWZmZV9pZCI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJyZXF1aXJlZCI6ZmFsc2UsIm5hbWUiOiJTdHJpbmcifSwiZ3JhbnRUeXBlcyI6eyJ0eXBlIjoiU2V0IiwiZWxlbWVudCI6eyJ0eXBlIjoiRW50aXR5T3JDb21tb24iLCJuYW1lIjoiU3RyaW5nIn19fX19fSwiYWN0aW9ucyI6eyJFeGVjdXRlIjp7ImFwcGxpZXNUbyI6eyJwcmluY2lwYWxUeXBlcyI6WyJXb3JrbG9hZCJdLCJyZXNvdXJjZVR5cGVzIjpbIkFwcGxpY2F0aW9uIl0sImNvbnRleHQiOnsidHlwZSI6IkNvbnRleHQifX19fX19"
        }
    }
}

sample_cedarling_update_token.java#

import io.jans.model.SimpleCustomProperty;
import io.jans.model.custom.script.model.CustomScript;
import io.jans.model.custom.script.type.token.UpdateTokenType;
import io.jans.service.custom.script.CustomScriptManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uniffi.cedarling_uniffi.*;
import io.jans.cedarling.binding.wrapper.CedarlingAdapter;
import java.util.Map;
import io.jans.as.server.service.external.context.ExternalUpdateTokenContext;
import io.jans.as.server.model.common.AccessToken;
import org.json.JSONObject;
import java.util.List;
import java.util.ArrayList;
import io.jans.as.model.common.GrantType;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.google.common.collect.Sets;


public class UpdateTokenCedarling implements UpdateTokenType {

    private static final Logger log = LoggerFactory.getLogger(CustomScriptManager.class);
    CedarlingAdapter cedarlingAdapter = null;


    public boolean init(Map < String, SimpleCustomProperty > configurationAttributes) {
        log.info("UpdateTokenCedarling initialized!!!");
        // Check if bootstrap JSON file path is configured
        if (!configurationAttributes.containsKey("BOOTSTRAP_JSON_PATH")) {
            log.error("Initialization. Property bootstrap_file_path is not specified.");
            return true;
        }
        log.info("Initialize Cedarling...");

        // Get bootstrap file path
        String bootstrapFilePath = configurationAttributes.get("BOOTSTRAP_JSON_PATH").getValue2();

        String bootstrapJson = null;
        try {
            // Read bootstrap JSON from file
            bootstrapJson = readFile(bootstrapFilePath);
            // Initialize Cedarling adapter
            cedarlingAdapter = new CedarlingAdapter();
            cedarlingAdapter.loadFromJson(bootstrapJson);
        } catch (CedarlingException e) {
            log.error("Unable to initialize Cedarling" + e.getMessage());
            return true;
        } catch (Exception e) {
            log.error("Unable to initialize Cedarling" + e.getMessage());
            return true;
        }
        log.info("Cedarling Initialization successful...");

        return true;
    }

    public boolean init(CustomScript customScript, Map < String, SimpleCustomProperty > configurationAttributes) {
        log.info("UpdateTokenCedarling initialized!!!");
        // Check if bootstrap JSON file path is configured
        if (!configurationAttributes.containsKey("BOOTSTRAP_JSON_PATH")) {
            log.error("Initialization. Property bootstrap_file_path is not specified.");
            return true;
        }
        log.info("Initialize Cedarling...");

        // Get bootstrap file path
        String bootstrapFilePath = configurationAttributes.get("BOOTSTRAP_JSON_PATH").getValue2();

        String bootstrapJson = null;
        try {
            // Read bootstrap JSON from file
            bootstrapJson = readFile(bootstrapFilePath);
            // Initialize Cedarling adapter
            cedarlingAdapter = new CedarlingAdapter();
            cedarlingAdapter.loadFromJson(bootstrapJson);
        } catch (CedarlingException e) {
            log.error("Unable to initialize Cedarling" + e.getMessage());
            return true;
        } catch (Exception e) {
            log.error("Unable to initialize Cedarling" + e.getMessage());
            return true;
        }
        log.info("Cedarling Initialization successful...");

        return true;
    }

    public boolean destroy(Map < String, SimpleCustomProperty > configurationAttributes) {
        return true;
    }

    public int getApiVersion() {
        return 1;
    }

    @Override
    public boolean modifyIdToken(Object jwr, Object tokenContext) {
        return false;
    }

    @Override
    public boolean modifyRefreshToken(Object refreshToken, Object tokenContext) {
        return false;
    }

    @Override
    public boolean modifyAccessToken(Object accessTokenObj, Object contextObj) {
        try {
            AccessToken accessToken = (AccessToken) accessTokenObj;
            ExternalUpdateTokenContext context = (ExternalUpdateTokenContext) contextObj;

            // Collect client grant types
            List < String > grantTypes = new ArrayList < > ();
            for (GrantType gt: context.getClient().getGrantTypes()) {
                grantTypes.add(gt.getValue());
            }

            // Build principal and resource entities
            JSONObject principalJson = buildPrincipalJson(context.getClient().getClientId(), grantTypes);
            JSONObject resourceJson = buildResourceJson(grantTypes);

            // Convert principal JSON to EntityData
            List < EntityData > principalEntities =
                List.of(EntityData.Companion.fromJson(principalJson.toString()));

            // Empty context (placeholder for future extension)
            JSONObject contextJson = new JSONObject("{}");

            // Call Cedarling authorization
            AuthorizeResult result = cedarlingAdapter.authorizeUnsigned(
                principalEntities,
                "Jans::Action::\"Execute\"",
                resourceJson,
                contextJson
            );

            log.info("Cedarling Authz Response Decision: {}", result.getDecision());

            // If authorized → overwrite scopes
            if (result.getDecision()) {
                context.overwriteAccessTokenScopes(accessToken, Sets.newHashSet("openid", "profile"));
                return true;
            }

        } catch (AuthorizeException | EntityException e) {
            log.error("Error in Cedarling Authz", e);
            return false;
        }

        return false;
    }

    /** Helper: Build Principal JSON 
     * {
     *    "cedar_entity_mapping": {
     *        "entity_type": "Jans::Workload",
     *        "id": "wl_id"
     *    },
     *    "client_id": "xxxxxxxx-xxxxx-xxxx-xxxxxxxx",
     *    "grantTypes": ["authorization_code", "refresh_token"]
     *}
     * */
    private JSONObject buildPrincipalJson(String clientId, List < String > grantTypes) {
        JSONObject json = new JSONObject();
        json.put("cedar_entity_mapping", new JSONObject()
            .put("entity_type", "Jans::Workload")
            .put("id", "wl_id"));
        json.put("client_id", clientId);
        json.put("grantTypes", grantTypes);

        log.debug("Principal JSON: {}", json);
        return json;
    }

    /** Helper: Build Resource JSON 
     * 
     * {
     *    "cedar_entity_mapping": {
     *        "entity_type": "Jans::Application",
     *        "id": "app_id"
     *    },
     *    "grantTypes": ["authorization_code", "client_credentials"]
     *}
     * */
    private JSONObject buildResourceJson(List < String > grantTypes) {
        JSONObject json = new JSONObject();
        json.put("cedar_entity_mapping", new JSONObject()
            .put("entity_type", "Jans::Application")
            .put("id", "app_id"));
        json.put("grantTypes", grantTypes);

        log.debug("Resource JSON: {}", json);
        return json;
    }

    @Override
    public int getRefreshTokenLifetimeInSeconds(Object tokenContext) {
        return 0;
    }

    @Override
    public int getIdTokenLifetimeInSeconds(Object context) {
        return 0;
    }

    @Override
    public int getAccessTokenLifetimeInSeconds(Object context) {
        return 0;
    }

    public String readFile(String filePath) {
        Path path = Paths.get(filePath).toAbsolutePath();
        try {
            return Files.readString(path);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}