Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic link signing #7

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
3c7115a
SLIB-66 - make existing code v2 specific; fix cert issues
umuser Nov 19, 2024
e4fedb6
SLIB-66 - add dynamic link authentication
umuser Nov 23, 2024
77c5f28
SLIB-66 - add person code and document number authentications
umuser Nov 26, 2024
d60753c
SLIB-66 - add authentication sessions result validation
umuser Dec 9, 2024
8ed709c
SLIB-66 - update java-client function names
umuser Dec 10, 2024
7e18043
SLIB-66 - update for java-client changes
umuser Dec 10, 2024
57d7616
SLIB-66 - update session status querying and fix showing errors
umuser Dec 13, 2024
632228e
SLIB-66 - add querying IP-address
umuser Dec 13, 2024
54965ff
SLIB-66 - code clean up
umuser Dec 13, 2024
a24e7e8
SLIB-73 - add base for dynamic-link certificate choice
umuser Dec 17, 2024
f2f846d
SLIB-76 - initial changes for notification-based certificate choice
umuser Dec 19, 2024
9192041
SLIB-76 - fix status refresh issues
umuser Jan 27, 2025
cce83b1
merge master into add-notification-based-certificate-choice
umuser Jan 27, 2025
66d6760
SLIB-76 - add querying certificate by document number
umuser Jan 27, 2025
878e392
SLIB-76 - add license headers
umuser Jan 27, 2025
e684e17
SLIB-76 - clean up code
umuser Jan 28, 2025
2cfe322
SLIB-74 - add signing areas
umuser Jan 28, 2025
0c441af
SLIB-74 - add signing with document number
umuser Feb 4, 2025
d066495
SLIB-74 - add signing with person code
umuser Feb 4, 2025
969a5f7
SLIB-74 - fix function names
umuser Feb 4, 2025
eb26eaa
merge master into add-dynamic-link-signing
umuser Feb 5, 2025
5f7c8d8
SLIB-74 - fix cancelling signing
umuser Feb 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/main/java/ee/sk/siddemo/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public ModelAndView handleSidOperationException(SidOperationException exception)

@ExceptionHandler(Exception.class)
public ModelAndView handleSmartIdException(Exception exception) {
logger.warn("Generic error caught", exception);
logger.warn("Generic error caught {}", exception.getMessage());

var model = new ModelMap();
model.addAttribute("errorMessage", exception.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public ModelAndView handleCertificateChoiceSessionsError(@RequestParam(value = "
}

@GetMapping(value = "/v3/dynamic-link/certificate-choice-result")
public ModelAndView getAuthenticationResult(ModelMap model, HttpSession session) {
public ModelAndView toCertificateChoiceResult(ModelMap model, HttpSession session) {
String documentNumber = (String) session.getAttribute("documentNumber");
String distinguishedName = (String) session.getAttribute("distinguishedName");
model.addAttribute("documentNumber", documentNumber);
Expand All @@ -113,7 +113,7 @@ public ModelAndView getAuthenticationResult(ModelMap model, HttpSession session)
}

@GetMapping(value = "/v3/dynamic-link/cancel-certificate-choice")
public ModelAndView cancelAuthentication(ModelMap model, HttpServletRequest request) {
public ModelAndView cancelCertificateChoice(ModelMap model, HttpServletRequest request) {
resetSession(request);
model.addAttribute("activeTab", "rp-api-v3");
return new ModelAndView("v3/main", model);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
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.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import ee.sk.siddemo.exception.SidOperationException;
import ee.sk.siddemo.model.DynamicContent;
import ee.sk.siddemo.model.SigningResult;
import ee.sk.siddemo.model.UserDocumentNumberRequest;
import ee.sk.siddemo.model.UserRequest;
import ee.sk.siddemo.services.DynamicContentService;
import ee.sk.siddemo.services.SmartIdV3DynamicLinkSignatureService;
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 SmartIdV3DynamicLinkSignatureController {

private final Logger logger = LoggerFactory.getLogger(SmartIdV3DynamicLinkSignatureController.class);

private final SmartIdV3DynamicLinkSignatureService smartIdV3DynamicLinkSignatureService;
private final SmartIdV3SessionsStatusService smartIdV3SessionsStatusService;
private final DynamicContentService dynamicContentService;

public SmartIdV3DynamicLinkSignatureController(SmartIdV3DynamicLinkSignatureService smartIdV3DynamicLinkSignatureService,
SmartIdV3SessionsStatusService smartIdV3SessionsStatusService,
DynamicContentService dynamicContentService) {
this.smartIdV3DynamicLinkSignatureService = smartIdV3DynamicLinkSignatureService;
this.smartIdV3SessionsStatusService = smartIdV3SessionsStatusService;
this.dynamicContentService = dynamicContentService;
}

@PostMapping(value = "v3/dynamic-link/start-signing-with-document-number")
public ModelAndView sendDynamicLinkSigningRequestWithDocumentNumber(@ModelAttribute("userDocumentNumberRequest") UserDocumentNumberRequest userDocumentNumberRequest,
BindingResult bindingResult,
ModelMap model,
RedirectAttributes redirectAttributes,
HttpServletRequest request) {
model.addAttribute("activeTab", "rp-api-v3");
if (userDocumentNumberRequest.getFile() == null || userDocumentNumberRequest.getFile().getOriginalFilename() == null || userDocumentNumberRequest.getFile().isEmpty()) {
bindingResult.rejectValue("file", "error.file", "Please select a file to upload");
}

if (bindingResult.hasErrors()) {
logger.debug("Validation errors: {}", bindingResult.getAllErrors());
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.userDocumentNumberRequest", bindingResult);
redirectAttributes.addFlashAttribute("userDocumentNumberRequest", userDocumentNumberRequest);
return new ModelAndView("redirect:/rp-api-v3");
}
HttpSession session = resetSession(request);
smartIdV3DynamicLinkSignatureService.startSigningWithDocumentNumber(session, userDocumentNumberRequest);
return new ModelAndView("v3/dynamic-link/signing", model);
}

@PostMapping(value = "v3/dynamic-link/start-signing-with-person-code")
public ModelAndView sendDynamicLinkSigningRequestWithPersonCode(@ModelAttribute("userRequest") UserRequest userRequest,
BindingResult bindingResult,
ModelMap model,
RedirectAttributes redirectAttributes,
HttpServletRequest request) {
model.addAttribute("activeTab", "rp-api-v3");
if (userRequest.getFile() == null || userRequest.getFile().getOriginalFilename() == null || userRequest.getFile().isEmpty()) {
bindingResult.rejectValue("file", "error.file", "Please select a file to upload");
}

if (bindingResult.hasErrors()) {
logger.debug("Validation errors: {}", bindingResult.getAllErrors());
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.userRequest", bindingResult);
redirectAttributes.addFlashAttribute("userRequest", userRequest);
return new ModelAndView("redirect:/rp-api-v3");
}
HttpSession session = resetSession(request);
smartIdV3DynamicLinkSignatureService.startSigningWithPersonCode(session, userRequest);
return new ModelAndView("v3/dynamic-link/signing", model);
}

@GetMapping(value = "v3/dynamic-link/check-signing-status")
@ResponseBody
public ResponseEntity<Map<String, String>> checkSigningStatus(HttpSession session) {
boolean checkCompleted;
try {
checkCompleted = smartIdV3DynamicLinkSignatureService.checkSignatureStatus(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"));
}

logger.debug("Generate dynamic content for session {}", session.getId());
DynamicContent dynamicContent = dynamicContentService.getDynamicContent(session, SessionType.SIGNATURE);
Map<String, String> content = new HashMap<>();
content.put("dynamicLink", dynamicContent.getDynamicLink().toString());
content.put("qrCode", dynamicContent.getQrCode());
return ResponseEntity.ok(content);
}

@GetMapping(value = "/v3/dynamic-link/sign-session-error")
public ModelAndView handleSigningSessionError(@RequestParam(value = "errorMessage", required = false) String errorMessage,
ModelMap model) {
model.addAttribute("errorMessage", errorMessage);
model.addAttribute("activeTab", "rp-api-v3");
return new ModelAndView("sidOperationError", model);
}

@GetMapping(value = "/v3/dynamic-link/signing-result")
public ModelAndView toSigningResult(ModelMap model, HttpSession session) {
SigningResult signingResult = smartIdV3DynamicLinkSignatureService.handleSignatureResult(session);
model.addAttribute("signingResult", signingResult);
model.addAttribute("activeTab", "rp-api-v3");
return new ModelAndView("v3/dynamic-link/signing-result", model);
}

@GetMapping(value = "/v3/dynamic-link/cancel-signing")
public ModelAndView cancelSigning(ModelMap model, HttpServletRequest request) {
resetSession(request);
return new ModelAndView("redirect:/rp-api-v3", 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public ResponseEntity<Map<String, String>> checkCertificateChoiceStatus(HttpSess
}

@GetMapping(value = "/v3/notification-based/certificate-choice-result")
public ModelAndView getAuthenticationResult(ModelMap model, HttpSession session) {
public ModelAndView toCertificateChoiceResult(ModelMap model, HttpSession session) {
String distinguishedName = (String) session.getAttribute("distinguishedName");
if (distinguishedName == null) {
return new ModelAndView("v3/main", model);
Expand All @@ -117,7 +117,7 @@ public ModelAndView getAuthenticationResult(ModelMap model, HttpSession session)
}

@GetMapping(value = "/v3/notification-based/cancel-certificate-choice")
public ModelAndView cancelAuthentication(ModelMap model, HttpServletRequest request) {
public ModelAndView cancelCertificateChoice(ModelMap model, HttpServletRequest request) {
resetSession(request);
model.addAttribute("activeTab", "rp-api-v3");
return new ModelAndView("v3/main", model);
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/ee/sk/siddemo/model/UserDocumentNumberRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
* #L%
*/

import org.springframework.web.multipart.MultipartFile;

import jakarta.validation.constraints.NotNull;

public class UserDocumentNumberRequest {

@NotNull
private String documentNumber;
private MultipartFile file;

public String getDocumentNumber() {
return documentNumber;
Expand All @@ -36,4 +39,12 @@ public String getDocumentNumber() {
public void setDocumentNumber(String documentNumber) {
this.documentNumber = documentNumber;
}

public MultipartFile getFile() {
return file;
}

public void setFile(MultipartFile file) {
this.file = file;
}
}
Loading