Skip to content
This repository was archived by the owner on Dec 9, 2025. It is now read-only.

Commit 3b50824

Browse files
committed
add api to update user2fa
1 parent 74f457a commit 3b50824

File tree

10 files changed

+143
-82
lines changed

10 files changed

+143
-82
lines changed

buildtokenproperties.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ AUTH0_NEW_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_ID_SECRET")
1616
AUTH0_NEW_NONINTERACTIVE_ID=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID")
1717
AUTH0_NEW_NONINTERACTIVE_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID_SECRET")
1818
DICEAUTH_DICE_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_URL")
19+
DICEAUTH_DICE_API_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_URL")
1920
DICEAUTH_API_KEY=$(eval "echo \$${ENV}_DICEAUTH_API_KEY")
2021
DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID")
2122
ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID")
@@ -89,6 +90,7 @@ perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/
8990
perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME
9091
echo $DICEAUTH_DICE_URL
9192
perl -pi -e "s|\{\{DICEAUTH_DICE_URL\}\}|$DICEAUTH_DICE_URL|g" $CONFFILENAME
93+
perl -pi -e "s|\{\{DICEAUTH_DICE_API_URL\}\}|$DICEAUTH_DICE_API_URL|g" $CONFFILENAME
9294
perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME
9395
perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME
9496
perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME

src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import org.slf4j.Logger;
1010
import org.slf4j.LoggerFactory;
1111

12+
import java.net.SocketTimeoutException;
13+
1214
import javax.ws.rs.client.Client;
1315
import javax.ws.rs.client.Entity;
1416
import javax.ws.rs.client.Invocation;
@@ -87,7 +89,11 @@ public void reFireEvent(EventMessage eventMessage) {
8789
if (response.getStatusInfo().getStatusCode() != HttpStatus.OK_200 && response.getStatusInfo().getStatusCode()!= HttpStatus.NO_CONTENT_204) {
8890
LOGGER.error("Unable to fire the event: {}", response);
8991
}
90-
} catch (Exception e) {
92+
} catch (SocketTimeoutException e) {
93+
if(!e.getMessage().equals("Read timed out")) {
94+
LOGGER.error("Failed to fire the event: {}", e);
95+
}
96+
} catch (Exception e) {
9197
LOGGER.error("Failed to fire the event: {}", e);
9298
}
9399
}

src/main/java/com/appirio/tech/core/service/identity/dao/UserDAO.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
import com.appirio.tech.core.service.identity.representation.Achievement;
3737
import com.appirio.tech.core.service.identity.representation.Country;
3838
import com.appirio.tech.core.service.identity.representation.Credential;
39-
import com.appirio.tech.core.service.identity.representation.CredentialVerification;
39+
import com.appirio.tech.core.service.identity.representation.User2fa;
4040
import com.appirio.tech.core.service.identity.representation.Email;
4141
import com.appirio.tech.core.service.identity.representation.GroupMembership;
4242
import com.appirio.tech.core.service.identity.representation.ProviderType;
@@ -98,9 +98,11 @@ public abstract class UserDAO implements DaoBase<User>, Transactional<UserDAO> {
9898
@SqlQuery(
9999
"SELECT " + USER_COLUMNS + ", " +
100100
"s.password AS credential$encodedPassword, e.address AS email, e.status_id AS emailStatus " +
101+
"mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " +
101102
"FROM common_oltp.user AS u " +
102103
"LEFT OUTER JOIN common_oltp.email AS e ON u.user_id = e.user_id AND e.email_type_id = 1 AND e.primary_ind = 1 " +
103104
"LEFT OUTER JOIN common_oltp.security_user AS s ON u.user_id = s.login_id " +
105+
"LEFT JOIN common_oltp.user_2fa mfa ON mfa.user_id = u.user_id " +
104106
"WHERE u.user_id = :id"
105107
)
106108
public abstract User findUserById(@Bind("id") long id);
@@ -130,18 +132,33 @@ public abstract class UserDAO implements DaoBase<User>, Transactional<UserDAO> {
130132

131133
@RegisterMapperFactory(TCBeanMapperFactory.class)
132134
@SqlQuery(
133-
"SELECT ud.id AS id, u.user_id AS userId, e.address AS email, ud.enabled AS enabled, ud.verified AS verified " +
135+
"SELECT mfa.id AS id, u.user_id AS userId, u.handle AS handle, u.first_name AS firstName, e.address AS email, mfa.enabled AS enabled, mfa.verified AS verified " +
134136
"FROM common_oltp.user AS u JOIN common_oltp.email AS e ON e.user_id = u.user_id " +
135-
"LEFT JOIN common_oltp.user_2fa AS ud ON ud.user_id = u.user_id " +
137+
"LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " +
136138
"WHERE LOWER(e.address) = LOWER(:email)"
137139
)
138-
public abstract List<CredentialVerification> findUser2faByEmail(@Bind("email") String email);
140+
public abstract List<User2fa> findUser2faByEmail(@Bind("email") String email);
141+
142+
@SqlQuery(
143+
"SELECT mfa.id AS id, u.user_id AS userId, u.handle AS handle, u.first_name AS firstName, e.address AS email, maf.enabled AS enabled, mfa.verified AS verified " +
144+
"FROM common_oltp.user AS u LEFT JOIN common_oltp.email AS e ON e.user_id = u.user_id " +
145+
"LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " +
146+
"WHERE u.user_id = :userId"
147+
)
148+
public abstract User2fa findUser2faById(@Bind("userId") long userId);
149+
150+
@SqlUpdate(
151+
"INSERT INTO common_oltp.user_2fa " +
152+
"(user_id, enabled) VALUES " +
153+
"(:userId, :enabled)")
154+
public abstract int insertUser2fa(@Bind("userId") long userId, @Bind("enabled") boolean enabled);
139155

140156
@SqlUpdate(
141157
"UPDATE common_oltp.user_2fa SET " +
158+
"enabled=:enabled " +
142159
"verified=:verified " +
143160
"WHERE id=:id")
144-
public abstract int update2faVerification(@Bind("id") long id, @Bind("verified") boolean verified);
161+
public abstract int update2fa(@Bind("id") long id, @Bind("enabled") boolean enabled, @Bind("verified") boolean verified);
145162

146163
@RegisterMapperFactory(TCBeanMapperFactory.class)
147164
@SqlQuery(
@@ -156,7 +173,9 @@ public abstract class UserDAO implements DaoBase<User>, Transactional<UserDAO> {
156173
@SqlQuery(
157174
"SELECT " + USER_COLUMNS + ", " +
158175
"e.address AS email, e.status_id AS emailStatus " +
176+
"mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " +
159177
"FROM common_oltp.user AS u " +
178+
"LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " +
160179
"<joinOnEmail> common_oltp.email AS e ON u.user_id = e.user_id AND e.primary_ind = 1 " +
161180
"<condition> " +
162181
"<order> " +
@@ -385,15 +404,15 @@ public User findUserByEmail(String email) {
385404
return users.get(0);
386405
}
387406

388-
public CredentialVerification findUserCredentialByEmail(String email) {
389-
List<CredentialVerification> users = findUser2faByEmail(email);
407+
public User2fa findUserCredentialByEmail(String email) {
408+
List<User2fa> users = findUser2faByEmail(email);
390409
if(users==null || users.size()==0)
391410
return null;
392411

393412
if(users.size()==1)
394413
return users.get(0);
395414

396-
for (CredentialVerification user : users) {
415+
for (User2fa user : users) {
397416
if(user.getEmail().equals(email))
398417
return user;
399418
}

src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java renamed to src/main/java/com/appirio/tech/core/service/identity/representation/User2fa.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package com.appirio.tech.core.service.identity.representation;
22

3-
public class CredentialVerification {
3+
public class User2fa {
44

55
private long id;
66
private long userId;
7+
private String handle;
8+
private String firstName;
79
private String email;
810
private Boolean enabled;
911
private Boolean verified;
@@ -24,6 +26,22 @@ public void setUserId(long userId) {
2426
this.userId = userId;
2527
}
2628

29+
public String getHandle() {
30+
return handle;
31+
}
32+
33+
public void setHandle(String handle) {
34+
this.handle = handle;
35+
}
36+
37+
public String getFirstName() {
38+
return firstName;
39+
}
40+
41+
public void setFirstName(String firstName) {
42+
this.firstName = firstName;
43+
}
44+
2745
public String getEmail() {
2846
return email;
2947
}

src/main/java/com/appirio/tech/core/service/identity/resource/UserResource.java

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,8 @@
5858
import com.appirio.tech.core.service.identity.representation.Achievement;
5959
import com.appirio.tech.core.service.identity.representation.Country;
6060
import com.appirio.tech.core.service.identity.representation.Credential;
61-
import com.appirio.tech.core.service.identity.representation.CredentialInvitation;
6261
import com.appirio.tech.core.service.identity.representation.CredentialRequest;
63-
import com.appirio.tech.core.service.identity.representation.CredentialVerification;
62+
import com.appirio.tech.core.service.identity.representation.User2fa;
6463
import com.appirio.tech.core.service.identity.representation.Email;
6564
import com.appirio.tech.core.service.identity.representation.ProviderType;
6665
import com.appirio.tech.core.service.identity.representation.Role;
@@ -1504,6 +1503,67 @@ public ApiResponse validateSocial(
15041503
createValidationResult((err == null), err));
15051504
}
15061505

1506+
@PATCH
1507+
@Path("/{resourceId}/2fa")
1508+
@Timed
1509+
public ApiResponse updateUser2fa(
1510+
@Auth AuthUser authUser,
1511+
@PathParam("resourceId") String resourceId,
1512+
@Valid PostPutRequest<User2fa> postRequest,
1513+
@Context HttpServletRequest request) {
1514+
1515+
logger.info(String.format("update user 2fa(%s)", resourceId));
1516+
1517+
TCID id = new TCID(resourceId);
1518+
validateResourceIdAndCheckPermission(authUser, id, user2faFactory.getUpdateScopes());
1519+
// checking param
1520+
checkParam(postRequest);
1521+
1522+
User2fa user2fa = postRequest.getParam();
1523+
1524+
if(user2fa.getEnabled() == null) {
1525+
throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "enabled"));
1526+
}
1527+
1528+
Long userId = Utils.toLongValue(id);
1529+
1530+
logger.info(String.format("findUserById(%s)", resourceId));
1531+
User2fa user2faInDb = userDao.findUser2faById(userId);
1532+
if(user2faInDb==null)
1533+
throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND);
1534+
1535+
Boolean shouldSendInvite = false;
1536+
if(user2faInDb.getEnabled() == null) {
1537+
userDao.insertUser2fa(userId, user2fa.getEnabled());
1538+
shouldSendInvite = user2fa.getEnabled();
1539+
} else if(!user2faInDb.getEnabled().equals(user2fa.getEnabled())) {
1540+
userDao.update2fa(user2faInDb.getId(), user2fa.getEnabled(), false);
1541+
shouldSendInvite = user2fa.getEnabled();
1542+
}
1543+
1544+
if (shouldSendInvite) {
1545+
Response response;
1546+
try {
1547+
response = new Request(diceAuth.getDiceApiUrl() + "/v1/connection/submit", "POST")
1548+
.param("emailId", user2faInDb.getEmail())
1549+
.header("x-api-key", diceAuth.getApiKey())
1550+
.execute();
1551+
} catch (Exception e) {
1552+
logger.error("Error when calling 2fa submit api", e);
1553+
throw new APIRuntimeException(SC_INTERNAL_SERVER_ERROR, "Error when calling 2fa submit api");
1554+
}
1555+
if (response.getStatusCode() != HttpURLConnection.HTTP_CREATED) {
1556+
throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR,
1557+
String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(),
1558+
response.getMessage()));
1559+
}
1560+
logger.info(response.getText());
1561+
send2faInvitationEmailEvent(user2faInDb, diceAuth.getDiceUrl() + "/verify/" + response.getText());
1562+
}
1563+
1564+
return ApiResponseFactory.createResponse("SUCCESS");
1565+
}
1566+
15071567
@POST
15081568
@Path("/2faCredentials")
15091569
@Timed
@@ -1524,15 +1584,15 @@ public ApiResponse issueCredentials(
15241584
logger.info(String.format("issue credential (%s)", credential.getEmail()));
15251585

15261586
// find user by email
1527-
User user = userDao.findUserByEmail(credential.getEmail());
1587+
User2fa user = userDao.findUserCredentialByEmail(credential.getEmail());
15281588

15291589
// return 404 if user is not found
15301590
if(user == null)
15311591
throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND);
1532-
if(user.getMfaEnabled() == null || !user.getMfaEnabled()) {
1592+
if(user.getEnabled() == null || !user.getEnabled()) {
15331593
throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user");
15341594
}
1535-
List<Role> roles = roleDao.getRolesBySubjectId(Long.parseLong(user.getId().getId()));
1595+
List<Role> roles = roleDao.getRolesBySubjectId(user.getUserId());
15361596
ObjectMapper mapper = new ObjectMapper();
15371597
ObjectNode body = mapper.createObjectNode();
15381598
body.put("comment", "TC credential");
@@ -1559,7 +1619,7 @@ public ApiResponse issueCredentials(
15591619
preview.set("attributes", attributes);
15601620
Response response;
15611621
try {
1562-
response = new Request(diceAuth.getDiceUrl()+"/v1/credentialoffer/api/credentialoffer", "POST")
1622+
response = new Request(diceAuth.getDiceApiUrl()+"/v1/credentialoffer/api/credentialoffer", "POST")
15631623
.header("x-api-key", diceAuth.getApiKey())
15641624
.json(mapper.writeValueAsString(body))
15651625
.execute();
@@ -1583,12 +1643,12 @@ public ApiResponse issueCredentials(
15831643
@Timed
15841644
public ApiResponse update2faVerification(
15851645
@Auth AuthUser authUser,
1586-
@Valid PostPutRequest<CredentialVerification> putRequest,
1646+
@Valid PostPutRequest<User2fa> putRequest,
15871647
@Context HttpServletRequest request) {
15881648

15891649
Utils.checkAccess(authUser, user2faFactory.getUpdateScopes(), Utils.AdminRoles);
15901650
checkParam(putRequest);
1591-
CredentialVerification credential = putRequest.getParam();
1651+
User2fa credential = putRequest.getParam();
15921652

15931653
if(credential.getEmail() == null || credential.getEmail().length() == 0) {
15941654
throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address"));
@@ -1599,7 +1659,7 @@ public ApiResponse update2faVerification(
15991659
logger.info(String.format("update 2fa verification (%s) - %b", credential.getEmail(), credential.getVerified()));
16001660

16011661
// find user by email
1602-
CredentialVerification credVerification = userDao.findUserCredentialByEmail(credential.getEmail());
1662+
User2fa credVerification = userDao.findUserCredentialByEmail(credential.getEmail());
16031663

16041664
// return 404 if user is not found
16051665
if(credVerification == null)
@@ -1609,43 +1669,11 @@ public ApiResponse update2faVerification(
16091669
throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user");
16101670
}
16111671
if(!credVerification.getVerified().equals(credential.getVerified())) {
1612-
userDao.update2faVerification(credVerification.getId(), credential.getVerified());
1672+
userDao.update2fa(credVerification.getId(), true, credential.getVerified());
16131673
}
16141674
return ApiResponseFactory.createResponse("User verification updated");
16151675
}
16161676

1617-
@POST
1618-
@Path("/2faInvitation")
1619-
@Timed
1620-
public ApiResponse send2faInvitation(
1621-
@Auth AuthUser authUser,
1622-
@Valid PostPutRequest<CredentialInvitation> postRequest,
1623-
@Context HttpServletRequest request) {
1624-
Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles);
1625-
checkParam(postRequest);
1626-
CredentialInvitation invitation = postRequest.getParam();
1627-
1628-
if(invitation.getEmail() == null || invitation.getEmail().length() == 0) {
1629-
throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address"));
1630-
}
1631-
if(invitation.getInvitationUrl() == null || invitation.getInvitationUrl().length() == 0) {
1632-
throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Invitation Url"));
1633-
}
1634-
logger.info(String.format("send 2fa invitation to (%s)", invitation.getEmail()));
1635-
1636-
// find user by email
1637-
User user = userDao.findUserByEmail(invitation.getEmail());
1638-
1639-
// return 404 if user is not found
1640-
if(user == null)
1641-
throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND);
1642-
if(user.getMfaEnabled() == null || !user.getMfaEnabled()) {
1643-
throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user");
1644-
}
1645-
send2faInvitationEmailEvent(user, invitation.getInvitationUrl());
1646-
return ApiResponseFactory.createResponse("SUCCESS");
1647-
}
1648-
16491677
@POST
16501678
@Path("/oneTimeToken")
16511679
@Timed
@@ -2061,7 +2089,7 @@ private void sendActivationEmailEvent(User user, String redirectUrl) {
20612089
}
20622090
}
20632091

2064-
private void send2faInvitationEmailEvent(User user, String inviteLink) {
2092+
private void send2faInvitationEmailEvent(User2fa user, String inviteLink) {
20652093

20662094
EventMessage msg = EventMessage.getDefault();
20672095
msg.setTopic("external.action.email");
@@ -2086,11 +2114,7 @@ private void send2faInvitationEmailEvent(User user, String inviteLink) {
20862114
payload.put("recipients", recipients);
20872115

20882116
msg.setPayload(payload);
2089-
try {
2090-
this.eventBusServiceClient.reFireEvent(msg);
2091-
} catch (Exception e) {
2092-
logger.error("Error occured while publishing the events to new kafka.");
2093-
}
2117+
this.eventBusServiceClient.reFireEvent(msg);
20942118
}
20952119

20962120
private void sendWelcomeEmailEvent(User user) {

0 commit comments

Comments
 (0)