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