====== Groovy scripts and their authorization ======
===== Process of executing a script =====
While a script is executed, each used class in the script body is checked. Every class must be allowed in the allowed classes or services. The check is made by the [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/security/domain/GroovySandboxFilter.java|GroovySandboxFilter]] in the method [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/security/domain/GroovySandboxFilter.java#L77-L100|filter]]. In this method is resolved [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/security/domain/GroovySandboxFilter.java#L82-L89|class wrapped as proxy]] to simple classes. This control prevents undesirable use of classes.
===== Script authorization =====
It's possible to add authorities for the script after it's created. The authorities consist of classes and services, which can be used in the script. **These authorities are only for the script that owns these authorities**. Scripts don't share authorities between each other.
{{ :devel:documentation:transformation_scripts:dev:script-authorities.png?nolink |}}
Permissions for each script are of two basic types:
* Services - beans/services which implement interface [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-api/src/main/java/eu/bcvsolutions/idm/core/api/script/ScriptEnabled.java|ScriptEnabled]]. An instance of this service is put into the script and the script is able to call public methods of this service. Before the script definition is saved, it's checked [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/model/service/impl/DefaultIdmScriptAuthorityService.java#L68-L80|if the service exists in allowed classes.]]
* Classes - All available classes in java. Before the script definition is saved, it's checked [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/model/service/impl/DefaultIdmScriptAuthorityService.java#L58-L66| if the class exists.]]
=== Allowed classes ===
The following classes don't need to be specially added as script authorities (they are allowed by default) - [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/security/domain/GroovySandboxFilter.java#L41-L46|GroovySandboxFilter]]
String.class, Integer.class, Double.class, Long.class, Date.class, Enum.class, Boolean.class,
BigDecimal.class, UUID.class, Character.class, GuardedString.class, DateTimeFormatter.class,
DateTimeFormat.class, DateTime.class, String[].class, LocalDateTime.class,
Map.class, HashMap.class, List.class, ArrayList.class, Set.class, HashSet.class,
LoggerFactory.class, Logger.class, ch.qos.logback.classic.Logger.class
===== Evaluating a script from another script =====
Scripts call other scripts via **scriptEvaluator** (scriptEvaluator is automatically added into its parent script - for example transformation to, and with builder is sent to child scripts). The instance of scriptEvaluator must be named as **scriptEvaluator**.
**Example of calling another script with code 'test':**
def result = scriptEvaluator.evaluate(
scriptEvaluator.newBuilder()
.setScriptCode('test')
.addParameter('scriptEvaluator', scriptEvaluator)
.addParameter('text', 'this is example text')
.build());
We've called the **test** script. The script has as parameters scriptEvaluator (script can call another script - CAUTION though, scripts can call only scripts from the same category, or from a BASIC category). The next parameter is called **text**, the attribute text contains some sample text. The result from the evaluated script with code **test** will be in the **result** attribute. The parent script must have authorities for classes that the child scripts returns.
Caution: authorities used in the script **aren't** shared with the child or parent script.
Currently, there is no control loop script between the pair.
// a sample loop script in between the pair, script A (code: parent) and script B (code: child)
// script A (code: parent)
scriptEvaluator.evaluate(
scriptEvaluator.newBuilder()
.setScriptCode('child')
.build());
// script B (code: child)
scriptEvaluator.evaluate(
scriptEvaluator.newBuilder()
.setScriptCode('parent')
.build());
// script A calls script B - an infinity loop
Be careful: if there is no return statement at the end, the script will return the last initialized attribute.
==== IdmSecurityException ====
If you use classes that are not among the allowed authorities, an exception [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/security/exception/IdmSecurityException.java|IdmSecurityException]] is thrown. The exception is caught in [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/script/evaluator/AbstractScriptEvaluator.java#L101-L109|AbstractScriptEvaluator]]. The exception contains code, name and category of the script that has thrown the exception. The logged exception is currently only for scripts evaluated by means of a scriptEvaluator.
==== scriptEvaluator and Builder ====
A script inside another script can be called with the **scriptEvaluator** instance. **scriptEvaluator** is the child of class [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/script/evaluator/AbstractScriptEvaluator.java|AbstractScriptEvaluator]]. Children are classified by [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/frontend/czechidm-core/src/enums/ScriptCategoryEnum.js|ScriptCategoryEnum]]. **It is only permitted to call scripts within the same category or basic category.**
As a parameter [[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/script/evaluator/AbstractScriptEvaluator.java#L128-L130|metody evaluate]] in scriptEvaluator you add **[[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/script/evaluator/AbstractScriptEvaluator.java#L143-L181|Builder]]**. The only required parameter is the **code** of the script.
scriptEvaluator.evaluate(
scriptEvaluator.newBuilder()
.setScriptCode('SCRIPT_CODE_001')
.addParameter('scriptEvaluator', scriptEvaluator)
.addParameter('attributeValue', attributeValue)
.addParameter('entity', entity)
.addParameter('text', 'test')
.build());
=== DefaultTransformToResourceEvaluator ===
[[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/acc/src/main/java/eu/bcvsolutions/idm/acc/script/evaluator/DefaultTransformToResourceEvaluator.java|DefaultTransformToResourceEvaluator]] - evaluator for transformation to a system, can call a script from the TRANSFORM_TO or DEFAULT categories. The evaluator is automatically added into the transformation to a system.
=== DefaultTransformFromResourceEvaluator ===
[[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/acc/src/main/java/eu/bcvsolutions/idm/acc/script/evaluator/DefaultTransformFromResourceEvaluator.java|DefaultTransformFromResourceEvaluator]] - evaluator for transformation from a system, can call a script from the TRANSFORM_FROM or DEFAULT categories. The evaluator is automatically added into the transformation from a system.
=== DefaultScriptEvaluator ===
[[https://github.com/bcvsolutions/CzechIdMng/blob/develop/Realization/backend/core/core-impl/src/main/java/eu/bcvsolutions/idm/core/script/evaluator/DefaultScriptEvaluator.java|DefaultScriptEvaluator]] - Evaluator for the DEFAULT category. The default script can be called from other scripts.
===== Attribute mapping and scripts =====
Code for script calling can be generated by a frontend component script area (see the first picture and button insert script). Modal window (second picture) is a list of all available scripts.
{{ :devel:documentation:transformation_scripts:dev:script-transformation-02.png?nolink |}}
{{ :devel:documentation:transformation_scripts:dev:script-transformation-01.png?nolink |}}
===== Script debug =====
For each script, a logger is enabled. Example of some messages:
org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger("script_name");
LOG.info("INFO Log");
LOG.error("ERROR Log");
LOG.warn("WARN Log");
If you want to see debug messages, you must initialize a LOG with prefix **eu.bcvsolutions.idm.**. Or update logback-spring.xml.
org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger("eu.bcvsolutions.idm.script_name");
LOG.debug("DEBUG Log");
==== Direct log only to console ====
To print a message to log, you can use the classic //System.out.println// statement, or better print:
println("test")
The second one doesn't need additional authorities.
===== Script upload and backup =====
==== Backup ====
Scripts agenda provides a backup of all scripts that are loaded in the CzechIdM. First, you must define a path to store the backup files. The path is defined by the application property: **idm.sec.core.backups.default.folder.path**. The backup folder must have permissions for read+write+execute, for the user that runs the application server (e.g. tomcat).
Every script will be saved into this folder with this name: \_\_.xml
==== Redeploy ====
The script agenda also provides functionality for the redeploy of **existing** scripts. Only the existing new script is deployed to IdM on application restart.
For redeploy you can use backup files. CzechIdM loads all files in a defined folder with a defined suffix (idm.sec.core.script.folder and idm.sec.core.script.fileSuffix). **The file name does not matter.** Script is loaded by code defined inside xml.
Redeploy folder is defined by the property: **idm.sec.core.script.folder**. The property can contain the class path or folder. A sample folder: ''%%file:///opt/czechidm/backup/%%'', a sample class path: ''
classpath*:/eu/bcvsolutions/idm/scripts/''
If you use a file folder, CzechIdM must have read+write+execute permissions on the folder that contains scripts as well as read permission on files.
===== Available services in script =====
For list of basic usable services in all scripts please visit [[devel:documentation:transformation_scripts:dev:available_services|this page]].
===== FAQ =====
[[faq:scripts:start|Scripts FAQ]]