• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DataBiosphere / consent / #6344

18 Aug 2025 06:24PM UTC coverage: 83.311% (-0.04%) from 83.355%
#6344

push

web-flow
DT-1636: Sync User Linked Account Status with ECM (#2640)

47 of 65 new or added lines in 8 files covered. (72.31%)

2 existing lines in 1 file now uncovered.

10972 of 13170 relevant lines covered (83.31%)

0.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.76
/src/main/java/org/broadinstitute/consent/http/service/NihService.java
1
package org.broadinstitute.consent.http.service;
2

3
import com.google.api.client.http.GenericUrl;
4
import com.google.api.client.http.HttpRequest;
5
import com.google.api.client.http.HttpResponse;
6
import com.google.api.client.http.HttpStatusCodes;
7
import com.google.inject.Inject;
8
import jakarta.ws.rs.BadRequestException;
9
import jakarta.ws.rs.NotFoundException;
10
import jakarta.ws.rs.ServerErrorException;
11
import java.time.Instant;
12
import java.util.Calendar;
13
import java.util.Date;
14
import java.util.List;
15
import java.util.Objects;
16
import org.apache.commons.lang3.StringUtils;
17
import org.broadinstitute.consent.http.configurations.ServicesConfiguration;
18
import org.broadinstitute.consent.http.db.UserDAO;
19
import org.broadinstitute.consent.http.db.UserPropertyDAO;
20
import org.broadinstitute.consent.http.enumeration.UserFields;
21
import org.broadinstitute.consent.http.models.AuthUser;
22
import org.broadinstitute.consent.http.models.DuosUser;
23
import org.broadinstitute.consent.http.models.NIHUserAccount;
24
import org.broadinstitute.consent.http.models.User;
25
import org.broadinstitute.consent.http.models.UserProperty;
26
import org.broadinstitute.consent.http.models.ecm.LinkInfo;
27
import org.broadinstitute.consent.http.service.dao.NihServiceDAO;
28
import org.broadinstitute.consent.http.util.ConsentLogger;
29
import org.broadinstitute.consent.http.util.HttpClientUtil;
30
import org.broadinstitute.consent.http.util.gson.GsonUtil;
31

32
public class NihService implements ConsentLogger {
33

34
  private final UserDAO userDAO;
35
  private final UserPropertyDAO userPropertyDAO;
36
  private final NihServiceDAO serviceDAO;
37
  private final HttpClientUtil clientUtil;
38
  private final ServicesConfiguration configuration;
39

40
  @Inject
41
  public NihService(UserDAO userDAO, UserPropertyDAO userPropertyDAO, NihServiceDAO serviceDAO,
42
      HttpClientUtil clientUtil, ServicesConfiguration configuration) {
1✔
43
    this.userDAO = userDAO;
1✔
44
    this.userPropertyDAO = userPropertyDAO;
1✔
45
    this.serviceDAO = serviceDAO;
1✔
46
    this.clientUtil = clientUtil;
1✔
47
    this.configuration = configuration;
1✔
48
  }
1✔
49

50
  public  User syncAccount(DuosUser duosUser) throws Exception {
51
    User user = duosUser.getUser();
1✔
52
    GenericUrl ecmRasProviderUrl = new GenericUrl(configuration.getEcmRasProviderUrl());
1✔
53
    HttpRequest request = clientUtil.buildGetRequest(ecmRasProviderUrl, duosUser);
1✔
54
    try {
55
      HttpResponse response = clientUtil.handleHttpRequest(request);
1✔
56
      if (!response.isSuccessStatusCode()) {
1✔
57
        throw new ServerErrorException(response.getStatusMessage(), response.getStatusCode());
1✔
58
      }
59
      String body = response.parseAsString();
1✔
60
      NIHUserAccount nihAccount = parseNihUserAccount(body);
1✔
61
      serviceDAO.updateUserNihStatus(user, nihAccount);
1✔
62
    } catch (NotFoundException e) {
1✔
63
      serviceDAO.deleteNihAccountById(user.getUserId());
1✔
64
    }
1✔
65
    return userDAO.findUserWithPropertiesById(user.getUserId(), UserFields.getValues());
1✔
66
  }
67

68
  public void validateNihUserAccount(NIHUserAccount nihAccount, AuthUser authUser)
69
      throws BadRequestException {
70
    if (Objects.isNull(nihAccount) || Objects.isNull(nihAccount.getEraExpiration())) {
1✔
71
      logWarn("Invalid NIH Account for user: " + authUser.getEmail());
1✔
72
      throw new BadRequestException("Invalid NIH Authentication for user : " + authUser.getEmail());
1✔
73
    }
74
  }
1✔
75

76
  public List<UserProperty> authenticateNih(NIHUserAccount nihAccount, AuthUser authUser,
77
      Integer userId) throws BadRequestException {
78
    // fail fast
79
    validateNihUserAccount(nihAccount, authUser);
1✔
80
    User user = userDAO.findUserById(userId);
1✔
81
    if (Objects.isNull(user)) {
1✔
82
      throw new NotFoundException("User not found: " + authUser.getEmail());
1✔
83
    }
84
    if (StringUtils.isNotEmpty(nihAccount.getNihUsername()) && !nihAccount.getNihUsername()
1✔
85
        .isEmpty()) {
1✔
86
      nihAccount.setEraExpiration(generateEraExpirationDates());
1✔
87
      nihAccount.setStatus(true);
1✔
88
      try {
89
        serviceDAO.updateUserNihStatus(user, nihAccount);
1✔
90
      } catch (IllegalArgumentException e) {
×
91
        logException(e);
×
92
      }
1✔
93
      return userPropertyDAO.findUserPropertiesByUserIdAndPropertyKeys(userId,
1✔
94
          UserFields.getValues());
1✔
95
    } else {
96
      throw new BadRequestException("Invalid NIH UserName for user : " + authUser.getEmail());
1✔
97
    }
98
  }
99

100
  public void deleteNihAccountById(DuosUser duosUser) {
NEW
101
    User user = duosUser.getUser();
×
102
    // Delete linkage locally
NEW
103
    serviceDAO.deleteNihAccountById(user.getUserId());
×
104
    try {
105
      // Delete linkage from ECM
NEW
106
      GenericUrl ecmRasProviderUrl = new GenericUrl(configuration.getEcmRasProviderUrl());
×
NEW
107
      HttpRequest request = clientUtil.buildDeleteRequest(ecmRasProviderUrl, duosUser);
×
NEW
108
      HttpResponse response = clientUtil.handleHttpRequest(request);
×
NEW
109
      if (!response.isSuccessStatusCode()) {
×
NEW
110
        throw new ServerErrorException(response.getStatusMessage(), response.getStatusCode());
×
111
      }
NEW
112
    } catch (Exception e) {
×
NEW
113
      logWarn(
×
NEW
114
          "Failed to delete NIH account for user: " + duosUser.getEmail() + " - " + e.getMessage());
×
NEW
115
      throw new ServerErrorException(
×
NEW
116
          "Failed to delete NIH account for user: " + duosUser.getEmail(),
×
117
          HttpStatusCodes.STATUS_CODE_SERVER_ERROR, e);
UNCOV
118
    }
×
119

UNCOV
120
  }
×
121

122

123
  private String generateEraExpirationDates() {
124
    Date currentDate = new Date();
1✔
125
    Calendar c = Calendar.getInstance();
1✔
126
    c.setTime(currentDate);
1✔
127
    c.add(Calendar.DATE, 30);
1✔
128
    Date expires = c.getTime();
1✔
129
    return String.valueOf(expires.getTime());
1✔
130
  }
131

132
  private NIHUserAccount parseNihUserAccount(String body) {
133
    try {
134
      LinkInfo linkInfo = GsonUtil.getInstance().fromJson(body, LinkInfo.class);
1✔
135
      // LinkInfo expirationTimestamp is in a date string.
136
      // Historically, we store this value as epoch milliseconds
137
      Instant instant = Instant.parse(linkInfo.expirationTimestamp());
1✔
138
      return new NIHUserAccount(
1✔
139
          linkInfo.externalUserId(), String.valueOf(instant.toEpochMilli()), linkInfo.authenticated());
1✔
140
    } catch (Exception e) {
1✔
141
      logWarn("Failed to parse ECM response: " + body);
1✔
142
      throw new ServerErrorException("Invalid response from ECM RAS Provider",
1✔
143
          HttpStatusCodes.STATUS_CODE_SERVER_ERROR);
144
    }
145
  }
146
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc