diff --git a/src/main/java/net/tirasa/connid/bundles/scim/common/SCIMConnectorConfiguration.java b/src/main/java/net/tirasa/connid/bundles/scim/common/SCIMConnectorConfiguration.java index 013f255..fc9671b 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/common/SCIMConnectorConfiguration.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/common/SCIMConnectorConfiguration.java @@ -102,6 +102,8 @@ public class SCIMConnectorConfiguration extends AbstractConfiguration implements private GuardedString authHttpHeaderValue; + private boolean enableURLPathEncoding = false; + @ConfigurationProperty(order = 1, displayMessageKey = "baseAddress.display", helpMessageKey = "baseAddress.help", @@ -430,6 +432,17 @@ public void setAuthHttpHeaderValue(final GuardedString authHttpHeaderValue) { this.authHttpHeaderValue = authHttpHeaderValue; } + @ConfigurationProperty(displayMessageKey = "enableURLPathEncoding.display", + helpMessageKey = "enableURLPathEncoding.help", + order = 31) + public boolean getEnableURLPathEncoding() { + return enableURLPathEncoding; + } + + public void setEnableURLPathEncoding(final boolean enableURLPathEncoding) { + this.enableURLPathEncoding = enableURLPathEncoding; + } + @Override public void validate() { if (StringUtil.isBlank(baseAddress)) { diff --git a/src/main/java/net/tirasa/connid/bundles/scim/common/service/AbstractSCIMService.java b/src/main/java/net/tirasa/connid/bundles/scim/common/service/AbstractSCIMService.java index ec4f8c4..f7ed3e4 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/common/service/AbstractSCIMService.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/common/service/AbstractSCIMService.java @@ -81,7 +81,6 @@ public AbstractSCIMService(final SCIMConnectorConfiguration config) { protected WebClient getWebclient(final String path, final Map params) { WebClient webClient; if (checkBearerToken()) { - webClient = WebClient.create(config.getBaseAddress()). header(HttpHeaders.AUTHORIZATION, "Bearer " + getBearerToken(false)); } else { @@ -122,7 +121,7 @@ protected WebClient getWebclient(final String path, final Map pa if (StringUtil.isNotBlank(config.getAuthHttpHeaderName())) { webClient.header(config.getAuthHttpHeaderName(), SecurityUtil.decrypt(config.getAuthHttpHeaderValue())); } - + webClient.type(config.getContentType()).accept(config.getAccept()).path(path); Optional.ofNullable(params).ifPresent(p -> p.forEach((k, v) -> webClient.query(k, v))); @@ -366,7 +365,7 @@ protected String checkServiceErrors(final Response response) { if (response.getStatusInfo().getFamily() != Status.Family.SUCCESSFUL) { SCIMUtils.handleGeneralError( "While executing SCIM request: status is " + response.getStatus() + " and reponse " - + responseAsString); + + responseAsString); } return responseAsString; } @@ -521,7 +520,7 @@ protected void readCustomAttributes(final PagedResults resources, final Json */ @Override public void deleteUser(final String userId) { - doDeleteUser(userId, getWebclient("Users", null).path(userId)); + doDeleteUser(userId, getWebclient("Users", null).path(SCIMUtils.getPath(userId, config))); } /** @@ -567,7 +566,8 @@ protected UT doCreateUser(final UT user) { protected UT doUpdateUser(final String userId, final P userPatch, final Class userType) { UT updated = null; - JsonNode node = doUpdatePatch(userPatch, Collections.emptySet(), getWebclient("Users", null).path(userId)); + JsonNode node = doUpdatePatch(userPatch, Collections.emptySet(), + getWebclient("Users", null).path(SCIMUtils.getPath(userId, config))); if (node == null) { SCIMUtils.handleGeneralError("While running update patch on service"); } @@ -592,9 +592,11 @@ protected UT doUpdateUser(final UT user, final Set replaceAttributes, UT updated = null; JsonNode node = - config.getUpdateUserMethod().equalsIgnoreCase("PATCH") && !replaceAttributes.isEmpty() ? doUpdatePatch( - replaceAttributes, getWebclient("Users", null).path(user.getId())) - : doUpdate(user, getWebclient("Users", null).path(user.getId())); + config.getUpdateUserMethod().equalsIgnoreCase("PATCH") && !replaceAttributes.isEmpty() + ? doUpdatePatch(replaceAttributes, getWebclient("Users", null).path( + SCIMUtils.getPath(user.getId(), config))) + : doUpdate(user, getWebclient("Users", null).path( + SCIMUtils.getPath(user.getId(), config))); if (node == null) { SCIMUtils.handleGeneralError("While running update on service"); } @@ -810,7 +812,8 @@ protected PagedResults doGetAllGroups(final WebClient webClient) { @Override public void deleteGroup(final String groupId) { - doDeleteGroup(groupId, getWebclient("Groups", null).path(groupId)); + doDeleteGroup(groupId, + getWebclient("Groups", null).path(SCIMUtils.getPath(groupId, config))); } @Override @@ -875,11 +878,11 @@ protected GT doUpdateGroup(final GT group, final Set replaceAttribute } GT updated = null; - JsonNode node = - config.getUpdateGroupMethod().equalsIgnoreCase("PATCH") && patch != null + JsonNode node = config.getUpdateGroupMethod().equalsIgnoreCase("PATCH") && patch != null ? doUpdatePatch(patch, replaceAttributes, - getWebclient("Groups", null).path(group.getId())) - : doUpdate(group, getWebclient("Groups", null).path(group.getId())); + getWebclient("Groups", null).path(SCIMUtils.getPath(group.getId(), config))) + : doUpdate(group, getWebclient("Groups", null).path( + SCIMUtils.getPath(group.getId(), config))); if (node == null) { SCIMUtils.handleGeneralError("While running update group on service"); } @@ -914,7 +917,8 @@ protected JsonNode doUpdate(final GT group, final WebClient webClient) { String responseEntity = checkServiceErrors(response); // some servers like Salesforce return empty response on group update with PUT, thus a re-read is needed result = StringUtil.isNotBlank(responseEntity) ? SCIMUtils.MAPPER.readTree(responseEntity) - : doGet(getWebclient("Groups", null).path(group.getId())); + : doGet(getWebclient("Groups", null).path( + SCIMUtils.getPath(group.getId(), config))); checkServiceResultErrors(result, response); } catch (IOException ex) { LOG.error(ex, "Unable to update entity"); diff --git a/src/main/java/net/tirasa/connid/bundles/scim/common/utils/SCIMUtils.java b/src/main/java/net/tirasa/connid/bundles/scim/common/utils/SCIMUtils.java index 467686c..b14278c 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/common/utils/SCIMUtils.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/common/utils/SCIMUtils.java @@ -20,11 +20,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.lang.reflect.Field; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; +import net.tirasa.connid.bundles.scim.common.SCIMConnectorConfiguration; import net.tirasa.connid.bundles.scim.common.SCIMProvider; import net.tirasa.connid.bundles.scim.common.dto.BaseResourceReference; import net.tirasa.connid.bundles.scim.common.dto.SCIMBaseAttribute; @@ -43,7 +46,7 @@ public final class SCIMUtils { public static final ObjectMapper MAPPER = new ObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .setSerializationInclusion(JsonInclude.Include.NON_EMPTY); + .setDefaultPropertyInclusion(JsonInclude.Include.NON_EMPTY); public static List getAllFieldsList(final Class cls) { List allFields = new ArrayList<>(); @@ -222,6 +225,10 @@ public static > Optional> extractSC return groupMemberBuilder.build(); } + public static String getPath(final String id, final SCIMConnectorConfiguration config) { + return config.getEnableURLPathEncoding() ? URLEncoder.encode(id, StandardCharsets.UTF_8) : id; + } + private SCIMUtils() { // private constructor for static utility class } diff --git a/src/main/java/net/tirasa/connid/bundles/scim/v11/service/SCIMv11Client.java b/src/main/java/net/tirasa/connid/bundles/scim/v11/service/SCIMv11Client.java index 5b6efc7..1d6a4e7 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/v11/service/SCIMv11Client.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/v11/service/SCIMv11Client.java @@ -48,7 +48,7 @@ public SCIMv11Client(final SCIMConnectorConfiguration config) { */ @Override public SCIMv11User getUser(final String userId) { - WebClient webClient = getWebclient("Users", null).path(userId); + WebClient webClient = getWebclient("Users", null).path(SCIMUtils.getPath(userId, config)); return doGetUser(webClient, SCIMv11User.class, SCIMv11Attribute.class); } @@ -84,7 +84,9 @@ public boolean testService() { @Override public SCIMv11Group getGroup(final String groupId) { - return doGetGroup(getWebclient("Groups", null).path(groupId), SCIMv11Group.class); + return doGetGroup( + getWebclient("Groups", null).path(SCIMUtils.getPath(groupId, config)), + SCIMv11Group.class); } @Override diff --git a/src/main/java/net/tirasa/connid/bundles/scim/v2/service/SCIMv2Client.java b/src/main/java/net/tirasa/connid/bundles/scim/v2/service/SCIMv2Client.java index 3bf1f93..dcc218a 100644 --- a/src/main/java/net/tirasa/connid/bundles/scim/v2/service/SCIMv2Client.java +++ b/src/main/java/net/tirasa/connid/bundles/scim/v2/service/SCIMv2Client.java @@ -46,7 +46,9 @@ public SCIMv2Client(final SCIMConnectorConfiguration config) { */ @Override public SCIMv2User getUser(final String userId) { - return doGetUser(getWebclient("Users", null).path(userId), SCIMv2User.class, SCIMv2Attribute.class); + return doGetUser( + getWebclient("Users", null).path(SCIMUtils.getPath(userId, config)), + SCIMv2User.class, SCIMv2Attribute.class); } /** @@ -79,13 +81,15 @@ public SCIMv2User updateUser(final String userId, final SCIMv2Patch userPatch) { @Override public SCIMv2Group getGroup(final String groupId) { - return doGetGroup(getWebclient("Groups", null).path(groupId), SCIMv2Group.class); + return doGetGroup( + getWebclient("Groups", null).path(SCIMUtils.getPath(groupId, config)), + SCIMv2Group.class); } @Override public SCIMv2EntitlementResource getEntitlement(final String entitlementId) { - return doGetEntitlement( - getWebclient("Entitlements", null).path(entitlementId), SCIMv2EntitlementResource.class); + return doGetEntitlement(getWebclient("Entitlements", null).path( + SCIMUtils.getPath(entitlementId, config)), SCIMv2EntitlementResource.class); } @Override @@ -105,7 +109,7 @@ public SCIMv2Group updateGroup(final SCIMv2Group group, final Set rep @Override public void deleteGroup(final String groupId) { - doDeleteGroup(groupId, getWebclient("Groups", null).path(groupId)); + doDeleteGroup(groupId, getWebclient("Groups", null).path(SCIMUtils.getPath(groupId, config))); } @Override diff --git a/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages.properties b/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages.properties index a827b38..5accf29 100644 --- a/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages.properties +++ b/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages.properties @@ -79,4 +79,7 @@ authHttpHeaderName.display=Auth http header name authHttpHeaderName.help=Specifies the name of the additional header sent on requests containing the authentication information. If empty header won't be added. authHttpHeaderValue.display=Auth http header value authHttpHeaderValue.help=The auth http header value to use to authenticate against the server. +enableURLPathEncoding.display=Enable url path encoding +enableURLPathEncoding.help=Whether to enable encoding on url path while performing requests to the SCIM server, for example the user id on user read. + diff --git a/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages_it.properties b/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages_it.properties index 17c0acd..8f6910a 100644 --- a/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages_it.properties +++ b/src/main/resources/net/tirasa/connid/bundles/scim/common/Messages_it.properties @@ -79,4 +79,5 @@ authHttpHeaderName.display=Nome header per autenticazione authHttpHeaderName.help=Specifica il nome dell \u0027header aggiuntivo inviato nelle richieste, contenente informazioni di authenticazione. Se vuota l \u0027header non viene aggiunto. authHttpHeaderValue.display=Valore http header per l \u0027autenticazione authHttpHeaderValue.help=Il valore dell \u0027header da usare per l \u0027autenticazione sul server. - +enableURLPathEncoding.display=Abilita encoding del percorso nella URL +enableURLPathEncoding.help=Specifica se abilitare oppure no l \u0027 encoding del percorso della richiesta inviate al server SCIM. Per esempio lo user id in fase di lettura utente. diff --git a/src/test/java/net/tirasa/connid/bundles/scim/v2/SCIMv2ConnectorTestsUtils.java b/src/test/java/net/tirasa/connid/bundles/scim/v2/SCIMv2ConnectorTestsUtils.java index 90624f4..fdcde1b 100644 --- a/src/test/java/net/tirasa/connid/bundles/scim/v2/SCIMv2ConnectorTestsUtils.java +++ b/src/test/java/net/tirasa/connid/bundles/scim/v2/SCIMv2ConnectorTestsUtils.java @@ -146,6 +146,8 @@ public static SCIMConnectorConfiguration buildConfiguration( break; } } + // enable url encoding only for test purposes + connectorConfiguration.setEnableURLPathEncoding(true); return connectorConfiguration; }