Groovy Script Examples
Examples SAML
Login any user as guestuser
if the attribute groups contains guests.
This script should be mapped to the Application-attribute Username and assumes that the usernames comes from the SAML Name-ID:
- // Check the group-attribute for the entry "guests"
- if(mapping.groups != null && mapping.groups.contains("guests")) {
- // Return the static value "guestuser"
- return "guestuser"
- } else {
- // Otherwise use the value from the Name ID
- return ATTR_NAMEID
- }
Set SAML attribute email to an unique value if the attribute is not present
This script should be mapped to the Application-attribute E-Mail Address.
- return mapping.'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'?.first() ?: "UID@example.com"
Set the last name to uppercase
This script should be applied to the Application-attribute Full Name and assumes the first name is in first
and the last name in last
- // If the attribute lastName is present transform it to uppercase,
- // otherwise use an empty string
- def lastName = mapping.lastName?.first() ? mapping.lastName.first().toUpperCase() : ""
- // Use an emptry String for the first name if it is not present
- def firstName = mapping.firstName?.first() ?: ""
- def fullName = "$firstName $lastName"
- // The SLF4J-logger de.resolution.retransform.impl.transformers.groovy.GroovyTransformerScript
- // is available as logger and can be used to write to the application-log.
- // warn is enabled by default, so this message should be visible in the log
- if (fullName.trim().isEmpty()) {
- logger.warn("Fullname is empty or contains only whitespace")
- }
- return fullName
Combine groups from attributes with the value true
In this example. the IdP sends a fixed set of group names as keys with the value true if the user is member of that group:
- "attributes": {
- "grp1": [ "true"],
- "grp2": [ "true"],
- "grp3": [ "false"]
- },
- def groups = []
- if(mapping.grp1?.contains("true")) {
- groups.add("grp1");
- }
- if(mapping.grp2?.contains("true")) {
- groups.add("grp2");
- }
- if(mapping.grp3?.contains("true")) {
- groups.add("grp3");
- }
- // This logger should not be used in a production-system
- logger.warn("Groups are {}", groups)
- return groups
Handle Groups Not Sent As Multivalue Attribute in SAML Response
- // list of key/ value to replace group names after splitting
- def trafoMap = ["20368564" : "ong-group", "10096280" : "other-group"]
- // read "Groups" attribute from SAML Response split by semicolon
- def splitted = mapping.groups?.first()?.split(";")
- if(splitted == null) {
- return DROP_ALL // return no values, so existing groups may be remove
- }
- return splitted
- .collect{trafoMap[it]} // apply transformation rules from trafoMap (search and replace)
- .findAll{it} // filter null values a.k.a. drop groups not in the trafoMap
Transform one group from the SAML response to two or more groups
- // Input your data as per the descriptions below
- // Replace YourIDPGroupAttribute with your actual IdP Group Attribute
- def idpGroupAttribute = "YourIDPGroupAttribute"
- // Replace IdP_groupName with the group name that you need to transform
- def idpGroupName = "IdP_groupName"
- // Replace "replacement1" and "replacement2" with the actual group names replacements, and you can add other elements if needed
- def replacements = ["replacement1", "replacement2"]
- // No need to change anything in the following section
- def groups = mapping.get(idpGroupAttribute)
- if (groups.contains(idpGroupName)) {
- groups.remove(idpGroupName)
- groups.addAll(replacements)
- }
- return groups
Transform one group from the SAML response to two or more groups and also perform more direct transformations
- // Input your data as per the descriptions below
- // Replace YourIDPGroupAttribute with your actual IdP Group Attribute
- // The example below is the Azure AD Default groups claim
- def idpGroupAttribute = "http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"
- // Replace IdP_groupName_1 with the group name that you want to transform into multiple other groups
- def idpGroupName_1 = "my-group-1"
- // Add as many groups as you want to be assigned to the user, if idpGroupName_1 is present
- def idpGroupName_1_transform_to_groups = ["your-group-1", "your-group-2"]
- // No need to change anything in the following block, this takes
- def groups = mapping.get(idpGroupAttribute)
- if (groups.contains(idpGroupName_1)) {
- groups.remove(idpGroupName_1)
- groups.addAll(idpGroupName_1_transform_to_groups)
- }
- // Add more 1:1 replacements here
- def idpGroupName_2 = "transform-me-1"
- def idpGroupNameReplacement_2 = "your-group-3"
- if (groups.contains(idpGroupName_2)) {
- groups.remove(idpGroupName_2)
- groups.add(idpGroupNameReplacement_2)
- }
- def idpGroupName_3 = "transform-me-2"
- def idpGroupNameReplacement_3 = "your-group-4"
- if (groups.contains(idpGroupName_3)) {
- groups.remove(idpGroupName_3)
- groups.add(idpGroupNameReplacement_3)
- }
- return groups
Allow user authentication based on the email domain of the user
- // Check the email-attribute and if it is not empty check if it contains the email domain
- if (mapping.email[0] != null) {
- if (mapping.email[0].contains("@lab.resolution.de")) {
- // if it contains the domain return the NameID
- return mapping.ATTR_NAMEID
- } else {
- // Otherwise drop the authentication
- return DROP_ALL
- }
- } else {
- // if email-attribute and if it is empty log a warning message and drop the authentication
- logger.warn("Dropping User authentication due to missing SAML attribute email")
- return DROP_ALL
- }
Add a user into a specific group when not calling the JSM portal and the IdP returns a specific group
- def groupsToReturn = (groups != null && groups != DROP) ? groups : []
- //Check ATTR_SD_CUSTOMER attribute is false and if user is in group g1, when both conditions are met add the user to the group jira-servicedesk-users
- if(ATTR_SD_CUSTOMER != ["true"]) {
- logger.warn("SD Portal is NOT called")
- if(groupsToReturn.contains("g1")) {
- logger.warn("User is in g1")
- groupsToReturn.add("jira-servicedesk-users")
- } else {
- //If the user is not in group g1
- logger.warn("User is not in g1")
- }
- //If user has called the JSM portal
- } else {
- //If user has called the JSM portal
- logger.warn("SD Portal is called")
- }
- return groupsToReturn
Drop the user if the email is already present
Use this to transform the email-attribute. If the email-address is found and don't belong to this user, drop the user.
- String email = mapping.email?.first()
- String username = mapping.ATTR_NAMEID?.first()
- // Check if there is already a user with this email in the system
- def existingUser = findUser("ATTR_EMAIL",email)
- if(existingUser == null) {
- return email
- } else {
- // If there is such a user check if it's the same username
- if(username == existingUser.get("ATTR_NAME").first()) {
- return email
- } else {
- // if not drop the user
- return DROP_USER
- }
- }
Exclude some users from being reactivated during login even if that option is enabled
Use the following Groovy code for the username attribute mapping (assuming that the username attribute is mapped to the default value originally ATTR_NAMEID
):
- // Enter the list of usernames not to be reactivated below:
- def usernameBlacklist = ["username1","username2","username3"]
- //
- String username = mapping.ATTR_NAMEID
- if (username in usernameBlacklist) {
- def user = findUser("ATTR_NAME",username)
- def active = user?.ATTR_ACTIVE
- if (active?.getAt(0) == "true") {
- return username
- } else {
- return DROP_ALL
- }
- } else {
- return username
- }
Fail the authentication if a value (among a list) of an attribute matches any value of another list
Use the following Groovy code for the username attribute mapping.
Assumptions:
The Jira Username attribute is mapped to
ATTR_NAMEID
The attribute to be checked is called
userDep
- // Enter here the list of values that would be checked against:
- allowedList = ["value1", "value2", "value3", "value4"]
- //
- String user = mapping.ATTR_NAMEID?.getAt(0)
- def dep = mapping.userDep
- if (dep.any { allowedList.contains( it ) }) {
- return user
- } else {
- return DROP_ALL
- }
Assign a specific group based on some conditions
In the following example, we are going to assign group 'myGroup' to the users if the following two conditions are both met:
The nameId starts with 'M' and followed by some numbers
The department attribute has a value of 'IT'
Assuming the following attributes returned by the IdP:
- "loginInformation" : {
- "nameId" : "M1234",
- "attributes" : {
- "ATTR_NAMEID" : [ "M1234" ],
- "groups" : [ "group1", "group2" ],
- "email" : [ "john.doe@example.com" ],
- "fullname" : [ "John Doe" ],
- "department" : [ "IT" ]
- }
- }
Use the following Groovy code for the Groups attribute mapping.
- username = mapping.ATTR_NAMEID
- dept = mapping.department
- grp = mapping.groups
- if (dept?.getAt(0) == "IT" && username.any {it ==~ /M\d+/} ) {
- grp.addAll("myGroup")
- }
- return grp
Examples User Sync
Remove any user from the group confluence-users if the user is disabled on the IdP side.
The script could be helpful since Confluence is sometimes displaying an incorrect number of active users. License will display the correct number of users only if the users are not part of any group with CAN-USE permission (in our case 'confluence-users').
This script should be mapped to the Application-attribute Groups:
- def groups = existing?.ATTR_GROUPS ?: []
- groups.addAll(con?.GROUPS ?: [])
- // Check if the account is disabled and the user is part of the group confluence-users
- if (con.accountEnabled == "false" && groups.contains("confluence-users")) {
- // If the criterias match remove the user from the group confluence-users
- groups.remove("confluence-users")
- }
- return groups.toUnique()
Transform group names using regular expressions
Replacing attributes using regular expressions can be done in a Groovy-transformation instead of adding Regexes to the configuration. Especially when a large number of regular expressions need to be applied it can be helpful to have all of them in a piece of code
- // collect{} applies the given closure to all
- // elements in a list and returns a list containing
- // all the transformed elements.
- // Using safe-dereference ?. to avoid a NullPointerException if GROUPS is not present
- return con.GROUPS?.collect{
- grp -> grp.toString() // toString() is required because the elements are StringStructuredData
- .replaceAll(/Pink Floyd/,'def') // using Slashy Strings for the regex avoids some escaping
- .replaceAll(/Blind(.*)/,'xyz$1') // using '' instead of "" for the replacements allows using $ without escaping
- .replaceAll(/\./,'%') // replacing . requires escaping (\.), in a normal String this would be \\., but not required in Slashy Strings
- // add more as needed
- } ?: [] // return an empty list of the GROUP-attribute is not present
Assuming the user data looks like this
- {
- "con": {
- "USERID": "damaris.rau",
- "Unique_ID": "b9e13bcc-3df9-4eaf-ab8c-c8e77485d484",
- "EMAIL": "damaris.rau@example.org",
- "FULLNAME": "Damaris Rau",
- "Manager": "zane.maggio",
- "GROUPS": [
- "Pink Floyd",
- "Blind Faith",
- "R.E.M."
- ]
- },
- "saml": {},
- "existing": {}
- }
This transformation returns
- ["def","xyz Faith","R%E%M%"]
Apply the Cleanup Behaviour (e.g. Disable) when a user is a member of a certain group
Use the following Groovy code for the Groups
attribute mapping in the connector:
- // Replace the <> placeholder with the group name below
- def exclusionGroup = "<enter the group name here>"
- if (con.GROUPS.contains(exclusionGroup)) {
- return DROP_ALL
- }
- return GROUPS