diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 38dcb0c..3347689 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -20,6 +20,7 @@ DICEAUTH_DICE_API_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_URL") DICEAUTH_DICE_VERIFIER=$(eval "echo \$${ENV}_DICEAUTH_DICE_VERIFIER") DICEAUTH_DICE_API_KEY=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_KEY") DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") +DICEAUTH_OTP_DURATION=$(eval "echo \$${ENV}_OTP_DURATION") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") AUTH_SECRET=$(eval "echo \$${ENV}_AUTH_SECRET") @@ -94,6 +95,7 @@ perl -pi -e "s|\{\{DICEAUTH_DICE_API_URL\}\}|$DICEAUTH_DICE_API_URL|g" $CONFFILE perl -pi -e "s|\{\{DICEAUTH_DICE_VERIFIER\}\}|$DICEAUTH_DICE_VERIFIER|g" $CONFFILENAME perl -pi -e "s|\{\{DICEAUTH_DICE_API_KEY\}\}|$DICEAUTH_DICE_API_KEY|g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_OTP_DURATION\}\}/$DICEAUTH_OTP_DURATION/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_ID\}\}/$ZENDESK_ID/g" $CONFFILENAME perl -pi -e "s/\{\{SERVICEACC01_CID\}\}/$SERVICEACC01_CID/g" $CONFFILENAME diff --git a/src/main/java/com/appirio/tech/core/service/identity/dao/UserDAO.java b/src/main/java/com/appirio/tech/core/service/identity/dao/UserDAO.java index c6ceece..e25ee07 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/dao/UserDAO.java +++ b/src/main/java/com/appirio/tech/core/service/identity/dao/UserDAO.java @@ -171,9 +171,9 @@ public abstract class UserDAO implements DaoBase, Transactional { @SqlUpdate( "UPDATE common_oltp.user_2fa SET " + "otp=:otp, " + - "otp_expire=current_timestamp + (5 ||' minutes')::interval " + + "otp_expire=current_timestamp + (:duration ||' minutes')::interval " + "WHERE id=:id") - public abstract int update2faOtp(@Bind("id") long id, @Bind("otp") String otp); + public abstract int update2faOtp(@Bind("id") long id, @Bind("otp") String otp, @Bind("duration") int duration); @SqlQuery( "UPDATE common_oltp.user_2fa x SET otp=null, otp_expire=null " + diff --git a/src/main/java/com/appirio/tech/core/service/identity/resource/UserResource.java b/src/main/java/com/appirio/tech/core/service/identity/resource/UserResource.java index afc57bd..e1b9429 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/resource/UserResource.java +++ b/src/main/java/com/appirio/tech/core/service/identity/resource/UserResource.java @@ -1676,7 +1676,10 @@ public ApiResponse update2faVerification( if(credVerification.getEnabled() == null || !credVerification.getEnabled()) { throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); } - if(!credVerification.getVerified().equals(credential.getVerified())) { + // update only if it's true. We need to prevent changing verification status from true to false + // Otherwise 2fa will be skipped during the login flow. + // The only way to set verification to false is disabling the 2fa for that user. + if(credential.getVerified()) { userDao.update2fa(credVerification.getId(), true, credential.getVerified()); } return ApiResponseFactory.createResponse("User verification updated"); @@ -1706,8 +1709,8 @@ public ApiResponse createOtp( throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); } String otp = Utils.generateRandomString(ALPHABET_DIGITS_EN, 6); - userDao.update2faOtp(user2faInDb.getId(), otp); - send2faCodeEmailEvent(user2faInDb, otp); + userDao.update2faOtp(user2faInDb.getId(), otp, diceAuth.getOtpDuration()); + send2faCodeEmailEvent(user2faInDb, otp, diceAuth.getOtpDuration()); return ApiResponseFactory.createResponse("SUCCESS"); } @@ -2193,7 +2196,7 @@ private void send2faInvitationEmailEvent(User2fa user, String inviteLink) { this.eventBusServiceClient.reFireEvent(msg); } - private void send2faCodeEmailEvent(User2fa user, String code) { + private void send2faCodeEmailEvent(User2fa user, String code, Integer duration) { EventMessage msg = EventMessage.getDefault(); msg.setTopic("external.action.email"); @@ -2202,6 +2205,7 @@ private void send2faCodeEmailEvent(User2fa user, String code) { Map data = new LinkedHashMap(); data.put("handle", user.getHandle()); data.put("code", code); + data.put("duration", duration); payload.put("data", data); diff --git a/src/main/java/com/appirio/tech/core/service/identity/util/auth/DICEAuth.java b/src/main/java/com/appirio/tech/core/service/identity/util/auth/DICEAuth.java index 402c07d..3d21257 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/util/auth/DICEAuth.java +++ b/src/main/java/com/appirio/tech/core/service/identity/util/auth/DICEAuth.java @@ -19,17 +19,22 @@ public class DICEAuth { @NotNull private String credDefId; + @NotNull + private Integer otpDuration; + private String credPreview = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview"; public DICEAuth() { } - public DICEAuth(String diceUrl, String diceApiUrl, String diceVerifier, String diceApiKey, String credDefId) { + public DICEAuth(String diceUrl, String diceApiUrl, String diceVerifier, String diceApiKey, String credDefId, + Integer otpDuration) { this.diceUrl = diceUrl; this.diceApiUrl = diceApiUrl; this.diceVerifier = diceVerifier; this.diceApiKey = diceApiKey; this.credDefId = credDefId; + this.otpDuration = otpDuration; } public String getDiceUrl() { @@ -72,6 +77,14 @@ public void setCredDefId(String credDefId) { this.credDefId = credDefId; } + public Integer getOtpDuration() { + return otpDuration; + } + + public void setOtpDuration(Integer otpDuration) { + this.otpDuration = otpDuration; + } + public String getCredPreview() { return credPreview; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 15af415..8f398c6 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -99,6 +99,7 @@ diceAuth: diceVerifier: @diceAuth.diceVerifier@ diceApiKey: @diceAuth.diceApiKey@ credDefId: @diceAuth.credDefId@ + otpDuration: @diceAuth.otpDuration@ # Authorized accounts serviceAccount: diff --git a/src/main/resources/config.yml.localdev b/src/main/resources/config.yml.localdev index 26cb2ab..6cf3a94 100644 --- a/src/main/resources/config.yml.localdev +++ b/src/main/resources/config.yml.localdev @@ -91,6 +91,7 @@ diceAuth: diceVerifier: dummy diceApiKey: dummy credDefId: dummy + otpDuration: 10 # LDAP Settings ldap: diff --git a/src/main/resources/sql/User_2fa_Create.sql b/src/main/resources/sql/User_2fa_Create.sql index f384668..98efdc3 100644 --- a/src/main/resources/sql/User_2fa_Create.sql +++ b/src/main/resources/sql/User_2fa_Create.sql @@ -1 +1 @@ -CREATE TABLE common_oltp.user_2fa (id SERIAL, user_id DECIMAL(10,0) UNIQUE NOT NULL, enabled BOOLEAN DEFAULT false NOT NULL, verified BOOLEAN DEFAULT false NOT NULL, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES common_oltp.user (user_id)); +CREATE TABLE common_oltp.user_2fa (id SERIAL NOT NULL, user_id NUMERIC(10,0) NOT NULL, enabled BOOLEAN DEFAULT false NOT NULL, verified BOOLEAN DEFAULT false NOT NULL, otp CHARACTER VARYING(6), otp_expire TIMESTAMP(6) WITHOUT TIME ZONE, CONSTRAINT user_2fa_pk PRIMARY KEY (id), CONSTRAINT user_2fa_user_id_fkey FOREIGN KEY (user_id) REFERENCES "user" ("user_id"), UNIQUE (user_id)); diff --git a/token.properties.localdev b/token.properties.localdev index fcca202..3b6096b 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -36,6 +36,7 @@ @diceAuth.diceVerifier@=dummy @diceAuth.diceApiKey@=dummy @diceAuth.credDefId@=dummy +@diceAuth.otpDuration@=10 @zendesk.secret@=ZENDESK_SECRET @zendesk.idprefix@=ZENDESK_PREFIX diff --git a/token.properties.template b/token.properties.template index 172a6ed..1e2d82d 100644 --- a/token.properties.template +++ b/token.properties.template @@ -56,6 +56,7 @@ @diceAuth.diceVerifier@={{DICEAUTH_DICE_VERIFIER}} @diceAuth.diceApiKey@={{DICEAUTH_DICE_API_KEY}} @diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} +@diceAuth.otpDuration@={{DICEAUTH_OTP_DURATION}} @zendesk.secret@={{ZENDESK_KEY}} @zendesk.idprefix@={{ZENDESK_ID}}