From 912dac69b095c5ec44ef66583c7135c4729f2c5f Mon Sep 17 00:00:00 2001 From: Sachin Maheshwari Date: Wed, 18 May 2022 16:13:48 +0530 Subject: [PATCH 01/32] deploying on dev --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 232f6a5..e53c464 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -146,7 +146,7 @@ workflows: context : org-global filters: branches: - only: [dev, 'feature/jira-plat-152'] + only: [dev, 'feature/jira-plat-152', 'auth0-kt'] # Production build is executed on "master" branch only. - "build-prod": context : org-global From 8ed808b6c4ff79d5ce37811d6116beed2836db78 Mon Sep 17 00:00:00 2001 From: Gunasekar-K Date: Wed, 18 May 2022 18:33:26 +0530 Subject: [PATCH 02/32] Update build-image.sh --- build/build-image.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/build-image.sh b/build/build-image.sh index e7cf902..6f3cb30 100755 --- a/build/build-image.sh +++ b/build/build-image.sh @@ -25,7 +25,7 @@ VER=`date "+%Y%m%d%H%M"` # } # configure_aws_cli -aws s3 cp "s3://appirio-platform-$CONFIG/services/common/dockercfg" ~/.dockercfg +# aws s3 cp "s3://appirio-platform-$CONFIG/services/common/dockercfg" ~/.dockercfg # Elastic Beanstalk Application name # dev @@ -97,6 +97,12 @@ cat $WORK_DIR/config/sumo-template.conf | sed -e "s/@APINAME@/${SERVICE}/g" | se cat $WORK_DIR/config/sumo-sources-template.json | sed -e "s/@APINAME@/${SERVICE}/g" | sed -e "s/@CONFIG@/${CONFIG}/g" > $DOCKER_DIR/sumo-sources.json cat $WORK_DIR/config/newrelic-template.yml | sed -e "s/@APINAME@/${SERVICE}/g" | sed -e "s/@CONFIG@/${CONFIG}/g" > $DOCKER_DIR/newrelic.yml +echo "Logging into docker" +echo "############################" +DOCKER_USER=$(aws ssm get-parameter --name /$CONFIG/build/dockeruser --with-decryption --output text --query Parameter.Value) +DOCKER_PASSWD=$(aws ssm get-parameter --name /$CONFIG/build/dockercfg --with-decryption --output text --query Parameter.Value) +echo $DOCKER_PASSWD | docker login -u $DOCKER_USER --password-stdin + echo "building docker image: ${IMAGE}" docker build -t $TAG $DOCKER_DIR handle_error "docker build failed." From 01b853c0414a1e991172634e394b9fc1fdcfef29 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Sat, 2 Jul 2022 19:05:16 +0300 Subject: [PATCH 03/32] add 2fa endpoints --- buildtokenproperties.sh | 24 +++ .../service/identity/IdentityApplication.java | 3 +- .../identity/IdentityConfiguration.java | 9 + .../identity/M2mAuthConfiguration.java | 12 ++ .../core/service/identity/dao/UserDAO.java | 32 ++++ .../representation/CredentialRequest.java | 23 +++ .../CredentialVerification.java | 50 +++++ .../identity/resource/UserResource.java | 143 +++++++++++++- .../service/identity/util/auth/DICEAuth.java | 177 ++++++++++++++++++ .../util/m2mscope/User2faFactory.java | 142 ++++++++++++++ src/main/resources/config.yml | 14 ++ src/main/resources/config.yml.localdev | 15 ++ src/main/resources/sql/User_2fa_Create.sql | 1 + .../identity/resource/UserResourceTest.java | 5 +- token.properties.localdev | 13 ++ token.properties.template | 13 ++ 16 files changed, 672 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/appirio/tech/core/service/identity/representation/CredentialRequest.java create mode 100644 src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java create mode 100644 src/main/java/com/appirio/tech/core/service/identity/util/auth/DICEAuth.java create mode 100644 src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java create mode 100644 src/main/resources/sql/User_2fa_Create.sql diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 048aa68..47ac828 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -15,6 +15,14 @@ AUTH0_NEW_ID=$(eval "echo \$${ENV}_AUTH0_NEW_ID") AUTH0_NEW_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_ID_SECRET") AUTH0_NEW_NONINTERACTIVE_ID=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID") AUTH0_NEW_NONINTERACTIVE_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID_SECRET") +DICEAUTH_ID=$(eval "echo \$${ENV}_DICEAUTH_ID") +DICEAUTH_ID_SECRET=$(eval "echo \$${ENV}_DICEAUTH_ID_SECRET") +DICEAUTH_PASSWORD=$(eval "echo \$${ENV}_DICEAUTH_PASSWORD") +DICEAUTH_SCOPE=$(eval "echo \$${ENV}_DICEAUTH_SCOPE") +DICEAUTH_TENANT=$(eval "echo \$${ENV}_DICEAUTH_TENANT") +DICEAUTH_USERNAME=$(eval "echo \$${ENV}_DICEAUTH_USERNAME") +DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") +DICEAUTH_CREDPREVIEW=$(eval "echo \$${ENV}_DICEAUTH_CREDPREVIEW") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") AUTH_SECRET=$(eval "echo \$${ENV}_AUTH_SECRET") @@ -33,6 +41,10 @@ M2MAUTHCONFIG_USERPROFILES_CREATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFIL M2MAUTHCONFIG_USERPROFILES_UPDATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFILES_UPDATE") M2MAUTHCONFIG_USERPROFILES_READ=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFILES_READ") M2MAUTHCONFIG_USERPROFILES_DELETE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFILES_DELETE") +M2MAUTHCONFIG_USER2FA_CREATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_CREATE") +M2MAUTHCONFIG_USER2FA_UPDATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_UPDATE") +M2MAUTHCONFIG_USER2FA_READ=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_READ") +M2MAUTHCONFIG_USER2FA_DELETE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_DELETE") DOMAIN=$(eval "echo \$${ENV}_DOMAIN") SMTP=$(eval "echo \$${ENV}_SMTP") @@ -79,6 +91,14 @@ perl -pi -e "s/\{\{AUTH0_NEW_ID\}\}/$AUTH0_NEW_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_ID_SECRET\}\}/$AUTH0_NEW_ID_SECRET/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_ID\}\}/$DICEAUTH_ID/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_ID_SECRET\}\}/$DICEAUTH_ID_SECRET/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_PASSWORD\}\}/$DICEAUTH_PASSWORD/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_SCOPE\}\}/$DICEAUTH_SCOPE/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_TENANT\}\}/$DICEAUTH_TENANT/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_USERNAME\}\}/$DICEAUTH_USERNAME/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_CREDPREVIEW\}\}/$DICEAUTH_CREDPREVIEW/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 @@ -109,6 +129,10 @@ perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_CREATE\}\}|$M2MAUTHCONFIG_USERPROF perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_UPDATE\}\}|$M2MAUTHCONFIG_USERPROFILES_UPDATE|g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_READ\}\}|$M2MAUTHCONFIG_USERPROFILES_READ|g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_DELETE\}\}|$M2MAUTHCONFIG_USERPROFILES_DELETE|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_CREATE\}\}|$M2MAUTHCONFIG_USER2FA_CREATE|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_UPDATE\}\}|$M2MAUTHCONFIG_USER2FA_UPDATE|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_READ\}\}|$M2MAUTHCONFIG_USER2FA_READ|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_DELETE\}\}|$M2MAUTHCONFIG_USER2FA_DELETE|g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_DOMAIN\}\}/$AUTH0_NEW_DOMAIN/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_DOMAIN\}\}/$AUTH0_DOMAIN/g" $CONFFILENAME perl -pi -e "s/\{\{SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME diff --git a/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java b/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java index c6d5175..96d534f 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java +++ b/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java @@ -234,8 +234,9 @@ public void run(IdentityConfiguration configuration, Environment environment) th configuration.getEventBusServiceClientConfig(), configuration.getM2mAuthConfiguration()); // Resources::users CacheService cacheService = configuration.getCache().createCacheService(); - UserResource userResource = new UserResource(userDao, roleDao, cacheService, eventProducer, eventBusServiceClient, configuration.getM2mAuthConfiguration().getUserProfiles()); + UserResource userResource = new UserResource(userDao, roleDao, cacheService, eventProducer, eventBusServiceClient, configuration.getM2mAuthConfiguration().getUserProfiles(), configuration.getM2mAuthConfiguration().getUser2fa()); userResource.setAuth0Client(configuration.getAuth0()); // TODO: constructor + userResource.setDiceAuth(configuration.getDiceAuth()); userResource.setDomain(configuration.getAuthDomain()); userResource.setSendgridTemplateId(Utils.getString("sendGridTemplateId")); userResource.setSendgridWelcomeTemplateId(Utils.getString("sendGridWelcomeTemplateId")); diff --git a/src/main/java/com/appirio/tech/core/service/identity/IdentityConfiguration.java b/src/main/java/com/appirio/tech/core/service/identity/IdentityConfiguration.java index db258e1..47bc920 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/IdentityConfiguration.java +++ b/src/main/java/com/appirio/tech/core/service/identity/IdentityConfiguration.java @@ -11,6 +11,7 @@ import com.appirio.clients.BaseClientConfiguration; import com.appirio.tech.core.api.v3.dropwizard.APIBaseConfiguration; import com.appirio.tech.core.service.identity.util.auth.Auth0Client; +import com.appirio.tech.core.service.identity.util.auth.DICEAuth; import com.appirio.tech.core.service.identity.util.auth.ServiceAccountAuthenticatorFactory; import com.appirio.tech.core.service.identity.util.cache.CacheServiceFactory; import com.appirio.tech.core.service.identity.util.event.EventSystemFactory; @@ -61,6 +62,10 @@ public class IdentityConfiguration extends APIBaseConfiguration { @Valid @JsonProperty private Auth0Client auth0New = new Auth0Client(); + + @Valid + @JsonProperty + private DICEAuth diceAuth = new DICEAuth(); @Valid @NotNull @@ -135,6 +140,10 @@ public Auth0Client getAuth0() { public Auth0Client getAuth0New() { return auth0New; } + + public DICEAuth getDiceAuth() { + return diceAuth; + } public LDAPServiceFactory getLdap() { return ldap; diff --git a/src/main/java/com/appirio/tech/core/service/identity/M2mAuthConfiguration.java b/src/main/java/com/appirio/tech/core/service/identity/M2mAuthConfiguration.java index 8b27c23..17d0f2c 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/M2mAuthConfiguration.java +++ b/src/main/java/com/appirio/tech/core/service/identity/M2mAuthConfiguration.java @@ -1,5 +1,6 @@ package com.appirio.tech.core.service.identity; +import com.appirio.tech.core.service.identity.util.m2mscope.User2faFactory; import com.appirio.tech.core.service.identity.util.m2mscope.UserProfilesFactory; import com.fasterxml.jackson.annotation.JsonProperty; import javax.validation.constraints.NotNull; @@ -65,6 +66,9 @@ public class M2mAuthConfiguration { @JsonProperty private UserProfilesFactory userProfiles = new UserProfilesFactory(); + @JsonProperty + private User2faFactory user2fa = new User2faFactory(); + public UserProfilesFactory getUserProfiles() { return userProfiles; } @@ -73,6 +77,14 @@ public void setUserProfiles(UserProfilesFactory userProfiles) { this.userProfiles = userProfiles; } + public User2faFactory getUser2fa() { + return user2fa; + } + + public void setUser2fa(User2faFactory user2fa) { + this.user2fa = user2fa; + } + /** * Get clientId * 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 254513a..7217635 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 @@ -36,6 +36,7 @@ import com.appirio.tech.core.service.identity.representation.Achievement; import com.appirio.tech.core.service.identity.representation.Country; import com.appirio.tech.core.service.identity.representation.Credential; +import com.appirio.tech.core.service.identity.representation.CredentialVerification; import com.appirio.tech.core.service.identity.representation.Email; import com.appirio.tech.core.service.identity.representation.GroupMembership; import com.appirio.tech.core.service.identity.representation.ProviderType; @@ -123,6 +124,21 @@ public abstract class UserDAO implements DaoBase, Transactional { ) public abstract List findUsersByEmail(@Bind("email") String email); + @RegisterMapperFactory(TCBeanMapperFactory.class) + @SqlQuery( + "SELECT ud.id AS id, u.user_id AS userId, e.address AS email, ud.enabled AS enabled, ud.verified AS verified " + + "FROM common_oltp.user AS u JOIN common_oltp.email AS e ON e.user_id = u.user_id " + + "LEFT JOIN common_oltp.user_2fa AS ud ON ud.user_id = u.user_id " + + "WHERE LOWER(e.address) = LOWER(:email)" + ) + public abstract List findUser2faByEmail(@Bind("email") String email); + + @SqlUpdate( + "UPDATE common_oltp.user_2fa SET " + + "verified=:verified " + + "WHERE id=:id") + public abstract int update2faVerification(@Bind("id") long id, @Bind("verified") boolean verified); + @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + @@ -364,6 +380,22 @@ public User findUserByEmail(String email) { // nothing matched with email parameter in the result, returns the first one. return users.get(0); } + + public CredentialVerification findUserCredentialByEmail(String email) { + List users = findUser2faByEmail(email); + if(users==null || users.size()==0) + return null; + + if(users.size()==1) + return users.get(0); + + for (CredentialVerification user : users) { + if(user.getEmail().equals(email)) + return user; + } + + return users.get(0); + } /** * diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialRequest.java b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialRequest.java new file mode 100644 index 0000000..1a61ae0 --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialRequest.java @@ -0,0 +1,23 @@ +package com.appirio.tech.core.service.identity.representation; + +public class CredentialRequest { + + private String email; + private String connectionId; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getConnectionId() { + return connectionId; + } + + public void setConnectionId(String connectionId) { + this.connectionId = connectionId; + } +} diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java new file mode 100644 index 0000000..159a780 --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java @@ -0,0 +1,50 @@ +package com.appirio.tech.core.service.identity.representation; + +public class CredentialVerification { + + private long id; + private long userId; + private String email; + private Boolean enabled; + private Boolean verified; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + this.enabled = enabled; + } + + public Boolean getVerified() { + return verified; + } + + public void setVerified(Boolean verified) { + this.verified = verified; + } +} 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 a84eda0..db55cb3 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 @@ -3,15 +3,21 @@ import static com.appirio.tech.core.service.identity.util.Constants.*; import static javax.servlet.http.HttpServletResponse.*; +import com.appirio.tech.core.service.identity.util.m2mscope.User2faFactory; import com.appirio.tech.core.service.identity.util.m2mscope.UserProfilesFactory; import io.dropwizard.auth.Auth; import io.dropwizard.jersey.PATCH; import java.net.HttpURLConnection; +import java.text.DateFormat; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import java.util.LinkedHashMap; import javax.servlet.http.HttpServletRequest; @@ -54,6 +60,8 @@ import com.appirio.tech.core.service.identity.representation.Achievement; import com.appirio.tech.core.service.identity.representation.Country; import com.appirio.tech.core.service.identity.representation.Credential; +import com.appirio.tech.core.service.identity.representation.CredentialRequest; +import com.appirio.tech.core.service.identity.representation.CredentialVerification; import com.appirio.tech.core.service.identity.representation.Email; import com.appirio.tech.core.service.identity.representation.ProviderType; import com.appirio.tech.core.service.identity.representation.Role; @@ -61,14 +69,20 @@ import com.appirio.tech.core.service.identity.representation.UserProfile; import com.appirio.tech.core.service.identity.util.Constants; import com.appirio.tech.core.service.identity.util.Utils; +import com.appirio.tech.core.service.identity.util.HttpUtil.Request; +import com.appirio.tech.core.service.identity.util.HttpUtil.Response; import com.appirio.tech.core.service.identity.util.auth.Auth0Client; +import com.appirio.tech.core.service.identity.util.auth.DICEAuth; import com.appirio.tech.core.service.identity.util.auth.OneTimeToken; import com.appirio.tech.core.service.identity.util.cache.CacheService; import com.appirio.tech.core.service.identity.util.event.MailRepresentation; import com.appirio.tech.core.service.identity.util.event.NotificationPayload; import com.appirio.tech.core.service.identity.util.ldap.MemberStatus; import com.codahale.metrics.annotation.Timed; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; /** @@ -119,6 +133,8 @@ public class UserResource implements GetResource, DDLResource { private Auth0Client auth0; + private DICEAuth diceAuth; + private final EventProducer eventProducer; private ObjectMapper objectMapper = new ObjectMapper(); @@ -133,6 +149,8 @@ public class UserResource implements GetResource, DDLResource { private final EventBusServiceClient eventBusServiceClient; private final UserProfilesFactory userProfilesFactory; + + private final User2faFactory user2faFactory; /** * Create UserResource @@ -149,7 +167,8 @@ public UserResource( RoleDAO roleDao, CacheService cacheService, EventProducer eventProducer, - EventBusServiceClient eventBusServiceClient, UserProfilesFactory userProfilesFactory) { + EventBusServiceClient eventBusServiceClient, UserProfilesFactory userProfilesFactory, + User2faFactory user2faFactory) { this.userDao = userDao; this.roleDao = roleDao; this.cacheService = cacheService; @@ -161,6 +180,12 @@ public UserResource( } else { this.userProfilesFactory = userProfilesFactory; } + if (user2faFactory == null) { + // create a default one + this.user2faFactory = new User2faFactory(); + } else { + this.user2faFactory = user2faFactory; + } } /** @@ -178,7 +203,7 @@ public UserResource( CacheService cacheService, EventProducer eventProducer, EventBusServiceClient eventBusServiceClient) { - this(userDao, roleDao, cacheService, eventProducer, eventBusServiceClient, null); + this(userDao, roleDao, cacheService, eventProducer, eventBusServiceClient, null, null); } protected void setObjectMapper(ObjectMapper objectMapper) { @@ -189,6 +214,10 @@ public void setAuth0Client(Auth0Client auth0) { this.auth0 = auth0; } + public void setDiceAuth(DICEAuth diceAuth) { + this.diceAuth = diceAuth; + } + private static void checkAccessAndUserProfile(AuthUser authUser, long userId, UserProfile profile, String[] allowedScopes) { Utils.checkAccess(authUser, allowedScopes, Utils.AdminRoles); @@ -1474,6 +1503,116 @@ public ApiResponse validateSocial( createValidationResult((err == null), err)); } + @POST + @Path("/2faCredentials") + @Timed + public ApiResponse issueCredentials( + @Auth AuthUser authUser, + @Valid PostPutRequest postRequest, + @Context HttpServletRequest request) { + Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles); + CredentialRequest credential = postRequest.getParam(); + + if(credential == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Request Body")); + } + if(credential.getEmail() == null || credential.getEmail().length() == 0) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); + } + if(credential.getConnectionId() == null || credential.getConnectionId().length() == 0) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Connection Id")); + } + logger.info(String.format("issue credential (%s)", credential.getEmail())); + + // find user by email + User user = userDao.findUserByEmail(credential.getEmail()); + + // return 404 if user is not found + if(user == null) + throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); + List roles = roleDao.getRolesBySubjectId(Long.parseLong(user.getId().getId())); + ObjectMapper mapper = new ObjectMapper(); + ObjectNode body = mapper.createObjectNode(); + body.put("comment", "TC credential"); + body.put("connection_id", credential.getConnectionId()); + body.put("cred_def_id", diceAuth.getCredDefId()); + ObjectNode preview = mapper.createObjectNode(); + preview.put("@type", diceAuth.getCredPreview()); + ArrayNode attributes = mapper.createArrayNode(); + ObjectNode name = attributes.addObject(); + ObjectNode email = attributes.addObject(); + ObjectNode role = attributes.addObject(); + ObjectNode validUntil = attributes.addObject(); + name.put("name", "Name"); + name.put("value", user.getFirstName()); + email.put("name", "Email"); + email.put("value", user.getEmail()); + role.put("name", "Role"); + role.put("value", roles.stream().map(x -> x.getRoleName()).collect(Collectors.joining(","))); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.YEAR, 1); + validUntil.put("name", "Valid_Till"); + validUntil.put("value", new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ").format(cal.getTime())); + body.set("credential_preview", preview); + preview.set("attributes", attributes); + Response response; + try { + response = new Request("https://dicecontroller-topcoder.wiprobc.com/api/credentialoffer", "POST") + .header("Authorization", "Bearer " + diceAuth.getToken()) + .json(mapper.writeValueAsString(body)) + .execute(); + } catch (JsonProcessingException e) { + logger.error("Error when processing JSON content", e); + throw new APIRuntimeException(SC_INTERNAL_SERVER_ERROR, "Error when calling credentialoffer api"); + } catch (Exception e) { + logger.error("Error when calling credentialoffer api", e); + throw new APIRuntimeException(SC_INTERNAL_SERVER_ERROR, "Error when calling credentialoffer api"); + } + if (response.getStatusCode() != HttpURLConnection.HTTP_CREATED) { + throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, + String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), + response.getMessage())); + } + return ApiResponseFactory.createResponse(response.getText()); + } + + @PUT + @Path("/2faVerification") + @Timed + public ApiResponse update2faVerification( + @Auth AuthUser authUser, + @Valid PostPutRequest putRequest, + @Context HttpServletRequest request) { + + Utils.checkAccess(authUser, user2faFactory.getUpdateScopes(), Utils.AdminRoles); + CredentialVerification credential = putRequest.getParam(); + if(credential == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Request Body")); + } + if(credential.getEmail() == null || credential.getEmail().length() == 0) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); + } + if(credential.getVerified() == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Verified")); + } + logger.info(String.format("update 2fa verification (%s) - %b", credential.getEmail(), credential.getVerified())); + + // find user by email + CredentialVerification credVerification = userDao.findUserCredentialByEmail(credential.getEmail()); + + // return 404 if user is not found + if(credVerification == null) + throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); + + if(credVerification.getEnabled() == null || !credVerification.getEnabled()) { + throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); + } + if(!credVerification.getVerified().equals(credential.getVerified())) { + userDao.update2faVerification(credVerification.getId(), credential.getVerified()); + } + return ApiResponseFactory.createResponse("User verification updated"); + } + @POST @Path("/oneTimeToken") @Timed 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 new file mode 100644 index 0000000..aa03e0f --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/util/auth/DICEAuth.java @@ -0,0 +1,177 @@ +package com.appirio.tech.core.service.identity.util.auth; + +import java.net.HttpURLConnection; +import java.util.Date; + +import javax.validation.constraints.NotNull; + +import org.apache.log4j.Logger; + +import com.appirio.tech.core.api.v3.exception.APIRuntimeException; +import com.appirio.tech.core.api.v3.util.jwt.InvalidTokenException; +import com.appirio.tech.core.service.identity.util.HttpUtil.Request; +import com.appirio.tech.core.service.identity.util.HttpUtil.Response; +import com.auth0.jwt.JWT; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.fasterxml.jackson.databind.ObjectMapper; + +public class DICEAuth { + private static final Logger logger = Logger.getLogger(Auth0Client.class); + + @NotNull + private String tenant; + + @NotNull + private String username; + + @NotNull + private String password; + + @NotNull + private String scope; + + @NotNull + private String clientId; + + @NotNull + private String clientSecret; + + @NotNull + private String credDefId; + + @NotNull + private String credPreview; + + private String cachedToken; + + public DICEAuth() { + } + + public DICEAuth(String tenant, String username, String password, String scope, String clientId, + String clientSecret, String credDefId, String credPreview) { + this.tenant = tenant; + this.username = username; + this.password = password; + this.scope = scope; + this.clientId = clientId; + this.clientSecret = clientSecret; + this.credDefId = credDefId; + this.credPreview = credPreview; + } + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public String getCredDefId() { + return credDefId; + } + + public void setCredDefId(String credDefId) { + this.credDefId = credDefId; + } + + public String getCredPreview() { + return credPreview; + } + + public void setCredPreview(String credPreview) { + this.credPreview = credPreview; + } + + public String getToken() throws Exception { + Boolean isCachedTokenExpired = false; + if (cachedToken != null) { + if (getTokenExpiryTime(cachedToken) <= 0) { + isCachedTokenExpired = true; + logger.info("Application cached token expired"); + } + } + if (cachedToken == null || isCachedTokenExpired) { + Response response = new Request( + "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token", "POST") + .param("grant_type", "password") + .param("username", getUsername()) + .param("password", getPassword()) + .param("scope", getScope()) + .param("client_id", getClientId()) + .param("client_secret", getClientSecret()).execute(); + if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { + throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, + String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), + response.getMessage())); + } + cachedToken = new ObjectMapper().readValue(response.getText(), Auth0Credential.class).getIdToken(); + } + return cachedToken; + } + + /** + * Get token expiry time in seconds + * + * @param token JWT token + * throws Exception if any error occurs + * @return the Integer result + */ + private Integer getTokenExpiryTime(String token) throws Exception { + DecodedJWT decodedJWT = null; + Integer tokenExpiryTime = 0; + if (token != null) { + try { + decodedJWT = JWT.decode(token); + } catch (JWTDecodeException e) { + throw new InvalidTokenException(token, "Error occurred in decoding token. " + e.getLocalizedMessage(), + e); + } + Date tokenExpiryDate = decodedJWT.getExpiresAt(); + Long tokenExpiryTimeInMilliSeconds = tokenExpiryDate.getTime() - (new Date().getTime()) - 60 * 1000; + tokenExpiryTime = (int) Math.floor(tokenExpiryTimeInMilliSeconds / 1000); + } + return tokenExpiryTime; + } +} diff --git a/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java b/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java new file mode 100644 index 0000000..15a0d11 --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java @@ -0,0 +1,142 @@ +package com.appirio.tech.core.service.identity.util.m2mscope; + +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * the configurationn for scopes of user 2fa. + */ +public class User2faFactory { + + public static final String SCOPE_DELIMITER = ","; + + /** + * Represents the create scopes for machine token validation. + */ + public static final String[] ReadScopes = { "all:user-2fa" }; + + /** + * Represents the create scopes for machine token validation. + */ + public static final String[] CreateScopes = { "all:user-2fa" }; + + /** + * Represents the delete scopes for machine token validation. + */ + public static final String[] DeleteScopes = { "all:user-2fa" }; + + /** + * Represents the update scopes for machine token validation. + */ + public static final String[] UpdateScopes = { "all:user-2fa" }; + + /** + * Represents the read attribute + */ + @JsonProperty + private String read; + + /** + * Represents the create attribute + */ + @JsonProperty + private String create; + + /** + * Represents the update attribute + */ + @JsonProperty + private String update; + + /** + * Represents the delete attribute + */ + @JsonProperty + private String delete; + + public User2faFactory() { + } + + public String getRead() { + return read; + } + + public void setRead(String read) { + this.read = read; + } + + public String getCreate() { + return create; + } + + public void setCreate(String create) { + this.create = create; + } + + public String getUpdate() { + return update; + } + + public void setUpdate(String update) { + this.update = update; + } + + public String getDelete() { + return delete; + } + + public void setDelete(String delete) { + this.delete = delete; + } + + /** + * Gets the read scopes. + * + * @return the read scopes. + */ + public String[] getReadScopes() { + if (read != null && read.trim().length() != 0) { + return read.split(SCOPE_DELIMITER); + } + + return ReadScopes; + } + + /** + * Gets the create scopes. + * + * @return the create scopes. + */ + public String[] getCreateScopes() { + if (create != null && create.trim().length() != 0) { + return create.split(SCOPE_DELIMITER); + } + + return CreateScopes; + } + + /** + * Gets the update scopes. + * + * @return the update scopes. + */ + public String[] getUpdateScopes() { + if (update != null && update.trim().length() != 0) { + return update.split(SCOPE_DELIMITER); + } + + return UpdateScopes; + } + + /** + * Gets the delete scopes. + * + * @return the delete scopes. + */ + public String[] getDeleteScopes() { + if (delete != null && delete.trim().length() != 0) { + return delete.split(SCOPE_DELIMITER); + } + + return DeleteScopes; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index fe805ea..7cfb13e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -91,6 +91,15 @@ auth0New: nonInteractiveClientId : @auth0.new.nonInteractive.clientId@ nonInteractiveClientSecret: @auth0.new.nonInteractive.clientSecret@ +diceAuth: + clientId: @diceAuth.clientId@ + clientSecret: @diceAuth.clientSecret@ + password: @diceAuth.password@ + scope: @diceAuth.scope@ + tenant: @diceAuth.tenant@ + username: @diceAuth.username@ + credDefId: @diceAuth.credDefId@ + credPreview: @diceAuth.credPreview@ # Authorized accounts serviceAccount: @@ -156,6 +165,11 @@ m2mAuthConfig: read: @m2mAuthConfig.userProfiles.read@ update: @m2mAuthConfig.userProfiles.update@ delete: @m2mAuthConfig.userProfiles.delete@ + user2fa: + create: @m2mAuthConfig.user2fa.create@ + read: @m2mAuthConfig.user2fa.read@ + update: @m2mAuthConfig.user2fa.update@ + delete: @m2mAuthConfig.user2fa.delete@ # Server settings server: diff --git a/src/main/resources/config.yml.localdev b/src/main/resources/config.yml.localdev index 7df95c7..16e96ed 100644 --- a/src/main/resources/config.yml.localdev +++ b/src/main/resources/config.yml.localdev @@ -85,6 +85,16 @@ auth0New: nonInteractiveClientId : AUTH0-NI-CLIENT-ID nonInteractiveClientSecret: AUTH0-NI-CLIENT-SECRET +diceAuth: + clientId: dummy + clientSecret: dummy + password: dummy + scope: dummy + tenant: dummy + username: dummy + credDefId: dummy + credPreview: dummy + # LDAP Settings ldap: host: ${DOCKER_IP} @@ -156,6 +166,11 @@ m2mAuthConfig: read: read:user_profiles,all:user_profiles update: update:user_profiles,all:user_profiles delete: delete:user_profiles,all:user_profiles + user2fa: + create: all:user-2fa + read: all:user-2fa + update: all:user-2fa + delete: all:user-2fa # Server settings server: diff --git a/src/main/resources/sql/User_2fa_Create.sql b/src/main/resources/sql/User_2fa_Create.sql new file mode 100644 index 0000000..f384668 --- /dev/null +++ b/src/main/resources/sql/User_2fa_Create.sql @@ -0,0 +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)); diff --git a/src/test/java/com/appirio/tech/core/service/identity/resource/UserResourceTest.java b/src/test/java/com/appirio/tech/core/service/identity/resource/UserResourceTest.java index fc6164a..e5a4646 100644 --- a/src/test/java/com/appirio/tech/core/service/identity/resource/UserResourceTest.java +++ b/src/test/java/com/appirio/tech/core/service/identity/resource/UserResourceTest.java @@ -27,6 +27,7 @@ import com.appirio.tech.core.service.identity.util.cache.CacheService; import com.appirio.tech.core.service.identity.util.event.MailRepresentation; import com.appirio.tech.core.service.identity.util.ldap.MemberStatus; +import com.appirio.tech.core.service.identity.util.m2mscope.User2faFactory; import com.appirio.tech.core.service.identity.util.m2mscope.UserProfilesFactory; import com.fasterxml.jackson.databind.ObjectMapper; @@ -68,6 +69,8 @@ public class UserResourceTest { private final RoleDAO mockRoleDao = mock(RoleDAO.class); private final UserProfilesFactory userProfilesFactory = new UserProfilesFactory(); + + private final User2faFactory user2faFactory = new User2faFactory(); @Before @SuppressWarnings("serial") @@ -144,7 +147,7 @@ public void testCreateSSOUserLogin() throws Exception { doNothing().when(eventProducer).publish(anyString(), anyString()); ObjectMapper objectMapper = mock(ObjectMapper.class); when(objectMapper.writeValueAsString(anyObject())).thenReturn("payload"); - UserResource testee = spy(new UserResource(userDao, mockRoleDao, cache, eventProducer, null, userProfilesFactory)); + UserResource testee = spy(new UserResource(userDao, mockRoleDao, cache, eventProducer, null, userProfilesFactory, user2faFactory)); // Creating mock: PostPutRequest - give mock user UserProfile userProfile = new UserProfile(); diff --git a/token.properties.localdev b/token.properties.localdev index 301e55b..68f0a8a 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -24,6 +24,15 @@ @auth0.new.clientSecret@= @auth0.new.domain@=dummy.auth0.com +@diceAuth.clientId@=dummy +@diceAuth.clientSecret@=dummy +@diceAuth.password@=dummy +@diceAuth.scope@=dummy +@diceAuth.tenant@=dummy +@diceAuth.username@=dummy +@diceAuth.credDefId@=dummy +@diceAuth.credPreview@=dummy + @zendesk.secret@=ZENDESK_SECRET @zendesk.idprefix@=ZENDESK_PREFIX @@ -59,3 +68,7 @@ @m2mAuthConfig.userProfiles.read@=read:user_profiles,all:user_profiles @m2mAuthConfig.userProfiles.update@=update:user_profiles,all:user_profiles @m2mAuthConfig.userProfiles.delete@=delete:user_profiles,all:user_profiles +@m2mAuthConfig.user2fa.create@=all:user-2fa +@m2mAuthConfig.user2fa.read@=all:user-2fa +@m2mAuthConfig.user2fa.update@=all:user-2fa +@m2mAuthConfig.user2fa.delete@=all:user-2fa \ No newline at end of file diff --git a/token.properties.template b/token.properties.template index 8ff9523..62ab096 100644 --- a/token.properties.template +++ b/token.properties.template @@ -49,6 +49,15 @@ @auth0.new.nonInteractive.clientSecret@={{AUTH0_NEW_NONINTERACTIVE_ID_SECRET}} @auth0.new.domain@={{AUTH0_NEW_DOMAIN}} +@diceAuth.clientId@={{DICEAUTH_ID}} +@diceAuth.clientSecret@={{DICEAUTH_ID_SECRET}} +@diceAuth.password@={{DICEAUTH_PASSWORD}} +@diceAuth.scope@={{DICEAUTH_SCOPE}} +@diceAuth.tenant@={{DICEAUTH_TENANT}} +@diceAuth.username@={{DICEAUTH_USERNAME}} +@diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} +@diceAuth.credPreview@={{DICEAUTH_CREDPREVIEW}} + @zendesk.secret@={{ZENDESK_KEY}} @zendesk.idprefix@={{ZENDESK_ID}} @@ -86,3 +95,7 @@ @m2mAuthConfig.userProfiles.read@={{M2MAUTHCONFIG_USERPROFILES_READ}} @m2mAuthConfig.userProfiles.update@={{M2MAUTHCONFIG_USERPROFILES_UPDATE}} @m2mAuthConfig.userProfiles.delete@={{M2MAUTHCONFIG_USERPROFILES_DELETE}} +@m2mAuthConfig.user2fa.create@={{M2MAUTHCONFIG_USER2FA_CREATE}} +@m2mAuthConfig.user2fa.read@={{M2MAUTHCONFIG_USER2FA_READ}} +@m2mAuthConfig.user2fa.update@={{M2MAUTHCONFIG_USER2FA_UPDATE}} +@m2mAuthConfig.user2fa.delete@={{M2MAUTHCONFIG_USER2FA_DELETE}} From 5e1d7e966a73440429583c090f02595b61133661 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Mon, 4 Jul 2022 20:24:20 +0300 Subject: [PATCH 04/32] update property --- buildtokenproperties.sh | 1 - .../tech/core/service/identity/util/auth/DICEAuth.java | 6 ++---- .../service/identity/util/m2mscope/User2faFactory.java | 8 ++++---- src/main/resources/config.yml | 1 - token.properties.template | 1 - 5 files changed, 6 insertions(+), 11 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 47ac828..3c0415f 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -22,7 +22,6 @@ DICEAUTH_SCOPE=$(eval "echo \$${ENV}_DICEAUTH_SCOPE") DICEAUTH_TENANT=$(eval "echo \$${ENV}_DICEAUTH_TENANT") DICEAUTH_USERNAME=$(eval "echo \$${ENV}_DICEAUTH_USERNAME") DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") -DICEAUTH_CREDPREVIEW=$(eval "echo \$${ENV}_DICEAUTH_CREDPREVIEW") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") AUTH_SECRET=$(eval "echo \$${ENV}_AUTH_SECRET") 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 aa03e0f..59082a7 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 @@ -40,8 +40,7 @@ public class DICEAuth { @NotNull private String credDefId; - @NotNull - private String credPreview; + private String credPreview = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview"; private String cachedToken; @@ -49,7 +48,7 @@ public DICEAuth() { } public DICEAuth(String tenant, String username, String password, String scope, String clientId, - String clientSecret, String credDefId, String credPreview) { + String clientSecret, String credDefId) { this.tenant = tenant; this.username = username; this.password = password; @@ -57,7 +56,6 @@ public DICEAuth(String tenant, String username, String password, String scope, S this.clientId = clientId; this.clientSecret = clientSecret; this.credDefId = credDefId; - this.credPreview = credPreview; } public String getTenant() { diff --git a/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java b/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java index 15a0d11..4ce6eb7 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java +++ b/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java @@ -12,22 +12,22 @@ public class User2faFactory { /** * Represents the create scopes for machine token validation. */ - public static final String[] ReadScopes = { "all:user-2fa" }; + public static final String[] ReadScopes = { "all:user_2fa" }; /** * Represents the create scopes for machine token validation. */ - public static final String[] CreateScopes = { "all:user-2fa" }; + public static final String[] CreateScopes = { "all:user_2fa" }; /** * Represents the delete scopes for machine token validation. */ - public static final String[] DeleteScopes = { "all:user-2fa" }; + public static final String[] DeleteScopes = { "all:user_2fa" }; /** * Represents the update scopes for machine token validation. */ - public static final String[] UpdateScopes = { "all:user-2fa" }; + public static final String[] UpdateScopes = { "all:user_2fa" }; /** * Represents the read attribute diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7cfb13e..4a26265 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -99,7 +99,6 @@ diceAuth: tenant: @diceAuth.tenant@ username: @diceAuth.username@ credDefId: @diceAuth.credDefId@ - credPreview: @diceAuth.credPreview@ # Authorized accounts serviceAccount: diff --git a/token.properties.template b/token.properties.template index 62ab096..e544c33 100644 --- a/token.properties.template +++ b/token.properties.template @@ -56,7 +56,6 @@ @diceAuth.tenant@={{DICEAUTH_TENANT}} @diceAuth.username@={{DICEAUTH_USERNAME}} @diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} -@diceAuth.credPreview@={{DICEAUTH_CREDPREVIEW}} @zendesk.secret@={{ZENDESK_KEY}} @zendesk.idprefix@={{ZENDESK_ID}} From b48f53a8ad459f33cd67c9ea774ef95bd4b67951 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Mon, 4 Jul 2022 20:45:09 +0300 Subject: [PATCH 05/32] fix tokenproperties --- buildtokenproperties.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 3c0415f..f7d269a 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -97,7 +97,6 @@ perl -pi -e "s/\{\{DICEAUTH_SCOPE\}\}/$DICEAUTH_SCOPE/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_TENANT\}\}/$DICEAUTH_TENANT/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_USERNAME\}\}/$DICEAUTH_USERNAME/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_CREDPREVIEW\}\}/$DICEAUTH_CREDPREVIEW/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 From 552ef403dde71ea69724c061599f03e5aa3ceee5 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Mon, 4 Jul 2022 22:21:59 +0300 Subject: [PATCH 06/32] log request --- .../tech/core/service/identity/util/auth/DICEAuth.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 59082a7..062dfe1 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 @@ -131,18 +131,20 @@ public String getToken() throws Exception { } } if (cachedToken == null || isCachedTokenExpired) { - Response response = new Request( + Request request = new Request( "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token", "POST") .param("grant_type", "password") .param("username", getUsername()) .param("password", getPassword()) .param("scope", getScope()) .param("client_id", getClientId()) - .param("client_secret", getClientSecret()).execute(); + .param("client_secret", getClientSecret()); + logger.info(request.getQuery()); + Response response = request.execute(); if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), - response.getMessage())); + response.getText())); } cachedToken = new ObjectMapper().readValue(response.getText(), Auth0Credential.class).getIdToken(); } From a575a9f2de3bb1e9411999f40314f2fa631beb05 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 7 Jul 2022 12:29:21 +0300 Subject: [PATCH 07/32] add mfa info to user object --- .../core/service/identity/dao/UserDAO.java | 8 ++++++-- .../service/identity/representation/User.java | 18 ++++++++++++++++++ .../identity/resource/UserResource.java | 7 ++++--- .../service/identity/util/auth/DICEAuth.java | 6 ++---- token.properties.localdev | 14 +++++++++----- 5 files changed, 39 insertions(+), 14 deletions(-) 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 7217635..da7857a 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 @@ -108,9 +108,11 @@ public abstract class UserDAO implements DaoBase, Transactional { @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + - "e.address AS email, e.status_id AS emailStatus " + + "e.address AS email, e.status_id AS emailStatus, " + + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u " + "LEFT OUTER JOIN common_oltp.email AS e ON u.user_id = e.user_id AND e.email_type_id = 1 " + + "LEFT JOIN common_oltp.user_2fa mfa ON mfa.user_id = u.user_id " + "WHERE u.handle_lower = LOWER(:handle)" ) public abstract User findUserByHandle(@Bind("handle") String handle); @@ -118,8 +120,10 @@ public abstract class UserDAO implements DaoBase, Transactional { @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + - "e.address AS email, e.status_id AS emailStatus " + + "e.address AS email, e.status_id AS emailStatus, " + + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u JOIN common_oltp.email AS e ON e.user_id = u.user_id " + + "LEFT JOIN common_oltp.user_2fa mfa ON mfa.user_id = u.user_id " + "WHERE LOWER(e.address) = LOWER(:email)" ) public abstract List findUsersByEmail(@Bind("email") String email); diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/User.java b/src/main/java/com/appirio/tech/core/service/identity/representation/User.java index dafa301..a904b92 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/representation/User.java +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/User.java @@ -41,6 +41,8 @@ public class User extends AbstractIdResource { private String utmMedium; private String utmCampaign; private List roles; + private Boolean mfaEnabled; + private Boolean mfaVerified; /** * Represents the ssoLogin attribute. @@ -188,6 +190,22 @@ public void setUtmCampaign(String utmCampaign) { public List getRoles() { return roles; } public void setRoles(List roles) { this.roles = roles; } + + public Boolean getMfaEnabled() { + return mfaEnabled; + } + + public void setMfaEnabled(Boolean mfaEnabled) { + this.mfaEnabled = mfaEnabled; + } + + public Boolean getMfaVerified() { + return mfaVerified; + } + + public void setMfaVerified(Boolean mfaVerified) { + this.mfaVerified = mfaVerified; + } @JsonIgnore public boolean isReferralProgramCampaign() { 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 db55cb3..a75d6d0 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 @@ -9,11 +9,9 @@ import io.dropwizard.jersey.PATCH; import java.net.HttpURLConnection; -import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -1530,6 +1528,9 @@ public ApiResponse issueCredentials( // return 404 if user is not found if(user == null) throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); + if(user.getMfaEnabled() == null || !user.getMfaEnabled()) { + throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); + } List roles = roleDao.getRolesBySubjectId(Long.parseLong(user.getId().getId())); ObjectMapper mapper = new ObjectMapper(); ObjectNode body = mapper.createObjectNode(); @@ -1573,7 +1574,7 @@ public ApiResponse issueCredentials( String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), response.getMessage())); } - return ApiResponseFactory.createResponse(response.getText()); + return ApiResponseFactory.createResponse("SUCCESS"); } @PUT 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 062dfe1..4a5a30f 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 @@ -131,16 +131,14 @@ public String getToken() throws Exception { } } if (cachedToken == null || isCachedTokenExpired) { - Request request = new Request( + Response response = new Request( "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token", "POST") .param("grant_type", "password") .param("username", getUsername()) .param("password", getPassword()) .param("scope", getScope()) .param("client_id", getClientId()) - .param("client_secret", getClientSecret()); - logger.info(request.getQuery()); - Response response = request.execute(); + .param("client_secret", getClientSecret()).execute(); if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), diff --git a/token.properties.localdev b/token.properties.localdev index 68f0a8a..f1a5a24 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -7,6 +7,11 @@ @auth.secret@=AUTH_SECRET +@application.sendgrid.template.id@=dummy +@application.sendgrid.welcome.template.id@=dummy +@application.sendgrid.selfservice.template.id@=dummy +@application.sendgrid.selfservice.welcome.template.id@=dummy + @ldap.host@=127.0.0.1 @ldap.port@=389 @ldap.password@=dummy @@ -31,7 +36,6 @@ @diceAuth.tenant@=dummy @diceAuth.username@=dummy @diceAuth.credDefId@=dummy -@diceAuth.credPreview@=dummy @zendesk.secret@=ZENDESK_SECRET @zendesk.idprefix@=ZENDESK_PREFIX @@ -68,7 +72,7 @@ @m2mAuthConfig.userProfiles.read@=read:user_profiles,all:user_profiles @m2mAuthConfig.userProfiles.update@=update:user_profiles,all:user_profiles @m2mAuthConfig.userProfiles.delete@=delete:user_profiles,all:user_profiles -@m2mAuthConfig.user2fa.create@=all:user-2fa -@m2mAuthConfig.user2fa.read@=all:user-2fa -@m2mAuthConfig.user2fa.update@=all:user-2fa -@m2mAuthConfig.user2fa.delete@=all:user-2fa \ No newline at end of file +@m2mAuthConfig.user2fa.create@=create:user_2fa,all:user_2fa +@m2mAuthConfig.user2fa.read@=read:user_2fa,all:user_2fa +@m2mAuthConfig.user2fa.update@=update:user_2fa,all:user_2fa +@m2mAuthConfig.user2fa.delete@=delete:user_2fa,all:user_2fa \ No newline at end of file From c88a757108a9af37adb845baea0880ec5f11ecfa Mon Sep 17 00:00:00 2001 From: eisbilir Date: Sun, 10 Jul 2022 22:18:03 +0300 Subject: [PATCH 08/32] add 2fa invitation endpoint --- buildtokenproperties.sh | 2 + .../service/identity/IdentityApplication.java | 1 + .../representation/CredentialInvitation.java | 23 ++++++ .../identity/resource/UserResource.java | 77 +++++++++++++++++++ src/main/resources/config.yml | 1 + token.properties.localdev | 1 + token.properties.template | 1 + 7 files changed, 106 insertions(+) create mode 100644 src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index f7d269a..883aae9 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -58,6 +58,7 @@ SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_RESE SENDGRID_WELCOME_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_WELCOME_EMAIL_TEMPLATE_ID") SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID") SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID") +SENDGRID_2FA_INVITATION_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_2FA_INVITATION_TEMPLATE_ID") if [[ -z "$ENV" ]] ; then @@ -137,3 +138,4 @@ perl -pi -e "s/\{\{SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_RE perl -pi -e "s/\{\{SENDGRID_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME +perl -pi -e "s/\{\{SENDGRID_2FA_INVITATION_TEMPLATE_ID\}\}/$SENDGRID_2FA_INVITATION_TEMPLATE_ID/g" $CONFFILENAME diff --git a/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java b/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java index 96d534f..3442f80 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java +++ b/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java @@ -242,6 +242,7 @@ public void run(IdentityConfiguration configuration, Environment environment) th userResource.setSendgridWelcomeTemplateId(Utils.getString("sendGridWelcomeTemplateId")); userResource.setSendgridSelfServiceTemplateId(Utils.getString("sendGridSelfServiceTemplateId")); userResource.setSendgridSelfServiceWelcomeTemplateId(Utils.getString("sendGridSelfServiceWelcomeTemplateId")); + userResource.setSendgrid2faInvitationTemplateId(Utils.getString("sendGrid2faInvitationTemplateId")); // this secret _used_ to be different from the one used in AuthorizationResource. // it _was_ the secret x2. (userResource.setSecret(getSecret()+getSecret());) // we assume this was done to further limit the usability of the oneTimeToken generated in userResource diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java new file mode 100644 index 0000000..a000b2a --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java @@ -0,0 +1,23 @@ +package com.appirio.tech.core.service.identity.representation; + +public class CredentialInvitation { + + private String email; + private String invitationUrl; + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getInvitationUrl() { + return invitationUrl; + } + + public void setInvitationUrl(String invitationUrl) { + this.invitationUrl = invitationUrl; + } +} 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 a75d6d0..94ec7db 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 @@ -58,6 +58,7 @@ import com.appirio.tech.core.service.identity.representation.Achievement; import com.appirio.tech.core.service.identity.representation.Country; import com.appirio.tech.core.service.identity.representation.Credential; +import com.appirio.tech.core.service.identity.representation.CredentialInvitation; import com.appirio.tech.core.service.identity.representation.CredentialRequest; import com.appirio.tech.core.service.identity.representation.CredentialVerification; import com.appirio.tech.core.service.identity.representation.Email; @@ -122,6 +123,8 @@ public class UserResource implements GetResource, DDLResource { private String sendgridSelfServiceTemplateId; private String sendgridSelfServiceWelcomeTemplateId; + + private String sendgrid2faInvitationTemplateId; protected UserDAO userDao; @@ -1614,6 +1617,40 @@ public ApiResponse update2faVerification( return ApiResponseFactory.createResponse("User verification updated"); } + @POST + @Path("/2faInvitation") + @Timed + public ApiResponse send2faInvitation( + @Auth AuthUser authUser, + @Valid PostPutRequest postRequest, + @Context HttpServletRequest request) { + Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles); + CredentialInvitation invitation = postRequest.getParam(); + + if(invitation == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Request Body")); + } + if(invitation.getEmail() == null || invitation.getEmail().length() == 0) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); + } + if(invitation.getInvitationUrl() == null || invitation.getInvitationUrl().length() == 0) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Invitation Url")); + } + logger.info(String.format("send 2fa invitation to (%s)", invitation.getEmail())); + + // find user by email + User user = userDao.findUserByEmail(invitation.getEmail()); + + // return 404 if user is not found + if(user == null) + throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); + if(user.getMfaEnabled() == null || !user.getMfaEnabled()) { + throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); + } + send2faInvitationEmailEvent(user, invitation.getInvitationUrl()); + return ApiResponseFactory.createResponse("SUCCESS"); + } + @POST @Path("/oneTimeToken") @Timed @@ -1937,6 +1974,14 @@ public void setSendgridSelfServiceTemplateId(String sendgridSelfServiceTemplateI this.sendgridSelfServiceTemplateId = sendgridSelfServiceTemplateId; } + public String getSendgrid2faInvitationTemplateId() { + return sendgrid2faInvitationTemplateId; + } + + public void setSendgrid2faInvitationTemplateId(String sendgrid2faInvitationTemplateId) { + this.sendgrid2faInvitationTemplateId = sendgrid2faInvitationTemplateId; + } + public String getSecret() { return secret; } @@ -2021,6 +2066,38 @@ private void sendActivationEmailEvent(User user, String redirectUrl) { } } + private void send2faInvitationEmailEvent(User user, String inviteLink) { + + EventMessage msg = EventMessage.getDefault(); + msg.setTopic("external.action.email"); + + Map payload = new LinkedHashMap(); + Map data = new LinkedHashMap(); + data.put("handle", user.getHandle()); + data.put("link", inviteLink); + + payload.put("data", data); + + Map from = new LinkedHashMap(); + from.put("email", String.format("Topcoder ", getDomain())); + payload.put("from", from); + + payload.put("version", "v3"); + payload.put("sendgrid_template_id", this.getSendgrid2faInvitationTemplateId()); + + ArrayList recipients = new ArrayList(); + recipients.add(user.getEmail()); + + payload.put("recipients", recipients); + + msg.setPayload(payload); + try { + this.eventBusServiceClient.reFireEvent(msg); + } catch (Exception e) { + logger.error("Error occured while publishing the events to new kafka."); + } + } + private void sendWelcomeEmailEvent(User user) { EventMessage msg = EventMessage.getDefault(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 4a26265..4243366 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -15,6 +15,7 @@ context: sendGridWelcomeTemplateId: @application.sendgrid.welcome.template.id@ sendGridSelfServiceTemplateId: @application.sendgrid.selfservice.template.id@ sendGridSelfServiceWelcomeTemplateId: @application.sendgrid.selfservice.welcome.template.id@ + sendGrid2faInvitationTemplateId: @application.sendgrid.2fa.invitation.template.id@ jwtExpirySeconds: 600 cookieExpirySeconds: 7776000 diff --git a/token.properties.localdev b/token.properties.localdev index f1a5a24..704ce5f 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -11,6 +11,7 @@ @application.sendgrid.welcome.template.id@=dummy @application.sendgrid.selfservice.template.id@=dummy @application.sendgrid.selfservice.welcome.template.id@=dummy +@application.sendgrid.2fa.invitation.template.id@=dummy @ldap.host@=127.0.0.1 @ldap.port@=389 diff --git a/token.properties.template b/token.properties.template index e544c33..4eabcc9 100644 --- a/token.properties.template +++ b/token.properties.template @@ -12,6 +12,7 @@ @application.sendgrid.welcome.template.id@={{SENDGRID_WELCOME_EMAIL_TEMPLATE_ID}} @application.sendgrid.selfservice.template.id@={{SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID}} @application.sendgrid.selfservice.welcome.template.id@={{SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID}} +@application.sendgrid.2fa.invitation.template.id@={{SENDGRID_2FA_INVITATION_TEMPLATE_ID}} @ldap.host@={{LDAP_SERVER}} @ldap.port@=389 From bdc9f91c140c9d4284ec81fe5096a7d429b15ae5 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 15:04:54 +0300 Subject: [PATCH 09/32] update dice urls --- buildtokenproperties.sh | 16 +- .../identity/resource/UserResource.java | 17 +-- .../service/identity/util/auth/DICEAuth.java | 144 ++---------------- src/main/resources/config.yml | 8 +- src/main/resources/config.yml.localdev | 9 +- token.properties.localdev | 8 +- token.properties.template | 8 +- 7 files changed, 31 insertions(+), 179 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 883aae9..36c90b6 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -15,12 +15,8 @@ AUTH0_NEW_ID=$(eval "echo \$${ENV}_AUTH0_NEW_ID") AUTH0_NEW_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_ID_SECRET") AUTH0_NEW_NONINTERACTIVE_ID=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID") AUTH0_NEW_NONINTERACTIVE_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID_SECRET") -DICEAUTH_ID=$(eval "echo \$${ENV}_DICEAUTH_ID") -DICEAUTH_ID_SECRET=$(eval "echo \$${ENV}_DICEAUTH_ID_SECRET") -DICEAUTH_PASSWORD=$(eval "echo \$${ENV}_DICEAUTH_PASSWORD") -DICEAUTH_SCOPE=$(eval "echo \$${ENV}_DICEAUTH_SCOPE") -DICEAUTH_TENANT=$(eval "echo \$${ENV}_DICEAUTH_TENANT") -DICEAUTH_USERNAME=$(eval "echo \$${ENV}_DICEAUTH_USERNAME") +DICEAUTH_DICE_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_URL") +DICEAUTH_API_KEY=$(eval "echo \$${ENV}_DICEAUTH_API_KEY") DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") @@ -91,12 +87,8 @@ perl -pi -e "s/\{\{AUTH0_NEW_ID\}\}/$AUTH0_NEW_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_ID_SECRET\}\}/$AUTH0_NEW_ID_SECRET/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_ID\}\}/$DICEAUTH_ID/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_ID_SECRET\}\}/$DICEAUTH_ID_SECRET/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_PASSWORD\}\}/$DICEAUTH_PASSWORD/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_SCOPE\}\}/$DICEAUTH_SCOPE/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_TENANT\}\}/$DICEAUTH_TENANT/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_USERNAME\}\}/$DICEAUTH_USERNAME/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_DICE_URL\}\}/$DICEAUTH_DICE_URL/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_ID\}\}/$ZENDESK_ID/g" $CONFFILENAME 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 94ec7db..4913c39 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 @@ -1512,11 +1512,9 @@ public ApiResponse issueCredentials( @Valid PostPutRequest postRequest, @Context HttpServletRequest request) { Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles); + checkParam(postRequest); CredentialRequest credential = postRequest.getParam(); - if(credential == null) { - throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Request Body")); - } if(credential.getEmail() == null || credential.getEmail().length() == 0) { throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); } @@ -1561,8 +1559,8 @@ public ApiResponse issueCredentials( preview.set("attributes", attributes); Response response; try { - response = new Request("https://dicecontroller-topcoder.wiprobc.com/api/credentialoffer", "POST") - .header("Authorization", "Bearer " + diceAuth.getToken()) + response = new Request(diceAuth.getDiceUrl()+"/credentialoffer/api/credentialoffer", "POST") + .header("x-api-key", diceAuth.getApiKey()) .json(mapper.writeValueAsString(body)) .execute(); } catch (JsonProcessingException e) { @@ -1589,10 +1587,9 @@ public ApiResponse update2faVerification( @Context HttpServletRequest request) { Utils.checkAccess(authUser, user2faFactory.getUpdateScopes(), Utils.AdminRoles); + checkParam(putRequest); CredentialVerification credential = putRequest.getParam(); - if(credential == null) { - throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Request Body")); - } + if(credential.getEmail() == null || credential.getEmail().length() == 0) { throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); } @@ -1625,11 +1622,9 @@ public ApiResponse send2faInvitation( @Valid PostPutRequest postRequest, @Context HttpServletRequest request) { Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles); + checkParam(postRequest); CredentialInvitation invitation = postRequest.getParam(); - if(invitation == null) { - throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Request Body")); - } if(invitation.getEmail() == null || invitation.getEmail().length() == 0) { throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); } 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 4a5a30f..4fffccc 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 @@ -1,109 +1,42 @@ package com.appirio.tech.core.service.identity.util.auth; -import java.net.HttpURLConnection; -import java.util.Date; - import javax.validation.constraints.NotNull; -import org.apache.log4j.Logger; - -import com.appirio.tech.core.api.v3.exception.APIRuntimeException; -import com.appirio.tech.core.api.v3.util.jwt.InvalidTokenException; -import com.appirio.tech.core.service.identity.util.HttpUtil.Request; -import com.appirio.tech.core.service.identity.util.HttpUtil.Response; -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.fasterxml.jackson.databind.ObjectMapper; - public class DICEAuth { - private static final Logger logger = Logger.getLogger(Auth0Client.class); - @NotNull - private String tenant; + private String diceUrl; @NotNull - private String username; - - @NotNull - private String password; - - @NotNull - private String scope; - - @NotNull - private String clientId; - - @NotNull - private String clientSecret; + private String apiKey; @NotNull private String credDefId; private String credPreview = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview"; - private String cachedToken; - public DICEAuth() { } - public DICEAuth(String tenant, String username, String password, String scope, String clientId, - String clientSecret, String credDefId) { - this.tenant = tenant; - this.username = username; - this.password = password; - this.scope = scope; - this.clientId = clientId; - this.clientSecret = clientSecret; + public DICEAuth(String diceUrl, String apiKey, String credDefId) { + this.diceUrl = diceUrl; + this.apiKey = apiKey; this.credDefId = credDefId; } - public String getTenant() { - return tenant; - } - - public void setTenant(String tenant) { - this.tenant = tenant; - } - - public String getUsername() { - return username; + public String getDiceUrl() { + return diceUrl; } - public void setUsername(String username) { - this.username = username; + public void setDiceUrl(String diceUrl) { + this.diceUrl = diceUrl; } - public String getPassword() { - return password; + public String getApiKey() { + return apiKey; } - public void setPassword(String password) { - this.password = password; - } - - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; + public void setApiKey(String apiKey) { + this.apiKey = apiKey; } public String getCredDefId() { @@ -121,55 +54,4 @@ public String getCredPreview() { public void setCredPreview(String credPreview) { this.credPreview = credPreview; } - - public String getToken() throws Exception { - Boolean isCachedTokenExpired = false; - if (cachedToken != null) { - if (getTokenExpiryTime(cachedToken) <= 0) { - isCachedTokenExpired = true; - logger.info("Application cached token expired"); - } - } - if (cachedToken == null || isCachedTokenExpired) { - Response response = new Request( - "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token", "POST") - .param("grant_type", "password") - .param("username", getUsername()) - .param("password", getPassword()) - .param("scope", getScope()) - .param("client_id", getClientId()) - .param("client_secret", getClientSecret()).execute(); - if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { - throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, - String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), - response.getText())); - } - cachedToken = new ObjectMapper().readValue(response.getText(), Auth0Credential.class).getIdToken(); - } - return cachedToken; - } - - /** - * Get token expiry time in seconds - * - * @param token JWT token - * throws Exception if any error occurs - * @return the Integer result - */ - private Integer getTokenExpiryTime(String token) throws Exception { - DecodedJWT decodedJWT = null; - Integer tokenExpiryTime = 0; - if (token != null) { - try { - decodedJWT = JWT.decode(token); - } catch (JWTDecodeException e) { - throw new InvalidTokenException(token, "Error occurred in decoding token. " + e.getLocalizedMessage(), - e); - } - Date tokenExpiryDate = decodedJWT.getExpiresAt(); - Long tokenExpiryTimeInMilliSeconds = tokenExpiryDate.getTime() - (new Date().getTime()) - 60 * 1000; - tokenExpiryTime = (int) Math.floor(tokenExpiryTimeInMilliSeconds / 1000); - } - return tokenExpiryTime; - } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 4243366..112773a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -93,12 +93,8 @@ auth0New: nonInteractiveClientSecret: @auth0.new.nonInteractive.clientSecret@ diceAuth: - clientId: @diceAuth.clientId@ - clientSecret: @diceAuth.clientSecret@ - password: @diceAuth.password@ - scope: @diceAuth.scope@ - tenant: @diceAuth.tenant@ - username: @diceAuth.username@ + diceUrl: @diceAuth.diceUrl@ + apiKey: @diceAuth.apiKey@ credDefId: @diceAuth.credDefId@ # Authorized accounts diff --git a/src/main/resources/config.yml.localdev b/src/main/resources/config.yml.localdev index 16e96ed..354b376 100644 --- a/src/main/resources/config.yml.localdev +++ b/src/main/resources/config.yml.localdev @@ -86,14 +86,9 @@ auth0New: nonInteractiveClientSecret: AUTH0-NI-CLIENT-SECRET diceAuth: - clientId: dummy - clientSecret: dummy - password: dummy - scope: dummy - tenant: dummy - username: dummy + diceUrl: dummy + apiKey: dummy credDefId: dummy - credPreview: dummy # LDAP Settings ldap: diff --git a/token.properties.localdev b/token.properties.localdev index 704ce5f..7807d5f 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -30,12 +30,8 @@ @auth0.new.clientSecret@= @auth0.new.domain@=dummy.auth0.com -@diceAuth.clientId@=dummy -@diceAuth.clientSecret@=dummy -@diceAuth.password@=dummy -@diceAuth.scope@=dummy -@diceAuth.tenant@=dummy -@diceAuth.username@=dummy +@diceAuth.diceUrl@=dummy +@diceAuth.apiKey@=dummy @diceAuth.credDefId@=dummy @zendesk.secret@=ZENDESK_SECRET diff --git a/token.properties.template b/token.properties.template index 4eabcc9..fa2f371 100644 --- a/token.properties.template +++ b/token.properties.template @@ -50,12 +50,8 @@ @auth0.new.nonInteractive.clientSecret@={{AUTH0_NEW_NONINTERACTIVE_ID_SECRET}} @auth0.new.domain@={{AUTH0_NEW_DOMAIN}} -@diceAuth.clientId@={{DICEAUTH_ID}} -@diceAuth.clientSecret@={{DICEAUTH_ID_SECRET}} -@diceAuth.password@={{DICEAUTH_PASSWORD}} -@diceAuth.scope@={{DICEAUTH_SCOPE}} -@diceAuth.tenant@={{DICEAUTH_TENANT}} -@diceAuth.username@={{DICEAUTH_USERNAME}} +@diceAuth.diceUrl@={{DICEAUTH_DICE_URL}} +@diceAuth.apiKey@={{DICEAUTH_API_KEY}} @diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} @zendesk.secret@={{ZENDESK_KEY}} From 721c0c298fafc67785a2afe4f058572b2e0fdb37 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 15:36:10 +0300 Subject: [PATCH 10/32] echo token properties --- buildtokenproperties.sh | 64 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 36c90b6..3568788 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -63,71 +63,133 @@ if [[ -z "$ENV" ]] ; then exit fi +echo $DOMAIN perl -pi -e "s/\{\{ENV_DOMAIN\}\}/$DOMAIN/g" $CONFFILENAME +echo $ENV perl -pi -e "s/\{\{ENV\}\}/$ENV/g" $CONFFILENAME +echo $SMTP perl -pi -e "s/\{\{ENV_SMTP\}\}/$SMTP/g" $CONFFILENAME +echo $DB_HOST_IP perl -pi -e "s/\{\{DB_HOST_IP\}\}/$DB_HOST_IP/g" $CONFFILENAME +echo $LDAP_SERVER perl -pi -e "s/\{\{LDAP_SERVER\}\}/$LDAP_SERVER/g" $CONFFILENAME +echo $REDIS_HOST perl -pi -e "s/\{\{REDIS_HOST\}\}/$REDIS_HOST/g" $CONFFILENAME +echo $AUTH_DB_HOST perl -pi -e "s/\{\{AUTH_DB_HOST\}\}/$AUTH_DB_HOST/g" $CONFFILENAME - +echo $AUTH_SECRET #echo ${AUTH_SECRET} perl -pi -e "s/\{\{AUTH_SECRET\}\}/$AUTH_SECRET/g" $CONFFILENAME +echo $DB_USER perl -pi -e "s/\{\{DB_USER\}\}/$DB_USER/g" $CONFFILENAME +echo $DB_PASSWORD perl -pi -e "s/\{\{DB_PASSWORD\}\}/$DB_PASSWORD/g" $CONFFILENAME +echo $LDAP_PASSWORD perl -pi -e "s/\{\{LDAP_PASSWORD\}\}/$LDAP_PASSWORD/g" $CONFFILENAME +echo $SG_API_KEY perl -pi -e "s/\{\{SG_API_KEY\}\}/$SG_API_KEY/g" $CONFFILENAME +echo $SG_TEMPLATEID perl -pi -e "s/\{\{SG_TEMPLATEID\}\}/$SG_TEMPLATEID/g" $CONFFILENAME +echo $SG_TEMPLATEID_PASSWORD perl -pi -e "s/\{\{SG_TEMPLATEID_PASSWORD\}\}/$SG_TEMPLATEID_PASSWORD/g" $CONFFILENAME +echo $AUTH0_ID perl -pi -e "s/\{\{AUTH0_ID\}\}/$AUTH0_ID/g" $CONFFILENAME +echo $AUTH0_ID_SECRET perl -pi -e "s/\{\{AUTH0_ID_SECRET\}\}/$AUTH0_ID_SECRET/g" $CONFFILENAME +echo $AUTH0_NONINTERACTIVE_ID perl -pi -e "s/\{\{AUTH0_NONINTERACTIVE_ID\}\}/$AUTH0_NONINTERACTIVE_ID/g" $CONFFILENAME +echo $AUTH0_NONINTERACTIVE_ID_SECRET perl -pi -e "s/\{\{AUTH0_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME +echo $AUTH0_NEW_ID perl -pi -e "s/\{\{AUTH0_NEW_ID\}\}/$AUTH0_NEW_ID/g" $CONFFILENAME +echo $AUTH0_NEW_ID_SECRET perl -pi -e "s/\{\{AUTH0_NEW_ID_SECRET\}\}/$AUTH0_NEW_ID_SECRET/g" $CONFFILENAME +echo $AUTH0_NEW_NONINTERACTIVE_ID perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/g" $CONFFILENAME +echo $AUTH0_NEW_NONINTERACTIVE_ID_SECRET perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME +echo $DICEAUTH_DICE_URL perl -pi -e "s/\{\{DICEAUTH_DICE_URL\}\}/$DICEAUTH_DICE_URL/g" $CONFFILENAME +echo $DICEAUTH_API_KEY perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME +echo $DICEAUTH_CREDDEFID perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME +echo $ZENDESK_KEY perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME +echo $ZENDESK_ID perl -pi -e "s/\{\{ZENDESK_ID\}\}/$ZENDESK_ID/g" $CONFFILENAME +echo $SERVICEACC01_CID perl -pi -e "s/\{\{SERVICEACC01_CID\}\}/$SERVICEACC01_CID/g" $CONFFILENAME +echo $SERVICEACC01_SECRET perl -pi -e "s|\{\{SERVICEACC01_SECRET\}\}|$SERVICEACC01_SECRET|g" $CONFFILENAME +echo $SERVICEACC01_UID perl -pi -e "s/\{\{SERVICEACC01_UID\}\}/$SERVICEACC01_UID/g" $CONFFILENAME +echo $SERVICEACC02_CID perl -pi -e "s/\{\{SERVICEACC02_CID\}\}/$SERVICEACC02_CID/g" $CONFFILENAME +echo $SERVICEACC02_SECRET perl -pi -e "s|\{\{SERVICEACC02_SECRET\}\}|$SERVICEACC02_SECRET|g" $CONFFILENAME +echo $SERVICEACC02_UID perl -pi -e "s/\{\{SERVICEACC02_UID\}\}/$SERVICEACC02_UID/g" $CONFFILENAME +echo $APP_PASSWORD perl -pi -e "s/\{\{APP_PASSWORD\}\}/$APP_PASSWORD/g" $CONFFILENAME +echo $APP_KEY perl -pi -e "s/\{\{APP_KEY\}\}/$APP_KEY/g" $CONFFILENAME +echo $APP_TOKEN perl -pi -e "s/\{\{APP_TOKEN\}\}/$APP_TOKEN/g" $CONFFILENAME +echo $AUTH_DB_USER perl -pi -e "s/\{\{AUTH_DB_USER\}\}/$AUTH_DB_USER/g" $CONFFILENAME +echo $AUTH_DB_PASSWORD perl -pi -e "s/\{\{AUTH_DB_PASSWORD\}\}/$AUTH_DB_PASSWORD/g" $CONFFILENAME +echo $EVENTBUSSERVICE_ENDPOINT #perl -pi -e "s/\{\{EVENTBUSSERVICE_ENDPOINT\}\}/$EVENTBUSSERVICE_ENDPOINT/g" $CONFFILENAME perl -pi -e "s|\{\{EVENTBUSSERVICE_ENDPOINT\}\}|$EVENTBUSSERVICE_ENDPOINT|g" $CONFFILENAME +echo $EVENTBUSSERVICE_TOPIC perl -pi -e "s/\{\{EVENTBUSSERVICE_TOPIC\}\}/$EVENTBUSSERVICE_TOPIC/g" $CONFFILENAME +echo $EVENTBUSSERVICE_ORIGINATOR perl -pi -e "s/\{\{EVENTBUSSERVICE_ORIGINATOR\}\}/$EVENTBUSSERVICE_ORIGINATOR/g" $CONFFILENAME +echo $M2MAUTHCONFIG_CID perl -pi -e "s/\{\{M2MAUTHCONFIG_CID\}\}/$M2MAUTHCONFIG_CID/g" $CONFFILENAME +echo $M2MAUTHCONFIG_SECRET perl -pi -e "s/\{\{M2MAUTHCONFIG_SECRET\}\}/$M2MAUTHCONFIG_SECRET/g" $CONFFILENAME +echo $M2MAUTHCONFIG_AUDIENCE #perl -pi -e "s/\{\{M2MAUTHCONFIG_AUDIENCE\}\}/$M2MAUTHCONFIG_AUDIENCE/g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_AUDIENCE\}\}|$M2MAUTHCONFIG_AUDIENCE|g" $CONFFILENAME +echo $M2MAUTHCONFIG_AUTHDOMAIN perl -pi -e "s/\{\{M2MAUTHCONFIG_AUTHDOMAIN\}\}/$M2MAUTHCONFIG_AUTHDOMAIN/g" $CONFFILENAME +echo $M2MAUTHCONFIG_TOKENEXPIRETIME perl -pi -e "s/\{\{M2MAUTHCONFIG_TOKENEXPIRETIME\}\}/$M2MAUTHCONFIG_TOKENEXPIRETIME/g" $CONFFILENAME +echo $M2MAUTHCONFIG_USERID perl -pi -e "s/\{\{M2MAUTHCONFIG_USERID\}\}/$M2MAUTHCONFIG_USERID/g" $CONFFILENAME +echo $M2MAUTHCONFIG_AUTHPROXYSERVERURL #perl -pi -e "s/\{\{M2MAUTHCONFIG_AUTHPROXYSERVERURL\}\}/$M2MAUTHCONFIG_AUTHPROXYSERVERURL/g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_AUTHPROXYSERVERURL\}\}|$M2MAUTHCONFIG_AUTHPROXYSERVERURL|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USERPROFILES_CREATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_CREATE\}\}|$M2MAUTHCONFIG_USERPROFILES_CREATE|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USERPROFILES_UPDATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_UPDATE\}\}|$M2MAUTHCONFIG_USERPROFILES_UPDATE|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USERPROFILES_READ perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_READ\}\}|$M2MAUTHCONFIG_USERPROFILES_READ|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USERPROFILES_DELETE perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_DELETE\}\}|$M2MAUTHCONFIG_USERPROFILES_DELETE|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USER2FA_CREATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_CREATE\}\}|$M2MAUTHCONFIG_USER2FA_CREATE|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USER2FA_UPDATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_UPDATE\}\}|$M2MAUTHCONFIG_USER2FA_UPDATE|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USER2FA_READ perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_READ\}\}|$M2MAUTHCONFIG_USER2FA_READ|g" $CONFFILENAME +echo $M2MAUTHCONFIG_USER2FA_DELETE perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_DELETE\}\}|$M2MAUTHCONFIG_USER2FA_DELETE|g" $CONFFILENAME +echo $AUTH0_NEW_DOMAIN perl -pi -e "s/\{\{AUTH0_NEW_DOMAIN\}\}/$AUTH0_NEW_DOMAIN/g" $CONFFILENAME +echo $AUTH0_DOMAIN perl -pi -e "s/\{\{AUTH0_DOMAIN\}\}/$AUTH0_DOMAIN/g" $CONFFILENAME +echo $SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME +echo $SENDGRID_WELCOME_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME +echo $SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME +echo $SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME +echo $SENDGRID_2FA_INVITATION_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_2FA_INVITATION_TEMPLATE_ID\}\}/$SENDGRID_2FA_INVITATION_TEMPLATE_ID/g" $CONFFILENAME From c14151f7090d471efd1058adfca106d449c66fe8 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 15:44:42 +0300 Subject: [PATCH 11/32] Revert "echo token properties" This reverts commit 721c0c298fafc67785a2afe4f058572b2e0fdb37. --- buildtokenproperties.sh | 64 +---------------------------------------- 1 file changed, 1 insertion(+), 63 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 3568788..36c90b6 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -63,133 +63,71 @@ if [[ -z "$ENV" ]] ; then exit fi -echo $DOMAIN perl -pi -e "s/\{\{ENV_DOMAIN\}\}/$DOMAIN/g" $CONFFILENAME -echo $ENV perl -pi -e "s/\{\{ENV\}\}/$ENV/g" $CONFFILENAME -echo $SMTP perl -pi -e "s/\{\{ENV_SMTP\}\}/$SMTP/g" $CONFFILENAME -echo $DB_HOST_IP perl -pi -e "s/\{\{DB_HOST_IP\}\}/$DB_HOST_IP/g" $CONFFILENAME -echo $LDAP_SERVER perl -pi -e "s/\{\{LDAP_SERVER\}\}/$LDAP_SERVER/g" $CONFFILENAME -echo $REDIS_HOST perl -pi -e "s/\{\{REDIS_HOST\}\}/$REDIS_HOST/g" $CONFFILENAME -echo $AUTH_DB_HOST perl -pi -e "s/\{\{AUTH_DB_HOST\}\}/$AUTH_DB_HOST/g" $CONFFILENAME -echo $AUTH_SECRET + #echo ${AUTH_SECRET} perl -pi -e "s/\{\{AUTH_SECRET\}\}/$AUTH_SECRET/g" $CONFFILENAME -echo $DB_USER perl -pi -e "s/\{\{DB_USER\}\}/$DB_USER/g" $CONFFILENAME -echo $DB_PASSWORD perl -pi -e "s/\{\{DB_PASSWORD\}\}/$DB_PASSWORD/g" $CONFFILENAME -echo $LDAP_PASSWORD perl -pi -e "s/\{\{LDAP_PASSWORD\}\}/$LDAP_PASSWORD/g" $CONFFILENAME -echo $SG_API_KEY perl -pi -e "s/\{\{SG_API_KEY\}\}/$SG_API_KEY/g" $CONFFILENAME -echo $SG_TEMPLATEID perl -pi -e "s/\{\{SG_TEMPLATEID\}\}/$SG_TEMPLATEID/g" $CONFFILENAME -echo $SG_TEMPLATEID_PASSWORD perl -pi -e "s/\{\{SG_TEMPLATEID_PASSWORD\}\}/$SG_TEMPLATEID_PASSWORD/g" $CONFFILENAME -echo $AUTH0_ID perl -pi -e "s/\{\{AUTH0_ID\}\}/$AUTH0_ID/g" $CONFFILENAME -echo $AUTH0_ID_SECRET perl -pi -e "s/\{\{AUTH0_ID_SECRET\}\}/$AUTH0_ID_SECRET/g" $CONFFILENAME -echo $AUTH0_NONINTERACTIVE_ID perl -pi -e "s/\{\{AUTH0_NONINTERACTIVE_ID\}\}/$AUTH0_NONINTERACTIVE_ID/g" $CONFFILENAME -echo $AUTH0_NONINTERACTIVE_ID_SECRET perl -pi -e "s/\{\{AUTH0_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME -echo $AUTH0_NEW_ID perl -pi -e "s/\{\{AUTH0_NEW_ID\}\}/$AUTH0_NEW_ID/g" $CONFFILENAME -echo $AUTH0_NEW_ID_SECRET perl -pi -e "s/\{\{AUTH0_NEW_ID_SECRET\}\}/$AUTH0_NEW_ID_SECRET/g" $CONFFILENAME -echo $AUTH0_NEW_NONINTERACTIVE_ID perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/g" $CONFFILENAME -echo $AUTH0_NEW_NONINTERACTIVE_ID_SECRET perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME -echo $DICEAUTH_DICE_URL perl -pi -e "s/\{\{DICEAUTH_DICE_URL\}\}/$DICEAUTH_DICE_URL/g" $CONFFILENAME -echo $DICEAUTH_API_KEY perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME -echo $DICEAUTH_CREDDEFID perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME -echo $ZENDESK_KEY perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME -echo $ZENDESK_ID perl -pi -e "s/\{\{ZENDESK_ID\}\}/$ZENDESK_ID/g" $CONFFILENAME -echo $SERVICEACC01_CID perl -pi -e "s/\{\{SERVICEACC01_CID\}\}/$SERVICEACC01_CID/g" $CONFFILENAME -echo $SERVICEACC01_SECRET perl -pi -e "s|\{\{SERVICEACC01_SECRET\}\}|$SERVICEACC01_SECRET|g" $CONFFILENAME -echo $SERVICEACC01_UID perl -pi -e "s/\{\{SERVICEACC01_UID\}\}/$SERVICEACC01_UID/g" $CONFFILENAME -echo $SERVICEACC02_CID perl -pi -e "s/\{\{SERVICEACC02_CID\}\}/$SERVICEACC02_CID/g" $CONFFILENAME -echo $SERVICEACC02_SECRET perl -pi -e "s|\{\{SERVICEACC02_SECRET\}\}|$SERVICEACC02_SECRET|g" $CONFFILENAME -echo $SERVICEACC02_UID perl -pi -e "s/\{\{SERVICEACC02_UID\}\}/$SERVICEACC02_UID/g" $CONFFILENAME -echo $APP_PASSWORD perl -pi -e "s/\{\{APP_PASSWORD\}\}/$APP_PASSWORD/g" $CONFFILENAME -echo $APP_KEY perl -pi -e "s/\{\{APP_KEY\}\}/$APP_KEY/g" $CONFFILENAME -echo $APP_TOKEN perl -pi -e "s/\{\{APP_TOKEN\}\}/$APP_TOKEN/g" $CONFFILENAME -echo $AUTH_DB_USER perl -pi -e "s/\{\{AUTH_DB_USER\}\}/$AUTH_DB_USER/g" $CONFFILENAME -echo $AUTH_DB_PASSWORD perl -pi -e "s/\{\{AUTH_DB_PASSWORD\}\}/$AUTH_DB_PASSWORD/g" $CONFFILENAME -echo $EVENTBUSSERVICE_ENDPOINT #perl -pi -e "s/\{\{EVENTBUSSERVICE_ENDPOINT\}\}/$EVENTBUSSERVICE_ENDPOINT/g" $CONFFILENAME perl -pi -e "s|\{\{EVENTBUSSERVICE_ENDPOINT\}\}|$EVENTBUSSERVICE_ENDPOINT|g" $CONFFILENAME -echo $EVENTBUSSERVICE_TOPIC perl -pi -e "s/\{\{EVENTBUSSERVICE_TOPIC\}\}/$EVENTBUSSERVICE_TOPIC/g" $CONFFILENAME -echo $EVENTBUSSERVICE_ORIGINATOR perl -pi -e "s/\{\{EVENTBUSSERVICE_ORIGINATOR\}\}/$EVENTBUSSERVICE_ORIGINATOR/g" $CONFFILENAME -echo $M2MAUTHCONFIG_CID perl -pi -e "s/\{\{M2MAUTHCONFIG_CID\}\}/$M2MAUTHCONFIG_CID/g" $CONFFILENAME -echo $M2MAUTHCONFIG_SECRET perl -pi -e "s/\{\{M2MAUTHCONFIG_SECRET\}\}/$M2MAUTHCONFIG_SECRET/g" $CONFFILENAME -echo $M2MAUTHCONFIG_AUDIENCE #perl -pi -e "s/\{\{M2MAUTHCONFIG_AUDIENCE\}\}/$M2MAUTHCONFIG_AUDIENCE/g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_AUDIENCE\}\}|$M2MAUTHCONFIG_AUDIENCE|g" $CONFFILENAME -echo $M2MAUTHCONFIG_AUTHDOMAIN perl -pi -e "s/\{\{M2MAUTHCONFIG_AUTHDOMAIN\}\}/$M2MAUTHCONFIG_AUTHDOMAIN/g" $CONFFILENAME -echo $M2MAUTHCONFIG_TOKENEXPIRETIME perl -pi -e "s/\{\{M2MAUTHCONFIG_TOKENEXPIRETIME\}\}/$M2MAUTHCONFIG_TOKENEXPIRETIME/g" $CONFFILENAME -echo $M2MAUTHCONFIG_USERID perl -pi -e "s/\{\{M2MAUTHCONFIG_USERID\}\}/$M2MAUTHCONFIG_USERID/g" $CONFFILENAME -echo $M2MAUTHCONFIG_AUTHPROXYSERVERURL #perl -pi -e "s/\{\{M2MAUTHCONFIG_AUTHPROXYSERVERURL\}\}/$M2MAUTHCONFIG_AUTHPROXYSERVERURL/g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_AUTHPROXYSERVERURL\}\}|$M2MAUTHCONFIG_AUTHPROXYSERVERURL|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USERPROFILES_CREATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_CREATE\}\}|$M2MAUTHCONFIG_USERPROFILES_CREATE|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USERPROFILES_UPDATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_UPDATE\}\}|$M2MAUTHCONFIG_USERPROFILES_UPDATE|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USERPROFILES_READ perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_READ\}\}|$M2MAUTHCONFIG_USERPROFILES_READ|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USERPROFILES_DELETE perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_DELETE\}\}|$M2MAUTHCONFIG_USERPROFILES_DELETE|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USER2FA_CREATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_CREATE\}\}|$M2MAUTHCONFIG_USER2FA_CREATE|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USER2FA_UPDATE perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_UPDATE\}\}|$M2MAUTHCONFIG_USER2FA_UPDATE|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USER2FA_READ perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_READ\}\}|$M2MAUTHCONFIG_USER2FA_READ|g" $CONFFILENAME -echo $M2MAUTHCONFIG_USER2FA_DELETE perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_DELETE\}\}|$M2MAUTHCONFIG_USER2FA_DELETE|g" $CONFFILENAME -echo $AUTH0_NEW_DOMAIN perl -pi -e "s/\{\{AUTH0_NEW_DOMAIN\}\}/$AUTH0_NEW_DOMAIN/g" $CONFFILENAME -echo $AUTH0_DOMAIN perl -pi -e "s/\{\{AUTH0_DOMAIN\}\}/$AUTH0_DOMAIN/g" $CONFFILENAME -echo $SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME -echo $SENDGRID_WELCOME_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME -echo $SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME -echo $SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME -echo $SENDGRID_2FA_INVITATION_TEMPLATE_ID perl -pi -e "s/\{\{SENDGRID_2FA_INVITATION_TEMPLATE_ID\}\}/$SENDGRID_2FA_INVITATION_TEMPLATE_ID/g" $CONFFILENAME From 9a924ae22e43e18070b79fd5113ba132819ec278 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 15:46:56 +0300 Subject: [PATCH 12/32] update url --- .../tech/core/service/identity/resource/UserResource.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4913c39..41b8a3d 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 @@ -1559,7 +1559,7 @@ public ApiResponse issueCredentials( preview.set("attributes", attributes); Response response; try { - response = new Request(diceAuth.getDiceUrl()+"/credentialoffer/api/credentialoffer", "POST") + response = new Request(diceAuth.getDiceUrl()+"/v1/credentialoffer/api/credentialoffer", "POST") .header("x-api-key", diceAuth.getApiKey()) .json(mapper.writeValueAsString(body)) .execute(); From 74f457aa5f32389d129f499ff71c0846e86e19bb Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 15:51:29 +0300 Subject: [PATCH 13/32] fix token --- buildtokenproperties.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 36c90b6..4cdaca9 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -87,7 +87,8 @@ perl -pi -e "s/\{\{AUTH0_NEW_ID\}\}/$AUTH0_NEW_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_ID_SECRET\}\}/$AUTH0_NEW_ID_SECRET/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_DICE_URL\}\}/$DICEAUTH_DICE_URL/g" $CONFFILENAME +echo $DICEAUTH_DICE_URL +perl -pi -e "s|\{\{DICEAUTH_DICE_URL\}\}|$DICEAUTH_DICE_URL|g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME From 3b508241c10ee4609a10cafdb47c4d5987658238 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 22:13:51 +0300 Subject: [PATCH 14/32] add api to update user2fa --- buildtokenproperties.sh | 2 + .../clients/EventBusServiceClient.java | 8 +- .../core/service/identity/dao/UserDAO.java | 35 +++-- .../representation/CredentialInvitation.java | 23 ---- ...edentialVerification.java => User2fa.java} | 20 ++- .../identity/resource/UserResource.java | 120 +++++++++++------- .../service/identity/util/auth/DICEAuth.java | 14 +- src/main/resources/config.yml | 1 + token.properties.localdev | 1 + token.properties.template | 1 + 10 files changed, 143 insertions(+), 82 deletions(-) delete mode 100644 src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java rename src/main/java/com/appirio/tech/core/service/identity/representation/{CredentialVerification.java => User2fa.java} (69%) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 4cdaca9..7a5d256 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -16,6 +16,7 @@ AUTH0_NEW_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_ID_SECRET") AUTH0_NEW_NONINTERACTIVE_ID=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID") AUTH0_NEW_NONINTERACTIVE_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID_SECRET") DICEAUTH_DICE_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_URL") +DICEAUTH_DICE_API_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_URL") DICEAUTH_API_KEY=$(eval "echo \$${ENV}_DICEAUTH_API_KEY") DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") @@ -89,6 +90,7 @@ perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/ perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME echo $DICEAUTH_DICE_URL perl -pi -e "s|\{\{DICEAUTH_DICE_URL\}\}|$DICEAUTH_DICE_URL|g" $CONFFILENAME +perl -pi -e "s|\{\{DICEAUTH_DICE_API_URL\}\}|$DICEAUTH_DICE_API_URL|g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME diff --git a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java index 7cf189a..c270b11 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java +++ b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java @@ -9,6 +9,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.SocketTimeoutException; + import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; @@ -87,7 +89,11 @@ public void reFireEvent(EventMessage eventMessage) { if (response.getStatusInfo().getStatusCode() != HttpStatus.OK_200 && response.getStatusInfo().getStatusCode()!= HttpStatus.NO_CONTENT_204) { LOGGER.error("Unable to fire the event: {}", response); } - } catch (Exception e) { + } catch (SocketTimeoutException e) { + if(!e.getMessage().equals("Read timed out")) { + LOGGER.error("Failed to fire the event: {}", e); + } + } catch (Exception e) { LOGGER.error("Failed to fire the event: {}", e); } } 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 da7857a..0f6084f 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 @@ -36,7 +36,7 @@ import com.appirio.tech.core.service.identity.representation.Achievement; import com.appirio.tech.core.service.identity.representation.Country; import com.appirio.tech.core.service.identity.representation.Credential; -import com.appirio.tech.core.service.identity.representation.CredentialVerification; +import com.appirio.tech.core.service.identity.representation.User2fa; import com.appirio.tech.core.service.identity.representation.Email; import com.appirio.tech.core.service.identity.representation.GroupMembership; import com.appirio.tech.core.service.identity.representation.ProviderType; @@ -98,9 +98,11 @@ public abstract class UserDAO implements DaoBase, Transactional { @SqlQuery( "SELECT " + USER_COLUMNS + ", " + "s.password AS credential$encodedPassword, e.address AS email, e.status_id AS emailStatus " + + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u " + "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 " + "LEFT OUTER JOIN common_oltp.security_user AS s ON u.user_id = s.login_id " + + "LEFT JOIN common_oltp.user_2fa mfa ON mfa.user_id = u.user_id " + "WHERE u.user_id = :id" ) public abstract User findUserById(@Bind("id") long id); @@ -130,18 +132,33 @@ public abstract class UserDAO implements DaoBase, Transactional { @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( - "SELECT ud.id AS id, u.user_id AS userId, e.address AS email, ud.enabled AS enabled, ud.verified AS verified " + + "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 " + "FROM common_oltp.user AS u JOIN common_oltp.email AS e ON e.user_id = u.user_id " + - "LEFT JOIN common_oltp.user_2fa AS ud ON ud.user_id = u.user_id " + + "LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " + "WHERE LOWER(e.address) = LOWER(:email)" ) - public abstract List findUser2faByEmail(@Bind("email") String email); + public abstract List findUser2faByEmail(@Bind("email") String email); + + @SqlQuery( + "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 " + + "FROM common_oltp.user AS u LEFT JOIN common_oltp.email AS e ON e.user_id = u.user_id " + + "LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " + + "WHERE u.user_id = :userId" + ) + public abstract User2fa findUser2faById(@Bind("userId") long userId); + + @SqlUpdate( + "INSERT INTO common_oltp.user_2fa " + + "(user_id, enabled) VALUES " + + "(:userId, :enabled)") + public abstract int insertUser2fa(@Bind("userId") long userId, @Bind("enabled") boolean enabled); @SqlUpdate( "UPDATE common_oltp.user_2fa SET " + + "enabled=:enabled " + "verified=:verified " + "WHERE id=:id") - public abstract int update2faVerification(@Bind("id") long id, @Bind("verified") boolean verified); + public abstract int update2fa(@Bind("id") long id, @Bind("enabled") boolean enabled, @Bind("verified") boolean verified); @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( @@ -156,7 +173,9 @@ public abstract class UserDAO implements DaoBase, Transactional { @SqlQuery( "SELECT " + USER_COLUMNS + ", " + "e.address AS email, e.status_id AS emailStatus " + + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u " + + "LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " + " common_oltp.email AS e ON u.user_id = e.user_id AND e.primary_ind = 1 " + " " + " " + @@ -385,15 +404,15 @@ public User findUserByEmail(String email) { return users.get(0); } - public CredentialVerification findUserCredentialByEmail(String email) { - List users = findUser2faByEmail(email); + public User2fa findUserCredentialByEmail(String email) { + List users = findUser2faByEmail(email); if(users==null || users.size()==0) return null; if(users.size()==1) return users.get(0); - for (CredentialVerification user : users) { + for (User2fa user : users) { if(user.getEmail().equals(email)) return user; } diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java b/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java deleted file mode 100644 index a000b2a..0000000 --- a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialInvitation.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.appirio.tech.core.service.identity.representation; - -public class CredentialInvitation { - - private String email; - private String invitationUrl; - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getInvitationUrl() { - return invitationUrl; - } - - public void setInvitationUrl(String invitationUrl) { - this.invitationUrl = invitationUrl; - } -} diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java b/src/main/java/com/appirio/tech/core/service/identity/representation/User2fa.java similarity index 69% rename from src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java rename to src/main/java/com/appirio/tech/core/service/identity/representation/User2fa.java index 159a780..57da5da 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/representation/CredentialVerification.java +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/User2fa.java @@ -1,9 +1,11 @@ package com.appirio.tech.core.service.identity.representation; -public class CredentialVerification { +public class User2fa { private long id; private long userId; + private String handle; + private String firstName; private String email; private Boolean enabled; private Boolean verified; @@ -24,6 +26,22 @@ public void setUserId(long userId) { this.userId = userId; } + public String getHandle() { + return handle; + } + + public void setHandle(String handle) { + this.handle = handle; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + public String getEmail() { return email; } 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 41b8a3d..2526871 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 @@ -58,9 +58,8 @@ import com.appirio.tech.core.service.identity.representation.Achievement; import com.appirio.tech.core.service.identity.representation.Country; import com.appirio.tech.core.service.identity.representation.Credential; -import com.appirio.tech.core.service.identity.representation.CredentialInvitation; import com.appirio.tech.core.service.identity.representation.CredentialRequest; -import com.appirio.tech.core.service.identity.representation.CredentialVerification; +import com.appirio.tech.core.service.identity.representation.User2fa; import com.appirio.tech.core.service.identity.representation.Email; import com.appirio.tech.core.service.identity.representation.ProviderType; import com.appirio.tech.core.service.identity.representation.Role; @@ -1504,6 +1503,67 @@ public ApiResponse validateSocial( createValidationResult((err == null), err)); } + @PATCH + @Path("/{resourceId}/2fa") + @Timed + public ApiResponse updateUser2fa( + @Auth AuthUser authUser, + @PathParam("resourceId") String resourceId, + @Valid PostPutRequest postRequest, + @Context HttpServletRequest request) { + + logger.info(String.format("update user 2fa(%s)", resourceId)); + + TCID id = new TCID(resourceId); + validateResourceIdAndCheckPermission(authUser, id, user2faFactory.getUpdateScopes()); + // checking param + checkParam(postRequest); + + User2fa user2fa = postRequest.getParam(); + + if(user2fa.getEnabled() == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "enabled")); + } + + Long userId = Utils.toLongValue(id); + + logger.info(String.format("findUserById(%s)", resourceId)); + User2fa user2faInDb = userDao.findUser2faById(userId); + if(user2faInDb==null) + throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); + + Boolean shouldSendInvite = false; + if(user2faInDb.getEnabled() == null) { + userDao.insertUser2fa(userId, user2fa.getEnabled()); + shouldSendInvite = user2fa.getEnabled(); + } else if(!user2faInDb.getEnabled().equals(user2fa.getEnabled())) { + userDao.update2fa(user2faInDb.getId(), user2fa.getEnabled(), false); + shouldSendInvite = user2fa.getEnabled(); + } + + if (shouldSendInvite) { + Response response; + try { + response = new Request(diceAuth.getDiceApiUrl() + "/v1/connection/submit", "POST") + .param("emailId", user2faInDb.getEmail()) + .header("x-api-key", diceAuth.getApiKey()) + .execute(); + } catch (Exception e) { + logger.error("Error when calling 2fa submit api", e); + throw new APIRuntimeException(SC_INTERNAL_SERVER_ERROR, "Error when calling 2fa submit api"); + } + if (response.getStatusCode() != HttpURLConnection.HTTP_CREATED) { + throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, + String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), + response.getMessage())); + } + logger.info(response.getText()); + send2faInvitationEmailEvent(user2faInDb, diceAuth.getDiceUrl() + "/verify/" + response.getText()); + } + + return ApiResponseFactory.createResponse("SUCCESS"); + } + @POST @Path("/2faCredentials") @Timed @@ -1524,15 +1584,15 @@ public ApiResponse issueCredentials( logger.info(String.format("issue credential (%s)", credential.getEmail())); // find user by email - User user = userDao.findUserByEmail(credential.getEmail()); + User2fa user = userDao.findUserCredentialByEmail(credential.getEmail()); // return 404 if user is not found if(user == null) throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); - if(user.getMfaEnabled() == null || !user.getMfaEnabled()) { + if(user.getEnabled() == null || !user.getEnabled()) { throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); } - List roles = roleDao.getRolesBySubjectId(Long.parseLong(user.getId().getId())); + List roles = roleDao.getRolesBySubjectId(user.getUserId()); ObjectMapper mapper = new ObjectMapper(); ObjectNode body = mapper.createObjectNode(); body.put("comment", "TC credential"); @@ -1559,7 +1619,7 @@ public ApiResponse issueCredentials( preview.set("attributes", attributes); Response response; try { - response = new Request(diceAuth.getDiceUrl()+"/v1/credentialoffer/api/credentialoffer", "POST") + response = new Request(diceAuth.getDiceApiUrl()+"/v1/credentialoffer/api/credentialoffer", "POST") .header("x-api-key", diceAuth.getApiKey()) .json(mapper.writeValueAsString(body)) .execute(); @@ -1583,12 +1643,12 @@ public ApiResponse issueCredentials( @Timed public ApiResponse update2faVerification( @Auth AuthUser authUser, - @Valid PostPutRequest putRequest, + @Valid PostPutRequest putRequest, @Context HttpServletRequest request) { Utils.checkAccess(authUser, user2faFactory.getUpdateScopes(), Utils.AdminRoles); checkParam(putRequest); - CredentialVerification credential = putRequest.getParam(); + User2fa credential = putRequest.getParam(); if(credential.getEmail() == null || credential.getEmail().length() == 0) { throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); @@ -1599,7 +1659,7 @@ public ApiResponse update2faVerification( logger.info(String.format("update 2fa verification (%s) - %b", credential.getEmail(), credential.getVerified())); // find user by email - CredentialVerification credVerification = userDao.findUserCredentialByEmail(credential.getEmail()); + User2fa credVerification = userDao.findUserCredentialByEmail(credential.getEmail()); // return 404 if user is not found if(credVerification == null) @@ -1609,43 +1669,11 @@ public ApiResponse update2faVerification( throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); } if(!credVerification.getVerified().equals(credential.getVerified())) { - userDao.update2faVerification(credVerification.getId(), credential.getVerified()); + userDao.update2fa(credVerification.getId(), true, credential.getVerified()); } return ApiResponseFactory.createResponse("User verification updated"); } - @POST - @Path("/2faInvitation") - @Timed - public ApiResponse send2faInvitation( - @Auth AuthUser authUser, - @Valid PostPutRequest postRequest, - @Context HttpServletRequest request) { - Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles); - checkParam(postRequest); - CredentialInvitation invitation = postRequest.getParam(); - - if(invitation.getEmail() == null || invitation.getEmail().length() == 0) { - throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Email address")); - } - if(invitation.getInvitationUrl() == null || invitation.getInvitationUrl().length() == 0) { - throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "Invitation Url")); - } - logger.info(String.format("send 2fa invitation to (%s)", invitation.getEmail())); - - // find user by email - User user = userDao.findUserByEmail(invitation.getEmail()); - - // return 404 if user is not found - if(user == null) - throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); - if(user.getMfaEnabled() == null || !user.getMfaEnabled()) { - throw new APIRuntimeException(SC_BAD_REQUEST, "2FA is not enabled for user"); - } - send2faInvitationEmailEvent(user, invitation.getInvitationUrl()); - return ApiResponseFactory.createResponse("SUCCESS"); - } - @POST @Path("/oneTimeToken") @Timed @@ -2061,7 +2089,7 @@ private void sendActivationEmailEvent(User user, String redirectUrl) { } } - private void send2faInvitationEmailEvent(User user, String inviteLink) { + private void send2faInvitationEmailEvent(User2fa user, String inviteLink) { EventMessage msg = EventMessage.getDefault(); msg.setTopic("external.action.email"); @@ -2086,11 +2114,7 @@ private void send2faInvitationEmailEvent(User user, String inviteLink) { payload.put("recipients", recipients); msg.setPayload(payload); - try { - this.eventBusServiceClient.reFireEvent(msg); - } catch (Exception e) { - logger.error("Error occured while publishing the events to new kafka."); - } + this.eventBusServiceClient.reFireEvent(msg); } private void sendWelcomeEmailEvent(User user) { 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 4fffccc..c586042 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 @@ -6,6 +6,9 @@ public class DICEAuth { @NotNull private String diceUrl; + @NotNull + private String diceApiUrl; + @NotNull private String apiKey; @@ -17,8 +20,9 @@ public class DICEAuth { public DICEAuth() { } - public DICEAuth(String diceUrl, String apiKey, String credDefId) { + public DICEAuth(String diceUrl, String diceApiUrl, String apiKey, String credDefId) { this.diceUrl = diceUrl; + this.diceApiUrl = diceApiUrl; this.apiKey = apiKey; this.credDefId = credDefId; } @@ -31,6 +35,14 @@ public void setDiceUrl(String diceUrl) { this.diceUrl = diceUrl; } + public String getDiceApiUrl() { + return diceApiUrl; + } + + public void setDiceApiUrl(String diceApiUrl) { + this.diceApiUrl = diceApiUrl; + } + public String getApiKey() { return apiKey; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 112773a..7b8178b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -94,6 +94,7 @@ auth0New: diceAuth: diceUrl: @diceAuth.diceUrl@ + diceApiUrl: @diceAuth.diceApiUrl@ apiKey: @diceAuth.apiKey@ credDefId: @diceAuth.credDefId@ diff --git a/token.properties.localdev b/token.properties.localdev index 7807d5f..29b6f3b 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -31,6 +31,7 @@ @auth0.new.domain@=dummy.auth0.com @diceAuth.diceUrl@=dummy +@diceAuth.diceApiUrl@=dummy @diceAuth.apiKey@=dummy @diceAuth.credDefId@=dummy diff --git a/token.properties.template b/token.properties.template index fa2f371..3ac4924 100644 --- a/token.properties.template +++ b/token.properties.template @@ -51,6 +51,7 @@ @auth0.new.domain@={{AUTH0_NEW_DOMAIN}} @diceAuth.diceUrl@={{DICEAUTH_DICE_URL}} +@diceAuth.diceApiUrl@={{DICEAUTH_DICE_API_URL}} @diceAuth.apiKey@={{DICEAUTH_API_KEY}} @diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} From b6c55d7431039ed1a63f7d60d5cd5e57b928d0c5 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 22:24:20 +0300 Subject: [PATCH 15/32] fix sql query --- buildtokenproperties.sh | 1 - .../com/appirio/tech/core/service/identity/dao/UserDAO.java | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 7a5d256..a95ecd0 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -88,7 +88,6 @@ perl -pi -e "s/\{\{AUTH0_NEW_ID\}\}/$AUTH0_NEW_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_ID_SECRET\}\}/$AUTH0_NEW_ID_SECRET/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME -echo $DICEAUTH_DICE_URL perl -pi -e "s|\{\{DICEAUTH_DICE_URL\}\}|$DICEAUTH_DICE_URL|g" $CONFFILENAME perl -pi -e "s|\{\{DICEAUTH_DICE_API_URL\}\}|$DICEAUTH_DICE_API_URL|g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/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 0f6084f..018e74d 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 @@ -97,7 +97,7 @@ public abstract class UserDAO implements DaoBase, Transactional { @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + - "s.password AS credential$encodedPassword, e.address AS email, e.status_id AS emailStatus " + + "s.password AS credential$encodedPassword, e.address AS email, e.status_id AS emailStatus, " + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u " + "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 " + @@ -172,7 +172,7 @@ public abstract class UserDAO implements DaoBase, Transactional { @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + - "e.address AS email, e.status_id AS emailStatus " + + "e.address AS email, e.status_id AS emailStatus, " + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u " + "LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " + From 6280122f610d2918dcd3cee175a79822a841e4c1 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 22:33:30 +0300 Subject: [PATCH 16/32] fix sql query --- .../com/appirio/tech/core/service/identity/dao/UserDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 018e74d..09206bf 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 @@ -140,7 +140,7 @@ public abstract class UserDAO implements DaoBase, Transactional { public abstract List findUser2faByEmail(@Bind("email") String email); @SqlQuery( - "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 " + + "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 " + "FROM common_oltp.user AS u LEFT JOIN common_oltp.email AS e ON e.user_id = u.user_id " + "LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " + "WHERE u.user_id = :userId" From 7649da12e0bc212982ccc2f64bc0c32e53e9ad19 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 22:42:57 +0300 Subject: [PATCH 17/32] register mapping --- .../java/com/appirio/tech/core/service/identity/dao/UserDAO.java | 1 + 1 file changed, 1 insertion(+) 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 09206bf..a898bb1 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 @@ -139,6 +139,7 @@ public abstract class UserDAO implements DaoBase, Transactional { ) public abstract List findUser2faByEmail(@Bind("email") String email); + @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "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 " + "FROM common_oltp.user AS u LEFT JOIN common_oltp.email AS e ON e.user_id = u.user_id " + From 6c6a04314b6ae12d80d3b908be2e666eb861575b Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 23:12:23 +0300 Subject: [PATCH 18/32] reset 2fa if user reset password --- .../com/appirio/tech/core/service/identity/dao/UserDAO.java | 2 +- .../tech/core/service/identity/resource/UserResource.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 a898bb1..b53e34d 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 @@ -156,7 +156,7 @@ public abstract class UserDAO implements DaoBase, Transactional { @SqlUpdate( "UPDATE common_oltp.user_2fa SET " + - "enabled=:enabled " + + "enabled=:enabled, " + "verified=:verified " + "WHERE id=:id") public abstract int update2fa(@Bind("id") long id, @Bind("enabled") boolean enabled, @Bind("verified") boolean verified); 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 2526871..4956e93 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 @@ -897,6 +897,7 @@ public ApiResponse changePassword( logger.debug(String.format("Auth0: updating password for user: %s", dbUser.getHandle())); userDao.updatePassword(dbUser); + userDao.update2fa(Utils.toLongValue(dbUser.getId()), false, false); return ApiResponseFactory.createResponse("password updated successfully."); } From 8e62c8f53cd4ef24ed95b29204966a27f68aef9a Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 21 Jul 2022 23:49:06 +0300 Subject: [PATCH 19/32] add reset 2fa --- .../service/identity/clients/EventBusServiceClient.java | 1 + .../appirio/tech/core/service/identity/dao/UserDAO.java | 7 +++++++ .../tech/core/service/identity/resource/UserResource.java | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java index c270b11..b4a8211 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java +++ b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java @@ -90,6 +90,7 @@ public void reFireEvent(EventMessage eventMessage) { LOGGER.error("Unable to fire the event: {}", response); } } catch (SocketTimeoutException e) { + LOGGER.info(e.getMessage()); if(!e.getMessage().equals("Read timed out")) { LOGGER.error("Failed to fire the event: {}", e); } 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 b53e34d..2e0ae80 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 @@ -161,6 +161,13 @@ public abstract class UserDAO implements DaoBase, Transactional { "WHERE id=:id") public abstract int update2fa(@Bind("id") long id, @Bind("enabled") boolean enabled, @Bind("verified") boolean verified); + @SqlUpdate( + "UPDATE common_oltp.user_2fa SET " + + "enabled=:enabled, " + + "verified=:verified " + + "WHERE user_id=:userId") + public abstract int update2faByUserId(@Bind("userId") long userId, @Bind("enabled") boolean enabled, @Bind("verified") boolean verified); + @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + 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 4956e93..c57f9c5 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 @@ -897,7 +897,7 @@ public ApiResponse changePassword( logger.debug(String.format("Auth0: updating password for user: %s", dbUser.getHandle())); userDao.updatePassword(dbUser); - userDao.update2fa(Utils.toLongValue(dbUser.getId()), false, false); + userDao.update2faByUserId(Utils.toLongValue(dbUser.getId()), false, false); return ApiResponseFactory.createResponse("password updated successfully."); } From c12fd6fa0d90d162a1fd6785a524fc8bba9a9614 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Mon, 25 Jul 2022 22:55:36 +0300 Subject: [PATCH 20/32] add mfa to roles endpoint --- .../com/appirio/tech/core/service/identity/dao/UserDAO.java | 4 +++- .../tech/core/service/identity/resource/UserResource.java | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) 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 2e0ae80..02064a7 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,8 +171,10 @@ public abstract class UserDAO implements DaoBase, Transactional { @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + - "e.address AS email, e.status_id AS emailStatus " + + "e.address AS email, e.status_id AS emailStatus, " + + "mfa.enabled AS mfaEnabled, mfa.verified AS mfaVerified " + "FROM common_oltp.user AS u JOIN common_oltp.email AS e ON e.user_id = u.user_id " + + "LEFT JOIN common_oltp.user_2fa AS mfa ON mfa.user_id = u.user_id " + "WHERE e.address = :email" ) public abstract List findUsersByEmailCS(@Bind("email") String email); 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 c57f9c5..61b0cfa 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 @@ -1513,8 +1513,6 @@ public ApiResponse updateUser2fa( @Valid PostPutRequest postRequest, @Context HttpServletRequest request) { - logger.info(String.format("update user 2fa(%s)", resourceId)); - TCID id = new TCID(resourceId); validateResourceIdAndCheckPermission(authUser, id, user2faFactory.getUpdateScopes()); // checking param @@ -1525,6 +1523,7 @@ public ApiResponse updateUser2fa( if(user2fa.getEnabled() == null) { throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "enabled")); } + logger.info(String.format("update user 2fa(%s) - %b", resourceId, user2fa.getEnabled())); Long userId = Utils.toLongValue(id); From 92c9d129f6298d9e9fa51af99e79710174262a0a Mon Sep 17 00:00:00 2001 From: eisbilir Date: Fri, 29 Jul 2022 00:22:53 +0300 Subject: [PATCH 21/32] update dice conf --- buildtokenproperties.sh | 16 +- .../clients/EventBusServiceClient.java | 8 +- .../identity/resource/UserResource.java | 34 ++-- .../service/identity/util/auth/DICEAuth.java | 156 +++++++++++++++++- src/main/resources/config.yml | 8 +- src/main/resources/config.yml.localdev | 9 +- token.properties.localdev | 8 +- token.properties.template | 8 +- 8 files changed, 215 insertions(+), 32 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index a95ecd0..83863a8 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -17,7 +17,13 @@ AUTH0_NEW_NONINTERACTIVE_ID=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID") AUTH0_NEW_NONINTERACTIVE_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIVE_ID_SECRET") DICEAUTH_DICE_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_URL") DICEAUTH_DICE_API_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_URL") -DICEAUTH_API_KEY=$(eval "echo \$${ENV}_DICEAUTH_API_KEY") +DICEAUTH_DICE_VERIFIER=$(eval "echo \$${ENV}_DICEAUTH_DICE_VERIFIER") +DICEAUTH_ID=$(eval "echo \$${ENV}_DICEAUTH_ID") +DICEAUTH_ID_SECRET=$(eval "echo \$${ENV}_DICEAUTH_ID_SECRET") +DICEAUTH_PASSWORD=$(eval "echo \$${ENV}_DICEAUTH_PASSWORD") +DICEAUTH_SCOPE=$(eval "echo \$${ENV}_DICEAUTH_SCOPE") +DICEAUTH_TENANT=$(eval "echo \$${ENV}_DICEAUTH_TENANT") +DICEAUTH_USERNAME=$(eval "echo \$${ENV}_DICEAUTH_USERNAME") DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") @@ -90,7 +96,13 @@ perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID\}\}/$AUTH0_NEW_NONINTERACTIVE_ID/ perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACTIVE_ID_SECRET/g" $CONFFILENAME perl -pi -e "s|\{\{DICEAUTH_DICE_URL\}\}|$DICEAUTH_DICE_URL|g" $CONFFILENAME perl -pi -e "s|\{\{DICEAUTH_DICE_API_URL\}\}|$DICEAUTH_DICE_API_URL|g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_API_KEY\}\}/$DICEAUTH_API_KEY/g" $CONFFILENAME +perl -pi -e "s|\{\{DICEAUTH_DICE_VERIFIER\}\}|$DICEAUTH_DICE_VERIFIER|g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_ID\}\}/$DICEAUTH_ID/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_ID_SECRET\}\}/$DICEAUTH_ID_SECRET/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_PASSWORD\}\}/$DICEAUTH_PASSWORD/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_SCOPE\}\}/$DICEAUTH_SCOPE/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_TENANT\}\}/$DICEAUTH_TENANT/g" $CONFFILENAME +perl -pi -e "s/\{\{DICEAUTH_USERNAME\}\}/$DICEAUTH_USERNAME/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_CREDDEFID\}\}/$DICEAUTH_CREDDEFID/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_ID\}\}/$ZENDESK_ID/g" $CONFFILENAME diff --git a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java index b4a8211..a6ab291 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java +++ b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java @@ -9,8 +9,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.SocketTimeoutException; - +import javax.ws.rs.ProcessingException; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; @@ -89,9 +88,8 @@ public void reFireEvent(EventMessage eventMessage) { if (response.getStatusInfo().getStatusCode() != HttpStatus.OK_200 && response.getStatusInfo().getStatusCode()!= HttpStatus.NO_CONTENT_204) { LOGGER.error("Unable to fire the event: {}", response); } - } catch (SocketTimeoutException e) { - LOGGER.info(e.getMessage()); - if(!e.getMessage().equals("Read timed out")) { + } catch (ProcessingException e) { + if(!e.getMessage().equals("java.net.SocketTimeoutException: Read timed out")) { LOGGER.error("Failed to fire the event: {}", e); } } catch (Exception e) { 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 61b0cfa..ce85fc8 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 @@ -1517,26 +1517,26 @@ public ApiResponse updateUser2fa( validateResourceIdAndCheckPermission(authUser, id, user2faFactory.getUpdateScopes()); // checking param checkParam(postRequest); - + User2fa user2fa = postRequest.getParam(); - if(user2fa.getEnabled() == null) { + if (user2fa.getEnabled() == null) { throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "enabled")); } logger.info(String.format("update user 2fa(%s) - %b", resourceId, user2fa.getEnabled())); Long userId = Utils.toLongValue(id); - + logger.info(String.format("findUserById(%s)", resourceId)); User2fa user2faInDb = userDao.findUser2faById(userId); - if(user2faInDb==null) + if (user2faInDb == null) throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); - + Boolean shouldSendInvite = false; - if(user2faInDb.getEnabled() == null) { + if (user2faInDb.getEnabled() == null) { userDao.insertUser2fa(userId, user2fa.getEnabled()); shouldSendInvite = user2fa.getEnabled(); - } else if(!user2faInDb.getEnabled().equals(user2fa.getEnabled())) { + } else if (!user2faInDb.getEnabled().equals(user2fa.getEnabled())) { userDao.update2fa(user2faInDb.getId(), user2fa.getEnabled(), false); shouldSendInvite = user2fa.getEnabled(); } @@ -1544,15 +1544,17 @@ public ApiResponse updateUser2fa( if (shouldSendInvite) { Response response; try { - response = new Request(diceAuth.getDiceApiUrl() + "/v1/connection/submit", "POST") + response = new Request(diceAuth.getDiceApiUrl() + "/connection/invitation", "POST") .param("emailId", user2faInDb.getEmail()) - .header("x-api-key", diceAuth.getApiKey()) + .header("Authorization", "Bearer " + diceAuth.getToken()) .execute(); } catch (Exception e) { logger.error("Error when calling 2fa submit api", e); + userDao.update2fa(user2faInDb.getId(), false, false); throw new APIRuntimeException(SC_INTERNAL_SERVER_ERROR, "Error when calling 2fa submit api"); } if (response.getStatusCode() != HttpURLConnection.HTTP_CREATED) { + userDao.update2fa(user2faInDb.getId(), false, false); throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), response.getMessage())); @@ -1560,7 +1562,7 @@ public ApiResponse updateUser2fa( logger.info(response.getText()); send2faInvitationEmailEvent(user2faInDb, diceAuth.getDiceUrl() + "/verify/" + response.getText()); } - + return ApiResponseFactory.createResponse("SUCCESS"); } @@ -1619,10 +1621,10 @@ public ApiResponse issueCredentials( preview.set("attributes", attributes); Response response; try { - response = new Request(diceAuth.getDiceApiUrl()+"/v1/credentialoffer/api/credentialoffer", "POST") - .header("x-api-key", diceAuth.getApiKey()) - .json(mapper.writeValueAsString(body)) - .execute(); + response = new Request(diceAuth.getDiceApiUrl() + "/cred/issuance/offer", "POST") + .header("Authorization", "Bearer " + diceAuth.getToken()) + .json(mapper.writeValueAsString(body)) + .execute(); } catch (JsonProcessingException e) { logger.error("Error when processing JSON content", e); throw new APIRuntimeException(SC_INTERNAL_SERVER_ERROR, "Error when calling credentialoffer api"); @@ -1635,6 +1637,9 @@ public ApiResponse issueCredentials( String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), response.getMessage())); } + if (user.getVerified()) { + userDao.update2fa(user.getId(), true, false); + } return ApiResponseFactory.createResponse("SUCCESS"); } @@ -2098,6 +2103,7 @@ private void send2faInvitationEmailEvent(User2fa user, String inviteLink) { Map data = new LinkedHashMap(); data.put("handle", user.getHandle()); data.put("link", inviteLink); + data.put("verifier", diceAuth.getDiceVerifier()); 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 c586042..2532418 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 @@ -1,8 +1,24 @@ package com.appirio.tech.core.service.identity.util.auth; +import java.net.HttpURLConnection; +import java.util.Date; + import javax.validation.constraints.NotNull; +import org.apache.log4j.Logger; + +import com.appirio.tech.core.api.v3.exception.APIRuntimeException; +import com.appirio.tech.core.api.v3.util.jwt.InvalidTokenException; +import com.appirio.tech.core.service.identity.util.HttpUtil.Request; +import com.appirio.tech.core.service.identity.util.HttpUtil.Response; +import com.auth0.jwt.JWT; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.fasterxml.jackson.databind.ObjectMapper; + public class DICEAuth { + private static final Logger logger = Logger.getLogger(Auth0Client.class); + @NotNull private String diceUrl; @@ -10,20 +26,47 @@ public class DICEAuth { private String diceApiUrl; @NotNull - private String apiKey; + private String diceVerifier; + + @NotNull + private String tenant; + + @NotNull + private String username; + + @NotNull + private String password; + + @NotNull + private String scope; + + @NotNull + private String clientId; + + @NotNull + private String clientSecret; @NotNull private String credDefId; private String credPreview = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview"; + private String cachedToken; + public DICEAuth() { } - public DICEAuth(String diceUrl, String diceApiUrl, String apiKey, String credDefId) { + public DICEAuth(String diceUrl, String diceApiUrl, String diceVerifier, String tenant, String username, + String password, String scope, String clientId, String clientSecret, String credDefId) { this.diceUrl = diceUrl; this.diceApiUrl = diceApiUrl; - this.apiKey = apiKey; + this.diceVerifier = diceVerifier; + this.tenant = tenant; + this.username = username; + this.password = password; + this.scope = scope; + this.clientId = clientId; + this.clientSecret = clientSecret; this.credDefId = credDefId; } @@ -43,12 +86,60 @@ public void setDiceApiUrl(String diceApiUrl) { this.diceApiUrl = diceApiUrl; } - public String getApiKey() { - return apiKey; + public String getDiceVerifier() { + return diceVerifier; + } + + public void setDiceVerifier(String diceVerifier) { + this.diceVerifier = diceVerifier; + } + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; } - public void setApiKey(String apiKey) { - this.apiKey = apiKey; + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; } public String getCredDefId() { @@ -66,4 +157,55 @@ public String getCredPreview() { public void setCredPreview(String credPreview) { this.credPreview = credPreview; } + + public String getToken() throws Exception { + Boolean isCachedTokenExpired = false; + if (cachedToken != null) { + if (getTokenExpiryTime(cachedToken) <= 0) { + isCachedTokenExpired = true; + logger.info("Application cached token expired"); + } + } + if (cachedToken == null || isCachedTokenExpired) { + Response response = new Request( + "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token", "POST") + .param("grant_type", "password") + .param("username", getUsername()) + .param("password", getPassword()) + .param("scope", getScope()) + .param("client_id", getClientId()) + .param("client_secret", getClientSecret()).execute(); + if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { + throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, + String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), + response.getText())); + } + cachedToken = new ObjectMapper().readValue(response.getText(), Auth0Credential.class).getIdToken(); + } + return cachedToken; + } + + /** + * Get token expiry time in seconds + * + * @param token JWT token + * throws Exception if any error occurs + * @return the Integer result + */ + private Integer getTokenExpiryTime(String token) throws Exception { + DecodedJWT decodedJWT = null; + Integer tokenExpiryTime = 0; + if (token != null) { + try { + decodedJWT = JWT.decode(token); + } catch (JWTDecodeException e) { + throw new InvalidTokenException(token, "Error occurred in decoding token. " + e.getLocalizedMessage(), + e); + } + Date tokenExpiryDate = decodedJWT.getExpiresAt(); + Long tokenExpiryTimeInMilliSeconds = tokenExpiryDate.getTime() - (new Date().getTime()) - 60 * 1000; + tokenExpiryTime = (int) Math.floor(tokenExpiryTimeInMilliSeconds / 1000); + } + return tokenExpiryTime; + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7b8178b..e73b481 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -95,7 +95,13 @@ auth0New: diceAuth: diceUrl: @diceAuth.diceUrl@ diceApiUrl: @diceAuth.diceApiUrl@ - apiKey: @diceAuth.apiKey@ + diceVerifier: @diceAuth.diceVerifier@ + clientId: @diceAuth.clientId@ + clientSecret: @diceAuth.clientSecret@ + password: @diceAuth.password@ + scope: @diceAuth.scope@ + tenant: @diceAuth.tenant@ + username: @diceAuth.username@ credDefId: @diceAuth.credDefId@ # Authorized accounts diff --git a/src/main/resources/config.yml.localdev b/src/main/resources/config.yml.localdev index 354b376..3ac7140 100644 --- a/src/main/resources/config.yml.localdev +++ b/src/main/resources/config.yml.localdev @@ -87,7 +87,14 @@ auth0New: diceAuth: diceUrl: dummy - apiKey: dummy + diceApiUrl: dummy + diceVerifier: dummy + clientId: dummy + clientSecret: dummy + password: dummy + scope: dummy + tenant: dummy + username: dummy credDefId: dummy # LDAP Settings diff --git a/token.properties.localdev b/token.properties.localdev index 29b6f3b..8578b82 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -32,7 +32,13 @@ @diceAuth.diceUrl@=dummy @diceAuth.diceApiUrl@=dummy -@diceAuth.apiKey@=dummy +@diceAuth.diceVerifier@=dummy +@diceAuth.clientId@=dummy +@diceAuth.clientSecret@=dummy +@diceAuth.password@=dummy +@diceAuth.scope@=dummy +@diceAuth.tenant@=dummy +@diceAuth.username@=dummy @diceAuth.credDefId@=dummy @zendesk.secret@=ZENDESK_SECRET diff --git a/token.properties.template b/token.properties.template index 3ac4924..d35c7a3 100644 --- a/token.properties.template +++ b/token.properties.template @@ -52,7 +52,13 @@ @diceAuth.diceUrl@={{DICEAUTH_DICE_URL}} @diceAuth.diceApiUrl@={{DICEAUTH_DICE_API_URL}} -@diceAuth.apiKey@={{DICEAUTH_API_KEY}} +@diceAuth.diceVerifier@={{DICEAUTH_DICE_VERIFIER}} +@diceAuth.clientId@={{DICEAUTH_ID}} +@diceAuth.clientSecret@={{DICEAUTH_ID_SECRET}} +@diceAuth.password@={{DICEAUTH_PASSWORD}} +@diceAuth.scope@={{DICEAUTH_SCOPE}} +@diceAuth.tenant@={{DICEAUTH_TENANT}} +@diceAuth.username@={{DICEAUTH_USERNAME}} @diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} @zendesk.secret@={{ZENDESK_KEY}} From 7266e7ee1030ab76ee0397de91085307582b92bd Mon Sep 17 00:00:00 2001 From: Emre Date: Fri, 29 Jul 2022 11:04:34 +0300 Subject: [PATCH 22/32] update token --- buildtokenproperties.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 83863a8..c73d663 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -99,7 +99,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_ID\}\}/$DICEAUTH_ID/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_ID_SECRET\}\}/$DICEAUTH_ID_SECRET/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_PASSWORD\}\}/$DICEAUTH_PASSWORD/g" $CONFFILENAME +perl -pi -e "s|\{\{DICEAUTH_PASSWORD\}\}|$DICEAUTH_PASSWORD|g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_SCOPE\}\}/$DICEAUTH_SCOPE/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_TENANT\}\}/$DICEAUTH_TENANT/g" $CONFFILENAME perl -pi -e "s/\{\{DICEAUTH_USERNAME\}\}/$DICEAUTH_USERNAME/g" $CONFFILENAME From 55b2dde3565b7145eb5b3da7922289e08f7c5294 Mon Sep 17 00:00:00 2001 From: Emre Date: Fri, 29 Jul 2022 16:28:48 +0300 Subject: [PATCH 23/32] update log statements --- .../core/service/identity/clients/EventBusServiceClient.java | 2 +- .../tech/core/service/identity/resource/UserResource.java | 3 +-- .../tech/core/service/identity/util/auth/DICEAuth.java | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java index a6ab291..8f72b06 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java +++ b/src/main/java/com/appirio/tech/core/service/identity/clients/EventBusServiceClient.java @@ -82,9 +82,9 @@ public void reFireEvent(EventMessage eventMessage) { String authToken = Utils.generateAuthToken(m2mAuthConfiguration); eventMessage.setOriginator(this.config.getAdditionalConfiguration().get("originator")); + LOGGER.info("Fire event {}", new ObjectMapper().writer().writeValueAsString(eventMessage)); Response response = request.header("Authorization", "Bearer " + authToken).post(Entity.entity(eventMessage.getData(), MediaType.APPLICATION_JSON_TYPE)); - LOGGER.info("Fire event {}", new ObjectMapper().writer().writeValueAsString(eventMessage)); if (response.getStatusInfo().getStatusCode() != HttpStatus.OK_200 && response.getStatusInfo().getStatusCode()!= HttpStatus.NO_CONTENT_204) { LOGGER.error("Unable to fire the event: {}", response); } 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 ce85fc8..20e7701 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 @@ -1527,7 +1527,6 @@ public ApiResponse updateUser2fa( Long userId = Utils.toLongValue(id); - logger.info(String.format("findUserById(%s)", resourceId)); User2fa user2faInDb = userDao.findUser2faById(userId); if (user2faInDb == null) throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); @@ -1559,7 +1558,7 @@ public ApiResponse updateUser2fa( String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), response.getMessage())); } - logger.info(response.getText()); + logger.info("Connection created: " + response.getText()); send2faInvitationEmailEvent(user2faInDb, diceAuth.getDiceUrl() + "/verify/" + response.getText()); } 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 2532418..ee69ada 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 @@ -167,8 +167,8 @@ public String getToken() throws Exception { } } if (cachedToken == null || isCachedTokenExpired) { - Response response = new Request( - "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token", "POST") + String url = "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token"; + Response response = new Request(url, "POST") .param("grant_type", "password") .param("username", getUsername()) .param("password", getPassword()) @@ -181,6 +181,7 @@ public String getToken() throws Exception { response.getText())); } cachedToken = new ObjectMapper().readValue(response.getText(), Auth0Credential.class).getIdToken(); + logger.info("Fetched token from URL: " + url); } return cachedToken; } From 0902a8d4957fe871ac05edc95bed5b3314e9efca Mon Sep 17 00:00:00 2001 From: Emre Date: Mon, 1 Aug 2022 17:58:16 +0300 Subject: [PATCH 24/32] add otp endpoints --- buildtokenproperties.sh | 2 + .../service/identity/IdentityApplication.java | 1 + .../core/service/identity/dao/UserDAO.java | 14 +++ .../identity/representation/UserOtp.java | 23 +++++ .../representation/UserOtpResponse.java | 15 +++ .../identity/resource/UserResource.java | 99 +++++++++++++++++++ src/main/resources/config.yml | 1 + token.properties.localdev | 1 + token.properties.template | 1 + 9 files changed, 157 insertions(+) create mode 100644 src/main/java/com/appirio/tech/core/service/identity/representation/UserOtp.java create mode 100644 src/main/java/com/appirio/tech/core/service/identity/representation/UserOtpResponse.java diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index c73d663..8bd6839 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -62,6 +62,7 @@ SENDGRID_WELCOME_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_WELCOME_EMAIL_ SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID") SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID") SENDGRID_2FA_INVITATION_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_2FA_INVITATION_TEMPLATE_ID") +SENDGRID_2FA_OTP_TEMPLATE_ID=$(eval "echo \$${ENV}_SENDGRID_2FA_OTP_TEMPLATE_ID") if [[ -z "$ENV" ]] ; then @@ -145,3 +146,4 @@ perl -pi -e "s/\{\{SENDGRID_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_WELCOME_EMAI perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID/g" $CONFFILENAME perl -pi -e "s/\{\{SENDGRID_2FA_INVITATION_TEMPLATE_ID\}\}/$SENDGRID_2FA_INVITATION_TEMPLATE_ID/g" $CONFFILENAME +perl -pi -e "s/\{\{SENDGRID_2FA_OTP_TEMPLATE_ID\}\}/$SENDGRID_2FA_OTP_TEMPLATE_ID/g" $CONFFILENAME diff --git a/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java b/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java index 3442f80..d1520c8 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java +++ b/src/main/java/com/appirio/tech/core/service/identity/IdentityApplication.java @@ -243,6 +243,7 @@ public void run(IdentityConfiguration configuration, Environment environment) th userResource.setSendgridSelfServiceTemplateId(Utils.getString("sendGridSelfServiceTemplateId")); userResource.setSendgridSelfServiceWelcomeTemplateId(Utils.getString("sendGridSelfServiceWelcomeTemplateId")); userResource.setSendgrid2faInvitationTemplateId(Utils.getString("sendGrid2faInvitationTemplateId")); + userResource.setSendgrid2faOtpTemplateId(Utils.getString("sendGrid2faOtpTemplateId")); // this secret _used_ to be different from the one used in AuthorizationResource. // it _was_ the secret x2. (userResource.setSecret(getSecret()+getSecret());) // we assume this was done to further limit the usability of the oneTimeToken generated in userResource 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 02064a7..418b45b 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 @@ -168,6 +168,20 @@ public abstract class UserDAO implements DaoBase, Transactional { "WHERE user_id=:userId") public abstract int update2faByUserId(@Bind("userId") long userId, @Bind("enabled") boolean enabled, @Bind("verified") boolean verified); + @SqlUpdate( + "UPDATE common_oltp.user_2fa SET " + + "otp=:otp, " + + "otp_expire=current_timestamp + (5 ||' minutes')::interval " + + "WHERE id=:id") + public abstract int update2faOtp(@Bind("id") long id, @Bind("otp") String otp); + + @SqlUpdate( + "UPDATE common_oltp.user_2fa SET otp=null, otp_expire=null " + + "FROM (SELECT id, otp, otp_expire FROM common_oltp.user_2fa WHERE user_id=:userId FOR UPDATE)y " + + "WHERE x.id=y.id " + + "RETURNING CASE WHEN y.otp=:otp and y.otp_expire > current_timestamp THEN 1 ELSE 0 END") + public abstract int verify2faOtp(@Bind("userId") long userId, @Bind("otp") String otp); + @RegisterMapperFactory(TCBeanMapperFactory.class) @SqlQuery( "SELECT " + USER_COLUMNS + ", " + diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/UserOtp.java b/src/main/java/com/appirio/tech/core/service/identity/representation/UserOtp.java new file mode 100644 index 0000000..4845f63 --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/UserOtp.java @@ -0,0 +1,23 @@ +package com.appirio.tech.core.service.identity.representation; + +public class UserOtp { + + private Long userId; + private String otp; + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } + + public String getOtp() { + return otp; + } + + public void setOtp(String otp) { + this.otp = otp; + } +} diff --git a/src/main/java/com/appirio/tech/core/service/identity/representation/UserOtpResponse.java b/src/main/java/com/appirio/tech/core/service/identity/representation/UserOtpResponse.java new file mode 100644 index 0000000..081d28f --- /dev/null +++ b/src/main/java/com/appirio/tech/core/service/identity/representation/UserOtpResponse.java @@ -0,0 +1,15 @@ +package com.appirio.tech.core.service.identity.representation; + +public class UserOtpResponse { + + private Boolean verified; + + public Boolean getVerified() { + return verified; + } + + public void setVerified(Boolean verified) { + this.verified = verified; + } + +} 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 20e7701..318b8b3 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 @@ -60,6 +60,8 @@ import com.appirio.tech.core.service.identity.representation.Credential; import com.appirio.tech.core.service.identity.representation.CredentialRequest; import com.appirio.tech.core.service.identity.representation.User2fa; +import com.appirio.tech.core.service.identity.representation.UserOtp; +import com.appirio.tech.core.service.identity.representation.UserOtpResponse; import com.appirio.tech.core.service.identity.representation.Email; import com.appirio.tech.core.service.identity.representation.ProviderType; import com.appirio.tech.core.service.identity.representation.Role; @@ -124,6 +126,8 @@ public class UserResource implements GetResource, DDLResource { private String sendgridSelfServiceWelcomeTemplateId; private String sendgrid2faInvitationTemplateId; + + private String sendgrid2faOtpTemplateId; protected UserDAO userDao; @@ -1678,6 +1682,65 @@ public ApiResponse update2faVerification( return ApiResponseFactory.createResponse("User verification updated"); } + @POST + @Path("/sendOtp") + @Timed + public ApiResponse createOtp( + @Valid PostPutRequest postRequest, + @Context HttpServletRequest request) { + + // checking param + checkParam(postRequest); + + UserOtp userOtp = postRequest.getParam(); + + if (userOtp.getUserId() == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "userId")); + } + logger.info(String.format("send otp to user (%d)", userOtp.getUserId())); + + User2fa user2faInDb = userDao.findUser2faById(userOtp.getUserId()); + if (user2faInDb == null) + throw new APIRuntimeException(SC_NOT_FOUND, MSG_TEMPLATE_USER_NOT_FOUND); + if (user2faInDb.getEnabled() == null || !user2faInDb.getEnabled()) { + 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); + return ApiResponseFactory.createResponse("SUCCESS"); + } + + @POST + @Path("/checkOtp") + @Timed + public ApiResponse checkOtp( + @Valid PostPutRequest postRequest, + @Context HttpServletRequest request) { + + // checking param + checkParam(postRequest); + + UserOtp userOtp = postRequest.getParam(); + + if (userOtp.getUserId() == null) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "userId")); + } + if (userOtp.getOtp() == null || userOtp.getOtp().length() == 0) { + throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "otp")); + } + logger.info(String.format("verify otp for user (%d)", userOtp.getUserId())); + + int result = userDao.verify2faOtp(userOtp.getUserId(), userOtp.getOtp()); + UserOtpResponse response = new UserOtpResponse(); + if (result == 1) { + response.setVerified(true); + } else { + response.setVerified(false); + } + return ApiResponseFactory.createResponse(response); + } + @POST @Path("/oneTimeToken") @Timed @@ -2009,6 +2072,14 @@ public void setSendgrid2faInvitationTemplateId(String sendgrid2faInvitationTempl this.sendgrid2faInvitationTemplateId = sendgrid2faInvitationTemplateId; } + public String getSendgrid2faOtpTemplateId() { + return sendgrid2faOtpTemplateId; + } + + public void setSendgrid2faOtpTemplateId(String sendgrid2faOtpTemplateId) { + this.sendgrid2faOtpTemplateId = sendgrid2faOtpTemplateId; + } + public String getSecret() { return secret; } @@ -2122,6 +2193,34 @@ private void send2faInvitationEmailEvent(User2fa user, String inviteLink) { this.eventBusServiceClient.reFireEvent(msg); } + private void send2faCodeEmailEvent(User2fa user, String code) { + + EventMessage msg = EventMessage.getDefault(); + msg.setTopic("external.action.email"); + + Map payload = new LinkedHashMap(); + Map data = new LinkedHashMap(); + data.put("handle", user.getHandle()); + data.put("code", code); + + payload.put("data", data); + + Map from = new LinkedHashMap(); + from.put("email", String.format("Topcoder ", getDomain())); + payload.put("from", from); + + payload.put("version", "v3"); + payload.put("sendgrid_template_id", this.getSendgrid2faOtpTemplateId()); + + ArrayList recipients = new ArrayList(); + recipients.add(user.getEmail()); + + payload.put("recipients", recipients); + + msg.setPayload(payload); + this.eventBusServiceClient.reFireEvent(msg); + } + private void sendWelcomeEmailEvent(User user) { EventMessage msg = EventMessage.getDefault(); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e73b481..a27f9ec 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -16,6 +16,7 @@ context: sendGridSelfServiceTemplateId: @application.sendgrid.selfservice.template.id@ sendGridSelfServiceWelcomeTemplateId: @application.sendgrid.selfservice.welcome.template.id@ sendGrid2faInvitationTemplateId: @application.sendgrid.2fa.invitation.template.id@ + sendGrid2faOtpTemplateId: @application.sendgrid.2fa.otp.template.id@ jwtExpirySeconds: 600 cookieExpirySeconds: 7776000 diff --git a/token.properties.localdev b/token.properties.localdev index 8578b82..5877068 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -12,6 +12,7 @@ @application.sendgrid.selfservice.template.id@=dummy @application.sendgrid.selfservice.welcome.template.id@=dummy @application.sendgrid.2fa.invitation.template.id@=dummy +@application.sendgrid.2fa.otp.template.id@=dummy @ldap.host@=127.0.0.1 @ldap.port@=389 diff --git a/token.properties.template b/token.properties.template index d35c7a3..1c26af1 100644 --- a/token.properties.template +++ b/token.properties.template @@ -13,6 +13,7 @@ @application.sendgrid.selfservice.template.id@={{SENDGRID_SELF_SERVICE_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID}} @application.sendgrid.selfservice.welcome.template.id@={{SENDGRID_SELF_SERVICE_WELCOME_EMAIL_TEMPLATE_ID}} @application.sendgrid.2fa.invitation.template.id@={{SENDGRID_2FA_INVITATION_TEMPLATE_ID}} +@application.sendgrid.2fa.otp.template.id@={{SENDGRID_2FA_OTP_TEMPLATE_ID}} @ldap.host@={{LDAP_SERVER}} @ldap.port@=389 From e2a140ea5848de3c561193e68f483f649d6e1bf8 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Mon, 1 Aug 2022 23:25:12 +0300 Subject: [PATCH 25/32] fix sql query --- .../com/appirio/tech/core/service/identity/dao/UserDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 418b45b..0fd787e 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 @@ -176,7 +176,7 @@ public abstract class UserDAO implements DaoBase, Transactional { public abstract int update2faOtp(@Bind("id") long id, @Bind("otp") String otp); @SqlUpdate( - "UPDATE common_oltp.user_2fa SET otp=null, otp_expire=null " + + "UPDATE common_oltp.user_2fa x SET otp=null, otp_expire=null " + "FROM (SELECT id, otp, otp_expire FROM common_oltp.user_2fa WHERE user_id=:userId FOR UPDATE)y " + "WHERE x.id=y.id " + "RETURNING CASE WHEN y.otp=:otp and y.otp_expire > current_timestamp THEN 1 ELSE 0 END") From 9be0e0433ff502b963897e7ee88d19e1c672e407 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Tue, 2 Aug 2022 00:13:57 +0300 Subject: [PATCH 26/32] fix annotation --- .../com/appirio/tech/core/service/identity/dao/UserDAO.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0fd787e..c6ceece 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 @@ -175,7 +175,7 @@ public abstract class UserDAO implements DaoBase, Transactional { "WHERE id=:id") public abstract int update2faOtp(@Bind("id") long id, @Bind("otp") String otp); - @SqlUpdate( + @SqlQuery( "UPDATE common_oltp.user_2fa x SET otp=null, otp_expire=null " + "FROM (SELECT id, otp, otp_expire FROM common_oltp.user_2fa WHERE user_id=:userId FOR UPDATE)y " + "WHERE x.id=y.id " + From e1ea8052bf1540f8d0427f810ca0a287997933c9 Mon Sep 17 00:00:00 2001 From: Emre Date: Wed, 3 Aug 2022 09:58:35 +0300 Subject: [PATCH 27/32] update 2fa m2m scopes --- buildtokenproperties.sh | 14 +-- .../identity/resource/UserResource.java | 6 +- .../util/m2mscope/User2faFactory.java | 110 +++++++----------- src/main/resources/config.yml | 7 +- src/main/resources/config.yml.localdev | 7 +- token.properties.localdev | 7 +- token.properties.template | 7 +- 7 files changed, 60 insertions(+), 98 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 8bd6839..67d9e0c 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -43,10 +43,9 @@ M2MAUTHCONFIG_USERPROFILES_CREATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFIL M2MAUTHCONFIG_USERPROFILES_UPDATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFILES_UPDATE") M2MAUTHCONFIG_USERPROFILES_READ=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFILES_READ") M2MAUTHCONFIG_USERPROFILES_DELETE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USERPROFILES_DELETE") -M2MAUTHCONFIG_USER2FA_CREATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_CREATE") -M2MAUTHCONFIG_USER2FA_UPDATE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_UPDATE") -M2MAUTHCONFIG_USER2FA_READ=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_READ") -M2MAUTHCONFIG_USER2FA_DELETE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_DELETE") +M2MAUTHCONFIG_USER2FA_ENABLE=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_ENABLE") +M2MAUTHCONFIG_USER2FA_VERIFY=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_VERIFY") +M2MAUTHCONFIG_USER2FA_CREDENTIAL=$(eval "echo \$${ENV}_M2MAUTHCONFIG_USER2FA_CREDENTIAL") DOMAIN=$(eval "echo \$${ENV}_DOMAIN") SMTP=$(eval "echo \$${ENV}_SMTP") @@ -135,10 +134,9 @@ perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_CREATE\}\}|$M2MAUTHCONFIG_USERPROF perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_UPDATE\}\}|$M2MAUTHCONFIG_USERPROFILES_UPDATE|g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_READ\}\}|$M2MAUTHCONFIG_USERPROFILES_READ|g" $CONFFILENAME perl -pi -e "s|\{\{M2MAUTHCONFIG_USERPROFILES_DELETE\}\}|$M2MAUTHCONFIG_USERPROFILES_DELETE|g" $CONFFILENAME -perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_CREATE\}\}|$M2MAUTHCONFIG_USER2FA_CREATE|g" $CONFFILENAME -perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_UPDATE\}\}|$M2MAUTHCONFIG_USER2FA_UPDATE|g" $CONFFILENAME -perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_READ\}\}|$M2MAUTHCONFIG_USER2FA_READ|g" $CONFFILENAME -perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_DELETE\}\}|$M2MAUTHCONFIG_USER2FA_DELETE|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_ENABLE\}\}|$M2MAUTHCONFIG_USER2FA_ENABLE|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_VERIFY\}\}|$M2MAUTHCONFIG_USER2FA_VERIFY|g" $CONFFILENAME +perl -pi -e "s|\{\{M2MAUTHCONFIG_USER2FA_CREDENTIAL\}\}|$M2MAUTHCONFIG_USER2FA_CREDENTIAL|g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_NEW_DOMAIN\}\}/$AUTH0_NEW_DOMAIN/g" $CONFFILENAME perl -pi -e "s/\{\{AUTH0_DOMAIN\}\}/$AUTH0_DOMAIN/g" $CONFFILENAME perl -pi -e "s/\{\{SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID\}\}/$SENDGRID_RESEND_ACTIVATION_EMAIL_TEMPLATE_ID/g" $CONFFILENAME 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 318b8b3..76fce09 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 @@ -1518,7 +1518,7 @@ public ApiResponse updateUser2fa( @Context HttpServletRequest request) { TCID id = new TCID(resourceId); - validateResourceIdAndCheckPermission(authUser, id, user2faFactory.getUpdateScopes()); + validateResourceIdAndCheckPermission(authUser, id, user2faFactory.getEnableScopes()); // checking param checkParam(postRequest); @@ -1576,7 +1576,7 @@ public ApiResponse issueCredentials( @Auth AuthUser authUser, @Valid PostPutRequest postRequest, @Context HttpServletRequest request) { - Utils.checkAccess(authUser, user2faFactory.getCreateScopes(), Utils.AdminRoles); + Utils.checkAccess(authUser, user2faFactory.getCredentialIssuerScopes(), Utils.AdminRoles); checkParam(postRequest); CredentialRequest credential = postRequest.getParam(); @@ -1654,7 +1654,7 @@ public ApiResponse update2faVerification( @Valid PostPutRequest putRequest, @Context HttpServletRequest request) { - Utils.checkAccess(authUser, user2faFactory.getUpdateScopes(), Utils.AdminRoles); + Utils.checkAccess(authUser, user2faFactory.getVerifyScopes(), Utils.AdminRoles); checkParam(putRequest); User2fa credential = putRequest.getParam(); diff --git a/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java b/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java index 4ce6eb7..ff8bf37 100644 --- a/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java +++ b/src/main/java/com/appirio/tech/core/service/identity/util/m2mscope/User2faFactory.java @@ -12,131 +12,99 @@ public class User2faFactory { /** * Represents the create scopes for machine token validation. */ - public static final String[] ReadScopes = { "all:user_2fa" }; + public static final String[] EnableScopes = { "enable:user_2fa", "all:user_2fa" }; /** * Represents the create scopes for machine token validation. */ - public static final String[] CreateScopes = { "all:user_2fa" }; - - /** - * Represents the delete scopes for machine token validation. - */ - public static final String[] DeleteScopes = { "all:user_2fa" }; + public static final String[] VerifyScopes = { "verify:user_2fa", "all:user_2fa" }; /** * Represents the update scopes for machine token validation. */ - public static final String[] UpdateScopes = { "all:user_2fa" }; + public static final String[] CredentialIssuerScopes = { "cred:user_2fa", "all:user_2fa" }; /** - * Represents the read attribute + * Represents the enable attribute */ @JsonProperty - private String read; + private String enable; /** - * Represents the create attribute + * Represents the verify attribute */ @JsonProperty - private String create; + private String verify; /** - * Represents the update attribute + * Represents the credential attribute */ @JsonProperty - private String update; - - /** - * Represents the delete attribute - */ - @JsonProperty - private String delete; + private String credential; public User2faFactory() { } - public String getRead() { - return read; - } - - public void setRead(String read) { - this.read = read; + public String getEnable() { + return enable; } - public String getCreate() { - return create; + public void setEnable(String enable) { + this.enable = enable; } - public void setCreate(String create) { - this.create = create; + public String getVerify() { + return verify; } - public String getUpdate() { - return update; + public void SetVerify(String verify) { + this.verify = verify; } - public void setUpdate(String update) { - this.update = update; + public String getCredential() { + return credential; } - public String getDelete() { - return delete; - } - - public void setDelete(String delete) { - this.delete = delete; - } - - /** - * Gets the read scopes. - * - * @return the read scopes. - */ - public String[] getReadScopes() { - if (read != null && read.trim().length() != 0) { - return read.split(SCOPE_DELIMITER); - } - - return ReadScopes; + public void setCredential(String credential) { + this.credential = credential; } /** - * Gets the create scopes. + * Gets the enable scopes. * - * @return the create scopes. + * @return the enable scopes. */ - public String[] getCreateScopes() { - if (create != null && create.trim().length() != 0) { - return create.split(SCOPE_DELIMITER); + public String[] getEnableScopes() { + if (enable != null && enable.trim().length() != 0) { + return enable.split(SCOPE_DELIMITER); } - return CreateScopes; + return EnableScopes; } /** - * Gets the update scopes. + * Gets the verify scopes. * - * @return the update scopes. + * @return the verify scopes. */ - public String[] getUpdateScopes() { - if (update != null && update.trim().length() != 0) { - return update.split(SCOPE_DELIMITER); + public String[] getVerifyScopes() { + if (verify != null && verify.trim().length() != 0) { + return verify.split(SCOPE_DELIMITER); } - return UpdateScopes; + return VerifyScopes; } /** - * Gets the delete scopes. + * Gets the credential issuer scopes. * - * @return the delete scopes. + * @return the credential issuer scopes. */ - public String[] getDeleteScopes() { - if (delete != null && delete.trim().length() != 0) { - return delete.split(SCOPE_DELIMITER); + public String[] getCredentialIssuerScopes() { + if (credential != null && credential.trim().length() != 0) { + return credential.split(SCOPE_DELIMITER); } - return DeleteScopes; + return CredentialIssuerScopes; } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a27f9ec..dfb31c7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -170,10 +170,9 @@ m2mAuthConfig: update: @m2mAuthConfig.userProfiles.update@ delete: @m2mAuthConfig.userProfiles.delete@ user2fa: - create: @m2mAuthConfig.user2fa.create@ - read: @m2mAuthConfig.user2fa.read@ - update: @m2mAuthConfig.user2fa.update@ - delete: @m2mAuthConfig.user2fa.delete@ + enable: @m2mAuthConfig.user2fa.enable@ + verify: @m2mAuthConfig.user2fa.verify@ + credential: @m2mAuthConfig.user2fa.credential@ # Server settings server: diff --git a/src/main/resources/config.yml.localdev b/src/main/resources/config.yml.localdev index 3ac7140..e51ee8b 100644 --- a/src/main/resources/config.yml.localdev +++ b/src/main/resources/config.yml.localdev @@ -169,10 +169,9 @@ m2mAuthConfig: update: update:user_profiles,all:user_profiles delete: delete:user_profiles,all:user_profiles user2fa: - create: all:user-2fa - read: all:user-2fa - update: all:user-2fa - delete: all:user-2fa + enable: enable:user-2fa,all:user-2fa + verify: verify:user-2fa,all:user-2fa + credential: cred:user-2fa,all:user-2fa # Server settings server: diff --git a/token.properties.localdev b/token.properties.localdev index 5877068..fd7a7f0 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -77,7 +77,6 @@ @m2mAuthConfig.userProfiles.read@=read:user_profiles,all:user_profiles @m2mAuthConfig.userProfiles.update@=update:user_profiles,all:user_profiles @m2mAuthConfig.userProfiles.delete@=delete:user_profiles,all:user_profiles -@m2mAuthConfig.user2fa.create@=create:user_2fa,all:user_2fa -@m2mAuthConfig.user2fa.read@=read:user_2fa,all:user_2fa -@m2mAuthConfig.user2fa.update@=update:user_2fa,all:user_2fa -@m2mAuthConfig.user2fa.delete@=delete:user_2fa,all:user_2fa \ No newline at end of file +@m2mAuthConfig.user2fa.enable@=enable:user_2fa,all:user_2fa +@m2mAuthConfig.user2fa.verify@=verify:user_2fa,all:user_2fa +@m2mAuthConfig.user2fa.credential@=cred:user_2fa,all:user_2fa \ No newline at end of file diff --git a/token.properties.template b/token.properties.template index 1c26af1..7f519e3 100644 --- a/token.properties.template +++ b/token.properties.template @@ -99,7 +99,6 @@ @m2mAuthConfig.userProfiles.read@={{M2MAUTHCONFIG_USERPROFILES_READ}} @m2mAuthConfig.userProfiles.update@={{M2MAUTHCONFIG_USERPROFILES_UPDATE}} @m2mAuthConfig.userProfiles.delete@={{M2MAUTHCONFIG_USERPROFILES_DELETE}} -@m2mAuthConfig.user2fa.create@={{M2MAUTHCONFIG_USER2FA_CREATE}} -@m2mAuthConfig.user2fa.read@={{M2MAUTHCONFIG_USER2FA_READ}} -@m2mAuthConfig.user2fa.update@={{M2MAUTHCONFIG_USER2FA_UPDATE}} -@m2mAuthConfig.user2fa.delete@={{M2MAUTHCONFIG_USER2FA_DELETE}} +@m2mAuthConfig.user2fa.enable@={{M2MAUTHCONFIG_USER2FA_ENABLE}} +@m2mAuthConfig.user2fa.verify@={{M2MAUTHCONFIG_USER2FA_VERIFY}} +@m2mAuthConfig.user2fa.credential@={{M2MAUTHCONFIG_USER2FA_CREDENTIAL}} From f6aa138ecec4c98f78202a7e927f2ad950fc4073 Mon Sep 17 00:00:00 2001 From: Emre Date: Wed, 3 Aug 2022 10:25:26 +0300 Subject: [PATCH 28/32] update dice endpoints --- buildtokenproperties.sh | 14 +- .../identity/resource/UserResource.java | 4 +- .../service/identity/util/auth/DICEAuth.java | 144 +----------------- src/main/resources/config.yml | 7 +- src/main/resources/config.yml.localdev | 7 +- token.properties.localdev | 7 +- token.properties.template | 7 +- 7 files changed, 15 insertions(+), 175 deletions(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 67d9e0c..38dcb0c 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -18,12 +18,7 @@ AUTH0_NEW_NONINTERACTIVE_ID_SECRET=$(eval "echo \$${ENV}_AUTH0_NEW_NONINTERACTIV DICEAUTH_DICE_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_URL") DICEAUTH_DICE_API_URL=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_URL") DICEAUTH_DICE_VERIFIER=$(eval "echo \$${ENV}_DICEAUTH_DICE_VERIFIER") -DICEAUTH_ID=$(eval "echo \$${ENV}_DICEAUTH_ID") -DICEAUTH_ID_SECRET=$(eval "echo \$${ENV}_DICEAUTH_ID_SECRET") -DICEAUTH_PASSWORD=$(eval "echo \$${ENV}_DICEAUTH_PASSWORD") -DICEAUTH_SCOPE=$(eval "echo \$${ENV}_DICEAUTH_SCOPE") -DICEAUTH_TENANT=$(eval "echo \$${ENV}_DICEAUTH_TENANT") -DICEAUTH_USERNAME=$(eval "echo \$${ENV}_DICEAUTH_USERNAME") +DICEAUTH_DICE_API_KEY=$(eval "echo \$${ENV}_DICEAUTH_DICE_API_KEY") DICEAUTH_CREDDEFID=$(eval "echo \$${ENV}_DICEAUTH_CREDDEFID") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") @@ -97,12 +92,7 @@ perl -pi -e "s/\{\{AUTH0_NEW_NONINTERACTIVE_ID_SECRET\}\}/$AUTH0_NEW_NONINTERACT perl -pi -e "s|\{\{DICEAUTH_DICE_URL\}\}|$DICEAUTH_DICE_URL|g" $CONFFILENAME perl -pi -e "s|\{\{DICEAUTH_DICE_API_URL\}\}|$DICEAUTH_DICE_API_URL|g" $CONFFILENAME perl -pi -e "s|\{\{DICEAUTH_DICE_VERIFIER\}\}|$DICEAUTH_DICE_VERIFIER|g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_ID\}\}/$DICEAUTH_ID/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_ID_SECRET\}\}/$DICEAUTH_ID_SECRET/g" $CONFFILENAME -perl -pi -e "s|\{\{DICEAUTH_PASSWORD\}\}|$DICEAUTH_PASSWORD|g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_SCOPE\}\}/$DICEAUTH_SCOPE/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_TENANT\}\}/$DICEAUTH_TENANT/g" $CONFFILENAME -perl -pi -e "s/\{\{DICEAUTH_USERNAME\}\}/$DICEAUTH_USERNAME/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/\{\{ZENDESK_KEY\}\}/$ZENDESK_KEY/g" $CONFFILENAME perl -pi -e "s/\{\{ZENDESK_ID\}\}/$ZENDESK_ID/g" $CONFFILENAME 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 76fce09..afc57bd 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 @@ -1549,7 +1549,7 @@ public ApiResponse updateUser2fa( try { response = new Request(diceAuth.getDiceApiUrl() + "/connection/invitation", "POST") .param("emailId", user2faInDb.getEmail()) - .header("Authorization", "Bearer " + diceAuth.getToken()) + .header("x-api-key", diceAuth.getDiceApiKey()) .execute(); } catch (Exception e) { logger.error("Error when calling 2fa submit api", e); @@ -1625,7 +1625,7 @@ public ApiResponse issueCredentials( Response response; try { response = new Request(diceAuth.getDiceApiUrl() + "/cred/issuance/offer", "POST") - .header("Authorization", "Bearer " + diceAuth.getToken()) + .header("x-api-key", diceAuth.getDiceApiKey()) .json(mapper.writeValueAsString(body)) .execute(); } catch (JsonProcessingException e) { 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 ee69ada..402c07d 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 @@ -1,23 +1,8 @@ package com.appirio.tech.core.service.identity.util.auth; -import java.net.HttpURLConnection; -import java.util.Date; - import javax.validation.constraints.NotNull; -import org.apache.log4j.Logger; - -import com.appirio.tech.core.api.v3.exception.APIRuntimeException; -import com.appirio.tech.core.api.v3.util.jwt.InvalidTokenException; -import com.appirio.tech.core.service.identity.util.HttpUtil.Request; -import com.appirio.tech.core.service.identity.util.HttpUtil.Response; -import com.auth0.jwt.JWT; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.fasterxml.jackson.databind.ObjectMapper; - public class DICEAuth { - private static final Logger logger = Logger.getLogger(Auth0Client.class); @NotNull private String diceUrl; @@ -29,44 +14,21 @@ public class DICEAuth { private String diceVerifier; @NotNull - private String tenant; - - @NotNull - private String username; - - @NotNull - private String password; - - @NotNull - private String scope; - - @NotNull - private String clientId; - - @NotNull - private String clientSecret; + private String diceApiKey; @NotNull private String credDefId; private String credPreview = "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/issue-credential/1.0/credential-preview"; - private String cachedToken; - public DICEAuth() { } - public DICEAuth(String diceUrl, String diceApiUrl, String diceVerifier, String tenant, String username, - String password, String scope, String clientId, String clientSecret, String credDefId) { + public DICEAuth(String diceUrl, String diceApiUrl, String diceVerifier, String diceApiKey, String credDefId) { this.diceUrl = diceUrl; this.diceApiUrl = diceApiUrl; this.diceVerifier = diceVerifier; - this.tenant = tenant; - this.username = username; - this.password = password; - this.scope = scope; - this.clientId = clientId; - this.clientSecret = clientSecret; + this.diceApiKey = diceApiKey; this.credDefId = credDefId; } @@ -94,52 +56,12 @@ public void setDiceVerifier(String diceVerifier) { this.diceVerifier = diceVerifier; } - public String getTenant() { - return tenant; - } - - public void setTenant(String tenant) { - this.tenant = tenant; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; + public String getDiceApiKey() { + return diceApiKey; } - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; + public void setDiceApiKey(String diceApiKey) { + this.diceApiKey = diceApiKey; } public String getCredDefId() { @@ -157,56 +79,4 @@ public String getCredPreview() { public void setCredPreview(String credPreview) { this.credPreview = credPreview; } - - public String getToken() throws Exception { - Boolean isCachedTokenExpired = false; - if (cachedToken != null) { - if (getTokenExpiryTime(cachedToken) <= 0) { - isCachedTokenExpired = true; - logger.info("Application cached token expired"); - } - } - if (cachedToken == null || isCachedTokenExpired) { - String url = "https://login.microsoftonline.com/" + getTenant() + "/oauth2/v2.0/token"; - Response response = new Request(url, "POST") - .param("grant_type", "password") - .param("username", getUsername()) - .param("password", getPassword()) - .param("scope", getScope()) - .param("client_id", getClientId()) - .param("client_secret", getClientSecret()).execute(); - if (response.getStatusCode() != HttpURLConnection.HTTP_OK) { - throw new APIRuntimeException(HttpURLConnection.HTTP_INTERNAL_ERROR, - String.format("Got unexpected response from remote service. %d %s", response.getStatusCode(), - response.getText())); - } - cachedToken = new ObjectMapper().readValue(response.getText(), Auth0Credential.class).getIdToken(); - logger.info("Fetched token from URL: " + url); - } - return cachedToken; - } - - /** - * Get token expiry time in seconds - * - * @param token JWT token - * throws Exception if any error occurs - * @return the Integer result - */ - private Integer getTokenExpiryTime(String token) throws Exception { - DecodedJWT decodedJWT = null; - Integer tokenExpiryTime = 0; - if (token != null) { - try { - decodedJWT = JWT.decode(token); - } catch (JWTDecodeException e) { - throw new InvalidTokenException(token, "Error occurred in decoding token. " + e.getLocalizedMessage(), - e); - } - Date tokenExpiryDate = decodedJWT.getExpiresAt(); - Long tokenExpiryTimeInMilliSeconds = tokenExpiryDate.getTime() - (new Date().getTime()) - 60 * 1000; - tokenExpiryTime = (int) Math.floor(tokenExpiryTimeInMilliSeconds / 1000); - } - return tokenExpiryTime; - } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index dfb31c7..15af415 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -97,12 +97,7 @@ diceAuth: diceUrl: @diceAuth.diceUrl@ diceApiUrl: @diceAuth.diceApiUrl@ diceVerifier: @diceAuth.diceVerifier@ - clientId: @diceAuth.clientId@ - clientSecret: @diceAuth.clientSecret@ - password: @diceAuth.password@ - scope: @diceAuth.scope@ - tenant: @diceAuth.tenant@ - username: @diceAuth.username@ + diceApiKey: @diceAuth.diceApiKey@ credDefId: @diceAuth.credDefId@ # Authorized accounts diff --git a/src/main/resources/config.yml.localdev b/src/main/resources/config.yml.localdev index e51ee8b..26cb2ab 100644 --- a/src/main/resources/config.yml.localdev +++ b/src/main/resources/config.yml.localdev @@ -89,12 +89,7 @@ diceAuth: diceUrl: dummy diceApiUrl: dummy diceVerifier: dummy - clientId: dummy - clientSecret: dummy - password: dummy - scope: dummy - tenant: dummy - username: dummy + diceApiKey: dummy credDefId: dummy # LDAP Settings diff --git a/token.properties.localdev b/token.properties.localdev index fd7a7f0..fcca202 100644 --- a/token.properties.localdev +++ b/token.properties.localdev @@ -34,12 +34,7 @@ @diceAuth.diceUrl@=dummy @diceAuth.diceApiUrl@=dummy @diceAuth.diceVerifier@=dummy -@diceAuth.clientId@=dummy -@diceAuth.clientSecret@=dummy -@diceAuth.password@=dummy -@diceAuth.scope@=dummy -@diceAuth.tenant@=dummy -@diceAuth.username@=dummy +@diceAuth.diceApiKey@=dummy @diceAuth.credDefId@=dummy @zendesk.secret@=ZENDESK_SECRET diff --git a/token.properties.template b/token.properties.template index 7f519e3..172a6ed 100644 --- a/token.properties.template +++ b/token.properties.template @@ -54,12 +54,7 @@ @diceAuth.diceUrl@={{DICEAUTH_DICE_URL}} @diceAuth.diceApiUrl@={{DICEAUTH_DICE_API_URL}} @diceAuth.diceVerifier@={{DICEAUTH_DICE_VERIFIER}} -@diceAuth.clientId@={{DICEAUTH_ID}} -@diceAuth.clientSecret@={{DICEAUTH_ID_SECRET}} -@diceAuth.password@={{DICEAUTH_PASSWORD}} -@diceAuth.scope@={{DICEAUTH_SCOPE}} -@diceAuth.tenant@={{DICEAUTH_TENANT}} -@diceAuth.username@={{DICEAUTH_USERNAME}} +@diceAuth.diceApiKey@={{DICEAUTH_DICE_API_KEY}} @diceAuth.credDefId@={{DICEAUTH_CREDDEFID}} @zendesk.secret@={{ZENDESK_KEY}} From ef519267bfb578aaabce82d9b4b2954042dfadb4 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Thu, 4 Aug 2022 19:34:07 +0300 Subject: [PATCH 29/32] update 2faVerification endpoint --- .../tech/core/service/identity/resource/UserResource.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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..ffa1035 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"); From dca8473a38079de997239098c0165c783ad90a3e Mon Sep 17 00:00:00 2001 From: eisbilir Date: Wed, 10 Aug 2022 16:26:18 +0300 Subject: [PATCH 30/32] make otp life configurable --- buildtokenproperties.sh | 2 ++ .../tech/core/service/identity/dao/UserDAO.java | 4 ++-- .../service/identity/resource/UserResource.java | 7 ++++--- .../core/service/identity/util/auth/DICEAuth.java | 15 ++++++++++++++- src/main/resources/config.yml | 1 + src/main/resources/config.yml.localdev | 1 + src/main/resources/sql/User_2fa_Create.sql | 2 +- token.properties.localdev | 1 + token.properties.template | 1 + 9 files changed, 27 insertions(+), 7 deletions(-) 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 ffa1035..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 @@ -1709,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"); } @@ -2196,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"); @@ -2205,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}} From 7dbe1c39aee816d76a54a779bf1e16e8cc7d6c67 Mon Sep 17 00:00:00 2001 From: eisbilir Date: Wed, 10 Aug 2022 16:54:16 +0300 Subject: [PATCH 31/32] fix token property --- buildtokenproperties.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildtokenproperties.sh b/buildtokenproperties.sh index 3347689..6fc7183 100755 --- a/buildtokenproperties.sh +++ b/buildtokenproperties.sh @@ -20,7 +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") +DICEAUTH_OTP_DURATION=$(eval "echo \$${ENV}_DICEAUTH_OTP_DURATION") ZENDESK_ID=$(eval "echo \$${ENV}_ZENDESK_ID") SERVICEACC02_UID=$(eval "echo \$${ENV}_SERVICEACC02_UID") AUTH_SECRET=$(eval "echo \$${ENV}_AUTH_SECRET") From a72750a6ab7041e6872dcb72b52b312724093a79 Mon Sep 17 00:00:00 2001 From: Emre Date: Thu, 11 Aug 2022 09:47:28 +0300 Subject: [PATCH 32/32] add log to roles endpoint --- .../tech/core/service/identity/resource/UserResource.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 e1b9429..ada5e94 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 @@ -817,7 +817,7 @@ public ApiResponse roles( @FormParam("email") String email, @FormParam("handle") String handle, @Context HttpServletRequest request) throws Exception { - + logger.info("auth0 roles request."); if(Utils.isEmpty(email) && Utils.isEmpty(handle)) throw new APIRuntimeException(SC_BAD_REQUEST, String.format(MSG_TEMPLATE_MANDATORY, "email/handle")); @@ -832,13 +832,13 @@ public ApiResponse roles( if(user==null) { throw new APIRuntimeException(SC_UNAUTHORIZED, "Credentials are incorrect."); } - + logger.info("auth0 roles: user found."); List roles = null; if (user.getId() != null) { roles = roleDao.getRolesBySubjectId(Long.parseLong(user.getId().getId())); } user.setRoles(roles); - + logger.info("auth0 roles: roles assigned"); // temp - just for testing user.setRegSource(userDao.generateSSOToken(Long.parseLong(user.getId().getId())));