5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay/*
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay *
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * Copyright (c) 2014 ForgeRock AS. All Rights Reserved
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay *
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * The contents of this file are subject to the terms
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * of the Common Development and Distribution License
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * (the License). You may not use this file except in
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * compliance with the License.
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay *
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * You can obtain a copy of the License at
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * http://forgerock.org/license/CDDLv1.0.html
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * See the License for the specific language governing
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * permission and limitations under the License.
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay *
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * When distributing Covered Code, include this CDDL
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * Header Notice in each file and include the License file
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * at http://forgerock.org/license/CDDLv1.0.html
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * If applicable, add the following below the CDDL Header,
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * with the fields enclosed by brackets [] replaced by
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * your own identifying information:
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay * "Portions Copyrighted [year] [name of copyright owner]"
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay */
3d1633e2e59dde32f1ada8abb88b8867b0596b5bJason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport groovyx.net.http.RESTClient
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport org.apache.http.client.HttpClient
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport org.forgerock.openicf.connectors.scriptedrest.ScriptedRESTConfiguration
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport org.forgerock.openicf.misc.scriptedcommon.OperationType
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport org.identityconnectors.common.logging.Log
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport org.identityconnectors.framework.common.objects.ObjectClass
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport org.identityconnectors.framework.common.objects.SyncToken
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayimport static groovyx.net.http.Method.GET
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaydef operation = operation as OperationType
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaydef configuration = configuration as ScriptedRESTConfiguration
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaydef httpClient = connection as HttpClient
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaydef connection = customizedConnection as RESTClient
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaydef log = log as Log
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaydef objectClass = objectClass as ObjectClass
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemaylog.info("Entering " + operation + " Script");
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemayif (OperationType.GET_LATEST_SYNC_TOKEN.equals(operation)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return connection.request(GET) { req ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.path = '/changelog'
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.query = [
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay _queryFilter: 'true',
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay _fields : '_id',
0893dda13a97d17709b5d86bee8373e2ef0c37cbJason Lemay _sortKeys : '-_id'
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay ]
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.success = { resp, json ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay def lastToken = "0"
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay json.result.each() { it ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay lastToken = it._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return new SyncToken(lastToken)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.failure = { resp, json ->
bff19f77bd0c2db1b9923d398472671e26f55ae5Jason Lemay throw new ConnectException(json.message)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay} else if (OperationType.SYNC.equals(operation)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay def token = token as Object
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay log.info("Entering SYNC");
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay switch (objectClass) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay case ObjectClass.ACCOUNT:
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return connection.request(GET) { req ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.path = '/changelog'
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.query = [
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay _queryFilter: "_id gt \"${token}\" and targetDN co \"ou=people,dc=example,dc=com\"",
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay _fields : '_id,changeType,targetDN'
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay ]
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.success = { resp, json ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay def lastToken = "0"
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay json.result.each() { changeLogEntry ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay lastToken = changeLogEntry._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay String resourceId = changeLogEntry.targetDN
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay resourceId = resourceId.substring(4, resourceId.indexOf(','))
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay handler({
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay syncToken lastToken
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay if ("add".equals(changeLogEntry.changeType)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay CREATE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay } else if ("modify".equals(changeLogEntry.changeType)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay UPDATE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay } else if ("delete".equals(changeLogEntry.changeType)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay DELETE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay object {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uid resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay id resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay delegate.objectClass(objectClass)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay } else {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay CREATE_OR_UPDATE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay connection.request(GET) { getReq ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.path = '/users/' + resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.success = { getResp, value ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay object {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uid value._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay id value._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'telephoneNumber', value?.contactInformation?.telephoneNumber
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'emailAddress', value?.contactInformation?.emailAddress
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'familyName', value?.name?.familyName
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'givenName', value?.name?.givenName
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'displayName', value?.displayName
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute ('groups', *(value?.groups))
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'created', value?.meta?.created
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'lastModified', value?.meta?.lastModified
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response."404" = { getResp, error ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay DELETE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay object {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uid resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay id resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay delegate.objectClass(objectClass)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.failure = { getResp, error ->
bff19f77bd0c2db1b9923d398472671e26f55ae5Jason Lemay throw new ConnectException(error.message)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay })
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return new SyncToken(lastToken)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.failure = { resp, json ->
bff19f77bd0c2db1b9923d398472671e26f55ae5Jason Lemay throw new ConnectException(json.message)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay break;
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay case ObjectClass.GROUP:
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return connection.request(GET) { req ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.path = '/changelog'
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.query = [
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay _queryFilter: "_id gt \"${token}\" and targetDN co \"ou=groups,dc=example,dc=com\"",
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay _fields : '_id,changeType,targetDN'
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay ]
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.success = { resp, json ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay def lastToken = "0"
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay json.result.each() { changeLogEntry ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay lastToken = changeLogEntry._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay String resourceId = changeLogEntry.targetDN
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay resourceId = resourceId.substring(3, resourceId.indexOf(','))
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay handler({
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay syncToken lastToken
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay if ("add".equals(changeLogEntry.changeType)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay CREATE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay } else if ("modify".equals(changeLogEntry.changeType)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay UPDATE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay } else if ("delete".equals(changeLogEntry.changeType)) {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay DELETE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay object {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uid resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay id resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay delegate.objectClass(objectClass)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay } else {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay CREATE_OR_UPDATE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay connection.request(GET) { getReq ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uri.path = '/groups/' + resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.success = { getResp, value ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay object {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uid value._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay id value._id
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay delegate.objectClass(objectClass)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute ('members', *(value?.members))
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'displayName', value?.displayName
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'created', value?.meta?.created
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay attribute 'lastModified', value?.meta?.lastModified
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response."404" = { getResp, error ->
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay DELETE()
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay object {
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay uid resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay id resourceId
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay delegate.objectClass(objectClass)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.failure = { getResp, error ->
bff19f77bd0c2db1b9923d398472671e26f55ae5Jason Lemay throw new ConnectException(error.message)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay })
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay return new SyncToken(lastToken)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay response.failure = { resp, json ->
bff19f77bd0c2db1b9923d398472671e26f55ae5Jason Lemay throw new ConnectException(json.message)
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay break;
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay }
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay} else { // action not implemented
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay log.error("Sync script: action '" + operation + "' is not implemented in this script");
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay}
5f22ff8ce7baf0b39668468cc854eec3eb946003Jason Lemay