diff --git a/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ConnectorConstants.java b/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ConnectorConstants.java index 43cedc9..d419b5f 100644 --- a/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ConnectorConstants.java +++ b/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ConnectorConstants.java @@ -36,6 +36,7 @@ public class Office365ConnectorConstants { public static final String OFFICE365_MEMBERSHIP_VALUE = "office-365-membership-rule-value"; public static final String WSO2_ROLE_CLAIM = "http://wso2.org/claims/role"; + public static final String WSO2_USERNAME_CLAIM = "http://wso2.org/claims/username"; public static final String OFFICE365_BASE_URL = "https://login.microsoftonline.com"; public static final String OFFICE365_TOKEN_ENDPOINT = "/oauth2/v2.0/token"; diff --git a/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ProvisioningConnector.java b/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ProvisioningConnector.java index 2a60df5..33ef8f4 100644 --- a/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ProvisioningConnector.java +++ b/components/org.wso2.carbon.identity.outbound.provisioning.connector.office365/src/main/java/org/wso2/carbon/identity/outbound/provisioning/connector/office365/Office365ProvisioningConnector.java @@ -27,6 +27,7 @@ import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.StringEntity; @@ -153,11 +154,19 @@ protected String createUser(ProvisioningEntity provisioningEntity) throws Identi jsonResponse.toString()); } } else { - String errorMessage = jsonResponse.getJSONObject("error").getString("message"); - log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " - + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + - "' while creating the user " + user.getString(Office365ConnectorConstants.OFFICE365_UPN) + - " in the Azure Active Directory."); + if (jsonResponse.has("error")) { + String errorMessage = jsonResponse.getJSONObject("error").getString("message"); + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + + "' while creating the user " + user.getString(Office365ConnectorConstants + .OFFICE365_UPN) + " in the Azure Active Directory."); + + } else { + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " while creating the user " + user + .getString(Office365ConnectorConstants.OFFICE365_UPN) + " in the Azure Active " + + "Directory."); + } if (log.isDebugEnabled()) { log.debug("The response received from server : " + jsonResponse.toString()); @@ -172,15 +181,68 @@ protected String createUser(ProvisioningEntity provisioningEntity) throws Identi log.debug("Returning provisioned user's ID: " + provisionedId); } } catch (IOException e) { - log.error("Error while closing HttpClient."); + log.error("Error while closing HttpClient.", e); } return provisionedId; } - protected void updateUser(ProvisioningEntity provisioningEntity) { + /** + * Call the update user endpoint of Azure AD and update the user properties. + * + * @param provisioningEntity user to be provisioned + * @throws IdentityProvisioningException if the user can not be created in the Azure AD + */ + protected void updateUser(ProvisioningEntity provisioningEntity) throws IdentityProvisioningException { + + String provisionedUserId = provisioningEntity.getIdentifier().getIdentifier(); + + try (CloseableHttpClient httpclient = HttpClientBuilder.create().useSystemProperties().build()) { + + JSONObject user = buildUserAsJson(provisioningEntity); + String updateUserEndpoint = Office365ConnectorConstants.OFFICE365_USER_ENDPOINT + '/' + provisionedUserId; + HttpPatch patchRequest = new HttpPatch(updateUserEndpoint); + setAuthorizationHeader(patchRequest); + + StringEntity requestBody = new StringEntity(user.toString()); + requestBody.setContentType(Office365ConnectorConstants.CONTENT_TYPE_APPLICATION_JSON); + patchRequest.setEntity(requestBody); + patchRequest.setHeader(Office365ConnectorConstants.CONTENT_TYPE, Office365ConnectorConstants + .CONTENT_TYPE_APPLICATION_JSON); + + try (CloseableHttpResponse response = httpclient.execute(patchRequest)) { + + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT) { + if (log.isDebugEnabled()) { + log.debug("Successfully updated the provisioned user with id " + provisionedUserId + " in " + + "the Azure Active Directory."); + } + } else { + JSONObject jsonResponse = new JSONObject(new JSONTokener(new InputStreamReader( + response.getEntity().getContent()))); + + if (jsonResponse.has("error")) { + String errorMessage = jsonResponse.getJSONObject("error").getString("message"); + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + + "' while updating the user with id " + provisionedUserId + " in the Azure Active " + + "Directory."); + } else { + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " while updating the user with id " + + provisionedUserId + " in the Azure Active " + "Directory."); + } - log.warn("Update user is not implemented."); - // TODO: 8/14/18 Implement update user logic + if (log.isDebugEnabled()) { + log.debug("The response received from server : " + jsonResponse.toString()); + } + } + } catch (IOException | JSONException e) { + throw new IdentityProvisioningException("Error while executing the update operation in user " + + "provisioning.", e); + } + } catch (IOException e) { + log.error("Error while closing HttpClient.", e); + } } /** @@ -211,12 +273,18 @@ protected void deleteUser(ProvisioningEntity provisioningEntity) throws Identity } else { JSONObject jsonResponse = new JSONObject(new JSONTokener(new InputStreamReader( response.getEntity().getContent()))); - String errorMessage = jsonResponse.getJSONObject("error").getString("message"); - log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " - + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + - "' while deleting the user with id " + provisionedUserId + " from the Azure Active " + - "Directory."); + if (jsonResponse.has("error")) { + String errorMessage = jsonResponse.getJSONObject("error").getString("message"); + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + + "' while deleting the user with id " + provisionedUserId + " from the Azure Active " + + "Directory."); + } else { + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " while deleting the user with id " + + provisionedUserId + " from the Azure Active Directory."); + } if (log.isDebugEnabled()) { log.debug("The response received from server : " + jsonResponse.toString()); @@ -227,7 +295,7 @@ protected void deleteUser(ProvisioningEntity provisioningEntity) throws Identity "provisioning", e); } } catch (IOException e) { - log.error("Error while closing HttpClient."); + log.error("Error while closing HttpClient.", e); } } @@ -259,12 +327,18 @@ protected void deleteUserPermanently(ProvisioningEntity provisioningEntity) thro } else { JSONObject jsonResponse = new JSONObject(new JSONTokener(new InputStreamReader( response.getEntity().getContent()))); - String errorMessage = jsonResponse.getJSONObject("error").getString("message"); - log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " - + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + - "' while permanently removing the user with id " + provisionedUserId + - " in the Azure Active Directory."); + if (jsonResponse.has("error")) { + String errorMessage = jsonResponse.getJSONObject("error").getString("message"); + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " with the message '" + errorMessage + + "' while permanently removing the user with id " + provisionedUserId + + " in the Azure Active Directory."); + } else { + log.error("Received response status code: " + response.getStatusLine().getStatusCode() + " " + + response.getStatusLine().getReasonPhrase() + " while permanently removing the user" + + " with id " + provisionedUserId + " in the Azure Active Directory."); + } if (log.isDebugEnabled()) { log.debug("The response received from server : " + jsonResponse.toString()); @@ -277,7 +351,7 @@ protected void deleteUserPermanently(ProvisioningEntity provisioningEntity) thro } } catch (IOException e) { - log.error("Error while closing HttpClient."); + log.error("Error while closing HttpClient.", e); } } @@ -335,7 +409,7 @@ private String getAccessToken() throws IdentityProvisioningException { throw new IdentityProvisioningException("Error while obtaining the access token from the response.", e); } } catch (IOException e) { - log.error("Error while closing HttpClient."); + log.error("Error while closing HttpClient.", e); } return accessToken; } @@ -361,29 +435,31 @@ private JSONObject buildUserAsJson(ProvisioningEntity provisioningEntity) throws if (ruleAttributeClaim.isEmpty() && !ruleAttributeName.isEmpty()) { ruleAttributeClaim = Office365ConnectorConstants.WSO2_ROLE_CLAIM; } - String displayName = requiredAttributes.get(displayNameClaim); - String mailNickName = requiredAttributes.get(mailNickNameClaim); - String immutableId = requiredAttributes.get(immutableIdClaim); - String upn = requiredAttributes.get(upnClaim); - String ruleAttributeValue = requiredAttributes.get(ruleAttributeClaim); + String displayName = getUserClaimValue(requiredAttributes, displayNameClaim, provisioningEntity); + String mailNickName = getUserClaimValue(requiredAttributes, mailNickNameClaim, provisioningEntity); + String immutableId = getUserClaimValue(requiredAttributes, immutableIdClaim, provisioningEntity); + String upn = getUserClaimValue(requiredAttributes, upnClaim, provisioningEntity); + String ruleAttributeValue = getUserClaimValue(requiredAttributes, ruleAttributeClaim, provisioningEntity); if (displayName == null || mailNickName == null || immutableId == null || upn == null) { throw new IdentityProvisioningException("One or more of the mandatory user attributes: display name, mail" + - " " + - "nickname, immutable id, user principal name do not have a value."); + " nickname, immutable id, user principal name do not have a value."); } else { - // Create a json object corresponding to the attributes of the user in the request. - JSONObject passwordProfile = new JSONObject(); - passwordProfile.put(Office365ConnectorConstants.FORCE_CHANGE_PASSWORD, false); - passwordProfile.put(Office365ConnectorConstants.PASSWORD, generateRandomPassword()); + // Create a json object corresponding to the attributes of the user in the request. JSONObject user = new JSONObject(); user.put(Office365ConnectorConstants.ACCOUNT_ENABLED, true); user.put(Office365ConnectorConstants.OFFICE365_DISPLAY_NAME, displayName); user.put(Office365ConnectorConstants.OFFICE365_EMAIL_NICKNAME, mailNickName); user.put(Office365ConnectorConstants.OFFICE365_UPN, getDomainSpecificUpn(upn)); user.put(Office365ConnectorConstants.OFFICE365_IMMUTABLE_ID, immutableId); - user.put(Office365ConnectorConstants.PASSWORD_PROFILE, passwordProfile); + + if (ProvisioningOperation.POST == provisioningEntity.getOperation()) { + JSONObject passwordProfile = new JSONObject(); + passwordProfile.put(Office365ConnectorConstants.FORCE_CHANGE_PASSWORD, false); + passwordProfile.put(Office365ConnectorConstants.PASSWORD, generateRandomPassword()); + user.put(Office365ConnectorConstants.PASSWORD_PROFILE, passwordProfile); + } if (!ruleAttributeName.isEmpty()) { user.put(ruleAttributeName, ruleAttributeValue); } @@ -395,6 +471,15 @@ private JSONObject buildUserAsJson(ProvisioningEntity provisioningEntity) throws } } + private String getUserClaimValue(Map attributes, String requiredClaim, ProvisioningEntity entity) { + + if (Office365ConnectorConstants.WSO2_USERNAME_CLAIM.equals(requiredClaim)) { + return entity.getEntityName(); + } else { + return attributes.get(requiredClaim); + } + } + private void setAuthorizationHeader(HttpRequestBase httpMethod) throws IdentityProvisioningException { String accessToken = getAccessToken();