Cedarling sample inputs
bootstrap.json
{
"CEDARLING_APPLICATION_NAME": "Cedarling-Test-In-Custom-Script",
"CEDARLING_POLICY_STORE_LOCAL_FN": "./custom/static/update_token_script.cjar",
"CEDARLING_LOG_LEVEL": "DEBUG",
"CEDARLING_LOG_TYPE": "std_out",
"CEDARLING_PRINCIPAL_BOOLEAN_OPERATION": {
"===": [{"var": "Jans::Workload"}, "ALLOW"]
}
}
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_JSON_PATH is not specified.");
return false;
}
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(), e);
cedarlingAdapter = null;
return false;
} catch (Exception e) {
log.error("Unable to initialize Cedarling: {}", e.getMessage(), e);
cedarlingAdapter = null;
return false;
}
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_JSON_PATH is not specified.");
return false;
}
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(), e);
cedarlingAdapter = null;
return false;
} catch (Exception e) {
log.error("Unable to initialize Cedarling: {}", e.getMessage(), e);
cedarlingAdapter = null;
return false;
}
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 (omit or pass null for partial evaluation without a principal)
EntityData principalEntity =
EntityData.Companion.fromJson(principalJson.toString());
// Empty context (placeholder for future extension)
JSONObject contextJson = new JSONObject("{}");
// Call Cedarling authorization
AuthorizeResult result =
cedarlingAdapter.authorizeUnsignedEntity(
principalEntity,
"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);
}
}
}