Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
[RDCC-6762]Update profileSync job to sync data between IDAM and SRD (#…
Browse files Browse the repository at this point in the history
…718)

* [RDCC-6762]Update profileSync job to sync data between IDAM and SRD

* Bumping chart version/ fixing aliases

* [RDCC-6762]Added Integration Test cases and fixed some failure test cases

* [RDCC-6762]Added Code Review comment

* [RDCC-6762]Fix the concurrent scheduler ID generation issue

* [RDCC-6762]CVE fix

* [RDCC-6762]Integration test failure fix in PR

---------

Co-authored-by: hmcts-jenkins-j-to-z <61242337+hmcts-jenkins-j-to-z[bot]@users.noreply.github.com>
  • Loading branch information
1 parent 94e7b2a commit 7a159f9
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 13 deletions.
2 changes: 1 addition & 1 deletion charts/rd-profile-sync/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ apiVersion: v2
appVersion: "0.1"
description: Reference data service for professional users
name: rd-profile-sync
version: 0.0.21
version: 0.0.22
dependencies:
- name: java
version: 4.0.13
Expand Down
1 change: 1 addition & 0 deletions charts/rd-profile-sync/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ java:
S2S_URL: http://rpe-service-auth-provider-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal
IDAM_URL: https://idam-api.{{ .Values.global.environment }}.platform.hmcts.net
USER_PROFILE_URL: http://rd-user-profile-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal
CASEWORKER_REF_URL: http://rd-caseworker-ref-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal
OAUTH2_REDIRECT_URI: https://rd-professional-api-{{ .Values.global.environment }}.service.core-compute-{{ .Values.global.environment }}.internal/oauth2redirect
AUTH_IDAM_CLIENT_BASEURL: https://idam-api.{{ .Values.global.environment }}.platform.hmcts.net

Expand Down
3 changes: 2 additions & 1 deletion config/owasp/suppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
</suppress>
<suppress>
<notes>Temporary suppression for commons-fileupload-1.4.jar</notes>
<cve>CVE-2023-24998</cve>
<cve>CVE-2023-24998</cve>
<cve>CVE-2023-20883</cve>
</suppress>
<suppress>
<notes><![CDATA[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import uk.gov.hmcts.reform.profilesync.client.CaseWorkerRefApiClient;
import uk.gov.hmcts.reform.profilesync.client.IdamClient;
import uk.gov.hmcts.reform.profilesync.client.UserProfileClient;
import uk.gov.hmcts.reform.profilesync.constants.IdamStatus;
Expand All @@ -30,6 +31,9 @@ public abstract class AuthorizationEnabledIntTest extends SpringBootIntTest {
@Autowired
protected IdamClient idamFeignClient;

@Autowired
protected CaseWorkerRefApiClient caseWorkerRefApiClient;

@Autowired
protected UserProfileSyncJobScheduler profileSyncJobScheduler;

Expand All @@ -45,6 +49,9 @@ public abstract class AuthorizationEnabledIntTest extends SpringBootIntTest {
@RegisterExtension
protected WireMockExtension userProfileService = new WireMockExtension(8091);

@RegisterExtension
protected WireMockExtension caseWorkerProfileService = new WireMockExtension(8095);

@RegisterExtension
protected WireMockExtension sidamService = new WireMockExtension(5000);

Expand Down Expand Up @@ -133,6 +140,22 @@ public void userProfileGetUserWireMock() {
+ "}")));
}

@BeforeEach
public void caseWorkerGetUserWireMock() {

caseWorkerProfileService.stubFor(WireMock.put(
urlEqualTo("/refdata/case-worker/users/sync"))
.willReturn(aResponse()
.withHeader("Content-Type", "application/json")
.withStatus(200)
.withBody("{"
+ " \"userId\":\"ef4fac86-d3e8-47b6-88a7-c7477fb69d3f\","
+ " \"firstName\": \"First\","
+ " \"lastName\": \"Last\","
+ " \"email\": \"dummy@email.com\","
+ " \"idamStatus\": \" true \""
+ "}")));
}

@AfterEach
public void cleanupTestData() {
Expand All @@ -159,7 +182,36 @@ public void userProfileCreateUserWireMock(HttpStatus status) {
}

userProfileService.stubFor(
WireMock.put(urlPathMatching("/v1/userprofile/ef4fac86-d3e8-47b6-88a7-c7477fb69d3f"))
WireMock.get(urlEqualTo("/v1/userprofile?userId=ef4fac86-d3e8-47b6-88a7-c7477fb69d3f"))
.willReturn(
aResponse()
.withHeader("Content-Type", "application/json")
.withBody(body)
.withStatus(returnHttpStaus)
)
);
}

public void caseWorkerUserSyncWireMock(HttpStatus status) {
String body = null;
int returnHttpStaus = status.value();
if (status.is2xxSuccessful()) {
body = "{"
+ " \"idamId\":\"ef4fac86-d3e8-47b6-88a7-c7477fb69d3f\","
+ " \"idamRegistrationResponse\":\"201\""
+ "}";
returnHttpStaus = 200;
} else if (status.is4xxClientError()) {
body = "{"
+ " \"errorMessage\": \"400\","
+ " \"errorDescription\": \"BAD REQUEST\","
+ " \"timeStamp\": \"23:10\""
+ "}";
returnHttpStaus = 400;
}

caseWorkerProfileService.stubFor(
WireMock.put(urlEqualTo("/refdata/case-worker/users/sync"))
.willReturn(
aResponse()
.withHeader("Content-Type", "application/json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ void whenSearchUserAndUpServiceCallSuccessAndSyncBatchStatusShouldBeSuccess() {
assertThat(syncAudit.getSchedulerId()).isPositive();
assertThat(syncAudit.getProfileSyncAuditDetails()).isNotNull();
syncAudit.getProfileSyncAuditDetails().forEach(profileSyncAuditDetails -> {
assertThat(profileSyncAuditDetails.getStatusCode()).isEqualTo(201);
assertThat(profileSyncAuditDetails.getStatusCode()).isEqualTo(200);
assertThat(profileSyncAuditDetails.getErrorDescription()).isEqualTo("success");
});
});
Expand Down Expand Up @@ -74,10 +74,25 @@ void whenSearchUserAndUpServiceCallSuccessAndSyncBatchStatusShouldBeSuccess() {
assertThat(syncAuditThirdRes.getSchedulerId()).isPositive();
assertThat(syncAuditThirdRes.getProfileSyncAuditDetails()).isNotNull();
syncAuditThirdRes.getProfileSyncAuditDetails().forEach(profileSyncAuditDetails -> {
assertThat(profileSyncAuditDetails.getStatusCode()).isEqualTo(201);
assertThat(profileSyncAuditDetails.getStatusCode()).isEqualTo(200);
assertThat(profileSyncAuditDetails.getErrorDescription()).isEqualTo("success");
});


caseWorkerUserSyncWireMock(HttpStatus.OK);
profileSyncJobScheduler.updateIdamDataWithUserProfile();
ProfileSyncAudit syncAuditFourthRes = profileSyncAuditRepository
.findFirstBySchedulerStatusOrderBySchedulerEndTimeDesc("success");
assertThat(syncAuditFourthRes).isNotNull();
assertThat(syncAuditFourthRes.getSchedulerStatus()).isEqualTo("success");
assertThat(syncAuditFourthRes.getSchedulerEndTime()).isNotNull();
assertThat(syncAuditFourthRes.getSchedulerStartTime()).isNotNull();
assertThat(syncAuditFourthRes.getSchedulerId()).isPositive();
assertThat(syncAuditFourthRes.getProfileSyncAuditDetails()).isNotNull();
syncAuditFourthRes.getProfileSyncAuditDetails().forEach(profileSyncAuditDetails -> {
assertThat(profileSyncAuditDetails.getStatusCode()).isEqualTo(200);
assertThat(profileSyncAuditDetails.getErrorDescription()).isEqualTo("success");
});
}

@Test
Expand All @@ -103,6 +118,28 @@ void whenSearchUserSucessAndUpServiceCallsFailScheduledIsCalledAtLeastOneTimes()

}

@Test
void whenSyncCaseWorkerReturns400StatusCodeAndInsertFailStatusForSycnBatch() {

caseWorkerUserSyncWireMock(HttpStatus.BAD_REQUEST);
jobScheduler.updateIdamDataWithUserProfile();
List<ProfileSyncAudit> syncAuditSecondRes = profileSyncAuditRepository.findAll();
assertThat(syncAuditSecondRes).isNotEmpty();
syncAuditSecondRes.forEach(syncAudit -> {
assertThat(syncAudit.getSchedulerStatus()).isEqualTo("fail");
assertThat(syncAudit.getSchedulerEndTime()).isNotNull();
assertThat(syncAudit.getSchedulerStartTime()).isNotNull();
assertThat(syncAudit.getSchedulerId()).isPositive();
assertThat(syncAudit.getProfileSyncAuditDetails()).isNotNull();
syncAudit.getProfileSyncAuditDetails().forEach(profileSyncAuditDetails -> {
assertThat(profileSyncAuditDetails.getStatusCode()).isEqualTo(404);
assertThat(profileSyncAuditDetails.getErrorDescription())
.isEqualTo("the case worker failed while updating the status");
});
});

}

@Test
void whenSearchUserReturns400StatusCodeAndInsertFailStatusForSycnBatch() {

Expand Down
2 changes: 2 additions & 0 deletions src/integrationTest/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ exui.role:
## user profile feign connection
userprofile.api.url: ${USER_PROFILE_URL:http://127.0.0.1:8091}

caseworker.api.url: ${CASEWORKER_REF_URL:http://127.0.0.1:8095}

loggingComponentName: RD_Profile_Sync

recordsPerPage: 100
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package uk.gov.hmcts.reform.profilesync.client;

import feign.Headers;
import feign.Response;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import uk.gov.hmcts.reform.profilesync.domain.CaseWorkerProfile;

import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

@FeignClient(name = "caseWorkerRefApiClient", url = "${caseworker.api.url}")
public interface CaseWorkerRefApiClient {

@PutMapping(value = "/refdata/case-worker/users/sync", consumes = {APPLICATION_JSON_VALUE},
produces = {APPLICATION_JSON_VALUE})
@Headers({"authorization: {authorization}", "serviceauthorization: {serviceauthorization}"})
public Response syncCaseWorkerUserStatus(@RequestHeader("authorization") String authorization,
@RequestHeader("serviceauthorization") String serviceAuthorization,
@RequestBody CaseWorkerProfile body);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package uk.gov.hmcts.reform.profilesync.domain;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class CaseWorkerProfile {


@JsonProperty("suspended")
private boolean idamStatus;

@JsonProperty("email_id")
private String email;

@JsonProperty("first_name")
private String firstName;

@JsonProperty("last_name")
private String lastName;

@JsonProperty("case_worker_id")
private String userId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public class UserProfileSyncJobScheduler {
public void updateIdamDataWithUserProfile() {

String searchQuery = "(roles:pui-case-manager OR roles:pui-user-manager OR roles:pui-organisation-manager OR "
+ "roles:pui-finance-manager OR roles:pui-caa OR roles:cwd-user) AND lastModified:>now-";
+ "roles:pui-finance-manager OR roles:pui-caa OR roles:cwd-user) "
+ "AND lastModified:>now-";
LocalDateTime startTime = LocalDateTime.now();
SyncJobConfig syncJobConfig = profileSyncConfigRepository.findByConfigName("firstsearchquery");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import uk.gov.hmcts.reform.profilesync.advice.UserProfileSyncException;
import uk.gov.hmcts.reform.profilesync.client.CaseWorkerRefApiClient;
import uk.gov.hmcts.reform.profilesync.client.IdamClient;
import uk.gov.hmcts.reform.profilesync.client.UserProfileClient;
import uk.gov.hmcts.reform.profilesync.constants.IdamStatus;
import uk.gov.hmcts.reform.profilesync.domain.CaseWorkerProfile;
import uk.gov.hmcts.reform.profilesync.domain.ProfileSyncAudit;
import uk.gov.hmcts.reform.profilesync.domain.ProfileSyncAuditDetails;
import uk.gov.hmcts.reform.profilesync.domain.ProfileSyncAuditDetailsId;
Expand All @@ -38,6 +40,9 @@ public class ProfileUpdateServiceImpl implements ProfileUpdateService {
@Autowired
private UserProfileClient userProfileClient;

@Autowired
private CaseWorkerRefApiClient caseWorkerRefApiClient;

@Value("${loggingComponentName}")
private String loggingComponentName;

Expand All @@ -46,6 +51,11 @@ public ProfileSyncAudit updateUserProfile(String searchQuery, String bearerToken
throws UserProfileSyncException {
log.info("{}:: Inside updateUserProfile::{}", loggingComponentName);
List<ProfileSyncAuditDetails> profileSyncAuditDetails = new ArrayList<>();
List<ProfileSyncAuditDetails> caseWorkerSyncAuditDetails = new ArrayList<>();




users.forEach(user -> {
Optional<GetUserProfileResponse> userProfile = userAcquisitionService.findUser(bearerToken, s2sToken,
user.getId());
Expand All @@ -64,17 +74,47 @@ public ProfileSyncAudit updateUserProfile(String searchQuery, String bearerToken
try {
//to update user profile details for matching user ids are collecting and storing in the list
// from syncUser method.
profileSyncAuditDetails.add(syncUser(bearerToken, s2sToken, user.getId(), updatedUserProfile,
syncAudit));
profileSyncAuditDetails.add(syncUser(bearerToken, s2sToken, user.getId(),
updatedUserProfile, syncAudit));

} catch (UserProfileSyncException e) {
syncAudit.setSchedulerStatus("fail");
log.error("{}:: User Not updated : - {}",loggingComponentName, e.getErrorMessage());
log.error("{}:: User Not updated : - {}", loggingComponentName, e.getErrorMessage());
}
log.info("{}:: User Status updated in User Profile::{}", loggingComponentName);
}

});

users.forEach(user -> {
StringBuilder sb = new StringBuilder();
sb.append(user.isActive());
sb.append(user.isPending());

CaseWorkerProfile updateCaseWorkerProfile = CaseWorkerProfile.builder()
.email(user.getEmail())
.userId(user.getId())
.firstName(user.getForename())
.lastName(user.getSurname())
.idamStatus(resolveIdamStatusForCaseWorker(sb))
.build();

try {
//to update caseworker profile details for matching user ids are collecting and storing in the list
// from syncCaseWorkerUser method.
caseWorkerSyncAuditDetails.add(syncCaseWorkerUser(bearerToken, s2sToken, user.getId(),
updateCaseWorkerProfile, syncAudit));

} catch (UserProfileSyncException e) {
syncAudit.setSchedulerStatus("fail");
log.error("{}:: User Not updated : - {}", loggingComponentName, e.getErrorMessage());
}


});

syncAudit.setProfileSyncAuditDetails(profileSyncAuditDetails);
syncAudit.setProfileSyncAuditDetails(caseWorkerSyncAuditDetails);
return syncAudit;
}

Expand All @@ -96,6 +136,28 @@ private ProfileSyncAuditDetails syncUser(String bearerToken, String s2sToken,
LocalDateTime.now());
}


private ProfileSyncAuditDetails syncCaseWorkerUser(String bearerToken, String s2sToken,
String userId, CaseWorkerProfile caseWorkerProfile,
ProfileSyncAudit syncAudit)
throws UserProfileSyncException {

log.info("{}:: Inside syncCaseWorkerUser method ::{}", loggingComponentName);
Response response = caseWorkerRefApiClient
.syncCaseWorkerUserStatus(bearerToken, s2sToken, caseWorkerProfile);
String message = "success";
if (response.status() > 300) {
log.error("{}:: Exception occurred while updating the case worker profile: Status - {}"
+ response.status(), loggingComponentName);
message = "the case worker failed while updating the status";
syncAudit.setSchedulerStatus("fail");
}

log.info("{}:: CaseWorker Status updated in Case Worker DB::{}", loggingComponentName);
return new ProfileSyncAuditDetails(new ProfileSyncAuditDetailsId(syncAudit,userId),response.status(),message,
LocalDateTime.now());
}

public String resolveIdamStatus(StringBuilder stringBuilder) {

if (stringBuilder.toString().equalsIgnoreCase("falsetrue")) {
Expand All @@ -107,4 +169,15 @@ public String resolveIdamStatus(StringBuilder stringBuilder) {
}
}

public boolean resolveIdamStatusForCaseWorker(StringBuilder stringBuilder) {

if (stringBuilder.toString().equalsIgnoreCase("falsetrue")) {
return false;
} else if (stringBuilder.toString().equalsIgnoreCase("truefalse")) {
return false;
} else {
return true;
}
}

}
6 changes: 6 additions & 0 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ userprofile:
api:
url: ${USER_PROFILE_URL:http://rd-user-profile-api-aat.service.core-compute-aat.internal}

caseworker:
api:
url: ${CASEWORKER_REF_URL:http://rd-caseworker-ref-api-aat.service.core-compute-aat.internal}



loggingComponentName: RD_Profile_Sync

recordsPerPage: 100
Loading

0 comments on commit 7a159f9

Please sign in to comment.