From 3e3c4f404c1df526057632199c3a97c9ba04689a Mon Sep 17 00:00:00 2001 From: Lubos Racansky Date: Tue, 19 Sep 2023 09:23:18 +0200 Subject: [PATCH] Fix #777: Add column for fake OTP delivery --- .../1.5.x/20230919-add-otp-fake.xml | 19 ++++++++++ ...g-1.5.0.xml => 20230919-add-tag-1.5.0.xml} | 2 +- .../1.5.x/db.changelog-version.xml | 3 +- docs/onboarding/Database-Structure.md | 33 ++++++++-------- ...Auth-Enrollment-Onboarding-Server-1.5.0.md | 21 ++++++++++ docs/sql/oracle/onboarding/create-schema.sql | 1 + .../postgresql/onboarding/create-schema.sql | 1 + .../database/entity/OnboardingOtpEntity.java | 7 +++- .../impl/service/OnboardingServiceImpl.java | 3 +- .../impl/service/OtpServiceImpl.java | 38 +++++++++++++++++++ ...rviceTest.testTerminateExpiredOtpCodes.sql | 8 ++-- 11 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-otp-fake.xml rename docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/{20230824-add-tag-1.5.0.xml => 20230919-add-tag-1.5.0.xml} (88%) diff --git a/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-otp-fake.xml b/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-otp-fake.xml new file mode 100644 index 000000000..edc0bdf3d --- /dev/null +++ b/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-otp-fake.xml @@ -0,0 +1,19 @@ + + + + + + + + + + Add fake column + + + + + + + diff --git a/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230824-add-tag-1.5.0.xml b/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-tag-1.5.0.xml similarity index 88% rename from docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230824-add-tag-1.5.0.xml rename to docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-tag-1.5.0.xml index 02ccab024..c7c3a870d 100644 --- a/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230824-add-tag-1.5.0.xml +++ b/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/20230919-add-tag-1.5.0.xml @@ -3,7 +3,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd"> - + diff --git a/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/db.changelog-version.xml b/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/db.changelog-version.xml index 1a6797e7c..2cc5996bf 100644 --- a/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/db.changelog-version.xml +++ b/docs/db/changelog/changesets/enrollment-server-onboarding/1.5.x/db.changelog-version.xml @@ -6,6 +6,7 @@ - + + \ No newline at end of file diff --git a/docs/onboarding/Database-Structure.md b/docs/onboarding/Database-Structure.md index f5c6632ca..977fafe71 100644 --- a/docs/onboarding/Database-Structure.md +++ b/docs/onboarding/Database-Structure.md @@ -69,22 +69,23 @@ Stores onboarding OTP codes used during activation and user verification. #### Schema -| Name | Type | Info | Note | -|---|---|---|---| -| `id` | `VARCHAR(36)` | `NOT NULL PRIMARY KEY` | Autogenerated record identifier (UUID). | -| `process_id` | `VARCHAR(36)` | `NOT NULL` | Process identifier (UUID). | -| `otp_code` | `VARCHAR(32)` | `NOT NULL` | Generated OTP code. | -| `status` | `VARCHAR(36)` | | Generated OTP code. | -| `type` | `VARCHAR(32)` | `NOT NULL` | OTP code type (`ACTIVATION`, `USER_VERIFICATION`). | -| `error_detail` | `VARCHAR(256)` | | Detail of error (e.g. information about timeout or exceeded number of failed attempts). | -| `error_origin` | `VARCHAR(256)` | | Origin of the error (`DOCUMENT_VERIFICATION`, `PRESENCE_CHECK`, `CLIENT_EVALUATION`, `OTP_VERIFICATION`, `PROCESS_LIMIT_CHECK`, `USER_REQUEST`). | -| `failed_attempts` | `INTEGER` | | Number of failed attempts for verification. | -| `total_attempts` | `INTEGER` | | Number of total attempts for verification. | -| `timestamp_created` | `TIMESTAMP` | `NOT NULL DEFAULT CURRENT_TIMESTAMP` | Timestamp when process was started. | -| `timestamp_expiration` | `TIMESTAMP` | `NOT NULL` | Timestamp when the OTP expires. | -| `timestamp_last_updated` | `TIMESTAMP` | | Timestamp when record was last updated. | -| `timestamp_verified` | `TIMESTAMP` | | Timestamp when OTP was verified. | -| `timestamp_failed` | `TIMESTAMP` | | Timestamp when OTP failed. | +| Name | Type | Info | Note | +|--------------------------|----------------|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` | `VARCHAR(36)` | `NOT NULL PRIMARY KEY` | Autogenerated record identifier (UUID). | +| `process_id` | `VARCHAR(36)` | `NOT NULL` | Process identifier (UUID). | +| `otp_code` | `VARCHAR(32)` | `NOT NULL` | Generated OTP code. | +| `status` | `VARCHAR(36)` | | Generated OTP code. | +| `type` | `VARCHAR(32)` | `NOT NULL` | OTP code type (`ACTIVATION`, `USER_VERIFICATION`). | +| `error_detail` | `VARCHAR(256)` | | Detail of error (e.g. information about timeout or exceeded number of failed attempts). | +| `error_origin` | `VARCHAR(256)` | | Origin of the error (`DOCUMENT_VERIFICATION`, `PRESENCE_CHECK`, `CLIENT_EVALUATION`, `OTP_VERIFICATION`, `PROCESS_LIMIT_CHECK`, `USER_REQUEST`). | +| `failed_attempts` | `INTEGER` | | Number of failed attempts for verification. | +| `total_attempts` | `INTEGER` | | Number of total attempts for verification. | +| `fake` | `BOOLEAN` | `NOT NULL DEFAULT FALSE` | Whether is a fake entry not supposed to be sent. | +| `timestamp_created` | `TIMESTAMP` | `NOT NULL DEFAULT CURRENT_TIMESTAMP` | Timestamp when process was started. | +| `timestamp_expiration` | `TIMESTAMP` | `NOT NULL` | Timestamp when the OTP expires. | +| `timestamp_last_updated` | `TIMESTAMP` | | Timestamp when record was last updated. | +| `timestamp_verified` | `TIMESTAMP` | | Timestamp when OTP was verified. | +| `timestamp_failed` | `TIMESTAMP` | | Timestamp when OTP failed. | diff --git a/docs/onboarding/PowerAuth-Enrollment-Onboarding-Server-1.5.0.md b/docs/onboarding/PowerAuth-Enrollment-Onboarding-Server-1.5.0.md index e50ca51ab..d30c20fcf 100644 --- a/docs/onboarding/PowerAuth-Enrollment-Onboarding-Server-1.5.0.md +++ b/docs/onboarding/PowerAuth-Enrollment-Onboarding-Server-1.5.0.md @@ -128,6 +128,27 @@ CREATE INDEX PROCESS_ID ON ES_SCA_RESULT (PROCESS_ID); ``` +### OTP Fake Marker + +A new column `fake` has been added to the table `es_onboarding_otp`. + + +#### PostgreSQL + +```sql +ALTER TABLE es_onboarding_otp + ADD COLUMN fake BOOLEAN NOT NULL DEFAULT FALSE; +``` + + +#### Oracle + +```sql +ALTER TABLE es_onboarding_OTP + ADD fake NUMBER(1) NOT NULL DEFAULT 0; +``` + + ## Dependencies PostgreSQL JDBC driver is already included in the WAR file. diff --git a/docs/sql/oracle/onboarding/create-schema.sql b/docs/sql/oracle/onboarding/create-schema.sql index 53f6d4c27..7000e1498 100644 --- a/docs/sql/oracle/onboarding/create-schema.sql +++ b/docs/sql/oracle/onboarding/create-schema.sql @@ -52,6 +52,7 @@ CREATE TABLE ES_ONBOARDING_OTP ( ERROR_ORIGIN VARCHAR2(256 CHAR), FAILED_ATTEMPTS INTEGER, TOTAL_ATTEMPTS INTEGER DEFAULT 0, + FAKE NUMBER(1) NOT NULL DEFAULT 0, TIMESTAMP_CREATED TIMESTAMP(6) NOT NULL, TIMESTAMP_EXPIRATION TIMESTAMP(6) NOT NULL, TIMESTAMP_LAST_UPDATED TIMESTAMP(6), diff --git a/docs/sql/postgresql/onboarding/create-schema.sql b/docs/sql/postgresql/onboarding/create-schema.sql index 1defbb886..a91ebe7c2 100644 --- a/docs/sql/postgresql/onboarding/create-schema.sql +++ b/docs/sql/postgresql/onboarding/create-schema.sql @@ -56,6 +56,7 @@ CREATE TABLE es_onboarding_otp ( error_origin VARCHAR(256), failed_attempts INTEGER, total_attempts INTEGER DEFAULT 0, + fake BOOLEAN NOT NULL DEFAULT false, timestamp_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, timestamp_expiration TIMESTAMP NOT NULL, timestamp_last_updated TIMESTAMP, diff --git a/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/entity/OnboardingOtpEntity.java b/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/entity/OnboardingOtpEntity.java index 3b4c97830..5137e65b7 100644 --- a/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/entity/OnboardingOtpEntity.java +++ b/enrollment-server-onboarding-common/src/main/java/com/wultra/app/onboardingserver/common/database/entity/OnboardingOtpEntity.java @@ -26,7 +26,6 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; -import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.UuidGenerator; import java.io.Serial; @@ -96,6 +95,12 @@ public class OnboardingOtpEntity implements Serializable { @Column(name = "total_attempts") private int totalAttempts; + /** + * Whether is a fake entry not supposed to be sent. + */ + @Column(name = "fake") + private boolean fake; + @Column(name = "timestamp_created", nullable = false) private Date timestampCreated; diff --git a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OnboardingServiceImpl.java b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OnboardingServiceImpl.java index 3e6a89079..9f3639627 100644 --- a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OnboardingServiceImpl.java +++ b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OnboardingServiceImpl.java @@ -173,11 +173,12 @@ public OnboardingStartResponse startOnboarding( throw new TooManyProcessesException("Maximum number of processes per day reached for user: " + userId); } - final String otpCode = otpService.createOtpCode(process, OtpType.ACTIVATION); if (userId == null) { logger.debug("User ID is null, OTP is not sent"); + otpService.createFakeOtpCode(process, OtpType.ACTIVATION); } else { logger.debug("Sending OTP for user ID: {}", userId); + final String otpCode = otpService.createOtpCode(process, OtpType.ACTIVATION); sendOtp(process, otpCode); } diff --git a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OtpServiceImpl.java b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OtpServiceImpl.java index 8ba0e08eb..2a00aeddc 100644 --- a/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OtpServiceImpl.java +++ b/enrollment-server-onboarding/src/main/java/com/wultra/app/onboardingserver/impl/service/OtpServiceImpl.java @@ -95,6 +95,18 @@ public String createOtpCode(OnboardingProcessEntity process, OtpType otpType) th return generateOtpCode(process, otpType); } + /** + * Create a fake OTP code for onboarding process. + * + * @param process Onboarding process. + * @param otpType OTP type. + * @throws OnboardingProcessException Thrown in case OTP code could not be generated. + * @see #createOtpCode(OnboardingProcessEntity, OtpType) + */ + public void createFakeOtpCode(OnboardingProcessEntity process, OtpType otpType) throws OnboardingProcessException { + generateFakeOtpCode(process, otpType); + } + /** * Create an OTP code for onboarding process for resend. * @param process Onboarding process. @@ -155,6 +167,31 @@ public void cancelOtp(OnboardingProcessEntity process, OtpType otpType) { * @throws OnboardingProcessException Thrown in case OTP code could not be generated. */ private String generateOtpCode(OnboardingProcessEntity process, OtpType otpType) throws OnboardingProcessException { + return generateOtpCode(process, otpType, false); + } + + /** + * Generate a fake OTP code for an onboarding process. + * + * @param process Onboarding process. + * @param otpType OTP type. + * @return OTP code. + * @throws OnboardingProcessException Thrown in case OTP code could not be generated. + */ + private void generateFakeOtpCode(OnboardingProcessEntity process, OtpType otpType) throws OnboardingProcessException { + generateOtpCode(process, otpType, true); + } + + /** + * Generate an OTP code for an onboarding process. + * + * @param process Onboarding process. + * @param otpType OTP type. + * @param fake Whether OTP should be marked as a fake. + * @return OTP code. + * @throws OnboardingProcessException Thrown in case OTP code could not be generated. + */ + private String generateOtpCode(OnboardingProcessEntity process, OtpType otpType, boolean fake) throws OnboardingProcessException { int otpLength = onboardingConfig.getOtpLength(); String otpCode = otpGeneratorService.generateOtpCode(otpLength); @@ -173,6 +210,7 @@ private String generateOtpCode(OnboardingProcessEntity process, OtpType otpType) otp.setTimestampExpiration(timestampExpiration); otp.setFailedAttempts(0); otp.setTotalAttempts(0); + otp.setFake(fake); if (otpType == OtpType.USER_VERIFICATION) { final String activationId = process.getActivationId(); diff --git a/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/task/cleaning/CleaningServiceTest.testTerminateExpiredOtpCodes.sql b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/task/cleaning/CleaningServiceTest.testTerminateExpiredOtpCodes.sql index fa258467f..c1307d611 100644 --- a/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/task/cleaning/CleaningServiceTest.testTerminateExpiredOtpCodes.sql +++ b/enrollment-server-onboarding/src/test/resources/com/wultra/app/onboardingserver/task/cleaning/CleaningServiceTest.testTerminateExpiredOtpCodes.sql @@ -1,7 +1,7 @@ INSERT INTO es_onboarding_process(id, identification_data, status, error_score, custom_data, timestamp_created) VALUES ('b4662611-df91-4053-bb3d-3970979baf5d', '{}', 'VERIFICATION_IN_PROGRESS', 0, '{}', now()); -INSERT INTO es_onboarding_otp(id, process_id, otp_code, failed_attempts, total_attempts, status, type, timestamp_created, timestamp_expiration) VALUES - ('f50b8c04-649d-43a7-8079-4dbf9b0bbc72', 'b4662611-df91-4053-bb3d-3970979baf5d', '123', 0, 0, 'ACTIVE', 'USER_VERIFICATION', now(), now()), - ('6560a85d-7d97-44c0-bd29-04c57051aa57', 'b4662611-df91-4053-bb3d-3970979baf5d', '123', 0, 0, 'ACTIVE', 'USER_VERIFICATION', now() - interval '301' second, now()), -- to be failed - ('e4974ef6-135a-4ae1-be91-a2c0f674c8fd', 'b4662611-df91-4053-bb3d-3970979baf5d', '123', 0, 0, 'VERIFIED', 'USER_VERIFICATION', now() - interval '301' second, now()); +INSERT INTO es_onboarding_otp(id, process_id, otp_code, failed_attempts, total_attempts, status, type, fake, timestamp_created, timestamp_expiration) VALUES + ('f50b8c04-649d-43a7-8079-4dbf9b0bbc72', 'b4662611-df91-4053-bb3d-3970979baf5d', '123', 0, 0, 'ACTIVE', 'USER_VERIFICATION', false, now(), now()), + ('6560a85d-7d97-44c0-bd29-04c57051aa57', 'b4662611-df91-4053-bb3d-3970979baf5d', '123', 0, 0, 'ACTIVE', 'USER_VERIFICATION', false, now() - interval '301' second, now()), -- to be failed + ('e4974ef6-135a-4ae1-be91-a2c0f674c8fd', 'b4662611-df91-4053-bb3d-3970979baf5d', '123', 0, 0, 'VERIFIED', 'USER_VERIFICATION', false, now() - interval '301' second, now());