From f3701b7f3ffdb1a0498842d6ad14e42fe1605c68 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Tue, 26 Mar 2019 23:12:18 +0100 Subject: [PATCH] Implement stem-less operation --- pom.xml | 2 +- .../grouper/rest/AccountProcessor.java | 35 +- .../grouper/rest/GroupProcessor.java | 73 +- .../grouper/rest/GrouperConfiguration.java | 82 ++- .../grouper/rest/GrouperConnector.java | 3 +- .../connector/grouper/rest/Processor.java | 670 +----------------- .../connector/grouper/test/GroupTests.java | 1 + .../grouper/test/GrouperTestHelper.java | 2 +- 8 files changed, 155 insertions(+), 713 deletions(-) diff --git a/pom.xml b/pom.xml index 7cf04c6..d37b3e5 100644 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ connector-grouper-rest - 0.1 + 0.2 jar Grouper REST Connector diff --git a/src/main/java/com/evolveum/polygon/connector/grouper/rest/AccountProcessor.java b/src/main/java/com/evolveum/polygon/connector/grouper/rest/AccountProcessor.java index c33afc4..670b9e9 100644 --- a/src/main/java/com/evolveum/polygon/connector/grouper/rest/AccountProcessor.java +++ b/src/main/java/com/evolveum/polygon/connector/grouper/rest/AccountProcessor.java @@ -1,4 +1,5 @@ -/******************************************************************************* +/* + ****************************************************************************** * Copyright 2017 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +25,7 @@ import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import static com.evolveum.polygon.connector.grouper.rest.Processor.*; @@ -32,13 +34,13 @@ * @author mederly * */ -public class AccountProcessor { +class AccountProcessor { private final Processor processor; - public static final String ATTR_GROUP = "group"; + private static final String ATTR_GROUP = "group"; - public AccountProcessor(Processor processor) { + AccountProcessor(Processor processor) { this.processor = processor; } @@ -151,13 +153,11 @@ private void getUser(String id, ResultsHandler handler) { private List selectGroupNames(JSONArray groups) { List rv = new ArrayList<>(); - String expectedPrefix = getConfiguration().getRootStem() + ":"; for (Object group : groups) { if (group instanceof JSONObject) { JSONObject gObject = (JSONObject) group; String name = processor.getStringOrNull(gObject, "name"); - String extension = processor.getStringOrNull(gObject, "extension"); - if (name != null && name.equals(expectedPrefix + extension)) { + if (groupNameMatches(name)) { rv.add(name); } } else { @@ -167,6 +167,27 @@ private List selectGroupNames(JSONArray groups) { return rv; } + private boolean groupNameMatches(String name) { + if (name == null) { + return false; + } + return groupNameMatches(name, getConfiguration().getGroupIncludePattern()) && + !groupNameMatches(name, getConfiguration().getGroupExcludePattern()); + } + + private boolean groupNameMatches(String name, String[] patterns) { + if (patterns == null) { + return false; + } + for (String pattern : patterns) { + Pattern compiled = Pattern.compile(pattern); + if (compiled.matcher(name).matches()) { + return true; + } + } + return false; + } + private GrouperConfiguration getConfiguration() { return processor.configuration; } diff --git a/src/main/java/com/evolveum/polygon/connector/grouper/rest/GroupProcessor.java b/src/main/java/com/evolveum/polygon/connector/grouper/rest/GroupProcessor.java index 9e4f6c1..d9f9bcf 100644 --- a/src/main/java/com/evolveum/polygon/connector/grouper/rest/GroupProcessor.java +++ b/src/main/java/com/evolveum/polygon/connector/grouper/rest/GroupProcessor.java @@ -30,13 +30,13 @@ * @author mederly * */ -public class GroupProcessor { +class GroupProcessor { private final Processor processor; private static final String ATTR_EXTENSION = "extension"; - public GroupProcessor(Processor processor) { + GroupProcessor(Processor processor) { this.processor = processor; } @@ -90,11 +90,12 @@ private void getAllGroups(ResultsHandler handler) { try { HttpPost request = new HttpPost(uriBuilder.build()); JSONObject body = new JSONObject() - .put("WsRestFindGroupsRequest", new JSONObject() - .put("wsQueryFilter", new JSONObject() - .put("queryFilterType", "FIND_BY_STEM_NAME") - .put("stemName", getConfiguration().getRootStem()))); - executeFindGroupsResponse(request, body, handler); + .put("WsRestGetMembersRequest", new JSONObject() + .put("wsGroupLookups", new JSONObject[] { new JSONObject() + .put("groupName", getConfiguration().getSuperGroup()) }) + .put("includeSubjectDetail", true) + .put("memberFilter", "Immediate")); + executeFindGroupsAsMembersResponse(request, body, handler); } catch (RuntimeException | URISyntaxException e) { throw processor.processException(e, uriBuilder, "Get all groups"); } @@ -107,7 +108,20 @@ private void executeFindGroupsResponse(HttpPost request, JSONObject body, Result processor.checkSuccess(response, "WsFindGroupsResults"); JSONArray groups = processor.getArray(response, "WsFindGroupsResults", "groupResults"); for (Object group : groups) { - if (!handlerGroupJsonObject(group, handler)) { + if (!handleGroupJsonObject(group, handler)) { + return; + } + } + } + + private void executeFindGroupsAsMembersResponse(HttpPost request, JSONObject body, ResultsHandler handler) { + System.out.println("Request = " + body.toString()); + JSONObject response = processor.callRequest(request, body, true, CONTENT_TYPE_JSON); + System.out.println("Got response: " + response); + processor.checkSuccess(response, WS_GET_MEMBERS_RESULTS); + JSONArray groups = processor.getArray(response, WS_GET_MEMBERS_RESULTS, RESULTS, WS_SUBJECTS); + for (Object group : groups) { + if (!handleGroupAsMemberJsonObject(group, handler)) { return; } } @@ -143,7 +157,7 @@ private void getGroupByUuid(String groupUuid, ResultsHandler handler) { } } - private boolean handlerGroupJsonObject(Object group, ResultsHandler handler) { + private boolean handleGroupJsonObject(Object group, ResultsHandler handler) { if (group instanceof JSONObject) { JSONObject gObject = (JSONObject) group; String name = processor.getStringOrNull(gObject, "name"); @@ -160,8 +174,49 @@ private boolean handlerGroupJsonObject(Object group, ResultsHandler handler) { } } + private boolean handleGroupAsMemberJsonObject(Object group, ResultsHandler handler) { + if (group instanceof JSONObject) { + JSONObject gObject = (JSONObject) group; + String sourceId = processor.getStringOrNull(gObject, "sourceId"); + if (sourceId == null || !sourceId.equals(getConfiguration().getGroupSource())) { + LOG.info("Skipping non-group member (source={0})", sourceId); + return true; + } + String name = processor.getStringOrNull(gObject, "name"); + String id = processor.getStringOrNull(gObject, "id"); + ConnectorObjectBuilder builder = new ConnectorObjectBuilder(); + builder.setObjectClass(ObjectClass.GROUP); + builder.setUid(id); + builder.setName(name); + return handler.handle(builder.build()); + } else { + throw new IllegalStateException("Expected group as JSONObject, got " + group); + } + } + private GrouperConfiguration getConfiguration() { return processor.configuration; } + void test() { + URIBuilder uriBuilder = processor.getURIBuilder().setPath(URI_BASE_PATH + PATH_GROUPS); + try { + HttpPost request = new HttpPost(uriBuilder.build()); + JSONObject body = new JSONObject() + .put("WsRestGetMembersRequest", new JSONObject() + .put("wsGroupLookups", new JSONObject[] { new JSONObject() + .put("groupName", getConfiguration().getSuperGroup()) }) + .put("includeSubjectDetail", true) + .put("memberFilter", "Immediate")); + System.out.println("Request = " + body.toString()); + JSONObject response = processor.callRequest(request, body, true, CONTENT_TYPE_JSON); + System.out.println("Got response: " + response); + processor.checkSuccess(response, WS_GET_MEMBERS_RESULTS); + JSONArray groups = processor.getArray(response, WS_GET_MEMBERS_RESULTS, RESULTS, WS_SUBJECTS); + System.out.println("Super-group members found: " + groups.length()); + } catch (RuntimeException | URISyntaxException e) { + throw processor.processException(e, uriBuilder, "Test"); + } + } + } diff --git a/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConfiguration.java b/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConfiguration.java index ffa0e5d..040ffa1 100644 --- a/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConfiguration.java +++ b/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConfiguration.java @@ -23,22 +23,29 @@ import org.identityconnectors.framework.spi.ConfigurationProperty; import org.identityconnectors.framework.spi.StatefulConfiguration; +import java.util.Arrays; + /** * @author surmanek * @author mederly * */ +@SuppressWarnings("WeakerAccess") public class GrouperConfiguration extends AbstractConfiguration implements StatefulConfiguration { private static final Log LOG = Log.getLog(GrouperConfiguration.class); - private String name; - private GuardedString password; + private static final String DEFAULT_GROUP_SOURCE_ID = "g:gsa"; + private String baseUrl; + private String username; + private GuardedString password; private String superGroup; - private String rootStem; + private String[] groupIncludePattern; + private String[] groupExcludePattern; private Boolean ignoreSslValidation; private String subjectSource; + private String groupSource; // getter and setter methods for "baseUrl" attribute: @ConfigurationProperty(order = 1, displayMessageKey = "baseUrl.display", helpMessageKey = "baseUrl.help", required = true) @@ -50,21 +57,23 @@ public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; } - // getter and setter methods for "name" attribute: + // getter and setter methods for "username" attribute: @ConfigurationProperty(order = 2, displayMessageKey = "username.display", helpMessageKey = "username.help", required = true) public String getUsername() { - return name; + return username; } public void setUsername(String name) { - this.name = name; + this.username = name; } private String stringPassword = ""; + @ConfigurationProperty(order = 3, displayMessageKey = "password.display", helpMessageKey = "password.help", required = true, confidential = false) public GuardedString getPassword() { return password; } + public void setPassword(GuardedString password) { this.password = password; } @@ -88,16 +97,25 @@ public void setSuperGroup(String superGroup) { this.superGroup = superGroup; } - @ConfigurationProperty(order = 5, displayMessageKey = "rootStem.display", helpMessageKey = "superGroup.help", required = true) - public String getRootStem() { - return rootStem; + @ConfigurationProperty(order = 5, displayMessageKey = "groupIncludePattern.display", helpMessageKey = "groupIncludePattern.help", required = true) + public String[] getGroupIncludePattern() { + return groupIncludePattern; + } + + public void setGroupIncludePattern(String[] groupIncludePattern) { + this.groupIncludePattern = groupIncludePattern; + } + + @ConfigurationProperty(order = 6, displayMessageKey = "groupExcludePattern.display", helpMessageKey = "groupExcludePattern.help", required = true) + public String[] getGroupExcludePattern() { + return groupExcludePattern; } - public void setRootStem(String rootStem) { - this.rootStem = rootStem; + public void setGroupExcludePattern(String[] groupExcludePattern) { + this.groupExcludePattern = groupExcludePattern; } - @ConfigurationProperty(order = 6, displayMessageKey = "ignoreSslValidation.display", helpMessageKey = "ignoreSslValidation.help", required = false) + @ConfigurationProperty(order = 7, displayMessageKey = "ignoreSslValidation.display", helpMessageKey = "ignoreSslValidation.help") public Boolean getIgnoreSslValidation() { return ignoreSslValidation; } @@ -106,7 +124,7 @@ public void setIgnoreSslValidation(Boolean ignoreSslValidation) { this.ignoreSslValidation = ignoreSslValidation; } - @ConfigurationProperty(order = 7, displayMessageKey = "subjectSource.display", helpMessageKey = "subjectSource.help", required = false) + @ConfigurationProperty(order = 8, displayMessageKey = "subjectSource.display", helpMessageKey = "subjectSource.help", required = true) public String getSubjectSource() { return subjectSource; } @@ -115,19 +133,28 @@ public void setSubjectSource(String subjectSource) { this.subjectSource = subjectSource; } + @ConfigurationProperty(order = 9, displayMessageKey = "groupSource.display", helpMessageKey = "groupSource.help") + public String getGroupSource() { + return groupSource != null ? groupSource : DEFAULT_GROUP_SOURCE_ID; + } + + public void setGroupSource(String groupSource) { + this.groupSource = groupSource; + } + @Override public void validate() { String exceptionMsg; if (baseUrl == null || StringUtil.isBlank(baseUrl)) { exceptionMsg = "Base url is not provided."; - } else if (name == null || StringUtil.isBlank(name)) { + } else if (username == null || StringUtil.isBlank(username)) { exceptionMsg = "Name is not provided."; } else if (password == null) { exceptionMsg = "Password is not provided."; } else if (superGroup == null) { exceptionMsg = "Super group is not provided."; - } else if (rootStem == null) { - exceptionMsg = "Root stem is not provided."; + } else if (groupIncludePattern == null || groupIncludePattern.length == 0) { + exceptionMsg = "Group include pattern is not provided."; } else if (subjectSource == null) { exceptionMsg = "Subject source is not provided."; } else { @@ -140,22 +167,27 @@ public void validate() { @Override public void release() { LOG.info("The release of configuration resources is being performed"); - this.password = null; - this.name = null; this.baseUrl = null; + this.password = null; + this.username = null; this.superGroup = null; - this.rootStem = null; + this.groupIncludePattern = null; + this.groupExcludePattern = null; + this.subjectSource = null; + this.groupSource = null; } - + @Override public String toString() { return "GrouperConfiguration{" + - "username='" + name + '\'' + - ", baseUrl='" + baseUrl + '\'' + + "baseUrl='" + baseUrl + '\'' + + ", username='" + username + '\'' + ", superGroup='" + superGroup + '\'' + - ", rootStem='" + rootStem + '\'' + - ", ignoreSslValidation='" + ignoreSslValidation + '\'' + + ", groupIncludePattern=" + Arrays.toString(groupIncludePattern) + + ", groupExcludePattern=" + Arrays.toString(groupExcludePattern) + + ", ignoreSslValidation=" + ignoreSslValidation + + ", subjectSource='" + subjectSource + '\'' + + ", groupSource='" + groupSource + '\'' + '}'; } - } diff --git a/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConnector.java b/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConnector.java index 8f63944..8ca1194 100644 --- a/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConnector.java +++ b/src/main/java/com/evolveum/polygon/connector/grouper/rest/GrouperConnector.java @@ -34,7 +34,6 @@ * */ @ConnectorClass(displayNameKey = "GrouperConnector.rest.display", configurationClass = GrouperConfiguration.class) - public class GrouperConnector implements TestOp, SchemaOp, Connector, SearchOp { private static final Log LOG = Log.getLog(GrouperConnector.class); @@ -76,7 +75,7 @@ public void dispose() { @Override public void test() { LOG.info("Testing connection..."); - processor.test(); + groupProcessor.test(); LOG.ok("Testing finished successfully."); } diff --git a/src/main/java/com/evolveum/polygon/connector/grouper/rest/Processor.java b/src/main/java/com/evolveum/polygon/connector/grouper/rest/Processor.java index 78ff601..a5f8fa4 100644 --- a/src/main/java/com/evolveum/polygon/connector/grouper/rest/Processor.java +++ b/src/main/java/com/evolveum/polygon/connector/grouper/rest/Processor.java @@ -13,13 +13,8 @@ ******************************************************************************/ package com.evolveum.polygon.connector.grouper.rest; -import org.apache.batik.transcoder.TranscoderException; -import org.apache.batik.transcoder.TranscoderInput; -import org.apache.batik.transcoder.TranscoderOutput; -import org.apache.batik.transcoder.image.JPEGTranscoder; import org.apache.commons.codec.binary.Base64; import org.apache.http.HttpEntity; -import org.apache.http.NameValuePair; import org.apache.http.client.methods.*; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.ssl.NoopHostnameVerifier; @@ -31,19 +26,14 @@ import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.util.EntityUtils; import org.identityconnectors.common.logging.Log; -import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.common.exceptions.*; import org.identityconnectors.framework.common.objects.*; import org.identityconnectors.framework.common.objects.filter.*; import org.json.JSONArray; import org.json.JSONObject; -import javax.imageio.ImageIO; -import java.awt.*; -import java.awt.image.BufferedImage; import java.io.*; import java.net.URISyntaxException; -import java.net.URLConnection; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -80,59 +70,10 @@ public class Processor { public static final String PATH_GROUPS = "/groups"; public static final String PATH_SUBJECTS = "/subjects"; - - static final String URI_USER_PATH = "/user"; - static final String URI_SEARCH_PATH = "/search"; - static final String PARAM_USERNAME = "username"; - static final String PARAM_START_AT = "startAt"; - static final String PARAM_MAX_RESULTS = "maxResults"; - static final String ATTR_GROUPS = "groups"; - static final String ATTR_AVATAR_URLS = "avatarUrls"; - - static final String USER_NAME = "USER"; - static final String PROJECT_NAME = "PROJECT"; - - static final String URI_PASSWORD_PATH = "/password"; - static final String URI_TEMP_AVATAR_PATH = "/avatar/temporary"; - static final String URI_AVATAR_PATH = "/avatar"; - static final String URI_GROUP_PATH = "/group"; - static final String URI_GROUPS_PICKER_PATH = "/groups/picker"; - static final String URI_PROJECT_PATH = "/project"; - - static final String PARAM_FILENAME = "filename"; - static final String PARAM_KEY = "key"; - static final String CONTENT_TYPE_JPEG_IMAGE = "image/jpeg"; - static final String UID = "key"; - - // project: - static final String ATTR_DEVELOPERS_GROUPS = "Developers.groups"; - static final String ATTR_DEVELOPERS_USERS = "Developers.users"; - static final String ATTR_ADMINISTRATORS_GROUPS = "Administrators.groups"; - static final String ATTR_ADMINISTRATORS_USERS = "Administrators.users"; - static final String ATTR_ACTOR_USER = "user"; - static final String ATTR_ACTOR_GROUP = "group"; - static final String ATTR_DEVELOPERS = "Developers"; - static final String ATTR_ADMINISTRATORS = "Administrators"; - - // user+project: - static final String ATTR_KEY = "key"; - static final String ATTR_AVATAR_BYTE_ARRRAY = "binaryAvatar"; - // user+group: - static final String ATTR_SELF = "self"; - static final String ATTR_NAME = "name"; - static final String ATTR_EXPAND = "expand"; - - static final String MIDPOINT_NAME = "__NAME__"; - static final boolean IS_MULTI_VALUE = true; - static final boolean IS_SINGLE_VALUE = false; - static final String EXTENDED_ATTR_NAME = "name"; - static final String EXTENDED_ATTR_ITEMS = "items"; - public Processor(GrouperConfiguration configuration) { this.configuration = configuration; } - //put objects of array1 to the end of array2 private JSONArray concatJSONArrays(JSONArray array1, JSONArray array2){ for (Object obj : array1){ @@ -141,7 +82,6 @@ private JSONArray concatJSONArrays(JSONArray array1, JSONArray array2){ return array2; } - JSONObject callRequest(HttpEntityEnclosingRequestBase request, JSONObject jo, Boolean parseResult, String contentType) { // don't log request here - password field !!! @@ -213,31 +153,6 @@ JSONObject callRequest(HttpRequestBase request, Boolean parseResult, String cont } } - JSONArray callRequest(HttpRequestBase request) { - //CloseableHttpResponse response = null; - LOG.ok("request URI: {0}", request.getURI()); - request.addHeader("Content-Type", CONTENT_TYPE_JSON); - request.addHeader("Authorization", "Basic " + authEncoding()); - try (CloseableHttpResponse response = execute(request)) { - - //response = execute(request); - LOG.ok("Response: {0}", response); - processResponseErrors(response); - // DO NOT USE getEntity() TWICE!!! - String result = EntityUtils.toString(response.getEntity()); - //closeResponse(response); - LOG.ok("Response body: {0}", result); - return new JSONArray(result); - } catch (IOException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Request failed: problem occured during execute request with URI: ") - .append(request.getURI()).append(": \n\t").append(e.getLocalizedMessage()); - //closeResponse(response); - LOG.error(exceptionMsg.toString()); - throw new ConnectorIOException(exceptionMsg.toString(), e); - } - } - String authEncoding() { String username = configuration.getUsername(); String password = configuration.getStringPassword(); @@ -358,11 +273,11 @@ void processResponseErrors(CloseableHttpResponse response) { if (statusCode == 418) { closeResponse(response); LOG.error(message.toString()); - throw new UnsupportedOperationException("Sorry, no cofee: " + message.toString()); + throw new UnsupportedOperationException("Sorry, no coffee: " + message.toString()); } closeResponse(response); - LOG.error(message.toString()); + LOG.error("{0}", message.toString()); throw new ConnectorException(message.toString()); } @@ -376,17 +291,6 @@ void closeResponse(CloseableHttpResponse response) { LOG.warn(e, "Failed to close response: " + response); } } - - void closeClient(CloseableHttpClient client){ - if (client == null){ - return; - } - try { - client.close(); - } catch (IOException e) { - LOG.warn(e, "Failed to close client."); - } - } // filter json objects by substring: JSONArray substringFiltering(JSONArray inputJsonArray, String attrName, String subValue) { @@ -411,48 +315,6 @@ JSONArray substringFiltering(JSONArray inputJsonArray, String attrName, String s return jsonArrayOut; } - JSONArray startsWithFiltering(Filter query, Attribute attr, OperationOptions options, String objClass) { - String attrValue = attr.getValue().get(0).toString(); - HttpGet request; - URIBuilder getUri = null; - if (attrValue != null) { - try { - getUri = getURIBuilder(); - getUri.setPath(URI_BASE_PATH + URI_USER_PATH + URI_SEARCH_PATH); - getUri.addParameter(PARAM_USERNAME, attrValue); - if (options.getPagedResultsOffset() != null || options.getPageSize() != null) { - int pageNumber = options.getPagedResultsOffset(); - int usersPerPage = options.getPageSize(); - int startAt = (pageNumber * usersPerPage) - usersPerPage; - //LOG.info("\n\tpage: {0}, users per page {1}, start at: {2}", pageNumber, usersPerPage, startAt); - getUri.addParameter(PARAM_MAX_RESULTS, String.valueOf(usersPerPage)); - getUri.addParameter(PARAM_START_AT, String.valueOf(startAt)); - } - ; - request = new HttpGet(getUri.build()); - - JSONArray objectsArray = new JSONArray(); - if (objClass.equals(ObjectClass.GROUP_NAME)) { - JSONObject object = callRequest(request, true, CONTENT_TYPE_JSON); - objectsArray = object.getJSONArray(ATTR_GROUPS); - } - if (objClass.equals(ObjectClass.ACCOUNT_NAME) || objClass.equals(PROJECT_NAME)) { - objectsArray = callRequest(request); - } - // handleObjects(objectsArray, handler, options, objClass); - return objectsArray; - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Get operation failed: problem occurred during executing URI: ").append(getUri) - .append(", using attribute: ").append(attrValue).append("\n\t").append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } else - throwNullAttrException(query); - return null; - } - // method called when attribute of query filter is null: void throwNullAttrException(Filter query) { StringBuilder exceptionMsg = new StringBuilder(); @@ -474,503 +336,8 @@ URIBuilder getURIBuilder() { } } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // avatar processing: - void createOrUpdateAvatar(byte[] avatar, String uid, String objectName) { - // crop image to square and resize it to needed size: - byte[] resizedImage = resizeAndCropImage(avatar, 48, 48); - String username = null, key = null; - - CloseableHttpClient client = HttpClientBuilder.create().build(); - - boolean needsCropping = false; - int cropperWidth, cropperOffsetX, cropperOffsetY; - JSONObject cropBody = new JSONObject(); - URIBuilder uri = getURIBuilder(); - JSONObject responseObject = new JSONObject(); - String avatarId = null; - - // delete old avatar before the new one will be successfully set: - deleteAvatar(uid, objectName); - - // uri for uploading user avatar: - if (objectName.equals(USER_NAME)) { // USER - username = getUsernameFromUid(uid); - uri.setPath(URI_BASE_PATH + URI_USER_PATH + URI_TEMP_AVATAR_PATH); - uri.addParameter(PARAM_USERNAME, username); - uri.addParameter(PARAM_FILENAME, username + ".jpeg"); - } - - // uri for uploading project avatar - if (objectName.equals(PROJECT_NAME)) { // PROJECT - key = getProjectKeyFromUid(uid); - uri.setPath(URI_BASE_PATH + URI_PROJECT_PATH + "/" + key + URI_TEMP_AVATAR_PATH); - uri.addParameter(PARAM_FILENAME, key + ".jpeg"); - // LOGGER.info("\n\tupload project avatar: {0}", uri.toString()); - } - - HttpEntityEnclosingRequestBase postRequest; - HttpEntityEnclosingRequestBase putRequest; - CloseableHttpResponse response = null; - // 1st step: upload avatar: - try { - postRequest = new HttpPost(uri.build()); - if (resizedImage != null) { - postRequest.setHeader("X-Atlassian-Token", "no-check"); - postRequest.setHeader("Authorization", "Basic YWRtaW5pc3RyYXRvcjp0cmFpbmluZw=="); - postRequest.setHeader("Content-Type", CONTENT_TYPE_JPEG_IMAGE); - postRequest.setEntity(new ByteArrayEntity(resizedImage)); - - response = (CloseableHttpResponse) client.execute(postRequest); - // print response code: - //LOG.ok("response code: {0}", String.valueOf(response.getStatusLine().getStatusCode())); - // client.close(); - // DO NOT CLOSE response HERE !!! - processResponseErrors(response); - String result = EntityUtils.toString(response.getEntity()); - - closeResponse(response); - responseObject = new JSONObject(result); - - if (responseObject.has("needsCropping")) { - needsCropping = "true".equals(responseObject.get("needsCropping").toString()); - // LOGGER.info("\n\tneedsCropping-{0}", needsCropping); - } - if (responseObject.has("cropperWidth")) { - cropperWidth = (int) responseObject.get("cropperWidth"); - // LOGGER.info("\n\tcropperWidth-{0}", cropperWidth); - cropBody.put("cropperWidth", cropperWidth); - } - if (responseObject.has("cropperOffsetX")) { - cropperOffsetX = (int) responseObject.get("cropperOffsetX"); - // LOGGER.info("\n\tcropperOffsetX-{0}",cropperOffsetX); - cropBody.put("cropperOffsetX", cropperOffsetX); - } - if (responseObject.has("cropperOffsetY")) { - cropperOffsetY = (int) responseObject.get("cropperOffsetY"); - // LOGGER.info("\n\tcropperOffsetY-{0}", cropperOffsetY); - cropBody.put("cropperOffsetY", cropperOffsetY); - } - if (responseObject.has("id")) { - avatarId = responseObject.getString("id"); - // LOGGER.info("\n\tid-{0}", cropperOffsetY); - } - } - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Uploading of the avatar failed: problem occurred during building URI: ").append(uri) - .append("\n\t").append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } catch (IOException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Uploading of the avatar failed: problem occured during request execution: \n\t") - .append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorIOException(exceptionMsg.toString()); - } - // 2nd step: crop avatar: - if (needsCropping) { - uri.removeQuery(); - if (objectName.equals(USER_NAME)) { // USER - uri.setPath(URI_BASE_PATH + URI_USER_PATH + URI_AVATAR_PATH); - uri.addParameter(PARAM_USERNAME, username); - } - if (objectName.equals(PROJECT_NAME)) { // PROJECT - uri.setPath(URI_BASE_PATH + URI_PROJECT_PATH + "/" + key + URI_AVATAR_PATH); - LOG.info("\n\tcrop project avatar: {0}", uri.toString()); - } - try { - postRequest = new HttpPost(uri.build()); - postRequest.setHeader("X-Atlassian-Token", "no-check"); - postRequest.setHeader("Content-Type", CONTENT_TYPE_JSON); - - HttpEntity entity = new ByteArrayEntity(cropBody.toString().getBytes("UTF-8")); - postRequest.setEntity(entity); - - response = (CloseableHttpResponse) client.execute(postRequest); - // print response code: - LOG.ok("response code: {0}", String.valueOf(response.getStatusLine().getStatusCode())); - // client.close(); - // DO NOT CLOSE response HERE !!! - processResponseErrors(response); - String result = EntityUtils.toString(response.getEntity()); - - closeResponse(response); - LOG.ok("response body: {0}", result); - responseObject = new JSONObject(result); - - avatarId = responseObject.getString("id"); - // LOGGER.info("\n\t2nd step: {0}", responseObject.toString()); - - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Cropping of the avatar failed: problem occurred during building URI: ").append(uri) - .append("\n\t").append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } catch (UnsupportedEncodingException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg - .append("Cropping of the avatar failed: problem occurred during encoding request body for URI: ") - .append(uri).append("\n\t").append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } catch (IOException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Cropping of the avatar failed: problem occured during request execution: \n\t") - .append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorIOException(exceptionMsg.toString()); - } - - } - // 3rd step: confirm avatar: - - try { - uri.removeQuery(); - if (objectName.equals(USER_NAME)) { // USER - uri.setPath(URI_BASE_PATH + URI_USER_PATH + URI_AVATAR_PATH); - uri.addParameter(PARAM_USERNAME, username); - } - if (objectName.equals(PROJECT_NAME)) { // PROJECT - uri.setPath(URI_BASE_PATH + URI_PROJECT_PATH + "/" + key + URI_AVATAR_PATH); - LOG.info("\n\tconfirm project avatar: {0}", uri.toString()); - } - - putRequest = new HttpPut(uri.build()); - putRequest.setHeader("X-Atlassian-Token", "no-check"); - putRequest.setHeader("Content-Type", CONTENT_TYPE_JSON); - JSONObject confirmBody = new JSONObject(); - confirmBody.put("id", avatarId); - - HttpEntity entity = new ByteArrayEntity(confirmBody.toString().getBytes("UTF-8")); - putRequest.setEntity(entity); - - response = (CloseableHttpResponse) client.execute(putRequest); - - LOG.ok("response code: {0}", String.valueOf(response.getStatusLine().getStatusCode())); - // client.close(); - // DO NOT CLOSE response HERE !!! - processResponseErrors(response); - - closeResponse(response); - - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Confirmation of the avatar failed: problem occurred during building URI: ").append(uri) - .append("\n\t").append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } catch (UnsupportedEncodingException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg - .append("Confirmation of the avatar failed: problem occurred during encoding request body for URI: ") - .append(uri).append("\n\t").append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } catch (IOException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Confirmation of the avatar failed: problem occured during request execution: \n\t") - .append(e.getLocalizedMessage()); - closeResponse(response); - closeClient(client); - LOG.error(exceptionMsg.toString()); - throw new ConnectorIOException(exceptionMsg.toString()); - } - } - - void deleteAvatar(String uid, String objectName) { - // user: - // http://example.com:8080/jira/rest/api/2/user/avatar/?username= - // project: - // http://example.com:8080/jira/rest/api/2/project//avatar/ - URIBuilder deleteUri = getURIBuilder(); - CloseableHttpResponse response = null; - if (uid != null) { - try { - deleteUri = getURIBuilder(); - - String avatarId = getAvatarId(uid, objectName); - if (avatarId == null) { - LOG.warn("Deleting of the avatar ignored: Requested avatar is probably default system avatar."); - return; - } - - if (objectName.equals(PROJECT_NAME)) { - String key = getProjectKeyFromUid(uid); - deleteUri.setPath(URI_BASE_PATH + URI_PROJECT_PATH + "/" + key + URI_AVATAR_PATH + "/" + avatarId); - } - if (objectName.equals(USER_NAME)) { - String username = getUsernameFromUid(uid); - deleteUri.setPath(URI_BASE_PATH + URI_USER_PATH + URI_AVATAR_PATH + "/" + avatarId); - deleteUri.addParameter(PARAM_USERNAME, username); - } - - HttpDelete request = new HttpDelete(deleteUri.build()); - request.addHeader("Authorization", "Basic " + authEncoding()); - response = execute(request); - int statusCode = response.getStatusLine().getStatusCode(); - if (statusCode == 401) { - LOG.warn("Deleting of the avatar was ignored: Avatar with id {0} is probably system avatar.", - avatarId); - return; - } else { - processResponseErrors(response); - } - closeResponse(response); - - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Deletion of the avatar failed: problem occurred during executing URI: ") - .append(deleteUri).append(", using uid attribute: ").append(uid).append("\n\t") - .append(e.getLocalizedMessage()); - closeResponse(response); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } - } - - String getAvatarId(String uid, String objectName) { - URIBuilder getUri = getURIBuilder(); - if (uid != null) { - try { - getUri = getURIBuilder(); - JSONObject object = null; - - if (objectName.equals(PROJECT_NAME)) { - getUri.setPath(URI_BASE_PATH + URI_PROJECT_PATH + "/" + uid); - } - if (objectName.equals(USER_NAME)) { - getUri.setPath(URI_BASE_PATH + URI_USER_PATH); - getUri.addParameter(PARAM_KEY, uid); - } - - HttpGet request = new HttpGet(getUri.build()); - object = callRequest(request, true, CONTENT_TYPE_JSON); - // LOGGER.info("project key: {0}", object.getString(ATTR_KEY)); - JSONObject avatarUrls = object.getJSONObject(ATTR_AVATAR_URLS); - String avatarUrl = avatarUrls.getString("48x48"); - URIBuilder avatarUri = new URIBuilder(avatarUrl); - List queryParameters = avatarUri.getQueryParams(); - - for (NameValuePair pair : queryParameters) { - String name = pair.getName(); - if (name.equals("avatarId")) { - return pair.getValue(); - } - } - - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Getting avatar uid failed: problem occurred during executing URI: ").append(getUri) - .append("\n\t").append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } - return null; - } - - byte[] resizeAndCropImage(byte[] image, int width, int height) { - ByteArrayInputStream bis = new ByteArrayInputStream(image); - BufferedImage buffImage; - try { - buffImage = ImageIO.read(bis); - if (buffImage == null) { - String exceptionMsg = "\n\tBuffering of the avatar for resize failed!"; - LOG.error(exceptionMsg); - throw new ConnectorIOException(exceptionMsg); - } - // crop image if needed: - int originalWidth = buffImage.getWidth(); - int originalHeight = buffImage.getHeight(); - BufferedImage croppedBuffImage; - if (originalWidth > originalHeight) { - croppedBuffImage = buffImage.getSubimage((originalWidth / 2 - originalHeight / 2), 0, originalHeight, - originalHeight); - } else if (originalHeight > originalWidth) { - croppedBuffImage = buffImage.getSubimage(0, (originalHeight / 2 - originalWidth / 2), originalWidth, - originalWidth); - } else { - croppedBuffImage = buffImage; - } - - // LOGGER.info("\n\tConverting image format and size..."); - // resize image: - BufferedImage resizedBuffImage = new BufferedImage(width, height, 5); - Graphics2D imgGraphics = resizedBuffImage.createGraphics(); - imgGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); - imgGraphics.drawImage(croppedBuffImage, 0, 0, width, height, null); - imgGraphics.dispose(); - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // LOGGER.info("\n\tWritting output image..."); - if (ImageIO.write(resizedBuffImage, "jpeg", bos) == false) { - LOG.error("\n\tConverting image format and size faild."); - return null; - } else { - // LOGGER.info("\n\tConverting finished successfully."); - byte[] resizedImage = bos.toByteArray(); - // ImageIO.write(resizedImage, "png", new File("D:\\out.png")); - return resizedImage; - - } - } catch (IOException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg - .append("Converting avatar image format failed: problem occured during converting format and writing it to byte array stream: \n\t") - .append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorIOException(exceptionMsg.toString()); - } - } - - byte[] getAvatar(String avatarUrl, ObjectClass objClass) { - byte[] result = null; - try { - URIBuilder getUri = new URIBuilder(avatarUrl); - HttpGet request = new HttpGet(getUri.build()); - request.addHeader("Authorization", "Basic " + authEncoding()); - request.addHeader("User-Agent", - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31"); - - CloseableHttpResponse response = execute(request); - processResponseErrors(response); - - HttpEntity entity = response.getEntity(); - result = EntityUtils.toByteArray(entity); - String imageType = URLConnection.guessContentTypeFromStream(new ByteArrayInputStream(result)); - // LOGGER.info("\n\ttype: {0}", contentType); - - // SVG avatar: - if (imageType.contains("xml")) { - // LOGGER.info("\n\tSVG avatar"); - TranscoderInput inputSVGimage = new TranscoderInput(avatarUrl); - OutputStream outputJPEGstream = new ByteArrayOutputStream(); - TranscoderOutput outputJPEGimage = new TranscoderOutput(outputJPEGstream); - JPEGTranscoder SVGtoJPEGconverter = new JPEGTranscoder(); - SVGtoJPEGconverter.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, new Float(1)); - try { - SVGtoJPEGconverter.transcode(inputSVGimage, outputJPEGimage); - result = ((ByteArrayOutputStream) outputJPEGstream).toByteArray(); - // ByteArrayInputStream bis = new - // ByteArrayInputStream(result); - // BufferedImage img = ImageIO.read(bis); - // ImageIO.write(img, "jpeg", new File("D:\\outJPEG.jpeg")); - outputJPEGstream.flush(); - outputJPEGstream.close(); - closeResponse(response); - return result; - } catch (TranscoderException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Converting from SVG format to JPEG foramt failed").append("\n\t") - .append(e.getLocalizedMessage()); - closeResponse(response); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } else { - return result; - } - } catch (IOException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Getting avatar failed: problem occured during determining of image format:") - .append("\n\t").append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorIOException(exceptionMsg.toString()); - } catch (URISyntaxException e1) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Getting avatar failed: Problem occured during bilding URI: ").append(avatarUrl) - .append("\n\t").append(e1.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - // return result; - } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - String getUsernameFromUid(String uid) { - URIBuilder getUri = getURIBuilder(); - if (uid != null) { - try { - getUri = getURIBuilder(); - getUri.setPath(URI_BASE_PATH + URI_USER_PATH); - getUri.addParameter(UID, uid); - HttpGet request = new HttpGet(getUri.build()); - JSONObject user = callRequest(request, true, CONTENT_TYPE_JSON); - // LOGGER.info("username: {0}", user.getString(ATTR_NAME)); - return user.getString(ATTR_NAME); - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Get username form user ID failed: problem occurred during executing URI: ") - .append(getUri).append(", using uid attribute: ").append(uid).append("\n\t") - .append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } - return null; - } - - String getUserIdFromName(String username) { - URIBuilder getUri = getURIBuilder(); - if (username != null) { - try { - getUri = getURIBuilder(); - getUri.setPath(URI_BASE_PATH + URI_USER_PATH); - getUri.addParameter(PARAM_USERNAME, username); - HttpGet request = new HttpGet(getUri.build()); - JSONObject user = callRequest(request, true, CONTENT_TYPE_JSON); - LOG.info("username: {0}", user.getString(ATTR_KEY)); - return user.getString(ATTR_KEY); - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Get user ID form user username failed: problem occurred during executing URI: ") - .append(getUri).append("\n\t").append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } - return null; - } - - String getProjectKeyFromUid(String uid) { - URIBuilder getUri = getURIBuilder(); - if (uid != null) { - try { - getUri = getURIBuilder(); - getUri.setPath(URI_BASE_PATH + URI_PROJECT_PATH + "/" + uid); - HttpGet request = new HttpGet(getUri.build()); - JSONObject project = callRequest(request, true, CONTENT_TYPE_JSON); - LOG.info("project key: {0}", project.getString(ATTR_KEY)); - return project.getString(ATTR_KEY); - } catch (URISyntaxException e) { - StringBuilder exceptionMsg = new StringBuilder(); - exceptionMsg.append("Get project key form uid failed: problem occurred during executing URI: ") - .append(getUri).append("\n\t").append(e.getLocalizedMessage()); - LOG.error(exceptionMsg.toString()); - throw new ConnectorException(exceptionMsg.toString()); - } - } - return null; - } - T addAttr(ConnectorObjectBuilder builder, String attrName, T attrVal) { if (attrVal != null) { builder.addAttribute(attrName, attrVal); @@ -982,20 +349,11 @@ String getStringAttr(Set attributes, String attrName) throws InvalidA return getAttr(attributes, attrName, String.class); } - GuardedString getGuardedStringAttr(Set attributes, String attrName) - throws InvalidAttributeValueException { - return getAttr(attributes, attrName, GuardedString.class); - } - T getAttr(Set attributes, String attrName, Class type) throws InvalidAttributeValueException { return getAttr(attributes, attrName, type, null); } - byte[] getByteArrayAttr(Set attributes, String attrName) - throws InvalidAttributeValueException { - return getAttr(attributes, attrName, byte[].class); - } @SuppressWarnings("unchecked") private T getAttr(Set attributes, String attrName, Class type, T defaultVal) @@ -1112,30 +470,6 @@ void putFieldIfExists(Set attributes, String fieldName, JSONObject jo } } - void test() { - URIBuilder uriBuilder = getURIBuilder() - .setPath(URI_BASE_PATH + PATH_STEMS) - .addParameter("wsLiteObjectType", "WsRestFindStemsLiteRequest") - .addParameter("stemName", configuration.getRootStem()) - .addParameter("stemQueryFilterType", "FIND_BY_STEM_NAME"); - try { - HttpGet request = new HttpGet(uriBuilder.build()); - JSONObject response = callRequest(request, true, CONTENT_TYPE_JSON); - System.out.println("Got response: " + response); - - checkSuccess(response, WS_FIND_STEMS_RESULTS); - JSONArray stemResults = getArray(response, WS_FIND_STEMS_RESULTS, STEM_RESULTS); - int stemsFound = stemResults.length(); - if (stemsFound == 0) { - throw new IllegalStateException("No stems named '" + configuration.getRootStem() + "' were found"); - } else if (stemsFound != 1) { - throw new IllegalStateException("More than one stem '" + configuration.getRootStem() + "' found: " + stemsFound); - } - } catch (RuntimeException|URISyntaxException e) { - throw processException(e, uriBuilder, "Test"); - } - } - public void checkSuccess(JSONObject response, String rootName) { Object success = get(response, rootName, RESULT_METADATA, SUCCESS); if (!"T".equals(success)) { diff --git a/src/test/java/com/evolveum/polygon/connector/grouper/test/GroupTests.java b/src/test/java/com/evolveum/polygon/connector/grouper/test/GroupTests.java index c847e92..ba1889d 100644 --- a/src/test/java/com/evolveum/polygon/connector/grouper/test/GroupTests.java +++ b/src/test/java/com/evolveum/polygon/connector/grouper/test/GroupTests.java @@ -77,6 +77,7 @@ public void findByGroupUuid() { public void allGroupsTest() { results.clear(); grouperConnector.executeQuery(ObjectClass.GROUP, null, handler, options); + // most probably here will be no groups, as etc:sysadmingroup has no direct group members for (ConnectorObject group : results) { System.out.println("Found group: " + group); } diff --git a/src/test/java/com/evolveum/polygon/connector/grouper/test/GrouperTestHelper.java b/src/test/java/com/evolveum/polygon/connector/grouper/test/GrouperTestHelper.java index 219e205..45c3d82 100644 --- a/src/test/java/com/evolveum/polygon/connector/grouper/test/GrouperTestHelper.java +++ b/src/test/java/com/evolveum/polygon/connector/grouper/test/GrouperTestHelper.java @@ -94,7 +94,7 @@ protected GrouperConfiguration getConfiguration() { config.setUsername(ADMIN_USERNAME); config.setPassword(new GuardedString(ADMIN_PASSWORD.toCharArray())); config.setSuperGroup(SUPER_GROUP); - config.setRootStem(ROOT_STEM); + config.setGroupIncludePattern(new String[] { SUPER_GROUP }); config.setIgnoreSslValidation(true); config.setSubjectSource(SUBJECT_SOURCE); return config;