From 3c7115a77d21d94e4761659b11e8deca67292044 Mon Sep 17 00:00:00 2001 From: Urmas Muser Date: Tue, 19 Nov 2024 16:36:36 +0200 Subject: [PATCH 01/20] SLIB-66 - make existing code v2 specific; fix cert issues --- .../{Config.java => SmartIdV2Config.java} | 27 ++++++------ ...ntroller.java => SmartIdV2Controller.java} | 24 +++++------ .../model/AuthenticationSessionInfo.java | 5 ++- .../sk/siddemo/model/SigningSessionInfo.java | 2 +- .../services/SmartIdCertificateService.java | 2 +- .../SmartIdCertificateServiceImpl.java | 14 +++---- ...va => SmartIdV2AuthenticationService.java} | 4 +- ...> SmartIdV2AuthenticationServiceImpl.java} | 31 +++++++------- ...ce.java => SmartIdV2SignatureService.java} | 2 +- ...ava => SmartIdV2SignatureServiceImpl.java} | 32 +++++++------- src/main/resources/application.yml | 39 +++++++++--------- src/main/resources/sid.trusted_root_certs.p12 | Bin 3990 -> 6358 bytes .../resources/templates/authentication.html | 12 +----- .../templates/authenticationResult.html | 10 +---- src/main/resources/templates/error.html | 10 +---- .../resources/templates/fragments/header.html | 20 +++++++++ src/main/resources/templates/index.html | 18 ++------ .../templates/sidOperationError.html | 10 +---- src/main/resources/templates/signature.html | 10 +---- .../resources/templates/signingResult.html | 10 +---- 20 files changed, 123 insertions(+), 159 deletions(-) rename src/main/java/ee/sk/siddemo/{Config.java => SmartIdV2Config.java} (79%) rename src/main/java/ee/sk/siddemo/controller/{SmartIdController.java => SmartIdV2Controller.java} (88%) rename src/main/java/ee/sk/siddemo/services/{SmartIdAuthenticationService.java => SmartIdV2AuthenticationService.java} (91%) rename src/main/java/ee/sk/siddemo/services/{SmartIdAuthenticationServiceImpl.java => SmartIdV2AuthenticationServiceImpl.java} (87%) rename src/main/java/ee/sk/siddemo/services/{SmartIdSignatureService.java => SmartIdV2SignatureService.java} (96%) rename src/main/java/ee/sk/siddemo/services/{SmartIdSignatureServiceImpl.java => SmartIdV2SignatureServiceImpl.java} (89%) create mode 100644 src/main/resources/templates/fragments/header.html diff --git a/src/main/java/ee/sk/siddemo/Config.java b/src/main/java/ee/sk/siddemo/SmartIdV2Config.java similarity index 79% rename from src/main/java/ee/sk/siddemo/Config.java rename to src/main/java/ee/sk/siddemo/SmartIdV2Config.java index b9614a3..88bb1ec 100644 --- a/src/main/java/ee/sk/siddemo/Config.java +++ b/src/main/java/ee/sk/siddemo/SmartIdV2Config.java @@ -37,36 +37,36 @@ import org.springframework.web.context.WebApplicationContext; import ee.sk.siddemo.model.UserSidSession; -import ee.sk.smartid.AuthenticationResponseValidator; -import ee.sk.smartid.SmartIdClient; +import ee.sk.smartid.v2.AuthenticationResponseValidator; +import ee.sk.smartid.v2.SmartIdClient; @Configuration -public class Config { +public class SmartIdV2Config { - @Value("${sid.client.relyingPartyUuid}") + @Value("${sid.v2.client.relyingPartyUuid}") private String sidRelyingPartyUuid; - @Value("${sid.client.relyingPartyName}") + @Value("${sid.v2.client.relyingPartyName}") private String sidRelyingPartyName; - @Value("${sid.client.applicationProviderHost}") + @Value("${sid.v2.client.applicationProviderHost}") private String sidApplicationProviderHost; - @Value("${sid.truststore.trusted-server-ssl-certs.filename}") + @Value("${sid.v2.truststore.trusted-server-ssl-certs.filename}") private String sidTrustedServerSslCertsFilename; - @Value("${sid.truststore.trusted-server-ssl-certs.password}") + @Value("${sid.v2.truststore.trusted-server-ssl-certs.password}") private String sidTrustedServerSslCertsPassword; - @Value("${sid.truststore.trusted-root-certs.filename}") + @Value("${sid.v2.truststore.trusted-root-certs.filename}") private String sidTrustedRootCertsFilename; - @Value("${sid.truststore.trusted-root-certs.password}") + @Value("${sid.v2.truststore.trusted-root-certs.password}") private String sidTrustedRootCertsPassword; @Bean - public SmartIdClient smartIdClient() throws Exception { - InputStream is = Config.class.getResourceAsStream(sidTrustedServerSslCertsFilename); + public SmartIdClient smartIdClientV2() throws Exception { + InputStream is = SmartIdV2Config.class.getResourceAsStream(sidTrustedServerSslCertsFilename); KeyStore trustStore = KeyStore.getInstance("PKCS12"); trustStore.load(is, sidTrustedServerSslCertsPassword.toCharArray()); @@ -92,7 +92,7 @@ public AuthenticationResponseValidator sidResponseValidator() throws Exception { List certificates = new ArrayList<>(); - InputStream is = Config.class.getResourceAsStream(sidTrustedRootCertsFilename); + InputStream is = SmartIdV2Config.class.getResourceAsStream(sidTrustedRootCertsFilename); KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(is, sidTrustedRootCertsPassword.toCharArray()); @@ -106,5 +106,4 @@ public AuthenticationResponseValidator sidResponseValidator() throws Exception { return new AuthenticationResponseValidator(certificates.toArray(new X509Certificate[0])); } - } diff --git a/src/main/java/ee/sk/siddemo/controller/SmartIdController.java b/src/main/java/ee/sk/siddemo/controller/SmartIdV2Controller.java similarity index 88% rename from src/main/java/ee/sk/siddemo/controller/SmartIdController.java rename to src/main/java/ee/sk/siddemo/controller/SmartIdV2Controller.java index ba22cc0..d59c6b0 100644 --- a/src/main/java/ee/sk/siddemo/controller/SmartIdController.java +++ b/src/main/java/ee/sk/siddemo/controller/SmartIdV2Controller.java @@ -41,22 +41,22 @@ import ee.sk.siddemo.model.SigningSessionInfo; import ee.sk.siddemo.model.UserRequest; import ee.sk.siddemo.model.UserSidSession; -import ee.sk.siddemo.services.SmartIdAuthenticationService; -import ee.sk.siddemo.services.SmartIdSignatureService; -import ee.sk.smartid.AuthenticationIdentity; +import ee.sk.siddemo.services.SmartIdV2AuthenticationService; +import ee.sk.siddemo.services.SmartIdV2SignatureService; +import ee.sk.smartid.v2.AuthenticationIdentity; import jakarta.validation.Valid; @RestController -public class SmartIdController { +public class SmartIdV2Controller { - private static final Logger logger = LoggerFactory.getLogger(SmartIdController.class); + private static final Logger logger = LoggerFactory.getLogger(SmartIdV2Controller.class); - private final SmartIdSignatureService signatureService; - private final SmartIdAuthenticationService authenticationService; + private final SmartIdV2SignatureService signatureService; + private final SmartIdV2AuthenticationService authenticationService; private final UserSidSession userSidSession; @Autowired - public SmartIdController(SmartIdSignatureService signatureService, SmartIdAuthenticationService authenticationService, UserSidSession userSidSession) { + public SmartIdV2Controller(SmartIdV2SignatureService signatureService, SmartIdV2AuthenticationService authenticationService, UserSidSession userSidSession) { this.signatureService = signatureService; this.authenticationService = authenticationService; this.userSidSession = userSidSession; // session scope, autowired @@ -67,7 +67,7 @@ public ModelAndView userRequestForm() { return new ModelAndView("index", "userRequest", new UserRequest()); } - @PostMapping(value = "/signatureRequest") + @PostMapping(value = "/v2/signatureRequest") public ModelAndView sendSignatureRequest(@ModelAttribute("userRequest") UserRequest userRequest, BindingResult bindingResult, ModelMap model) { @@ -88,7 +88,7 @@ public ModelAndView sendSignatureRequest(@ModelAttribute("userRequest") UserRequ return new ModelAndView("/signature", model); } - @PostMapping(value = "/sign") + @PostMapping(value = "/v2/sign") public ModelAndView sign(ModelMap model) { SigningResult signingResult = signatureService.sign(userSidSession.getSigningSessionInfo()); @@ -100,7 +100,7 @@ public ModelAndView sign(ModelMap model) { return new ModelAndView("signingResult", model); } - @PostMapping(value = "/authenticationRequest") + @PostMapping(value = "/v2/authenticationRequest") public ModelAndView sendAuthenticationRequest(@ModelAttribute("userRequest") @Valid UserRequest userRequest, BindingResult bindingResult, ModelMap model) { @@ -117,7 +117,7 @@ public ModelAndView sendAuthenticationRequest(@ModelAttribute("userRequest") @Va return new ModelAndView("/authentication", model); } - @PostMapping(value = "/authenticate") + @PostMapping(value = "/v2/authenticate") public ModelAndView authenticate(ModelMap model) { AuthenticationIdentity person = authenticationService.authenticate(userSidSession.getAuthenticationSessionInfo()); model.addAttribute("person", person); diff --git a/src/main/java/ee/sk/siddemo/model/AuthenticationSessionInfo.java b/src/main/java/ee/sk/siddemo/model/AuthenticationSessionInfo.java index de1e1f6..ef2241b 100644 --- a/src/main/java/ee/sk/siddemo/model/AuthenticationSessionInfo.java +++ b/src/main/java/ee/sk/siddemo/model/AuthenticationSessionInfo.java @@ -22,8 +22,9 @@ * #L% */ -import ee.sk.smartid.AuthenticationHash; -import ee.sk.smartid.rest.dao.SemanticsIdentifier; + +import ee.sk.smartid.v2.AuthenticationHash; +import ee.sk.smartid.v2.rest.dao.SemanticsIdentifier; public class AuthenticationSessionInfo { diff --git a/src/main/java/ee/sk/siddemo/model/SigningSessionInfo.java b/src/main/java/ee/sk/siddemo/model/SigningSessionInfo.java index df6b81a..3b43424 100644 --- a/src/main/java/ee/sk/siddemo/model/SigningSessionInfo.java +++ b/src/main/java/ee/sk/siddemo/model/SigningSessionInfo.java @@ -25,7 +25,7 @@ import org.digidoc4j.Container; import org.digidoc4j.DataToSign; -import ee.sk.smartid.SignableHash; +import ee.sk.smartid.v2.SignableHash; public class SigningSessionInfo { diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdCertificateService.java b/src/main/java/ee/sk/siddemo/services/SmartIdCertificateService.java index 1e3bd3b..d0fae2c 100644 --- a/src/main/java/ee/sk/siddemo/services/SmartIdCertificateService.java +++ b/src/main/java/ee/sk/siddemo/services/SmartIdCertificateService.java @@ -23,7 +23,7 @@ */ import ee.sk.siddemo.model.UserRequest; -import ee.sk.smartid.SmartIdCertificate; +import ee.sk.smartid.v2.SmartIdCertificate; public interface SmartIdCertificateService { diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdCertificateServiceImpl.java b/src/main/java/ee/sk/siddemo/services/SmartIdCertificateServiceImpl.java index 036b74e..f2be280 100644 --- a/src/main/java/ee/sk/siddemo/services/SmartIdCertificateServiceImpl.java +++ b/src/main/java/ee/sk/siddemo/services/SmartIdCertificateServiceImpl.java @@ -28,25 +28,25 @@ import ee.sk.siddemo.exception.SidOperationException; import ee.sk.siddemo.model.UserRequest; -import ee.sk.smartid.SmartIdCertificate; -import ee.sk.smartid.SmartIdClient; import ee.sk.smartid.exception.permanent.ServerMaintenanceException; import ee.sk.smartid.exception.permanent.SmartIdClientException; import ee.sk.smartid.exception.useraccount.DocumentUnusableException; import ee.sk.smartid.exception.useraccount.UserAccountNotFoundException; import ee.sk.smartid.exception.useraction.SessionTimeoutException; import ee.sk.smartid.exception.useraction.UserRefusedException; -import ee.sk.smartid.rest.dao.SemanticsIdentifier; +import ee.sk.smartid.v2.SmartIdCertificate; +import ee.sk.smartid.v2.SmartIdClient; +import ee.sk.smartid.v2.rest.dao.SemanticsIdentifier; @Service public class SmartIdCertificateServiceImpl implements SmartIdCertificateService { private static final Logger logger = LoggerFactory.getLogger(SmartIdCertificateServiceImpl.class); - private final SmartIdClient client; + private final SmartIdClient smartIdClientV2; - public SmartIdCertificateServiceImpl(SmartIdClient client) { - this.client = client; + public SmartIdCertificateServiceImpl(SmartIdClient smartIdClientV2) { + this.smartIdClientV2 = smartIdClientV2; } @Override @@ -62,7 +62,7 @@ public SmartIdCertificate getCertificate(UserRequest userRequest) { userRequest.getNationalIdentityNumber()); - SmartIdCertificate responseWithSigningCertificate = client + SmartIdCertificate responseWithSigningCertificate = smartIdClientV2 .getCertificate() .withSemanticsIdentifier(semanticsIdentifier) .withCertificateLevel("QUALIFIED") diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdAuthenticationService.java b/src/main/java/ee/sk/siddemo/services/SmartIdV2AuthenticationService.java similarity index 91% rename from src/main/java/ee/sk/siddemo/services/SmartIdAuthenticationService.java rename to src/main/java/ee/sk/siddemo/services/SmartIdV2AuthenticationService.java index 1479b1c..4b12a21 100644 --- a/src/main/java/ee/sk/siddemo/services/SmartIdAuthenticationService.java +++ b/src/main/java/ee/sk/siddemo/services/SmartIdV2AuthenticationService.java @@ -24,9 +24,9 @@ import ee.sk.siddemo.model.AuthenticationSessionInfo; import ee.sk.siddemo.model.UserRequest; -import ee.sk.smartid.AuthenticationIdentity; +import ee.sk.smartid.v2.AuthenticationIdentity; -public interface SmartIdAuthenticationService { +public interface SmartIdV2AuthenticationService { AuthenticationSessionInfo startAuthentication(UserRequest userRequest); diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdAuthenticationServiceImpl.java b/src/main/java/ee/sk/siddemo/services/SmartIdV2AuthenticationServiceImpl.java similarity index 87% rename from src/main/java/ee/sk/siddemo/services/SmartIdAuthenticationServiceImpl.java rename to src/main/java/ee/sk/siddemo/services/SmartIdV2AuthenticationServiceImpl.java index f4b3a1a..8e15521 100644 --- a/src/main/java/ee/sk/siddemo/services/SmartIdAuthenticationServiceImpl.java +++ b/src/main/java/ee/sk/siddemo/services/SmartIdV2AuthenticationServiceImpl.java @@ -34,11 +34,7 @@ import ee.sk.siddemo.exception.SidOperationException; import ee.sk.siddemo.model.AuthenticationSessionInfo; import ee.sk.siddemo.model.UserRequest; -import ee.sk.smartid.AuthenticationHash; -import ee.sk.smartid.AuthenticationIdentity; -import ee.sk.smartid.AuthenticationResponseValidator; -import ee.sk.smartid.SmartIdAuthenticationResponse; -import ee.sk.smartid.SmartIdClient; + import ee.sk.smartid.exception.UnprocessableSmartIdResponseException; import ee.sk.smartid.exception.permanent.ServerMaintenanceException; import ee.sk.smartid.exception.useraccount.CertificateLevelMismatchException; @@ -47,23 +43,28 @@ import ee.sk.smartid.exception.useraction.SessionTimeoutException; import ee.sk.smartid.exception.useraction.UserRefusedException; import ee.sk.smartid.exception.useraction.UserSelectedWrongVerificationCodeException; -import ee.sk.smartid.rest.dao.Interaction; -import ee.sk.smartid.rest.dao.SemanticsIdentifier; +import ee.sk.smartid.v2.AuthenticationHash; +import ee.sk.smartid.v2.AuthenticationIdentity; +import ee.sk.smartid.v2.AuthenticationResponseValidator; +import ee.sk.smartid.v2.SmartIdAuthenticationResponse; +import ee.sk.smartid.v2.SmartIdClient; +import ee.sk.smartid.v2.rest.dao.Interaction; +import ee.sk.smartid.v2.rest.dao.SemanticsIdentifier; @Service -public class SmartIdAuthenticationServiceImpl implements SmartIdAuthenticationService { +public class SmartIdV2AuthenticationServiceImpl implements SmartIdV2AuthenticationService { - private static final Logger logger = LoggerFactory.getLogger(SmartIdAuthenticationServiceImpl.class); + private static final Logger logger = LoggerFactory.getLogger(SmartIdV2AuthenticationServiceImpl.class); - @Value("${sid.auth.displayText}") + @Value("${sid.v2.auth.displayText}") private String sidAuthDisplayText; - private final SmartIdClient client; + private final SmartIdClient smartIdClientV2; private final AuthenticationResponseValidator sidAuthenticationResponseValidator; - public SmartIdAuthenticationServiceImpl(SmartIdClient client, - AuthenticationResponseValidator sidAuthenticationResponseValidator) { - this.client = client; + public SmartIdV2AuthenticationServiceImpl(SmartIdClient smartIdClientV2, + AuthenticationResponseValidator sidAuthenticationResponseValidator) { + this.smartIdClientV2 = smartIdClientV2; this.sidAuthenticationResponseValidator = sidAuthenticationResponseValidator; } @@ -100,7 +101,7 @@ public AuthenticationIdentity authenticate(AuthenticationSessionInfo authenticat AuthenticationIdentity authIdentity = null; try { - SmartIdAuthenticationResponse response = client + SmartIdAuthenticationResponse response = smartIdClientV2 .createAuthentication() .withSemanticsIdentifier(authenticationSessionInfo.getSemanticsIdentifier()) .withAuthenticationHash(authenticationHash) diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdSignatureService.java b/src/main/java/ee/sk/siddemo/services/SmartIdV2SignatureService.java similarity index 96% rename from src/main/java/ee/sk/siddemo/services/SmartIdSignatureService.java rename to src/main/java/ee/sk/siddemo/services/SmartIdV2SignatureService.java index bf0c805..0389531 100644 --- a/src/main/java/ee/sk/siddemo/services/SmartIdSignatureService.java +++ b/src/main/java/ee/sk/siddemo/services/SmartIdV2SignatureService.java @@ -26,7 +26,7 @@ import ee.sk.siddemo.model.SigningSessionInfo; import ee.sk.siddemo.model.UserRequest; -public interface SmartIdSignatureService { +public interface SmartIdV2SignatureService { SigningSessionInfo sendSignatureRequest(UserRequest userRequest); diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdSignatureServiceImpl.java b/src/main/java/ee/sk/siddemo/services/SmartIdV2SignatureServiceImpl.java similarity index 89% rename from src/main/java/ee/sk/siddemo/services/SmartIdSignatureServiceImpl.java rename to src/main/java/ee/sk/siddemo/services/SmartIdV2SignatureServiceImpl.java index b51a4bc..68890b6 100644 --- a/src/main/java/ee/sk/siddemo/services/SmartIdSignatureServiceImpl.java +++ b/src/main/java/ee/sk/siddemo/services/SmartIdV2SignatureServiceImpl.java @@ -50,43 +50,43 @@ import ee.sk.siddemo.model.SigningSessionInfo; import ee.sk.siddemo.model.UserRequest; import ee.sk.smartid.HashType; -import ee.sk.smartid.SignableData; -import ee.sk.smartid.SignableHash; -import ee.sk.smartid.SmartIdCertificate; -import ee.sk.smartid.SmartIdClient; -import ee.sk.smartid.SmartIdSignature; +import ee.sk.smartid.v2.SignableData; +import ee.sk.smartid.v2.SignableHash; +import ee.sk.smartid.v2.SmartIdCertificate; +import ee.sk.smartid.v2.SmartIdClient; +import ee.sk.smartid.v2.SmartIdSignature; import ee.sk.smartid.exception.permanent.ServerMaintenanceException; import ee.sk.smartid.exception.useraccount.DocumentUnusableException; import ee.sk.smartid.exception.useraccount.UserAccountNotFoundException; import ee.sk.smartid.exception.useraction.SessionTimeoutException; import ee.sk.smartid.exception.useraction.UserRefusedException; import ee.sk.smartid.exception.useraction.UserSelectedWrongVerificationCodeException; -import ee.sk.smartid.rest.dao.Interaction; -import ee.sk.smartid.rest.dao.SemanticsIdentifier; +import ee.sk.smartid.v2.rest.dao.Interaction; +import ee.sk.smartid.v2.rest.dao.SemanticsIdentifier; @Service -public class SmartIdSignatureServiceImpl implements SmartIdSignatureService { +public class SmartIdV2SignatureServiceImpl implements SmartIdV2SignatureService { - private static final Logger logger = LoggerFactory.getLogger(SmartIdSignatureServiceImpl.class); + private static final Logger logger = LoggerFactory.getLogger(SmartIdV2SignatureServiceImpl.class); - @Value("${sid.sign.displayText}") + @Value("${sid.v2.sign.displayText}") private String sidSignDisplayText; - @Value("${sid.client.relyingPartyUuid}") + @Value("${sid.v2.client.relyingPartyUuid}") private String sidRelyingPartyUuid; - @Value("${sid.client.relyingPartyName}") + @Value("${sid.v2.client.relyingPartyName}") private String sidRelyingPartyName; @Value("${app.signed-files-directory}") private String signedFilesDirectory; private final SmartIdCertificateService certificateService; - private final SmartIdClient client; + private final SmartIdClient smartIdClientV2; - public SmartIdSignatureServiceImpl(SmartIdCertificateService certificateService, SmartIdClient client) { + public SmartIdV2SignatureServiceImpl(SmartIdCertificateService certificateService, SmartIdClient smartIdClientV2) { this.certificateService = certificateService; - this.client = client; + this.smartIdClientV2 = smartIdClientV2; } @Override @@ -149,7 +149,7 @@ public SigningResult sign(SigningSessionInfo signingSessionInfo) { try { - SmartIdSignature smartIdSignature = client + SmartIdSignature smartIdSignature = smartIdClientV2 .createSignature() .withDocumentNumber(signingSessionInfo.getDocumentNumber()) .withSignableHash(signingSessionInfo.getHashToSign()) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 7693e6f..7072e24 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,25 +4,26 @@ spring.servlet.multipart: server.port: 8081 sid: - client: - relyingPartyUuid: 00000000-0000-0000-0000-000000000000 - relyingPartyName: DEMO - applicationProviderHost: https://sid.demo.sk.ee/smart-id-rp/v2/ - auth: - displayText: Log in with Smart-ID demo? - displayTextFormat: GSM7 - displayTextLanguage: ENG - sign: - displayText: Подписать? - displayTextFormat: UCS2 - displayTextLanguage: RUS - truststore: - trusted-server-ssl-certs: - filename: /sid.trusted_server_certs.p12 - password: changeit - trusted-root-certs: - filename: /sid.trusted_root_certs.p12 - password: changeit + v2: + client: + relyingPartyUuid: 00000000-0000-0000-0000-000000000000 + relyingPartyName: DEMO + applicationProviderHost: https://sid.demo.sk.ee/smart-id-rp/v2/ + auth: + displayText: Log in with Smart-ID demo? + displayTextFormat: GSM7 + displayTextLanguage: ENG + sign: + displayText: Подписать? + displayTextFormat: UCS2 + displayTextLanguage: RUS + truststore: + trusted-server-ssl-certs: + filename: /sid.trusted_server_certs.p12 + password: changeit + trusted-root-certs: + filename: /sid.trusted_root_certs.p12 + password: changeit app: signed-files-directory: target/signed-files \ No newline at end of file diff --git a/src/main/resources/sid.trusted_root_certs.p12 b/src/main/resources/sid.trusted_root_certs.p12 index 3e75dfccdeb4b33699301bcd0fe24bf558204097..465d8928137e92b89666c91bb6a389c326a63a69 100644 GIT binary patch delta 6340 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 G0w)liH7U^m delta 3954 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 MQPSKG#{vQ;5YD}N{Qv*} diff --git a/src/main/resources/templates/authentication.html b/src/main/resources/templates/authentication.html index 51f3cce..0ec19af 100644 --- a/src/main/resources/templates/authentication.html +++ b/src/main/resources/templates/authentication.html @@ -35,15 +35,7 @@ -
- -
+
-
+
diff --git a/src/main/resources/templates/authenticationResult.html b/src/main/resources/templates/authenticationResult.html index ae1dc36..c6b1437 100644 --- a/src/main/resources/templates/authenticationResult.html +++ b/src/main/resources/templates/authenticationResult.html @@ -35,15 +35,7 @@ -
- -
+
From a24e7e81b8193d659e18ebaf7b925b73381f19e6 Mon Sep 17 00:00:00 2001 From: Urmas Muser Date: Tue, 17 Dec 2024 23:20:23 +0200 Subject: [PATCH 10/20] SLIB-73 - add base for dynamic-link certificate choice --- ...artIdV3AuthenticationStatusController.java | 3 +- .../SmartIdV3CertificateChoiceController.java | 109 ++++++ .../services/DynamicContentService.java | 12 +- .../SmartIdV3CertificateChoiceService.java | 116 +++++++ src/main/resources/static/css/style.css | 20 +- .../v3/certificate-choice-result.html | 27 ++ .../templates/v3/certificate-choice.html | 99 ++++++ src/main/resources/templates/v3/main.html | 324 +++++++++++++----- 8 files changed, 608 insertions(+), 102 deletions(-) create mode 100644 src/main/java/ee/sk/siddemo/controller/SmartIdV3CertificateChoiceController.java create mode 100644 src/main/java/ee/sk/siddemo/services/SmartIdV3CertificateChoiceService.java create mode 100644 src/main/resources/templates/v3/certificate-choice-result.html create mode 100644 src/main/resources/templates/v3/certificate-choice.html diff --git a/src/main/java/ee/sk/siddemo/controller/SmartIdV3AuthenticationStatusController.java b/src/main/java/ee/sk/siddemo/controller/SmartIdV3AuthenticationStatusController.java index 68d40af..9fa6f03 100644 --- a/src/main/java/ee/sk/siddemo/controller/SmartIdV3AuthenticationStatusController.java +++ b/src/main/java/ee/sk/siddemo/controller/SmartIdV3AuthenticationStatusController.java @@ -17,6 +17,7 @@ import ee.sk.siddemo.model.DynamicContent; import ee.sk.siddemo.services.DynamicContentService; import ee.sk.siddemo.services.SmartIdV3AuthenticationService; +import ee.sk.smartid.v3.SessionType; import jakarta.servlet.http.HttpSession; @RestController @@ -49,7 +50,7 @@ public ResponseEntity> checkAuthenticationStatus(HttpSession // Generate QR-code and dynamic link logger.debug("Generate dynamic content for session {}", session.getId()); - DynamicContent dynamicContent = dynamicContentService.getDynamicContent(session); + DynamicContent dynamicContent = dynamicContentService.getDynamicContent(session, SessionType.AUTHENTICATION); Map content = new HashMap<>(); content.put("dynamicLink", dynamicContent.getDynamicLink().toString()); content.put("qrCode", dynamicContent.getQrCode()); diff --git a/src/main/java/ee/sk/siddemo/controller/SmartIdV3CertificateChoiceController.java b/src/main/java/ee/sk/siddemo/controller/SmartIdV3CertificateChoiceController.java new file mode 100644 index 0000000..66b7068 --- /dev/null +++ b/src/main/java/ee/sk/siddemo/controller/SmartIdV3CertificateChoiceController.java @@ -0,0 +1,109 @@ +package ee.sk.siddemo.controller; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.servlet.ModelAndView; + +import ee.sk.siddemo.exception.SidOperationException; +import ee.sk.siddemo.model.DynamicContent; +import ee.sk.siddemo.services.DynamicContentService; +import ee.sk.siddemo.services.SmartIdV3CertificateChoiceService; +import ee.sk.siddemo.services.SmartIdV3SessionsStatusService; +import ee.sk.smartid.v3.SessionType; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; + +@Controller +public class SmartIdV3CertificateChoiceController { + + private static final Logger logger = LoggerFactory.getLogger(SmartIdV3CertificateChoiceController.class); + + private final SmartIdV3CertificateChoiceService smartIdV3CertificateChoiceService; + private final SmartIdV3SessionsStatusService smartIdV3SessionsStatusService; + private final DynamicContentService dynamicContentService; + + public SmartIdV3CertificateChoiceController(SmartIdV3CertificateChoiceService smartIdV3CertificateChoiceService, + SmartIdV3SessionsStatusService smartIdV3SessionsStatusService, + DynamicContentService dynamicContentService) { + this.smartIdV3CertificateChoiceService = smartIdV3CertificateChoiceService; + this.smartIdV3SessionsStatusService = smartIdV3SessionsStatusService; + this.dynamicContentService = dynamicContentService; + } + + @GetMapping(value = "/v3/start-certificate-choice") + public ModelAndView startCertificateChoice(ModelMap model, HttpServletRequest request) { + HttpSession session = resetSession(request); + smartIdV3CertificateChoiceService.startCertificateChoice(session); + model.addAttribute("activeTab", "rp-api-v3"); + return new ModelAndView("v3/certificate-choice", model); + } + + @GetMapping(value = "/v3/check-certificate-choice-status") + @ResponseBody + public ResponseEntity> checkCertificateChoiceStatus(HttpSession session) { + boolean checkCompleted; + try { + checkCompleted = smartIdV3CertificateChoiceService.checkCertificateChoiceStatus(session); + } catch (SidOperationException ex) { + logger.error("Error occurred while checking authentication status", ex); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("errorMessage", ex.getMessage())); + } + if (checkCompleted) { + logger.debug("Session status: COMPLETED"); + return ResponseEntity.ok(Map.of("sessionStatus", "COMPLETED")); + } + + // Generate QR-code and dynamic link + logger.debug("Generate dynamic content for session {}", session.getId()); + DynamicContent dynamicContent = dynamicContentService.getDynamicContent(session, SessionType.CERTIFICATE_CHOICE); + Map content = new HashMap<>(); + content.put("dynamicLink", dynamicContent.getDynamicLink().toString()); + content.put("qrCode", dynamicContent.getQrCode()); + return ResponseEntity.ok(content); + } + + @GetMapping(value = "/certificate-choice-session-error") + public ModelAndView handleCertificateChoiceSessionsError(@RequestParam(value = "errorMessage", required = false) String errorMessage, + ModelMap model) { + model.addAttribute("errorMessage", errorMessage); + return new ModelAndView("sidOperationError", model); + } + + @GetMapping(value = "/v3/certificate-choice-result") + public ModelAndView getAuthenticationResult(ModelMap model, HttpSession session) { + String documentNumber = (String) session.getAttribute("documentNumber"); + String distinguishedName = (String) session.getAttribute("distinguishedName"); + model.addAttribute("documentNumber", documentNumber); + model.addAttribute("distinguishedName", distinguishedName); + model.addAttribute("activeTab", "rp-api-v3"); + return new ModelAndView("v3/certificate-choice-result", model); + } + + @GetMapping(value = "/v3/cancel-certificate-choice") + public ModelAndView cancelAuthentication(ModelMap model, HttpServletRequest request) { + resetSession(request); + model.addAttribute("activeTab", "rp-api-v3"); + return new ModelAndView("v3/main", model); + } + + private HttpSession resetSession(HttpServletRequest request) { + HttpSession session = request.getSession(); + if (session != null) { + smartIdV3SessionsStatusService.cancelPolling(session.getId()); + session.invalidate(); + } + // Create a new session + session = request.getSession(true); + return session; + } +} diff --git a/src/main/java/ee/sk/siddemo/services/DynamicContentService.java b/src/main/java/ee/sk/siddemo/services/DynamicContentService.java index 89cc648..90c91a0 100644 --- a/src/main/java/ee/sk/siddemo/services/DynamicContentService.java +++ b/src/main/java/ee/sk/siddemo/services/DynamicContentService.java @@ -31,32 +31,32 @@ public DynamicContentService(SmartIdClient smartIdClientV3) { this.smartIdClientV3 = smartIdClientV3; } - public DynamicContent getDynamicContent(HttpSession session) { + public DynamicContent getDynamicContent(HttpSession session, SessionType sessionType) { String sessionSecret = (String) session.getAttribute("sessionSecret"); String sessionToken = (String) session.getAttribute("sessionToken"); Instant responseReceivedTime = (Instant) session.getAttribute("responseReceivedTime"); - return getDynamicContent(sessionToken, sessionSecret, responseReceivedTime); + return getDynamicContent(sessionType, sessionToken, sessionSecret, responseReceivedTime); } - public DynamicContent getDynamicContent(String sessionToken, String sessionSecret, Instant responseReceivedTime) { + public DynamicContent getDynamicContent(SessionType sessionType, String sessionToken, String sessionSecret, Instant responseReceivedTime) { long elapsedSeconds = Duration.between(responseReceivedTime, Instant.now()).getSeconds(); logger.info("Dynamic content elapsed seconds: {}", elapsedSeconds); DynamicContentBuilder contentBuilder = smartIdClientV3.createDynamicContent() .withBaseUrl(dynamicLinkUrl) - .withSessionType(SessionType.AUTHENTICATION) + .withSessionType(sessionType) .withSessionToken(sessionToken) .withElapsedSeconds(elapsedSeconds); URI dynamicLink = contentBuilder .withDynamicLinkType(DynamicLinkType.WEB_2_APP) - .withAuthCode(AuthCode.createHash(DynamicLinkType.WEB_2_APP, SessionType.AUTHENTICATION, elapsedSeconds, sessionSecret)) + .withAuthCode(AuthCode.createHash(DynamicLinkType.WEB_2_APP, sessionType, elapsedSeconds, sessionSecret)) .createUri(); String qrDataUri = contentBuilder .withDynamicLinkType(DynamicLinkType.QR_CODE) - .withAuthCode(AuthCode.createHash(DynamicLinkType.QR_CODE, SessionType.AUTHENTICATION, elapsedSeconds, sessionSecret)) + .withAuthCode(AuthCode.createHash(DynamicLinkType.QR_CODE, sessionType, elapsedSeconds, sessionSecret)) .createQrCodeDataUri(); return new DynamicContent(dynamicLink, qrDataUri); } diff --git a/src/main/java/ee/sk/siddemo/services/SmartIdV3CertificateChoiceService.java b/src/main/java/ee/sk/siddemo/services/SmartIdV3CertificateChoiceService.java new file mode 100644 index 0000000..bd93540 --- /dev/null +++ b/src/main/java/ee/sk/siddemo/services/SmartIdV3CertificateChoiceService.java @@ -0,0 +1,116 @@ +package ee.sk.siddemo.services; + +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; + +import org.apache.hc.client5.http.utils.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import ee.sk.siddemo.exception.SidOperationException; +import ee.sk.smartid.exception.useraction.SessionTimeoutException; +import ee.sk.smartid.v3.ErrorResultHandler; +import ee.sk.smartid.v3.SmartIdClient; +import ee.sk.smartid.v3.rest.dao.DynamicLinkSessionResponse; +import ee.sk.smartid.v3.rest.dao.SessionResult; +import ee.sk.smartid.v3.rest.dao.SessionStatus; +import jakarta.servlet.http.HttpSession; + +@Service +public class SmartIdV3CertificateChoiceService { + + private static final Logger logger = LoggerFactory.getLogger(SmartIdV3CertificateChoiceService.class); + + private final SmartIdClient smartIdClientV3; + private final SmartIdV3SessionsStatusService smartIdV3SessionsStatusService; + + public SmartIdV3CertificateChoiceService(SmartIdClient smartIdClientV3, + SmartIdV3SessionsStatusService smartIdV3SessionsStatusService) { + this.smartIdClientV3 = smartIdClientV3; + this.smartIdV3SessionsStatusService = smartIdV3SessionsStatusService; + } + + public void startCertificateChoice(HttpSession session) { + // TODO - 16.12.24: uncomment when anonymous certificate choice is supported by RP API v3 +// DynamicLinkSessionResponse response = this.smartIdClientV3.createDynamicLinkCertificateRequest() +// .withCertificateLevel(CertificateLevel.QUALIFIED) +// .withShareMdClientIpAddress(true) +// .initCertificateChoice(); + DynamicLinkSessionResponse response = new DynamicLinkSessionResponse(); + response.setSessionID("fake-session-id"); + response.setSessionToken("fake-token"); + response.setSessionSecret(Base64.encodeBase64String("fake-secret".getBytes(StandardCharsets.UTF_8))); + + Instant responseReceivedTime = Instant.now(); + + session.setAttribute("sessionID", response.getSessionID()); + session.setAttribute("sessionToken", response.getSessionToken()); + session.setAttribute("sessionSecret", response.getSessionSecret()); + session.setAttribute("responseReceivedTime", responseReceivedTime); + + // TODO - 16.12.24: uncomment when anonymous certificate choice session can be created +// smartIdV3SessionsStatusService.startPolling(session, response); + } + + public boolean checkCertificateChoiceStatus(HttpSession session) { + // TODO - 16.12.24: uncomment when anonymous certificate choice is supported by RP API v3 + // Optional sessionStatus = smartIdV3SessionsStatusService.getSessionsStatus(session.getId()); + + // Dummy session status to simulate querying the session status, displaying dynamic sessions for 10seconds + // Remove after RP API v3 supports dynamic-link certificate choice + Instant responseReceivedTime = (Instant) session.getAttribute("responseReceivedTime"); + long elapsedSeconds = Duration.between(responseReceivedTime, Instant.now()).getSeconds(); + SessionStatus status = dummySessionsStatus(elapsedSeconds); + Optional sessionStatus = Optional.of(status); + + return sessionStatus + .map(ss -> { + if (ss.getState().equals("COMPLETE")) { + saveValidateResponse(session, ss); + session.setAttribute("session_status", "COMPLETED"); + logger.debug("Mobile device IP address: {}", ss.getDeviceIpAddress()); + return true; + } + return false; + }) + .orElse(false); + } + + // TODO - 17.12.24: only used for simulating querying the session status, remove after actuall functionality can be used + private static SessionStatus dummySessionsStatus(long elapsedSeconds) { + SessionStatus status; + if (elapsedSeconds > 10) { + SessionResult result = new SessionResult(); + result.setEndResult("OK"); + result.setDocumentNumber("PNOEE-1234567890-MOCK-Q"); + + status = new SessionStatus(); + status.setState("COMPLETE"); + status.setResult(result); + } else { + status = new SessionStatus(); + status.setState("RUNNING"); + } + return status; + } + + private static void saveValidateResponse(HttpSession session, SessionStatus status) { + try { + // validate sessions status does not contain errors + if (!"OK".equals(status.getResult().getEndResult())) { + ErrorResultHandler.handle(status.getResult().getEndResult()); + } + // TODO - 17.12.24: uncomment when anonymous certificate choice is supported by RP API v3 +// X509Certificate certificate = CertificateParser.parseX509Certificate(status.getCert().getValue()); +// String distinguishedName = certificate.getSubjectX500Principal().getName(); + String distinguishedName = "CN=John Doe, OU=IT, O=Company, C=EE"; + session.setAttribute("distinguishedName", distinguishedName); + session.setAttribute("documentNumber", status.getResult().getDocumentNumber()); + } catch (SessionTimeoutException ex) { + throw new SidOperationException("Session timed out", ex); + } + } +} diff --git a/src/main/resources/static/css/style.css b/src/main/resources/static/css/style.css index d7ac9e6..9bfef03 100644 --- a/src/main/resources/static/css/style.css +++ b/src/main/resources/static/css/style.css @@ -1,5 +1,6 @@ -html, body { +body, html { height: 100%; + margin: 0; } body { @@ -10,9 +11,22 @@ body { background-color: #f5f5f5; } +main { + display: flex; + justify-content: center; + align-items: center; + height: 95vh; +} + +.sticky-tabs { + position: sticky; + top: 0; + z-index: 10; + border-bottom: 1px solid #ddd; +} + .content-area { - height: 90vh; - overflow: auto; + overflow: hidden; } .view-content { diff --git a/src/main/resources/templates/v3/certificate-choice-result.html b/src/main/resources/templates/v3/certificate-choice-result.html new file mode 100644 index 0000000..f082606 --- /dev/null +++ b/src/main/resources/templates/v3/certificate-choice-result.html @@ -0,0 +1,27 @@ + + + + + + Smart-ID + + + + + + +
+ +
+

Certificate choice result

+

+ +
+ +

+
+ + + + + \ No newline at end of file diff --git a/src/main/resources/templates/v3/certificate-choice.html b/src/main/resources/templates/v3/certificate-choice.html new file mode 100644 index 0000000..f6b2e14 --- /dev/null +++ b/src/main/resources/templates/v3/certificate-choice.html @@ -0,0 +1,99 @@ + + + + + + Smart-ID + + + + + + + + +
+ +
+
+
+
+

+ Please scan the QR code with the Smart-ID app to proceed +

+
+
+ QR code +
+
+ +
+
+

+ Link option is only meant to work on mobile device where Smart-ID app is installed. + If app is not available on your device, then link should direct you to the app store. +

+
+ +
+
Link content
+
+ +
+
+
+
+ Cancel +
+
+
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/v3/main.html b/src/main/resources/templates/v3/main.html index 79fbf74..e970aef 100644 --- a/src/main/resources/templates/v3/main.html +++ b/src/main/resources/templates/v3/main.html @@ -6,123 +6,263 @@ Smart-ID - +
-
-
-
- -