diff --git a/connector-scim2/pom.xml b/connector-scim2/pom.xml new file mode 100644 index 0000000..8b7c46f --- /dev/null +++ b/connector-scim2/pom.xml @@ -0,0 +1,94 @@ + + + + 4.0.0 + + + connector-parent + com.evolveum.polygon + 1.5.0.0 + + + edu.unc.polygon + connector-scim2 + .1-SNAPSHOT + jar + + Scim2 Connector + + + edu.unc.polygon.connector.scim2 + Scim2Connector + + + + + evolveum-nexus-releases + Internal Releases + http://nexus.evolveum.com/nexus/content/repositories/releases/ + + + evolveum-nexus-snapshots + Internal Releases + http://nexus.evolveum.com/nexus/content/repositories/snapshots/ + + + apache-snapshots + Apache Snapshots + http://repository.apache.org/snapshots/ + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-resources-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + + connector-rest + com.evolveum.polygon + 1.4.2.14-SNAPSHOT + + + org.json + json + 20190722 + + + + + + diff --git a/connector-scim2/samples/improv.xml b/connector-scim2/samples/improv.xml new file mode 100644 index 0000000..078f908 --- /dev/null +++ b/connector-scim2/samples/improv.xml @@ -0,0 +1,284 @@ + + + + improv + + 2020-02-06T15:29:09.728Z + + + + http://midpoint.evolveum.com/xml/ns/public/gui/channels-3#user + + 0 + + + up + + + + + + + username+sw+%22kromhout%22 + https://improvapidev.itsapps.unc.edu + + + + http://www.w3.org/2001/04/xmlenc#aes256-cbc + + + asn37wSv5ncINVV2s1DWJ1L2OZw= + + + ioFdIyvE0D7n8QBBS8Zh8VFmrxh1iZoD70OHEN1+MgnHfo4it6+wTYWsJ8PfPgrh + + + + kromhout + id,active,username,externalId + + + + + 2020-02-05T19:09:25.301Z + e73c55a3cf739291-2b25ec7393242e89 + + + + + + + + + + + icfs:uid + icfs:name + icfs:name + icfs:name + __ACCOUNT__ + account + true + + + + + + + 120 + active + + + + + + + 130 + userName + + + + + + + ConnId Name + 110 + __NAME__ + + + + + + + 140 + id + + + + + + + 150 + externalId + + + + + + + ConnId UID + 100 + read + + + + + + + + + + + account + default + true + AccountObjectClass + + icfs:uid + + + $user/name + + + + + $user/name + + + + + + ri:externalId + + + $user/extension/uncPerson:subId + + + + $user/extension/uncPerson:subId + + + + + + ri:active + + + $user/extension/uncPerson:isActive + + + + + ri:userName + + + $user/extension/uncPerson:logonId + + + + + $user/extension/uncPerson:logonId + + + + + + + + + 2020-02-05T19:09:25.291Z + eaa11c2945c3b022-9f2d263021027cc7 + + + + + + + connector + + + + + + + false + + + + + true + + + true + + connector + + + + true + + true + true + true + + + false + false + + + false + false + + + false + false + true + + + + true + false + + + + + + Account sync policy + AccountObjectClass + account + default + c:UserType + true + + + polyStringNorm + c:name + + Matches using Name + declare namespace ri="http://midpoint.evolveum.com/xml/ns/public/resource/instance-3"; $account/attributes/icfs:name + + + + false + + linked + true + + + deleted + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#deleteFocus + + + + unlinked + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#link + + + + unmatched + true + + http://midpoint.evolveum.com/xml/ns/public/model/action-3#addFocus + + + + + + + diff --git a/connector-scim2/samples/outbound.xml b/connector-scim2/samples/outbound.xml new file mode 100644 index 0000000..7e0d561 --- /dev/null +++ b/connector-scim2/samples/outbound.xml @@ -0,0 +1,48 @@ + AccountObjectClass + + icfs:uid + + + $user/name + + + + + $user/name + + + + + ri:externalId + + + $user/extension/uncPerson:subId + + + + + $user/extension/uncPerson:subId + + + + + ri:active + + + $user/extension/uncPerson:isActive + + + + + ri:userName + + + $user/extension/uncPerson:logonId + + + + + $user/extension/uncPerson:logonId + + + diff --git a/connector-scim2/src/main/assembly/connector.xml b/connector-scim2/src/main/assembly/connector.xml new file mode 100644 index 0000000..efca6d1 --- /dev/null +++ b/connector-scim2/src/main/assembly/connector.xml @@ -0,0 +1,47 @@ + + + + + connector + + + jar + + + false + + + + target/classes + + + + + + + lib + false + runtime + + net.tirasa.connid:connector-framework + + + + \ No newline at end of file diff --git a/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Configuration.java b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Configuration.java new file mode 100644 index 0000000..4cfbddc --- /dev/null +++ b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Configuration.java @@ -0,0 +1,116 @@ +package edu.unc.polygon.connector.scim2; + +import com.evolveum.polygon.rest.AbstractRestConfiguration; +import org.identityconnectors.common.logging.Log; +import org.identityconnectors.framework.common.exceptions.ConfigurationException; +import org.identityconnectors.framework.common.objects.ObjectClass; +import org.identityconnectors.framework.spi.AbstractConfiguration; +import org.identityconnectors.framework.spi.ConfigurationProperty; + +import java.io.*; +import java.nio.charset.Charset; +import java.util.*; + + +/** + * @author ekromhout@gmail.com + * + */ +public class Scim2Configuration extends AbstractRestConfiguration { + + private static final Log LOG = Log.getLog(Scim2Configuration.class); + + private String Scim2Attributes; + private String Scim2ExcludedAttributes; + private String Scim2Filter; + private String Scim2SortBy; + private String Scim2SortOrder; + private String Scim2StartIndex; + private String Scim2Count; + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_ATTRIBUTES", + helpMessageKey = "UI_SCIM2_ATTRIBUTES_HELP") + public String getScim2Attributes() { + return Scim2Attributes; + } + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_EXCLUDE_ATTRIBUTES", + helpMessageKey = "UI_SCIM2_EXCLUDE_ATTRIBUTES_HELP") + public String getScim2ExcludedAttributes() { + return Scim2ExcludedAttributes; + } + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_FILTER", + helpMessageKey = "UI_SCIM2_FILTER_HELP") + public String getScim2Filter() { + return Scim2Filter; + } + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_SORTBY", + helpMessageKey = "UI_SCIM2_SORTBY_HELP") + public String getScim2SortBy() { + return Scim2SortBy; + } + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_SORT_ORDER", + helpMessageKey = "UI_SCIM2_SORT_ORDER_HELP") + public String getScim2SortOrder() { + return Scim2SortOrder; + } + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_START_INDEX", + helpMessageKey = "UI_SCIM2_START_INDEX_HELP") + public String getScim2StartIndex() { + return Scim2StartIndex; + } + + @ConfigurationProperty( + displayMessageKey = "UI_SCIM2_COUNT", + helpMessageKey = "UI_SCIM2_COUNT_HELP") + public String getScim2Count() { + return Scim2Count; + } + + + public void setScim2Attributes(String Scim2Attributes) { + this.Scim2Attributes = Scim2Attributes; + } + + public void setScim2ExcludedAttributes(String Scim2ExcludedAttributes) { + this.Scim2ExcludedAttributes = Scim2ExcludedAttributes; + } + + public void setScim2Filter(String Scim2Filter) { + this.Scim2Filter = Scim2Filter; + } + + public void setScim2SortBy(String Scim2SortBy) { + this.Scim2SortBy = Scim2SortBy; + } + + public void setScim2SortOrder(String Scim2SortOrder) { + this.Scim2SortOrder = Scim2SortOrder; + } + + public void setScim2StartIndex(String Scim2StartIndex) { + this.Scim2StartIndex = Scim2StartIndex; + } + + public void setScim2Count(String Scim2Count) { + this.Scim2Count = Scim2Count; + } + +@Override + public void validate() { + // TODO + } + +} + + diff --git a/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Connector.java b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Connector.java new file mode 100644 index 0000000..73f4615 --- /dev/null +++ b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Connector.java @@ -0,0 +1,490 @@ +package edu.unc.polygon.connector.scim2; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.HttpEntity; +import org.apache.http.HttpRequest; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPatch; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.apache.http.entity.StringEntity; +import org.apache.http.auth.AuthenticationException; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.client.methods.*; +import org.apache.http.annotation.NotThreadSafe; +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONException; +//import org.identityconnectors.common.Base64; +import org.identityconnectors.common.StringUtil; +import org.identityconnectors.framework.common.objects.ObjectClassInfoBuilder; +import org.identityconnectors.framework.common.objects.Schema; +import org.identityconnectors.framework.common.objects.SchemaBuilder; +import org.identityconnectors.framework.spi.Configuration; +import org.identityconnectors.framework.spi.Connector; +import org.identityconnectors.framework.spi.PoolableConnector; +import org.identityconnectors.framework.spi.ConnectorClass; +import org.identityconnectors.framework.spi.operations.*; +import org.identityconnectors.framework.common.exceptions.*; +import org.identityconnectors.framework.common.exceptions.ConfigurationException; +import org.identityconnectors.framework.common.exceptions.ConnectorException; +import org.identityconnectors.framework.common.objects.*; +import org.identityconnectors.common.logging.Log; +import org.identityconnectors.common.security.GuardedString; +import org.identityconnectors.framework.common.objects.filter.FilterTranslator; +import com.evolveum.polygon.common.GuardedStringAccessor; +import java.io.IOException; +import java.util.Iterator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.ArrayList; +import java.io.*; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.Object; +import java.util.Base64; + + +import com.evolveum.polygon.rest.AbstractRestConnector; +/** + * @author ethan@unc.edu + * + */ +@ConnectorClass(displayNameKey = "connector.federation.manager.display", configurationClass = Scim2Configuration.class) +public class Scim2Connector extends AbstractRestConnector implements TestOp, SchemaOp, Connector, SearchOp { + + private static final Log LOG = Log.getLog(Scim2Connector.class); + private static final String ATTR_ID = "id"; //__UID__ + private static final String ATTR_USER_NAME = "userName"; // __NAME__ + private static final String ATTR_ACTIVE = "active"; + public static final String ATTR_EXTERNAL_ID = "externalId"; + //public static final String ATTR_MAIL = "email"; + //public static final String ATTR_NAME = "id"; //hope to change this to username later __NAME__ + //public static final String ATTR_FAX_NUMBER = "faxnumber"; + //public static final String ATTR_MOBILE_NUMBER = "mobilenumber"; + //public static final String ATTR_PHONE_NUMBER = "phonenumber"; + //public static final String ATTR_ROLES = "roles"; + //public static final String ATTR_FIRST_NAME = "firstname"; + //public static final String ATTR_LAST_NAME = "lastname"; + //public static final String ATTR_MIDDLE_NAME = "middlename"; + //public static final String ATTR_INFORMAL_NAME = "informalname"; + //public static final String ATTR_WEBSITE = "website"; + public static final String CONTENT_TYPE = "application/json"; + + + private Scim2Configuration configuration; + + @Override + public void init(Configuration configuration) { + LOG.info(">>> Initializing connector"); + + if (!(configuration instanceof Scim2Configuration)) { + throw new ConfigurationException("Configuration is not instance of " + Scim2Configuration.class.getName()); + } + + Scim2Configuration scim2Config = (Scim2Configuration) configuration; + scim2Config.validate(); + this.configuration = scim2Config; + //super.init(configuration); + getConfiguration(); + LOG.info(">>> Connector initialization finished"); + } + @Override + public void dispose() { + configuration = null; + //handler = null; + } + @Override + public void test() { + LOG.info(">>> TestOp"); + try { + CloseableHttpClient client = HttpClients.createDefault(); + HttpRequestBase restHead; + restHead = new HttpHead(configuration.getServiceAddress() + "/scim/v2/onyen/Users"); + authHeader(restHead); + CloseableHttpResponse headResponse = client.execute(restHead); + processResponseErrors(headResponse); + } catch (IOException IOE) { + throw new ConnectorIOException(IOE.getMessage(), IOE); + } + + } + +/* + @Override + public void checkAlive() { + test(); + } +*/ + + private void authHeader(HttpRequest request) { + //request.setHeader(configuration.getTokenName(), configuration.getTokenValue()); + GuardedString guardedPassword = configuration.getPassword(); + GuardedStringAccessor accessor = new GuardedStringAccessor(); + guardedPassword.access(accessor); + String credentials = configuration.getUsername() + ":" + accessor.getClearString(); + //LOG.info("credentials--" + credentials); + //byte[] credentialBytes = credentials.getBytes(); + //String encodedCredentials = Base64.encode(credentials.getBytes()); + String encodedCredentials = Base64.getEncoder().encodeToString(credentials.getBytes()); + String credentialHeader = "Basic " + encodedCredentials; + LOG.info("credentialHeader--" + credentialHeader); + request.setHeader("Authorization", credentialHeader); + } + + @Override + public Schema schema() { + SchemaBuilder schemaBuilder = new SchemaBuilder(Scim2Connector.class); + //Begin Account Objectclass + Set accountAttributes = new HashSet(); + AttributeInfoBuilder id = new AttributeInfoBuilder(); + id.setName(ATTR_ID); + id.setCreateable(true); + id.setUpdateable(true); + id.setReadable(true); + id.setRequired(true); + id.setMultiValued(false); + accountAttributes.add(id.build()); + AttributeInfoBuilder externalId = new AttributeInfoBuilder(); + externalId.setName(ATTR_EXTERNAL_ID); + externalId.setCreateable(true); + externalId.setUpdateable(true); + externalId.setReadable(true); + externalId.setRequired(false); + externalId.setMultiValued(false); + accountAttributes.add(externalId.build()); + AttributeInfoBuilder userName = new AttributeInfoBuilder(); + userName.setName(ATTR_USER_NAME); + userName.setCreateable(true); + userName.setUpdateable(true); + userName.setReadable(true); + userName.setRequired(false); + userName.setMultiValued(false); + accountAttributes.add(userName.build()); + AttributeInfoBuilder active = new AttributeInfoBuilder(); + active.setName(ATTR_ACTIVE); + active.setCreateable(true); + active.setUpdateable(true); + active.setReadable(true); + active.setRequired(false); + active.setMultiValued(false); + accountAttributes.add(active.build()); + accountAttributes.add(OperationalAttributeInfos.ENABLE); + schemaBuilder.defineObjectClass(ObjectClass.ACCOUNT_NAME,accountAttributes); + //Finish Account Objectclass, add others before return if needed + LOG.info(">>> schema finished"); + return schemaBuilder.build(); + + + + } + + public FilterTranslator createFilterTranslator(ObjectClass oc, OperationOptions oo) { + LOG.info("inside createFilterTranslator"); + return new Scim2FilterTranslator(); + } + + @Override + public void executeQuery(ObjectClass oc, Scim2Filter filter, ResultsHandler handler, OperationOptions oo) { + LOG.info("starting executeQuery"); + LOG.info("ObjectClass.ACCOUNT_NAME is " + ObjectClass.ACCOUNT_NAME); + LOG.info("executeQuery ObjectClass is " + oc.getObjectClassValue() + "--"); + String Scim2Attributes = ""; + String Scim2ExcludedAttributes = ""; + String Scim2Filter = ""; + String Scim2SortBy = ""; + String Scim2SortOrder = ""; + String Scim2StartIndex = "0"; + String Scim2Count = "200"; + if (configuration.getScim2Attributes() != null && !StringUtil.isEmpty(configuration.getScim2Attributes())) { + Scim2Attributes = "attributes=" + configuration.getScim2Attributes(); + } + if (configuration.getScim2ExcludedAttributes() != null && !StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + Scim2ExcludedAttributes = "excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + if (configuration.getScim2Filter() != null && !StringUtil.isEmpty(configuration.getScim2Filter())) { + Scim2Filter = "filter=" + configuration.getScim2Filter(); + } + if (configuration.getScim2SortBy() != null && !StringUtil.isEmpty(configuration.getScim2SortBy())) { + Scim2SortBy = "sortBy=" + configuration.getScim2SortBy(); + } + if (configuration.getScim2SortOrder() != null && !StringUtil.isEmpty(configuration.getScim2SortOrder())) { + Scim2SortOrder = "sortOrder=" + configuration.getScim2SortOrder(); + } + if (configuration.getScim2StartIndex() != null && !StringUtil.isEmpty(configuration.getScim2StartIndex())) { + Scim2StartIndex = "startIndex=" + configuration.getScim2StartIndex(); + } + if (configuration.getScim2Count() != null && !StringUtil.isEmpty(configuration.getScim2Count())) { + Scim2Count = "count=" + configuration.getScim2Count(); + } + + + if ( oc.is(ObjectClass.ACCOUNT_NAME)) { + LOG.info("executeQuery ObjectClass.ACCOUNT_NAME"); + if (filter != null && filter.byUid != null) { + String searchId = filter.byUid; + String parameters = ""; + JSONObject uidSearchResponseJson = new JSONObject(); + if (!StringUtil.isEmpty(configuration.getScim2Attributes()) && !StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + parameters = "?attributes=" + configuration.getScim2Attributes() + "&excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + else if (!StringUtil.isEmpty(configuration.getScim2Attributes())) { + parameters = "?attributes=" + configuration.getScim2Attributes(); + } + else if (!StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + parameters = "?excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + HttpGet request = new HttpGet(configuration.getServiceAddress() + "/scim/v2/onyen/Users/" + searchId + parameters); + try { + uidSearchResponseJson = callRequest(request); + FileWriter file8 = new FileWriter("/tmp/file8.txt"); + file8.write(uidSearchResponseJson.toString()); + System.out.println("Successfully Copied JSON Object to File..."); + System.out.println("\nJSON Object: " + uidSearchResponseJson); + file8.flush(); + file8.close(); + //builder.setUid(new Uid(String.valueOf(uidSearchResponseJson.getInt(ATTR_ID)))); + handleUserId( handler, uidSearchResponseJson ); + } catch (IOException IOE) { + throw new ConnectorIOException(IOE.getMessage(), IOE); + } + + } + + else if (filter != null && filter.byName != null) { + String searchName = filter.byName; + String parameters = ""; + JSONObject nameSearchResponseJson = new JSONObject(); + if (!StringUtil.isEmpty(configuration.getScim2Attributes()) && !StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + parameters = "?attributes=" + configuration.getScim2Attributes() + "&excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + else if (!StringUtil.isEmpty(configuration.getScim2Attributes())) { + parameters = "?attributes=" + configuration.getScim2Attributes(); + } + else if (!StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + parameters = "?excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + HttpGet request = new HttpGet(configuration.getServiceAddress() + "/scim/v2/onyen/Users/" + searchName + parameters); + try { + nameSearchResponseJson = callRequest(request); + FileWriter file8 = new FileWriter("/tmp/file8.txt"); + file8.write(nameSearchResponseJson.toString()); + System.out.println("Successfully Copied JSON Object to File..."); + System.out.println("\nJSON Object: " + nameSearchResponseJson); + file8.flush(); + file8.close(); + //builder.setUid(new Uid(String.valueOf(uidSearchResponseJson.getInt(ATTR_ID)))); + handleUserId( handler, nameSearchResponseJson ); + } catch (IOException IOE) { + throw new ConnectorIOException(IOE.getMessage(), IOE); + } + + } + + else if (filter != null && filter.byExternalId != null) { + String searchExternalId = filter.byExternalId; + String parameters = ""; + Scim2Filter = "?filter=externalId+eq+%22" + searchExternalId + "%22"; + JSONObject externalIdSearchResponseJson = new JSONObject(); + if (!StringUtil.isEmpty(configuration.getScim2Attributes())) { + parameters = "&attributes=" + configuration.getScim2Attributes(); + } + if (!StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + parameters = parameters + "&excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + HttpGet request = new HttpGet(configuration.getServiceAddress() + "/scim/v2/onyen/Users/" + Scim2Filter + parameters); + try { + externalIdSearchResponseJson = callRequest(request); + FileWriter file8 = new FileWriter("/tmp/file8.txt"); + file8.write(externalIdSearchResponseJson.toString()); + System.out.println("Successfully Copied JSON Object to File..."); + System.out.println("\nJSON Object: " + externalIdSearchResponseJson); + file8.flush(); + file8.close(); + //builder.setUid(new Uid(String.valueOf(uidSearchResponseJson.getInt(ATTR_ID)))); + handleUserId( handler, externalIdSearchResponseJson ); + } catch (IOException IOE) { + throw new ConnectorIOException(IOE.getMessage(), IOE); + } + } + else { + //wide open search + Integer pagedResultsOffset = oo.getPagedResultsOffset(); + Integer startIndex = new Integer(Scim2StartIndex); + String parameters = ""; + if (!StringUtil.isEmpty(configuration.getScim2Attributes())) { + parameters = "&attributes=" + configuration.getScim2Attributes(); + } + if (!StringUtil.isEmpty(configuration.getScim2ExcludedAttributes())) { + parameters = parameters + "&excludedAttributes=" + configuration.getScim2ExcludedAttributes(); + } + if (!StringUtil.isEmpty(configuration.getScim2Filter())) { + parameters = parameters + "&filter=" + configuration.getScim2Filter(); + } + if (!StringUtil.isEmpty(configuration.getScim2SortBy())) { + parameters = parameters + "&sortBy=" + configuration.getScim2SortBy(); + } + if (!StringUtil.isEmpty(configuration.getScim2SortOrder())) { + parameters = parameters + "&sortOrder=" + configuration.getScim2SortOrder(); + } + boolean morePages = true; + while ( morePages ) { + try { + CloseableHttpClient client = HttpClients.createDefault(); + HttpRequestBase restGet; + restGet = new HttpGet(configuration.getServiceAddress() + "/scim/v2/onyen/Users/?startIndex=" + Scim2StartIndex + "&count=" + Scim2Count + parameters ); + authHeader(restGet); + //CloseableHttpResponse getResponse = client.execute(restGet); + //processResponseErrors(getResponse); + JSONObject searchResponseJson = new JSONObject(); + searchResponseJson = callRequest(restGet); + FileWriter file9 = new FileWriter("/tmp/file9.txt"); + file9.write(searchResponseJson.toString()); + System.out.println("Successfully Copied JSON Object to File..."); + System.out.println("\nJSON Object: " + searchResponseJson); + file9.flush(); + file9.close(); + JSONArray peopleArray = new JSONArray(); + if ( searchResponseJson.has("Resources") && searchResponseJson.get("Resources") != null ) { + peopleArray = searchResponseJson.getJSONArray("Resources"); + Integer Scim2CountInteger = new Integer(Scim2Count); + if ( peopleArray.length() < Scim2CountInteger ) { + morePages = false; + } + else { + startIndex = startIndex + Scim2CountInteger; + Scim2StartIndex = startIndex.toString(); + } + for ( int i = 0; i < peopleArray.length(); i++ ) { + JSONObject personJson = peopleArray.getJSONObject(i); + LOG.info(">>> processing ID " + i); + handleUserId( handler, personJson ); + } + } + else { + LOG.info("No data object found in response"); + } + + } catch (IOException IOE) { + throw new ConnectorIOException(IOE.getMessage(), IOE); + } + } + } + } + + } + + protected JSONObject callRequest(HttpRequestBase request) throws IOException { + // don't log request here - password field !!! + LOG.info("request URI: {0}", request.getURI()); + request.setHeader("Content-Type", CONTENT_TYPE); + CloseableHttpClient client = HttpClients.createDefault(); + authHeader(request); + CloseableHttpResponse response = client.execute(request); + LOG.info("response: "); + String responseText = EntityUtils.toString(response.getEntity()); + FileWriter file = new FileWriter("/tmp/file1.txt"); + file.write(responseText); + System.out.println("Successfully Copied JSON Object to File..."); + System.out.println("\nJSON Object: " + responseText); + file.flush(); + file.close(); + int statusCode = response.getStatusLine().getStatusCode(); + /* No status responses to handle yet + if (statusCode == 500) { + JSONObject errorResult = new JSONObject(responseText); + //JSONObject errorData = errorResult.getJSONObject("data"); + if (errorResult.getString("code").equals("existing_user_login")) { + closeResponse(response); + throw new AlreadyExistsException(jo.getString(ATTR_NAME)); + } + if (errorResult.getString("code").equals("existing_user_email")) { + closeResponse(response); + throw new AlreadyExistsException(jo.getString(ATTR_MAIL)); + } + } + if (statusCode == 404) { + JSONObject errorResult = new JSONObject(responseText); + //JSONObject errorData = errorResult.getJSONObject("data"); + if (errorResult.getString("code").equals("rest_user_invalid_id")) { + closeResponse(response); + throw new UnknownUidException(errorResult.toString()); + } + } + */ + processResponseErrors(response); + JSONObject result = new JSONObject (responseText); + LOG.info("response body: "); + closeResponse(response); + return result; + } + + protected JSONArray callRequestArray(HttpRequestBase request) throws IOException { + // don't log request here - password field !!! + LOG.info("request URI: {0}", request.getURI()); + request.setHeader("Content-Type", CONTENT_TYPE); + CloseableHttpClient client = HttpClients.createDefault(); + authHeader(request); + CloseableHttpResponse response = client.execute(request); + LOG.info("response: "); + String responseText = EntityUtils.toString(response.getEntity()); + FileWriter file = new FileWriter("/tmp/file2.txt"); + file.write(responseText); + System.out.println("Successfully Copied JSON Object to File..."); + System.out.println("\nJSON Object: " + responseText); + file.flush(); + file.close(); + processResponseErrors(response); + JSONArray result = new JSONArray (responseText); + LOG.info("response body: "); + closeResponse(response); + return result; + } + private void handleUserId ( ResultsHandler handler, JSONObject uidSearchResponseJson ) { + LOG.info("inside handleUserId " + String.valueOf(uidSearchResponseJson.getString(ATTR_ID))); + ConnectorObjectBuilder builder = new ConnectorObjectBuilder(); + builder.setUid(new Uid(String.valueOf(uidSearchResponseJson.getString(ATTR_ID)))); + //JSONObject attributes = new JSONObject(); + //if ( uidSearchResponseJson.has("attributes") && uidSearchResponseJson.get("attributes") != null ) { + // attributes = (JSONObject) uidSearchResponseJson.get("attributes"); + //} + //builder.setUid(new Uid(String.valueOf(id))); + String [] potentialAttributes = { ATTR_ID, ATTR_EXTERNAL_ID, ATTR_USER_NAME, ATTR_ACTIVE}; + for ( String potentialAttribute: potentialAttributes ) { + LOG.info(">>> checking for attribute " + potentialAttribute ); + if ( uidSearchResponseJson.has(potentialAttribute) && uidSearchResponseJson.get(potentialAttribute) != null && !JSONObject.NULL.equals(uidSearchResponseJson.get(potentialAttribute)) ) { + LOG.info(">>> found attribute " + potentialAttribute ); + if ( potentialAttribute.equals(ATTR_USER_NAME) ) { + //builder.setName(attributes.getString(potentialAttribute)); + builder.setName(uidSearchResponseJson.getString(ATTR_USER_NAME)); + } + if ( potentialAttribute.equals(ATTR_ID) ) { + builder.setUid(uidSearchResponseJson.getString(ATTR_ID)); + } + if ( potentialAttribute.equals(ATTR_ACTIVE) ) { + addAttr(builder, potentialAttribute, uidSearchResponseJson.getBoolean(potentialAttribute)); + } + else { + addAttr(builder, potentialAttribute, uidSearchResponseJson.getString(potentialAttribute)); + } + } + } + ConnectorObject connectorObject = builder.build(); + handler.handle(connectorObject); + } + +} diff --git a/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Filter.java b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Filter.java new file mode 100644 index 0000000..749839d --- /dev/null +++ b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Filter.java @@ -0,0 +1,19 @@ +package edu.unc.polygon.connector.scim2; + +/** + * + */ +public class Scim2Filter { + public String byName; + public String byUid; + public String byExternalId; + + @Override + public String toString() { + return "Scim2Filter{" + + "byName='" + byName + '\'' + + ", byUid=" + byUid + + ", byExternalId='" + byExternalId + '\'' + + '}'; + } +} diff --git a/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.java b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.java new file mode 100644 index 0000000..7371d5c --- /dev/null +++ b/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.java @@ -0,0 +1,64 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package edu.unc.polygon.connector.scim2; + +import org.identityconnectors.common.logging.Log; +import org.identityconnectors.framework.common.objects.Attribute; +import org.identityconnectors.framework.common.objects.Name; +import org.identityconnectors.framework.common.objects.Uid; +import org.identityconnectors.framework.common.objects.filter.AbstractFilterTranslator; +import org.identityconnectors.framework.common.objects.filter.EqualsFilter; + +/** + */ +public class Scim2FilterTranslator extends AbstractFilterTranslator { + private static final Log LOG = Log.getLog(Scim2FilterTranslator.class); + + @Override + protected Scim2Filter createEqualsExpression(EqualsFilter filter, boolean not) { + LOG.ok("createEqualsExpression, filter: {0}, not: {1}", filter, not); + + if (not) { + return null; // not supported + } + + Attribute attr = filter.getAttribute(); + LOG.ok("attr.getName: {0}, attr.getValue: {1}, Uid.NAME: {2}, Name.NAME: {3}", attr.getName(), attr.getValue(), Uid.NAME, Name.NAME); + if (Uid.NAME.equals(attr.getName())) { + if (attr.getValue() != null && attr.getValue().get(0) != null) { + Scim2Filter lf = new Scim2Filter(); + lf.byUid = String.valueOf(attr.getValue().get(0)); + LOG.ok("lf.byUid: {0}, attr.getValue().get(0): {1}", lf.byUid, attr.getValue().get(0)); + return lf; + } + } + else if (Name.NAME.equals(attr.getName())) { + if (attr.getValue() != null && attr.getValue().get(0) != null) { + Scim2Filter lf = new Scim2Filter(); + lf.byName = String.valueOf(attr.getValue().get(0)); + return lf; + } + } + else if (Scim2Connector.ATTR_EXTERNAL_ID.equals(attr.getName())) { + if (attr.getValue() != null && attr.getValue().get(0) != null) { + Scim2Filter lf = new Scim2Filter(); + lf.byExternalId = String.valueOf(attr.getValue().get(0)); + return lf; + } + } + + return null; // not supported + } +} diff --git a/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Configuration.class b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Configuration.class new file mode 100644 index 0000000..a3e223a Binary files /dev/null and b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Configuration.class differ diff --git a/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Connector.class b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Connector.class new file mode 100644 index 0000000..1b65555 Binary files /dev/null and b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Connector.class differ diff --git a/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Filter.class b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Filter.class new file mode 100644 index 0000000..b95a371 Binary files /dev/null and b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2Filter.class differ diff --git a/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.class b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.class new file mode 100644 index 0000000..87b7f3c Binary files /dev/null and b/connector-scim2/target/classes/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.class differ diff --git a/connector-scim2/target/connector-scim2-.1-SNAPSHOT.jar b/connector-scim2/target/connector-scim2-.1-SNAPSHOT.jar new file mode 100644 index 0000000..a1ed350 Binary files /dev/null and b/connector-scim2/target/connector-scim2-.1-SNAPSHOT.jar differ diff --git a/connector-scim2/target/maven-archiver/pom.properties b/connector-scim2/target/maven-archiver/pom.properties new file mode 100644 index 0000000..2268583 --- /dev/null +++ b/connector-scim2/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Fri Feb 07 09:09:02 EST 2020 +version=.1-SNAPSHOT +groupId=edu.unc.polygon +artifactId=connector-scim2 diff --git a/connector-scim2/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/connector-scim2/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..a5c0a85 --- /dev/null +++ b/connector-scim2/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,4 @@ +edu/unc/polygon/connector/scim2/Scim2FilterTranslator.class +edu/unc/polygon/connector/scim2/Scim2Configuration.class +edu/unc/polygon/connector/scim2/Scim2Connector.class +edu/unc/polygon/connector/scim2/Scim2Filter.class diff --git a/connector-scim2/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/connector-scim2/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..891eca4 --- /dev/null +++ b/connector-scim2/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,4 @@ +/home/ekromhout/src/midpoint-connectors/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Connector.java +/home/ekromhout/src/midpoint-connectors/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Configuration.java +/home/ekromhout/src/midpoint-connectors/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2FilterTranslator.java +/home/ekromhout/src/midpoint-connectors/connector-scim2/src/main/java/edu/unc/polygon/connector/scim2/Scim2Filter.java