From 7a218bd3bb6a6c6bac6cfabce29855e7166860da Mon Sep 17 00:00:00 2001 From: John Date: Fri, 30 Apr 2021 13:35:09 -0400 Subject: [PATCH] PB-70375. Add support for IDV authentication --- .../java/com/silanis/esl/api/model/Auth.java | 78 +++++++---- .../silanis/esl/api/model/IdvWorkflow.java | 82 ++++++++++++ .../api/model/IdvWorkflowConfiguration.java | 97 ++++++++++++++ .../com/silanis/esl/sdk/Authentication.java | 15 ++- .../silanis/esl/sdk/AuthenticationMethod.java | 2 + .../java/com/silanis/esl/sdk/IdvWorkflow.java | 45 +++++++ .../silanis/esl/sdk/IdvWorkflowConfig.java | 54 ++++++++ .../esl/sdk/builder/IdvWorkflowBuilder.java | 49 +++++++ .../sdk/builder/IdvWorkflowConfigBuilder.java | 60 +++++++++ .../esl/sdk/builder/SignerBuilder.java | 122 +++++++++++++----- .../esl/sdk/examples/IdvAuthExample.java | 95 ++++++++++++++ .../silanis/esl/sdk/internal/UrlTemplate.java | 1 + .../converter/AuthenticationConverter.java | 24 ++-- .../converter/IdvWorkflowConfigConverter.java | 70 ++++++++++ .../converter/IdvWorkflowConverter.java | 68 ++++++++++ .../esl/sdk/service/AccountConfigService.java | 59 ++++++++- .../apiclient/AccountConfigClient.java | 58 +++++++++ .../silanis/esl/sdk/AuthenticationTest.java | 2 +- .../sdk/builder/IdvWorkflowBuilderTest.java | 32 +++++ .../esl/sdk/builder/SignerBuilderTest.java | 40 ++++-- .../converter/IdvWorkflowConverterTest.java | 120 +++++++++++++++++ .../esl/sdk/examples/IdvAuthExampleTest.java | 95 ++++++++++++++ 22 files changed, 1183 insertions(+), 85 deletions(-) create mode 100644 sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflow.java create mode 100644 sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflowConfiguration.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflow.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflowConfig.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilder.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowConfigBuilder.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/examples/IdvAuthExample.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConfigConverter.java create mode 100644 sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverter.java create mode 100644 sdk/src/test/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilderTest.java create mode 100644 sdk/src/test/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverterTest.java create mode 100644 tester/src/test/java/com/silanis/esl/sdk/examples/IdvAuthExampleTest.java diff --git a/sdk/src/main/java/com/silanis/esl/api/model/Auth.java b/sdk/src/main/java/com/silanis/esl/api/model/Auth.java index 2c61b6af5..b124cbbd3 100644 --- a/sdk/src/main/java/com/silanis/esl/api/model/Auth.java +++ b/sdk/src/main/java/com/silanis/esl/api/model/Auth.java @@ -1,76 +1,100 @@ package com.silanis.esl.api.model; // + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.silanis.esl.api.util.SchemaSanitizer; import java.util.ArrayList; import java.util.List; -@JsonIgnoreProperties(ignoreUnknown=true) + +@JsonIgnoreProperties(ignoreUnknown = true) public class Auth extends Model - implements java.io.Serializable -{ - + implements java.io.Serializable { + // Dirty Flag Constants @JsonIgnore public static final String FIELD_CHALLENGES = "challenges"; @JsonIgnore public static final String FIELD_SCHEME = "scheme"; - + @JsonIgnore + public static final String FIELD_IDV_WORKFLOW = "idvWorkflow"; + // Empty Constructor - public Auth ( ) {} - + public Auth() { + } + // Fields protected List _challenges = new ArrayList(); + protected IdvWorkflow _idvWorkflow; protected String _scheme = "NONE"; - + // Accessors - - - public Auth setChallenges( List value ){ - SchemaSanitizer.throwOnNull(FIELD_CHALLENGES,value); + + public IdvWorkflow getIdvWorkflow() { + return _idvWorkflow; + } + + public Auth setIdvWorkflow(IdvWorkflow value) { + this._idvWorkflow = value; + setDirty(FIELD_IDV_WORKFLOW); + return this; + } + + public Auth setChallenges(List value) { + SchemaSanitizer.throwOnNull(FIELD_CHALLENGES, value); // TODO With proper compare // if ( this._challenges == value ) return this; this._challenges = value; setDirty(FIELD_CHALLENGES); return this; } + // Used internally by aws. Invokes a the corresponding setter if the value is not null @JsonIgnore - public Auth safeSetChallenges( List value ){ - if ( value != null ) { this.setChallenges( value ); } + public Auth safeSetChallenges(List value) { + if (value != null) { + this.setChallenges(value); + } return this; } - public List getChallenges(){ + + public List getChallenges() { return _challenges; } + // List adder - public Auth addChallenge( AuthChallenge value ){ - if (value == null) { throw new IllegalArgumentException("Argument cannot be null"); } + public Auth addChallenge(AuthChallenge value) { + if (value == null) { + throw new IllegalArgumentException("Argument cannot be null"); + } this._challenges.add(value); setDirty(FIELD_CHALLENGES); return this; } - - - - public Auth setScheme( String value ){ - SchemaSanitizer.throwOnNull(FIELD_SCHEME,value); + + + public Auth setScheme(String value) { + SchemaSanitizer.throwOnNull(FIELD_SCHEME, value); // TODO With proper compare // if ( this._scheme == value ) return this; this._scheme = value; setDirty(FIELD_SCHEME); return this; } + // Used internally by aws. Invokes a the corresponding setter if the value is not null @JsonIgnore - public Auth safeSetScheme( String value ){ - if ( value != null ) { this.setScheme( value ); } + public Auth safeSetScheme(String value) { + if (value != null) { + this.setScheme(value); + } return this; } - public String getScheme(){ + + public String getScheme() { return _scheme; } - - + + } \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflow.java b/sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflow.java new file mode 100644 index 000000000..eb079e31d --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflow.java @@ -0,0 +1,82 @@ +package com.silanis.esl.api.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import static com.silanis.esl.api.util.SchemaSanitizer.throwOnNull; + +/** + * Created by schoi on 2021-03-10. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class IdvWorkflow extends Model implements java.io.Serializable { + + @JsonIgnore + public static final String FIELD_ID = "id"; + @JsonIgnore + public static final String FIELD_TYPE = "type"; + @JsonIgnore + public static final String FIELD_TENANT = "tenant"; + @JsonIgnore + public static final String FIELD_DESC = "desc"; + + // Empty Constructor + public IdvWorkflow() { + } + + // Fields + protected String id; + protected String type; + protected String tenant; + protected String desc; + + + public IdvWorkflow setId(String value) { + throwOnNull(FIELD_ID, value); + + this.id = value; + setDirty(FIELD_ID); + return this; + } + + public String getId() { + return id; + } + + + public IdvWorkflow setType(String value) { + throwOnNull(FIELD_TYPE, value); + + this.type = value; + setDirty(FIELD_TYPE); + return this; + } + + public String getType() { + return type; + } + + + public IdvWorkflow setTenant(String value) { + throwOnNull(FIELD_TENANT, value); + + this.tenant = value; + setDirty(FIELD_TENANT); + return this; + } + + public String getTenant() { + return tenant; + } + + + public IdvWorkflow setDesc(String value) { + this.desc = value; + setDirty(FIELD_DESC); + return this; + } + + public String getDesc() { + return desc; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflowConfiguration.java b/sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflowConfiguration.java new file mode 100644 index 000000000..8b5adf2e8 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/api/model/IdvWorkflowConfiguration.java @@ -0,0 +1,97 @@ +package com.silanis.esl.api.model; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +import static com.silanis.esl.api.util.SchemaSanitizer.throwOnNull; + +/** + * Created by schoi on 2021-05-06. + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class IdvWorkflowConfiguration extends Model implements java.io.Serializable { + + @JsonIgnore + public static final String FIELD_ID = "id"; + @JsonIgnore + public static final String FIELD_TYPE = "type"; + @JsonIgnore + public static final String FIELD_TENANT = "tenant"; + @JsonIgnore + public static final String FIELD_DESC = "desc"; + @JsonIgnore + public static final String FIELD_SKIP_WHEN_ACCESSING_SIGNED_DOCUMENTS = "skipWhenAccessingSignedDocuments"; + + @JsonProperty("id") + protected String workflowId; + @JsonProperty("type") + protected String type; + @JsonProperty("tenant") + protected String tenant; + @JsonProperty("desc") + protected String desc; + @JsonProperty("skipWhenAccessingSignedDocuments") + protected boolean skipWhenAccessingSignedDocuments; + + public IdvWorkflowConfiguration setWorkflowId(String value) { + throwOnNull(FIELD_ID, value); + + this.workflowId = value; + setDirty(FIELD_ID); + return this; + } + + public String getWorkflowId() { + return workflowId; + } + + + public IdvWorkflowConfiguration setType(String value) { + throwOnNull(FIELD_TYPE, value); + + this.type = value; + setDirty(FIELD_TYPE); + return this; + } + + public String getType() { + return type; + } + + + public IdvWorkflowConfiguration setTenant(String value) { + throwOnNull(FIELD_TENANT, value); + + this.tenant = value; + setDirty(FIELD_TENANT); + return this; + } + + public String getTenant() { + return tenant; + } + + + public IdvWorkflowConfiguration setDesc(String value) { + this.desc = value; + setDirty(FIELD_DESC); + return this; + } + + public String getDesc() { + return desc; + } + + + public IdvWorkflowConfiguration setSkipWhenAccessingSignedDocuments(boolean value) { + this.skipWhenAccessingSignedDocuments = value; + setDirty(FIELD_SKIP_WHEN_ACCESSING_SIGNED_DOCUMENTS); + return this; + } + + public boolean isSkipWhenAccessingSignedDocuments() { + return skipWhenAccessingSignedDocuments; + } + +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/Authentication.java b/sdk/src/main/java/com/silanis/esl/sdk/Authentication.java index 9d8267852..5b5c3ebc6 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/Authentication.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/Authentication.java @@ -8,6 +8,7 @@ public class Authentication { private final AuthenticationMethod method; private List challenges = new ArrayList(); private String phoneNumber; + private IdvWorkflow idvWorkflow; public Authentication(AuthenticationMethod method) { this.method = method; @@ -18,11 +19,17 @@ public Authentication(List challenges) { this.challenges.addAll(challenges); } - public Authentication(String phoneNumber) { - this(AuthenticationMethod.SMS); + public Authentication(AuthenticationMethod method, String phoneNumber) { + this(method); this.phoneNumber = phoneNumber; } + public Authentication(AuthenticationMethod method, String phoneNumber, IdvWorkflow idvWorkflow) { + this(method); + this.phoneNumber = phoneNumber; + this.idvWorkflow = idvWorkflow; + } + public AuthenticationMethod getMethod() { return method; } @@ -34,4 +41,8 @@ public List getChallenges() { public String getPhoneNumber() { return phoneNumber; } + + public IdvWorkflow getIdvWorkflow() { + return idvWorkflow; + } } \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/AuthenticationMethod.java b/sdk/src/main/java/com/silanis/esl/sdk/AuthenticationMethod.java index 85fb2b42b..8f9a13be5 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/AuthenticationMethod.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/AuthenticationMethod.java @@ -12,6 +12,7 @@ public class AuthenticationMethod extends EslEnumeration { public static final AuthenticationMethod SMS = new AuthenticationMethod("SMS", "SMS", 2); public static final AuthenticationMethod KBA = new AuthenticationMethod("KBA", "KBA", 3); public static final AuthenticationMethod SSO = new AuthenticationMethod("SSO", "SSO", 4); + public static final AuthenticationMethod IDV = new AuthenticationMethod("ID_VERIFICATION", "IDV", 5); /** * DO NOT USE! This is an internal implementation concern. It is there to avoid crashes in existing code when new values are added to the enumerations @@ -32,6 +33,7 @@ public static final AuthenticationMethod UNRECOGNIZED(String unknownValue){ sdkValues.put(SMS.name(), SMS); sdkValues.put(KBA.name(), KBA); sdkValues.put(SSO.name(), SSO); + sdkValues.put(IDV.name(), IDV); } private AuthenticationMethod(String apiValue, String sdkValue, int index) { diff --git a/sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflow.java b/sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflow.java new file mode 100644 index 000000000..20e3e8c16 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflow.java @@ -0,0 +1,45 @@ +package com.silanis.esl.sdk; + +/** + * Created by schoi on 2021-03-10. + */ +public class IdvWorkflow { + + private String id; + private String type; + private String tenant; + private String desc; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflowConfig.java b/sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflowConfig.java new file mode 100644 index 000000000..d43b57b35 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/IdvWorkflowConfig.java @@ -0,0 +1,54 @@ +package com.silanis.esl.sdk; + +import java.io.Serializable; + +/** + * Created by schoi on 2021-05-06. + */ +public class IdvWorkflowConfig implements Serializable { + private String id; + private String type; + private String tenant; + private String desc; + private boolean skipWhenAccessingSignedDocuments; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getTenant() { + return tenant; + } + + public void setTenant(String tenant) { + this.tenant = tenant; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public boolean isSkipWhenAccessingSignedDocuments() { + return skipWhenAccessingSignedDocuments; + } + + public void setSkipWhenAccessingSignedDocuments(boolean skipWhenAccessingSignedDocuments) { + this.skipWhenAccessingSignedDocuments = skipWhenAccessingSignedDocuments; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilder.java b/sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilder.java new file mode 100644 index 000000000..3dce6db55 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilder.java @@ -0,0 +1,49 @@ +package com.silanis.esl.sdk.builder; + +import com.silanis.esl.sdk.IdvWorkflow; + +/** + * Created by schoi on 2021-03-10. + */ +public class IdvWorkflowBuilder { + + private String id; + private String type; + private String tenant; + private String desc; + + private IdvWorkflowBuilder(String id) { + this.id = id; + } + + public static IdvWorkflowBuilder newIdvWorkflow(String id) { + if (id == null) { + throw new BuilderException("IdvWorkflow id cannot be null."); + } + return new IdvWorkflowBuilder(id); + } + + public IdvWorkflowBuilder withType(String type) { + this.type = type; + return this; + } + + public IdvWorkflowBuilder withTenant(String tenant) { + this.tenant = tenant; + return this; + } + + public IdvWorkflowBuilder withDesc(String desc) { + this.desc = desc; + return this; + } + + public IdvWorkflow build() { + IdvWorkflow idvWorkflow = new IdvWorkflow(); + idvWorkflow.setId(id); + idvWorkflow.setType(type); + idvWorkflow.setTenant(tenant); + idvWorkflow.setDesc(desc); + return idvWorkflow; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowConfigBuilder.java b/sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowConfigBuilder.java new file mode 100644 index 000000000..0d5ad26ed --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/builder/IdvWorkflowConfigBuilder.java @@ -0,0 +1,60 @@ +package com.silanis.esl.sdk.builder; + +import com.silanis.esl.sdk.IdvWorkflowConfig; + +/** + * Created by schoi on 2021-05-06. + */ +public class IdvWorkflowConfigBuilder { + private String id; + private String type; + private String tenant; + private String desc; + private boolean skipWhenAccessingSignedDocuments; + + private IdvWorkflowConfigBuilder(String id) { + this.id = id; + } + + public static IdvWorkflowConfigBuilder newIdvWorkflowConfig(String id) { + if (id == null) { + throw new BuilderException("IdvWorkflowConfig id cannot be null."); + } + return new IdvWorkflowConfigBuilder(id); + } + + public IdvWorkflowConfigBuilder withType(String type) { + this.type = type; + return this; + } + + public IdvWorkflowConfigBuilder withTenant(String tenant) { + this.tenant = tenant; + return this; + } + + public IdvWorkflowConfigBuilder withDesc(String desc) { + this.desc = desc; + return this; + } + + public IdvWorkflowConfigBuilder enableSkipWhenAccessingSignedDocuments() { + this.skipWhenAccessingSignedDocuments = true; + return this; + } + + public IdvWorkflowConfigBuilder disableSkipWhenAccessingSignedDocuments() { + this.skipWhenAccessingSignedDocuments = false; + return this; + } + + public IdvWorkflowConfig build() { + IdvWorkflowConfig idvWorkflowConfig = new IdvWorkflowConfig(); + idvWorkflowConfig.setId(id); + idvWorkflowConfig.setType(type); + idvWorkflowConfig.setTenant(tenant); + idvWorkflowConfig.setDesc(desc); + idvWorkflowConfig.setSkipWhenAccessingSignedDocuments(skipWhenAccessingSignedDocuments); + return idvWorkflowConfig; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/builder/SignerBuilder.java b/sdk/src/main/java/com/silanis/esl/sdk/builder/SignerBuilder.java index 4cf4ec745..901e0fd63 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/builder/SignerBuilder.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/builder/SignerBuilder.java @@ -6,6 +6,7 @@ import com.silanis.esl.sdk.Challenge; import com.silanis.esl.sdk.EslException; import com.silanis.esl.sdk.GroupId; +import com.silanis.esl.sdk.IdvWorkflow; import com.silanis.esl.sdk.KnowledgeBasedAuthentication; import com.silanis.esl.sdk.Placeholder; import com.silanis.esl.sdk.Signer; @@ -17,7 +18,7 @@ import java.util.List; import java.util.Locale; -import static com.silanis.esl.sdk.AuthenticationMethod.SSO; +import static com.silanis.esl.sdk.AuthenticationMethod.*; import static com.silanis.esl.sdk.builder.SignerBuilder.AuthenticationBuilder.newAuthenticationWithMethod; /** @@ -75,7 +76,7 @@ private SignerBuilder(GroupId groupId) { * * @param placeholder the placeholder. */ - private SignerBuilder(Placeholder placeholder){ + private SignerBuilder(Placeholder placeholder) { this.email = null; this.groupId = null; this.id = placeholder.getId(); @@ -117,6 +118,7 @@ public static SignerBuilder newSignerPlaceholder(Placeholder placeholder) { * Sets the ID of the signer for this package. *

* E.g.: the signer's email makes for a good unique ID. john@do.com + * * @param id the signer's ID @size(min="1", max="64") * @return the signer builder itself */ @@ -127,10 +129,11 @@ public SignerBuilder withCustomId(String id) { /** * Sets the signer's ID to the placeholder's ID. + * * @param placeholder * @return */ - public SignerBuilder replacing(Placeholder placeholder){ + public SignerBuilder replacing(Placeholder placeholder) { this.id = placeholder.getId(); return this; } @@ -164,15 +167,15 @@ public SignerBuilder withLastName(String lastName) { *

* E.g.: a signer with a signingOrder of 1 would be required to sign before a signer with a signingOrder of 2, for example. * - * @param signingOrder a value greater than zero - * @return the signer builder itself + * @param signingOrder a value greater than zero + * @return the signer builder itself */ public SignerBuilder signingOrder(int signingOrder) { this.signingOrder = signingOrder; return this; } - private Signer buildGroupSigner(){ + private Signer buildGroupSigner() { Signer result = new Signer(groupId); result.setSigningOrder(signingOrder); @@ -184,11 +187,11 @@ private Signer buildGroupSigner(){ return result; } - private Signer buildPlaceholderSigner(){ + private Signer buildPlaceholderSigner() { Signer result = new Signer(id); result.setPlaceholderName(placeholderName); - Asserts.notNullOrEmpty(id, "No placeholder set for this signer!" ); + Asserts.notNullOrEmpty(id, "No placeholder set for this signer!"); result.setSigningOrder(signingOrder); result.setCanChangeSigner(canChangeSigner); result.setMessage(message); @@ -197,7 +200,7 @@ private Signer buildPlaceholderSigner(){ return result; } - private Signer buildRegularSigner(){ + private Signer buildRegularSigner() { if (authentication == null) { authentication = authenticationBuilder.build(); } @@ -232,11 +235,9 @@ public Signer build() { Signer signer; if (isGroupSigner()) { signer = buildGroupSigner(); - } - else if (isPlaceholder()){ + } else if (isPlaceholder()) { signer = buildPlaceholderSigner(); - } - else{ + } else { signer = buildRegularSigner(); } return signer; @@ -250,9 +251,9 @@ else if (isPlaceholder()){ * The signer will be asked to authenticate, before accessing his signing * ceremony, by providing answers to authentication questions. * - * @see ChallengeBuilder * @param challengeBuilder the challenge builder * @return the signer builder object itself + * @see ChallengeBuilder */ public SignerBuilder challengedWithQuestions(ChallengeBuilder challengeBuilder) { this.authenticationBuilder = challengeBuilder; @@ -287,6 +288,33 @@ public SignerBuilder withSSOAuthentication() { return this; } + /** + *

+ * Sets the signer's authentication type to SAA. + *

+ * + * @param idvWorkflow + * @return the signer builder object itself + */ + public SignerBuilder withIDVAuthentication(IdvWorkflow idvWorkflow) { + this.authenticationBuilder = new IDVAuthenticationBuilder(idvWorkflow); + return this; + } + + /** + *

+ * Sets the signer's authentication type to SAA. + *

+ * + * @param phoneNumber + * @param idvWorkflow + * @return the signer builder object itself + */ + public SignerBuilder withIDVAuthentication(String phoneNumber, IdvWorkflow idvWorkflow) { + this.authenticationBuilder = new IDVAuthenticationBuilder(phoneNumber, idvWorkflow); + return this; + } + /** * Sets the Signer's authentication. The authentication types are email, * questions and answers (challenges) or SMS. @@ -304,7 +332,7 @@ public SignerBuilder withAuthentication(Authentication authentication) { * E.g.: Mr., Mrs., Ms., etc... * * @param title the signer's title @size(min="0", max="64") - * @return the signer builder object itself + * @return the signer builder object itself */ public SignerBuilder withTitle(String title) { Asserts.genericAssert(!isGroupSigner(), "title can not be set for a group signer"); @@ -316,7 +344,7 @@ public SignerBuilder withTitle(String title) { *

Sets the signer's company name.

* * @param company the signer's company name @size(max="255") - * @return the signer builder object itself + * @return the signer builder object itself * @throws EslException throws an exception if signer is a group signer. */ public SignerBuilder withCompany(String company) { @@ -329,7 +357,7 @@ public SignerBuilder withCompany(String company) { *

Sets the signer's language.

* * @param language the signer's language - * @return the signer builder object itself + * @return the signer builder object itself * @throws EslException throws an exception if signer is a group signer. */ public SignerBuilder withLanguage(Locale language) { @@ -341,6 +369,7 @@ public SignerBuilder withLanguage(Locale language) { /** * The signer can assign someone else to sign the package. *

Sets the canChangeSigner property to true.

+ * * @return the signer builder object itself */ public SignerBuilder canChangeSigner() { @@ -362,7 +391,8 @@ public SignerBuilder withEmailMessage(String message) { /** *

Invoking this method results in documents being distributed back to the sender as an email attachments once the package is complete.

- * @return the signer builder object itself + * + * @return the signer builder object itself */ public SignerBuilder deliverSignedDocumentsByEmail() { deliverSignedDocumentsByEmail = true; @@ -388,9 +418,9 @@ public SignerBuilder withLocalLanguage() { *

Adds an attachment requirement for the signer. The attachment requirement is conveniently customized by the * builder provided as parameter.

* - * @see AttachmentRequirementBuilder * @param builder the attachment requirement builder * @return the signer builder object itself + * @see AttachmentRequirementBuilder */ public SignerBuilder withAttachmentRequirement(AttachmentRequirementBuilder builder) { return withAttachmentRequirement(builder.build()); @@ -445,7 +475,7 @@ public SignerBuilder challengedWithKnowledgeBasedAuthentication(SignerInformatio * @return the signer builder itself */ public SignerBuilder challengedWithKnowledgeBasedAuthentication(SignerInformationForEquifaxCanada signerInformationForEquifaxCanada) { - if(this.knowledgeBasedAuthentication == null) { + if (this.knowledgeBasedAuthentication == null) { this.knowledgeBasedAuthentication = new KnowledgeBasedAuthentication(); } this.knowledgeBasedAuthentication.setSignerInformationForEquifaxCanada(signerInformationForEquifaxCanada); @@ -469,7 +499,7 @@ public SignerBuilder challengedWithKnowledgeBasedAuthentication(SignerInformatio * @return the signer builder itself */ public SignerBuilder challengedWithKnowledgeBasedAuthentication(SignerInformationForEquifaxUSA signerInformationForEquifaxUSA) { - if(this.knowledgeBasedAuthentication == null) { + if (this.knowledgeBasedAuthentication == null) { this.knowledgeBasedAuthentication = new KnowledgeBasedAuthentication(); } this.knowledgeBasedAuthentication.setSignerInformationForEquifaxUSA(signerInformationForEquifaxUSA); @@ -479,6 +509,7 @@ public SignerBuilder challengedWithKnowledgeBasedAuthentication(SignerInformatio /** * Authentication builder is a convenient class used to create an Authentication object * with email defined as the authentication method. + * * @author admin */ public static class AuthenticationBuilder { @@ -505,7 +536,6 @@ public Authentication build() { * Challenge builder is a convenient class used to create an Authentication * object. It is used to help define the authentication questions and * answers when the user logs on to eSignLive. - * */ public static class ChallengeBuilder extends AuthenticationBuilder { @@ -514,6 +544,7 @@ public static class ChallengeBuilder extends AuthenticationBuilder { /** * Challenge builder constructor. + * * @param question the question @size(min="1", max="255") */ public ChallengeBuilder(String question) { @@ -522,6 +553,7 @@ public ChallengeBuilder(String question) { /** * First question asked to the user when they log on to eSignLive. + * * @param question the first question @size(min="1", max="255") * @return This */ @@ -531,6 +563,7 @@ public static ChallengeBuilder firstQuestion(String question) { /** * Second question asked to the user when they log on to eSignLive. + * * @param question the second question @size(min="1", max="255") * @return This */ @@ -547,10 +580,10 @@ public ChallengeBuilder secondQuestion(String question) { *

* It should not be invoked more than twice. * - * @see #firstQuestion(String) - * @see #secondQuestion(String) * @param answer answer to the authentication questions @size(min="1", max="255") * @return This + * @see #firstQuestion(String) + * @see #secondQuestion(String) */ public ChallengeBuilder answer(String answer) { challenges.add(new Challenge(question, answer)); @@ -565,11 +598,11 @@ public ChallengeBuilder answer(String answer) { *

* It should not be invoked more than twice. * - * @see #firstQuestion(String) - * @see #secondQuestion(String) - * @param answer answer to the authentication questions @size(min="1", max="255") + * @param answer answer to the authentication questions @size(min="1", max="255") * @param maskOption enable/disable masking of challenge * @return This + * @see #firstQuestion(String) + * @see #secondQuestion(String) */ @Deprecated public ChallengeBuilder answer(String answer, Challenge.MaskOptions maskOption) { @@ -585,10 +618,10 @@ public ChallengeBuilder answer(String answer, Challenge.MaskOptions maskOption) *

* It should not be invoked more than twice. * - * @see #firstQuestion(String) - * @see #secondQuestion(String) * @param answer answer to the authentication questions @size(min="1", max="255") * @return This + * @see #firstQuestion(String) + * @see #secondQuestion(String) */ public ChallengeBuilder answerWithMaskInput(String answer) { challenges.add(new Challenge(question, answer, Challenge.MaskOptions.MaskInput)); @@ -627,7 +660,34 @@ public SMSAuthenticationBuilder(String phoneNumber) { @Override public Authentication build() { Asserts.notNullOrEmpty(phoneNumber, "phone number"); - return new Authentication(phoneNumber); + return new Authentication(SMS, phoneNumber); + } + } + + public static class IDVAuthenticationBuilder extends AuthenticationBuilder { + + private String phoneNumber; + private final IdvWorkflow idvWorkflow; + + /** + * Builder used to define authentication with eSignLive by entering an + * SMS PIN number sent at the phone number defined below when the user + * attempts to log in. + * + * @param idvWorkflow + */ + public IDVAuthenticationBuilder(IdvWorkflow idvWorkflow) { + this.idvWorkflow = idvWorkflow; + } + + public IDVAuthenticationBuilder(String phoneNumber, IdvWorkflow idvWorkflow) { + this.phoneNumber = phoneNumber; + this.idvWorkflow = idvWorkflow; + } + + @Override + public Authentication build() { + return new Authentication(IDV, phoneNumber, idvWorkflow); } } @@ -635,7 +695,7 @@ private boolean isGroupSigner() { return groupId != null; } - private boolean isPlaceholder(){ + private boolean isPlaceholder() { return groupId == null && email == null; } } \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/examples/IdvAuthExample.java b/sdk/src/main/java/com/silanis/esl/sdk/examples/IdvAuthExample.java new file mode 100644 index 000000000..b23de5ab3 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/examples/IdvAuthExample.java @@ -0,0 +1,95 @@ +package com.silanis.esl.sdk.examples; + +import com.silanis.esl.sdk.DocumentPackage; +import com.silanis.esl.sdk.DocumentType; +import com.silanis.esl.sdk.IdvWorkflowConfig; +import com.silanis.esl.sdk.service.AccountConfigService; + +import java.util.List; + +import static com.silanis.esl.sdk.builder.DocumentBuilder.newDocumentWithName; +import static com.silanis.esl.sdk.builder.IdvWorkflowBuilder.newIdvWorkflow; +import static com.silanis.esl.sdk.builder.IdvWorkflowConfigBuilder.newIdvWorkflowConfig; +import static com.silanis.esl.sdk.builder.PackageBuilder.newPackageNamed; +import static com.silanis.esl.sdk.builder.SignatureBuilder.signatureFor; +import static com.silanis.esl.sdk.builder.SignerBuilder.newSignerWithEmail; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; + +/** + * Created by schoi on 2020-10-01. + */ +public class IdvAuthExample extends SDKSample { + + public static final String PHONE_NUMBER = "+15555555555"; + public static final String IDV_WORKFLOW_ID1 = "00000000-0000-0001-0000-200000000055"; + public static final String TYPE1 = "DV"; + public static final String TENANT = "oss"; + public static final String DESC1 = "This is Mitek Document verification only Mock workflow."; + + public static final String IDV_WORKFLOW_ID2 = "00000000-0001-0001-0000-200000000055"; + public static final String TYPE2 = "DVF"; + public static final String DESC2 = "This is Mitek Document Verification with Facial Comparison Mock workflow."; + + public List idvWorkflowConfigsBeforeCreating, idvWorkflowConfigsAfterCreating, + idvWorkflowConfigsAfterUpdating, idvWorkflowConfigsAfterDeleting; + + public static void main(String... args) { + new IdvAuthExample().run(); + } + + public void execute() { + AccountConfigService accountConfigService = eslClient.getAccountConfigService(); + idvWorkflowConfigsBeforeCreating = accountConfigService.getIdvWorkflowConfigs(); + + if (!idvWorkflowConfigsBeforeCreating.isEmpty()) { + accountConfigService.deleteIdvWorkflowConfigs(); + idvWorkflowConfigsBeforeCreating = accountConfigService.getIdvWorkflowConfigs(); + } + + idvWorkflowConfigsAfterCreating = accountConfigService + .createIdvWorkflowConfigs(singletonList(newIdvWorkflowConfig(IDV_WORKFLOW_ID1) + .withType(TYPE1) + .withTenant(TENANT) + .withDesc(DESC1) + .enableSkipWhenAccessingSignedDocuments() + .build())); + + idvWorkflowConfigsAfterUpdating = accountConfigService + .updateIdvWorkflowConfigs(asList(newIdvWorkflowConfig(IDV_WORKFLOW_ID1) + .withType(TYPE1) + .withTenant(TENANT) + .withDesc(DESC1) + .enableSkipWhenAccessingSignedDocuments() + .build(), newIdvWorkflowConfig(IDV_WORKFLOW_ID2) + .withType(TYPE2) + .withTenant(TENANT) + .withDesc(DESC2) + .enableSkipWhenAccessingSignedDocuments() + .build())); + + DocumentPackage superDuperPackage = newPackageNamed(getPackageName()) + .describedAs("This is a Signer IDV authentication example") + .withSigner(newSignerWithEmail(email1) + .withFirstName("Jamie Anne") + .withLastName("Kurtz") + .withIDVAuthentication(PHONE_NUMBER, + newIdvWorkflow(IDV_WORKFLOW_ID1) + .withType(TYPE1) + .withTenant(TENANT) + .build())) + .withDocument(newDocumentWithName("First Document") + .fromStream(documentInputStream1, DocumentType.PDF) + .withSignature(signatureFor(email1) + .onPage(0) + .atPosition(100, 100))) + .build(); + + packageId = eslClient.createPackage(superDuperPackage); + eslClient.sendPackage(packageId); + retrievedPackage = eslClient.getPackage(packageId); + + accountConfigService.deleteIdvWorkflowConfigs(); + idvWorkflowConfigsAfterDeleting = accountConfigService.getIdvWorkflowConfigs(); + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/internal/UrlTemplate.java b/sdk/src/main/java/com/silanis/esl/sdk/internal/UrlTemplate.java index 92d5a2e0c..3a2e23803 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/internal/UrlTemplate.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/internal/UrlTemplate.java @@ -182,6 +182,7 @@ public class UrlTemplate { public static final String ACCOUNT_CONFIG_PATH = "/accountConfig"; public static final String HANDOVER_URL_PATH = "/accountConfig/handoverUrl/{language}"; public static final String DECLINE_REASONS_URL_PATH = "/accountConfig/declineReasons/{language}"; + public static final String IDV_WORKFLOW_CONFIGS_PATH = "/accountConfig/idvWorkflowConfigs"; // Account SubAccount Service public static final String ACCOUNT_SUBACCOUNTS_PATH="/account/subaccounts"; diff --git a/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/AuthenticationConverter.java b/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/AuthenticationConverter.java index 65593737c..3bffbe7ac 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/AuthenticationConverter.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/AuthenticationConverter.java @@ -1,6 +1,8 @@ package com.silanis.esl.sdk.internal.converter; import com.silanis.esl.api.model.AuthChallenge; +import com.silanis.esl.sdk.Authentication; +import com.silanis.esl.sdk.AuthenticationMethod; import com.silanis.esl.sdk.Challenge; import com.silanis.esl.sdk.builder.SignerBuilder; @@ -11,14 +13,14 @@ * User: jessica * Date: 21/11/13 * Time: 4:39 PM - * + *

* Converter for SDK Authentication and API Authentication. - * */ public class AuthenticationConverter { com.silanis.esl.api.model.Auth apiAuth; - com.silanis.esl.sdk.Authentication sdkAuth; + Authentication sdkAuth; + /** * Construct with API authentication. * @@ -33,7 +35,7 @@ public AuthenticationConverter(com.silanis.esl.api.model.Auth apiAuth) { * * @param sdkAuth */ - public AuthenticationConverter(com.silanis.esl.sdk.Authentication sdkAuth) { + public AuthenticationConverter(Authentication sdkAuth) { this.sdkAuth = sdkAuth; } @@ -57,6 +59,10 @@ public com.silanis.esl.api.model.Auth toAPIAuthentication() { auth.addChallenge(new AuthChallenge().setQuestion(sdkAuth.getPhoneNumber())); } + if (sdkAuth.getIdvWorkflow() != null) { + auth.setIdvWorkflow(new IdvWorkflowConverter(sdkAuth.getIdvWorkflow()).toAPIIdvWorkflow()); + } + return auth; } @@ -65,7 +71,7 @@ public com.silanis.esl.api.model.Auth toAPIAuthentication() { * * @return API auth */ - public com.silanis.esl.sdk.Authentication toSDKAuthentication() { + public Authentication toSDKAuthentication() { if (apiAuth == null) { return sdkAuth; } @@ -79,7 +85,7 @@ public com.silanis.esl.sdk.Authentication toSDKAuthentication() { if (!apiAuth.getChallenges().isEmpty()) { List sdkChallenges = new ArrayList(); - for (AuthChallenge apiChallenge: apiAuth.getChallenges()) { + for (AuthChallenge apiChallenge : apiAuth.getChallenges()) { if ("CHALLENGE".equals(apiAuth.getScheme())) { sdkChallenges.add(new ChallengeConverter(apiChallenge).toSDKChallenge()); } else { @@ -89,9 +95,11 @@ public com.silanis.esl.sdk.Authentication toSDKAuthentication() { } if ("CHALLENGE".equals(apiAuth.getScheme())) { - sdkAuth = new com.silanis.esl.sdk.Authentication(sdkChallenges); + sdkAuth = new Authentication(sdkChallenges); } else if ("SMS".equals(apiAuth.getScheme())) { - sdkAuth = new com.silanis.esl.sdk.Authentication(telephoneNumber); + sdkAuth = new Authentication(AuthenticationMethod.SMS, telephoneNumber); + } else if ("ID_VERIFICATION".equals(apiAuth.getScheme())) { + sdkAuth = new Authentication(AuthenticationMethod.IDV, telephoneNumber, new IdvWorkflowConverter(apiAuth.getIdvWorkflow()).toSDKIdvWorkflow()); } } diff --git a/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConfigConverter.java b/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConfigConverter.java new file mode 100644 index 000000000..e8f679c03 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConfigConverter.java @@ -0,0 +1,70 @@ +package com.silanis.esl.sdk.internal.converter; + +import com.silanis.esl.api.model.IdvWorkflowConfiguration; +import com.silanis.esl.sdk.IdvWorkflowConfig; +import com.silanis.esl.sdk.builder.IdvWorkflowConfigBuilder; + +/** + * Created by schoi on 2021-05-06. + */ +public class IdvWorkflowConfigConverter { + + private IdvWorkflowConfiguration apiIdvWorkflowConfiguration; + private IdvWorkflowConfig sdkIdvWorkflowConfig; + + + /** + * Construct with API object involved in conversion. + * + * @param apiIdvWorkflowConfiguration + */ + public IdvWorkflowConfigConverter(IdvWorkflowConfiguration apiIdvWorkflowConfiguration) { + this.apiIdvWorkflowConfiguration = apiIdvWorkflowConfiguration; + } + + /** + * Construct with SDK object involved in conversion. + * + * @param sdkIdvWorkflowConfig + */ + public IdvWorkflowConfigConverter(IdvWorkflowConfig sdkIdvWorkflowConfig) { + this.sdkIdvWorkflowConfig = sdkIdvWorkflowConfig; + } + + /** + * Convert from SDK to API. + * + * @return + */ + public IdvWorkflowConfiguration toAPIIdvWorkflowConfiguration() { + if (sdkIdvWorkflowConfig == null) { + return apiIdvWorkflowConfiguration; + } + + return new IdvWorkflowConfiguration() + .setWorkflowId(sdkIdvWorkflowConfig.getId()) + .setType(sdkIdvWorkflowConfig.getType()) + .setTenant(sdkIdvWorkflowConfig.getTenant()) + .setDesc(sdkIdvWorkflowConfig.getDesc()) + .setSkipWhenAccessingSignedDocuments(sdkIdvWorkflowConfig.isSkipWhenAccessingSignedDocuments()); + } + + /** + * Convert from API to SDK. + * + * @return + */ + public IdvWorkflowConfig toSDKIdvWorkflowConfig() { + if (apiIdvWorkflowConfiguration == null) { + return sdkIdvWorkflowConfig; + } + + IdvWorkflowConfig idvWorkflowConfig = IdvWorkflowConfigBuilder.newIdvWorkflowConfig(apiIdvWorkflowConfiguration.getWorkflowId()) + .withType(apiIdvWorkflowConfiguration.getType()) + .withTenant(apiIdvWorkflowConfiguration.getTenant()) + .withDesc(apiIdvWorkflowConfiguration.getDesc()) + .build(); + idvWorkflowConfig.setSkipWhenAccessingSignedDocuments(apiIdvWorkflowConfiguration.isSkipWhenAccessingSignedDocuments()); + return idvWorkflowConfig; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverter.java b/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverter.java new file mode 100644 index 000000000..a63faf690 --- /dev/null +++ b/sdk/src/main/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverter.java @@ -0,0 +1,68 @@ +package com.silanis.esl.sdk.internal.converter; + +import com.silanis.esl.api.model.IdvWorkflow; +import com.silanis.esl.sdk.builder.IdvWorkflowBuilder; + +/** + * Created by schoi on 2021-03-10. + */ +public class IdvWorkflowConverter { + + private IdvWorkflow apiIdvWorkflow; + private com.silanis.esl.sdk.IdvWorkflow sdkIdvWorkflow; + + + /** + * Construct with API object involved in conversion. + * + * @param apiIdvWorkflow + */ + public IdvWorkflowConverter(IdvWorkflow apiIdvWorkflow) { + this.apiIdvWorkflow = apiIdvWorkflow; + } + + /** + * Construct with SDK object involved in conversion. + * + * @param sdkIdvWorkflow + */ + public IdvWorkflowConverter(com.silanis.esl.sdk.IdvWorkflow sdkIdvWorkflow) { + this.sdkIdvWorkflow = sdkIdvWorkflow; + } + + /** + * Convert from SDK to API. + * + * @return + */ + public IdvWorkflow toAPIIdvWorkflow() { + if (sdkIdvWorkflow == null) { + return apiIdvWorkflow; + } + + return new IdvWorkflow() + .setId(sdkIdvWorkflow.getId()) + .setType(sdkIdvWorkflow.getType()) + .setTenant(sdkIdvWorkflow.getTenant()) + .setDesc(sdkIdvWorkflow.getDesc()); + } + + /** + * Convert from API to SDK. + * + * @return + */ + public com.silanis.esl.sdk.IdvWorkflow toSDKIdvWorkflow() { + if (apiIdvWorkflow == null) { + return sdkIdvWorkflow; + } + + return IdvWorkflowBuilder + .newIdvWorkflow(apiIdvWorkflow.getId()) + .withType(apiIdvWorkflow.getType()) + .withTenant(apiIdvWorkflow.getTenant()) + .withDesc(apiIdvWorkflow.getDesc()) + .build(); + } + +} \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/service/AccountConfigService.java b/sdk/src/main/java/com/silanis/esl/sdk/service/AccountConfigService.java index 39de7b8ac..e618473ed 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/service/AccountConfigService.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/service/AccountConfigService.java @@ -1,6 +1,13 @@ package com.silanis.esl.sdk.service; +import com.google.common.base.Function; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.silanis.esl.api.model.IdvWorkflowConfiguration; +import com.silanis.esl.sdk.Handover; +import com.silanis.esl.sdk.IdvWorkflowConfig; import com.silanis.esl.sdk.internal.converter.HandoverConverter; +import com.silanis.esl.sdk.internal.converter.IdvWorkflowConfigConverter; import com.silanis.esl.sdk.service.apiclient.AccountConfigClient; import java.util.List; @@ -19,18 +26,18 @@ public AccountConfigService(AccountConfigClient apiClient) { this.apiClient = apiClient; } - public com.silanis.esl.sdk.Handover getHandoverUrl(Locale language) { + public Handover getHandoverUrl(Locale language) { com.silanis.esl.api.model.Handover handover = apiClient.getHandoverUrl(convertToString(language)); return new HandoverConverter(handover).toSDKHandover(language); } - public com.silanis.esl.sdk.Handover createHandoverUrl(com.silanis.esl.sdk.Handover sdkHandover) { + public Handover createHandoverUrl(Handover sdkHandover) { com.silanis.esl.api.model.Handover apiHandover = new HandoverConverter(sdkHandover).toAPIHandover(); apiHandover = apiClient.createHandoverUrl(convertToString(sdkHandover.getLanguage()), apiHandover); return new HandoverConverter(apiHandover).toSDKHandover(sdkHandover.getLanguage()); } - public com.silanis.esl.sdk.Handover updateHandoverUrl(com.silanis.esl.sdk.Handover handover) { + public Handover updateHandoverUrl(Handover handover) { com.silanis.esl.api.model.Handover apiHandover = new HandoverConverter(handover).toAPIHandover(); apiHandover = apiClient.updateHandoverUrl(convertToString(handover.getLanguage()), apiHandover); return new HandoverConverter(apiHandover).toSDKHandover(handover.getLanguage()); @@ -56,4 +63,50 @@ public void deleteDeclineReasons(Locale language) { apiClient.deleteDeclineReasons(convertToString(language)); } + public List getIdvWorkflowConfigs() { + List idvWorkflowConfigurations = apiClient.getIdvWorkflowConfigs(); + return Lists.newArrayList(Iterables.transform(idvWorkflowConfigurations, new Function() { + @Override + public IdvWorkflowConfig apply(final IdvWorkflowConfiguration input) { + return new IdvWorkflowConfigConverter(input).toSDKIdvWorkflowConfig(); + } + })); + } + + public List createIdvWorkflowConfigs(List idvWorkflowConfigs) { + List idvWorkflowConfigurations = Lists.newArrayList(Iterables.transform(idvWorkflowConfigs, new Function() { + @Override + public IdvWorkflowConfiguration apply(final IdvWorkflowConfig input) { + return new IdvWorkflowConfigConverter(input).toAPIIdvWorkflowConfiguration(); + } + })); + idvWorkflowConfigurations = apiClient.createIdvWorkflowConfigs(idvWorkflowConfigurations); + return Lists.newArrayList(Iterables.transform(idvWorkflowConfigurations, new Function() { + @Override + public IdvWorkflowConfig apply(final IdvWorkflowConfiguration input) { + return new IdvWorkflowConfigConverter(input).toSDKIdvWorkflowConfig(); + } + })); + } + + public List updateIdvWorkflowConfigs(List idvWorkflowConfigs) { + List idvWorkflowConfigurations = Lists.newArrayList(Iterables.transform(idvWorkflowConfigs, new Function() { + @Override + public IdvWorkflowConfiguration apply(final IdvWorkflowConfig input) { + return new IdvWorkflowConfigConverter(input).toAPIIdvWorkflowConfiguration(); + } + })); + idvWorkflowConfigurations = apiClient.updateIdvWorkflowConfigs(idvWorkflowConfigurations); + return Lists.newArrayList(Iterables.transform(idvWorkflowConfigurations, new Function() { + @Override + public IdvWorkflowConfig apply(final IdvWorkflowConfiguration input) { + return new IdvWorkflowConfigConverter(input).toSDKIdvWorkflowConfig(); + } + })); + } + + public void deleteIdvWorkflowConfigs() { + apiClient.deleteIdvWorkflowConfigs(); + } + } \ No newline at end of file diff --git a/sdk/src/main/java/com/silanis/esl/sdk/service/apiclient/AccountConfigClient.java b/sdk/src/main/java/com/silanis/esl/sdk/service/apiclient/AccountConfigClient.java index 49132f43b..4bacd136f 100644 --- a/sdk/src/main/java/com/silanis/esl/sdk/service/apiclient/AccountConfigClient.java +++ b/sdk/src/main/java/com/silanis/esl/sdk/service/apiclient/AccountConfigClient.java @@ -1,6 +1,7 @@ package com.silanis.esl.sdk.service.apiclient; import com.silanis.esl.api.model.Handover; +import com.silanis.esl.api.model.IdvWorkflowConfiguration; import com.silanis.esl.sdk.EslException; import com.silanis.esl.sdk.internal.EslServerException; import com.silanis.esl.sdk.internal.RequestException; @@ -142,4 +143,61 @@ public void deleteDeclineReasons(String language) { throw new EslException("Could not delete decline reasons.", e); } } + + + public List getIdvWorkflowConfigs() { + String path = template.urlFor(UrlTemplate.IDV_WORKFLOW_CONFIGS_PATH) + .build(); + try { + String stringResponse = restClient.get(path); + + return Serialization.fromJsonToList(stringResponse, IdvWorkflowConfiguration.class); + } catch (RequestException e) { + throw new EslServerException("Could not get IdvWorkflow Configs.", e); + } catch (Exception e) { + throw new EslException("Could not get IdvWorkflow Configs.", e); + } + } + + public List createIdvWorkflowConfigs(List idvWorkflowConfigurations) { + String path = template.urlFor(UrlTemplate.IDV_WORKFLOW_CONFIGS_PATH) + .build(); + try { + String json = Serialization.toJson(idvWorkflowConfigurations); + String stringResponse = restClient.post(path, json); + + return Serialization.fromJsonToList(stringResponse, IdvWorkflowConfiguration.class); + } catch (RequestException e) { + throw new EslServerException("Could not create IdvWorkflow Configs.", e); + } catch (Exception e) { + throw new EslException("Could not create IdvWorkflow Configs.", e); + } + } + + public List updateIdvWorkflowConfigs(List idvWorkflowConfigurations) { + String path = template.urlFor(UrlTemplate.IDV_WORKFLOW_CONFIGS_PATH) + .build(); + try { + String json = Serialization.toJson(idvWorkflowConfigurations); + String stringResponse = restClient.put(path, json); + + return Serialization.fromJsonToList(stringResponse, IdvWorkflowConfiguration.class); + } catch (RequestException e) { + throw new EslServerException("Could not update IdvWorkflow Configs.", e); + } catch (Exception e) { + throw new EslException("Could not update IdvWorkflow Configs.", e); + } + } + + public void deleteIdvWorkflowConfigs() { + String path = template.urlFor(UrlTemplate.IDV_WORKFLOW_CONFIGS_PATH) + .build(); + try { + restClient.delete(path); + } catch (RequestException e) { + throw new EslServerException("Could not delete IdvWorkflow Configs.", e); + } catch (Exception e) { + throw new EslException("Could not delete IdvWorkflow Configs.", e); + } + } } \ No newline at end of file diff --git a/sdk/src/test/java/com/silanis/esl/sdk/AuthenticationTest.java b/sdk/src/test/java/com/silanis/esl/sdk/AuthenticationTest.java index 6e9f0b9f0..72999f8c2 100644 --- a/sdk/src/test/java/com/silanis/esl/sdk/AuthenticationTest.java +++ b/sdk/src/test/java/com/silanis/esl/sdk/AuthenticationTest.java @@ -47,7 +47,7 @@ public void constructorWithListOfChallenges() { public Authentication newSMSAuthentication() { phoneNumber = "1234567890"; - return new Authentication(phoneNumber); + return new Authentication(AuthenticationMethod.SMS, phoneNumber); } @Test diff --git a/sdk/src/test/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilderTest.java b/sdk/src/test/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilderTest.java new file mode 100644 index 000000000..fb9f93b17 --- /dev/null +++ b/sdk/src/test/java/com/silanis/esl/sdk/builder/IdvWorkflowBuilderTest.java @@ -0,0 +1,32 @@ +package com.silanis.esl.sdk.builder; + +import com.silanis.esl.sdk.IdvWorkflow; +import org.junit.Test; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +/** + * Created by schoi on 2021-04-30. + */ +public class IdvWorkflowBuilderTest { + + @Test + public void test() { + String id = "id"; + String type = "type"; + String tenant = "tenant"; + String desc = "desc"; + + IdvWorkflow idvWorkflow = IdvWorkflowBuilder.newIdvWorkflow(id) + .withType(type) + .withTenant(tenant) + .withDesc(desc) + .build(); + + assertThat(idvWorkflow.getId(), is(id)); + assertThat(idvWorkflow.getType(), is(type)); + assertThat(idvWorkflow.getTenant(), is(tenant)); + assertThat(idvWorkflow.getDesc(), is(desc)); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/silanis/esl/sdk/builder/SignerBuilderTest.java b/sdk/src/test/java/com/silanis/esl/sdk/builder/SignerBuilderTest.java index 5f1239819..4d0e0000b 100644 --- a/sdk/src/test/java/com/silanis/esl/sdk/builder/SignerBuilderTest.java +++ b/sdk/src/test/java/com/silanis/esl/sdk/builder/SignerBuilderTest.java @@ -7,8 +7,8 @@ import com.silanis.esl.sdk.Signer; import org.junit.Test; -import static com.silanis.esl.sdk.AuthenticationMethod.SMS; -import static com.silanis.esl.sdk.AuthenticationMethod.SSO; +import static com.silanis.esl.sdk.AuthenticationMethod.*; +import static com.silanis.esl.sdk.builder.IdvWorkflowBuilder.newIdvWorkflow; import static com.silanis.esl.sdk.builder.SignerBuilder.ChallengeBuilder.firstQuestion; import static com.silanis.esl.sdk.builder.SignerBuilder.newSignerPlaceholder; import static com.silanis.esl.sdk.builder.SignerBuilder.newSignerWithEmail; @@ -25,24 +25,24 @@ public void buildWithSpecifiedValues() { String lastName = "withLastName"; int signingOrder = 1; Signer signer = newSignerWithEmail(email) - .withFirstName( firstName ) - .withLastName( lastName ) - .signingOrder( signingOrder ) + .withFirstName(firstName) + .withLastName(lastName) + .signingOrder(signingOrder) .build(); - assertEquals( email, signer.getEmail() ); - assertEquals( firstName, signer.getFirstName() ); - assertEquals( lastName, signer.getLastName() ); - assertEquals( signingOrder, signer.getSigningOrder() ); + assertEquals(email, signer.getEmail()); + assertEquals(firstName, signer.getFirstName()); + assertEquals(lastName, signer.getLastName()); + assertEquals(signingOrder, signer.getSigningOrder()); } @Test - public void buildPlaceholder(){ + public void buildPlaceholder() { String id = "placeholderId"; Signer signer = newSignerPlaceholder(new Placeholder(id)) - .build(); + .build(); - assertEquals( id, signer.getId() ); + assertEquals(id, signer.getId()); } @Test(expected = EslException.class) @@ -95,7 +95,7 @@ public void canSpecifyTitleAndCompany() { @Test public void authenticationDefaultsToEmail() { - Signer signer = newSignerWithEmail("joe@blow.com") + Signer signer = newSignerWithEmail("joe@blow.com") .withFirstName("Joe") .withLastName("Blow") .build(); @@ -161,6 +161,20 @@ public void setsUpSSOAuthentication() { assertThat(signer.getAuthenticationMethod(), is(SSO)); } + @Test + public void setsUpIDVAuthentication() { + Signer signer = newSignerWithEmail("joe@blow.com") + .withFirstName("Joe") + .withLastName("Blow") + .withIDVAuthentication(newIdvWorkflow("00000000-0000-0001-0000-200000000055") + .withTenant("oss") + .withType("DVF") + .build()) + .build(); + + assertThat(signer.getAuthenticationMethod(), is(IDV)); + } + @Test(expected = EslException.class) public void nullPhoneNumberNotAllowed() { newSignerWithEmail("joe@blow.com") diff --git a/sdk/src/test/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverterTest.java b/sdk/src/test/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverterTest.java new file mode 100644 index 000000000..b4669a105 --- /dev/null +++ b/sdk/src/test/java/com/silanis/esl/sdk/internal/converter/IdvWorkflowConverterTest.java @@ -0,0 +1,120 @@ +package com.silanis.esl.sdk.internal.converter; + +import com.silanis.esl.api.model.IdvWorkflow; +import com.silanis.esl.sdk.builder.IdvWorkflowBuilder; +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +/** + * Created by schoi on 2021-04-30. + */ +public class IdvWorkflowConverterTest implements ConverterTest { + private com.silanis.esl.api.model.IdvWorkflow apiIdvWorkflow1 = null; + private com.silanis.esl.api.model.IdvWorkflow apiIdvWorkflow2 = null; + private com.silanis.esl.sdk.IdvWorkflow sdkIdvWorkflow1 = null; + private com.silanis.esl.sdk.IdvWorkflow sdkIdvWorkflow2 = null; + private IdvWorkflowConverter converter = null; + + @Override + @Test + public void convertNullSDKToAPI() { + sdkIdvWorkflow1 = null; + converter = new IdvWorkflowConverter(sdkIdvWorkflow1); + assertThat(converter.toAPIIdvWorkflow(), nullValue()); + } + + @Override + @Test + public void convertNullAPIToSDK() { + apiIdvWorkflow1 = null; + converter = new IdvWorkflowConverter(apiIdvWorkflow1); + assertThat(converter.toSDKIdvWorkflow(), nullValue()); + } + + @Override + @Test + public void convertNullSDKToSDK() { + sdkIdvWorkflow1 = null; + converter = new IdvWorkflowConverter(sdkIdvWorkflow1); + assertThat(converter.toSDKIdvWorkflow(), nullValue()); + } + + @Override + @Test + public void convertNullAPIToAPI() { + apiIdvWorkflow1 = null; + converter = new IdvWorkflowConverter(apiIdvWorkflow1); + assertThat(converter.toAPIIdvWorkflow(), nullValue()); + } + + @Override + @Test + public void convertSDKToSDK() { + sdkIdvWorkflow1 = createTypicalSDKIdvWorkflow(); + sdkIdvWorkflow2 = new IdvWorkflowConverter(sdkIdvWorkflow1).toSDKIdvWorkflow(); + + assertThat(sdkIdvWorkflow2, notNullValue()); + assertThat(sdkIdvWorkflow2.getId(), is(sdkIdvWorkflow1.getId())); + assertThat(sdkIdvWorkflow2.getType(), is(sdkIdvWorkflow1.getType())); + assertThat(sdkIdvWorkflow2.getTenant(), is(sdkIdvWorkflow1.getTenant())); + assertThat(sdkIdvWorkflow2.getDesc(), is(sdkIdvWorkflow1.getDesc())); + } + + @Override + @Test + public void convertAPIToAPI() { + apiIdvWorkflow1 = createTypicalAPIIdvWorkflow(); + apiIdvWorkflow2 = new IdvWorkflowConverter(apiIdvWorkflow1).toAPIIdvWorkflow(); + + assertThat(apiIdvWorkflow2, notNullValue()); + assertThat(apiIdvWorkflow2.getId(), is(apiIdvWorkflow1.getId())); + assertThat(apiIdvWorkflow2.getType(), is(apiIdvWorkflow1.getType())); + assertThat(apiIdvWorkflow2.getTenant(), is(apiIdvWorkflow1.getTenant())); + assertThat(apiIdvWorkflow2.getDesc(), is(apiIdvWorkflow1.getDesc())); + } + + @Override + @Test + public void convertAPIToSDK() { + apiIdvWorkflow1 = createTypicalAPIIdvWorkflow(); + sdkIdvWorkflow1 = new IdvWorkflowConverter(apiIdvWorkflow1).toSDKIdvWorkflow(); + + assertThat(sdkIdvWorkflow1, notNullValue()); + assertThat(sdkIdvWorkflow1.getId(), is(apiIdvWorkflow1.getId())); + assertThat(sdkIdvWorkflow1.getType(), is(apiIdvWorkflow1.getType())); + assertThat(sdkIdvWorkflow1.getTenant(), is(apiIdvWorkflow1.getTenant())); + assertThat(sdkIdvWorkflow1.getDesc(), is(apiIdvWorkflow1.getDesc())); + } + + @Override + @Test + public void convertSDKToAPI() { + sdkIdvWorkflow1 = createTypicalSDKIdvWorkflow(); + apiIdvWorkflow1 = new IdvWorkflowConverter(sdkIdvWorkflow1).toAPIIdvWorkflow(); + + assertThat(apiIdvWorkflow1, notNullValue()); + assertThat(apiIdvWorkflow1.getId(), is(sdkIdvWorkflow1.getId())); + assertThat(apiIdvWorkflow1.getType(), is(sdkIdvWorkflow1.getType())); + assertThat(apiIdvWorkflow1.getTenant(), is(sdkIdvWorkflow1.getTenant())); + assertThat(apiIdvWorkflow1.getDesc(), is(sdkIdvWorkflow1.getDesc())); + } + + private com.silanis.esl.sdk.IdvWorkflow createTypicalSDKIdvWorkflow() { + return IdvWorkflowBuilder.newIdvWorkflow("id") + .withType("sdkType") + .withTenant("sdkTenant") + .withDesc("sdkDesc") + .build(); + } + + private IdvWorkflow createTypicalAPIIdvWorkflow() { + IdvWorkflow idvWorkflow = new IdvWorkflow(); + idvWorkflow.setId("id"); + idvWorkflow.setType("apiType"); + idvWorkflow.setTenant("apiTenant"); + idvWorkflow.setDesc("apiDesc"); + return idvWorkflow; + } +} \ No newline at end of file diff --git a/tester/src/test/java/com/silanis/esl/sdk/examples/IdvAuthExampleTest.java b/tester/src/test/java/com/silanis/esl/sdk/examples/IdvAuthExampleTest.java new file mode 100644 index 000000000..4d2a57bca --- /dev/null +++ b/tester/src/test/java/com/silanis/esl/sdk/examples/IdvAuthExampleTest.java @@ -0,0 +1,95 @@ +package com.silanis.esl.sdk.examples; + +import com.silanis.esl.sdk.DocumentPackage; +import com.silanis.esl.sdk.IdvWorkflow; +import com.silanis.esl.sdk.IdvWorkflowConfig; +import com.silanis.esl.sdk.Signer; +import org.apache.commons.lang.StringUtils; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.silanis.esl.sdk.AuthenticationMethod.IDV; +import static com.silanis.esl.sdk.builder.IdvWorkflowConfigBuilder.newIdvWorkflowConfig; +import static com.silanis.esl.sdk.examples.IdvAuthExample.*; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.fail; + +/** + * Created by schoi on 2020-10-01. + */ +public class IdvAuthExampleTest { + + @Test + public void verifyResult() { + IdvAuthExample example = new IdvAuthExample(); + example.run(); + DocumentPackage documentPackage = example.getRetrievedPackage(); + + assertIdvWorkflowConfigs(example.idvWorkflowConfigsBeforeCreating, new ArrayList()); + assertIdvWorkflowConfigs(example.idvWorkflowConfigsAfterCreating, singletonList(newIdvWorkflowConfig(IDV_WORKFLOW_ID1) + .withType(TYPE1) + .withTenant(TENANT) + .withDesc(DESC1) + .enableSkipWhenAccessingSignedDocuments() + .build())); + assertIdvWorkflowConfigs(example.idvWorkflowConfigsAfterUpdating, asList(newIdvWorkflowConfig(IDV_WORKFLOW_ID1) + .withType(TYPE1) + .withTenant(TENANT) + .withDesc(DESC1) + .enableSkipWhenAccessingSignedDocuments() + .build(), newIdvWorkflowConfig(IDV_WORKFLOW_ID2) + .withType(TYPE2) + .withTenant(TENANT) + .withDesc(DESC2) + .enableSkipWhenAccessingSignedDocuments() + .build())); + assertIdvWorkflowConfigs(example.idvWorkflowConfigsAfterDeleting, new ArrayList()); + + Signer signer = documentPackage.getSigner(example.email1); + assertThat(signer.getAuthenticationMethod(), is(IDV)); + assertThat(signer.getChallengeQuestions(), hasSize(0)); + assertThat(signer.getPhoneNumber(), is(PHONE_NUMBER)); + + IdvWorkflow idvWorkflow = signer.getAuthentication().getIdvWorkflow(); + assertThat(idvWorkflow.getId(), is(IDV_WORKFLOW_ID1)); + assertThat(idvWorkflow.getTenant(), is(TENANT)); + } + + private void assertIdvWorkflowConfigs(List actual, List expected) { + assertThat("The idvWorkflowConfig is not set correctly.", actual, hasSize(expected.size())); + + if (actual.isEmpty()) { + return; + } + + for (IdvWorkflowConfig config : expected) { + IdvWorkflowConfig idvWorkflowConfig = findById(config.getId(), actual); + if (idvWorkflowConfig == null) { + fail("The idvWorkflowConfig is not set correctly"); + } + assertIdvWorkflowConfig(idvWorkflowConfig, config); + } + } + + private IdvWorkflowConfig findById(String id, List idvWorkflowConfigs) { + for (IdvWorkflowConfig config : idvWorkflowConfigs) { + if (StringUtils.equals(config.getId(), id)) { + return config; + } + } + return null; + } + + private void assertIdvWorkflowConfig(IdvWorkflowConfig actual, IdvWorkflowConfig expected) { + assertThat("The idvWorkflowConfig id is not set correctly.", actual.getId(), is(expected.getId())); + assertThat("The idvWorkflowConfig type is not set correctly.", actual.getType(), is(expected.getType())); + assertThat("The idvWorkflowConfig desc is not set correctly.", actual.getDesc(), is(expected.getDesc())); + assertThat("The idvWorkflowConfig skipWhenAccessingSignedDocuments is not set correctly.", actual.isSkipWhenAccessingSignedDocuments(), is(expected.isSkipWhenAccessingSignedDocuments())); + } +} \ No newline at end of file