From 08aeafe0eb737cbfb47b90aa66a20965dff3c113 Mon Sep 17 00:00:00 2001 From: CharlesShuller Date: Fri, 20 Oct 2023 17:37:57 -0500 Subject: [PATCH] Add specific version for lombok and improved logging of Java Springboot Example (#371) * Add specific version for lombok * Added better logging --- .gitignore | 1 + examples/java-springboot/pom.xml | 15 ++++++ .../didkitexample/config/WebConfig.java | 2 +- .../controller/CredentialOfferController.java | 7 +++ ...rifiablePresentationRequestController.java | 16 ++++++ .../controller/VersionController.java | 6 +++ .../didkitexample/user/UserController.java | 9 ++++ .../util/VerifiablePresentation.java | 53 ++++++++++++++++--- 8 files changed, 101 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index a2928941..419a17b2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target Cargo.lock __pycache__/ +*~ \ No newline at end of file diff --git a/examples/java-springboot/pom.xml b/examples/java-springboot/pom.xml index 3dd6bb8b..b2c7762b 100644 --- a/examples/java-springboot/pom.xml +++ b/examples/java-springboot/pom.xml @@ -69,6 +69,7 @@ org.projectlombok lombok true + 1.18.20 @@ -89,6 +90,20 @@ system ${basedir}/didkit.jar + + + org.apache.logging.log4j + log4j-api + 2.21.0 + + + + org.apache.logging.log4j + log4j-core + 2.21.0 + + + diff --git a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/config/WebConfig.java b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/config/WebConfig.java index 640b90d3..5123d983 100644 --- a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/config/WebConfig.java +++ b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/config/WebConfig.java @@ -3,10 +3,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.slf4j.Logger; @Configuration public class WebConfig { - @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); diff --git a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/CredentialOfferController.java b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/CredentialOfferController.java index 4208a7fe..3208a85b 100644 --- a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/CredentialOfferController.java +++ b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/CredentialOfferController.java @@ -25,11 +25,16 @@ import java.util.Map; import java.util.UUID; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + @RestController @AllArgsConstructor public class CredentialOfferController { private final UserService userService; private final StringRedisTemplate redisTemplate; + private static Logger logger = LogManager.getLogger(); private static final DateTimeFormatter dateFormat = DateTimeFormatter.ISO_INSTANT.withZone(ZoneId.from(ZoneOffset.UTC)); @@ -40,6 +45,7 @@ public CredentialOffer credentialOfferGet( final Resource keyFile; final String key; final String issuer; + logger.info("GET /credential-offer/" + token); try { keyFile = new FileSystemResource(Resources.key); @@ -93,6 +99,7 @@ public Map credentialOfferPost( @PathVariable("token") String token, @RequestParam("subject_id") String did ) throws Exception { + logger.info("/credential-offer/" + token); final String username = redisTemplate.opsForValue().get(token); final User user = (User) userService.loadUserByUsername(username); diff --git a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VerifiablePresentationRequestController.java b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VerifiablePresentationRequestController.java index b9c8e17b..b5f7df72 100644 --- a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VerifiablePresentationRequestController.java +++ b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VerifiablePresentationRequestController.java @@ -29,12 +29,16 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + @RestController @AllArgsConstructor public class VerifiablePresentationRequestController { private final UserService userService; private final StringRedisTemplate redisTemplate; + private static Logger logger = LogManager.getLogger(); @Autowired private final ConcurrentHashMap sessionMap; @@ -43,6 +47,7 @@ public class VerifiablePresentationRequestController { public VerifiablePresentationRequest vpRequestGet( @PathVariable("challenge") String challenge ) { + logger.info("GET /verifiable-presentation-request/" + challenge); return new VerifiablePresentationRequest( "VerifiablePresentationRequest", Collections.singletonList(new VerifiablePresentationRequestQuery( @@ -66,20 +71,25 @@ public void vpRequestPost( @PathVariable("challenge") String challenge, @RequestParam("presentation") String presentation ) throws Exception { + logger.info("POST /verifiable-presentation-request/" + challenge); final Resource keyFile; final String key; + logger.info("Attempting to load key"); try { keyFile = new FileSystemResource(Resources.key); key = Files.readString(keyFile.getFile().toPath()); } catch (Exception e) { + logger.error("POST verifiable-presentation-request failed to load key"); throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to load key"); } + logger.info("VerifiablePresentation.verifyPresentation"); final Map vc = VerifiablePresentation.verifyPresentation(key, presentation, challenge); final Map credentialSubject = (Map) vc.get("credentialSubject"); final String username = credentialSubject.get("alumniOf").toString(); + logger.info("userService.loadUserByUsername"); final User user = (User) userService.loadUserByUsername(username); final String uuid = UUID.randomUUID().toString(); @@ -87,14 +97,20 @@ public void vpRequestPost( redisTemplate.expire(uuid, Duration.ofSeconds(90)); if (sessionMap.containsKey(challenge)) { + logger.info("SessionMap has a challenge"); try { + logger.info("Trying to send message"); sessionMap.get(challenge).sendMessage(new TextMessage(uuid)); } catch (Exception e) { + logger.error("POST Failed to return sign in token"); throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to return sign in token"); } sessionMap.remove(challenge); } else { + logger.info("SessionMap does not have a challenge"); + logger.error("POST invalid or expired token"); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid or expired token"); } + logger.info("Success"); } } diff --git a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VersionController.java b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VersionController.java index f5d7498b..4bade413 100644 --- a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VersionController.java +++ b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/controller/VersionController.java @@ -4,11 +4,17 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + @RestController public class VersionController { + private static Logger logger = LogManager.getLogger(); @RequestMapping("/version") public String version() { + logger.info("GET /version"); return DIDKit.getVersion(); } } diff --git a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/user/UserController.java b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/user/UserController.java index f253b68e..21f87fb7 100644 --- a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/user/UserController.java +++ b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/user/UserController.java @@ -14,6 +14,9 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import java.time.Duration; import java.util.UUID; @@ -22,20 +25,24 @@ public class UserController { private final UserService userService; private final StringRedisTemplate redisTemplate; + private static Logger logger = LogManager.getLogger(); @GetMapping("/sign-up") String signUpGet(User user) { + logger.info("GET /sign-up"); return "sign-up"; } @PostMapping("/sign-up") String signUpPost(User user) { + logger.info("POST /sign-up"); userService.signUp(user); return "redirect:/sign-in"; } @GetMapping("/sign-in") ModelAndView signIn() throws Exception { + logger.info("GET /sign-in"); final String uuid = UUID.randomUUID().toString(); final String url = "https://" + Resources.baseUrl + "/verifiable-presentation-request/" + uuid; final ModelAndView model = QRCode.getModelAndView("sign-in", url); @@ -47,6 +54,7 @@ ModelAndView signIn() throws Exception { ModelAndView credential( @AuthenticationPrincipal User user ) throws Exception { + logger.info("GET /credential"); final String uuid = UUID.randomUUID().toString(); redisTemplate.opsForValue().set(uuid, user.getUsername()); redisTemplate.expire(uuid, Duration.ofSeconds(90)); @@ -60,6 +68,7 @@ ModelAndView credentialOffer( @RequestParam("did") String did, ModelAndView model ) throws Exception { + logger.info("POST /credential"); final String credential = userService.issueCredential(did, user); model.addObject("credential", credential); return model; diff --git a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/util/VerifiablePresentation.java b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/util/VerifiablePresentation.java index 967021c7..a9b4b1cc 100644 --- a/examples/java-springboot/src/main/java/com/spruceid/didkitexample/util/VerifiablePresentation.java +++ b/examples/java-springboot/src/main/java/com/spruceid/didkitexample/util/VerifiablePresentation.java @@ -6,21 +6,31 @@ import org.springframework.http.HttpStatus; import org.springframework.web.server.ResponseStatusException; +import java.util.AbstractList; import java.util.List; import java.util.Map; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + + public class VerifiablePresentation { + private static Logger logger = LogManager.getLogger(); + public static Map verifyPresentation( final String key, final String presentation, final String challenge ) throws Exception { + logger.info("Converting String VP into Map"); + logger.info("VP: " + presentation); final ObjectMapper mapper = new ObjectMapper(); - final Map presentationMap = mapper.readValue(presentation, new TypeReference<>() { - }); + final Map presentationMap = + mapper.readValue(presentation, new TypeReference<>() {}); - return VerifiablePresentation.verifyPresentation(key, presentationMap, challenge); + return VerifiablePresentation + .verifyPresentation(key, presentationMap, challenge); } public static Map verifyPresentation( @@ -28,6 +38,8 @@ public static Map verifyPresentation( final Map presentation, final String challenge ) { + logger.info("Attempting to verify Map presentation"); + final ObjectMapper mapper = new ObjectMapper(); try { @@ -40,20 +52,29 @@ public static Map verifyPresentation( final String vpStr = mapper.writeValueAsString(presentation); final String optionsStr = mapper.writeValueAsString(options); + logger.info("vpStr: " + vpStr); + logger.info("optionsStr: " + optionsStr); + + final String result = DIDKit.verifyPresentation(vpStr, optionsStr); - final Map resultMap = mapper.readValue(result, new TypeReference<>() { - }); + logger.info("DIDKit.verifyPresentation result: " + result); + final Map resultMap = + mapper.readValue(result, new TypeReference<>() { }); if (((List) resultMap.get("errors")).size() > 0) { - System.out.println("[ERROR] VP: " + resultMap.get("errors")); + logger.error("VP: " + resultMap.get("errors")); throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid presentation"); } } catch (Exception e) { + logger.error("Failed to verify presentation: " + e.toString()); throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Failed to verify presentation"); } + //Select the first vc if we have multiple in the presentation final Object vcs = presentation.get("verifiableCredential"); - final Map vc = (Map) (vcs instanceof Object[] ? ((Object[]) vcs)[0] : vcs); + logger.info("vcs type: " + vcs.getClass()); + //final Map vc = (Map) (vcs instanceof Object[] ? ((Object[]) vcs)[0] : vcs); + final Map vc = getFirstVc(vcs); try { final DIDKitOptions options = new DIDKitOptions( @@ -79,4 +100,22 @@ public static Map verifyPresentation( return vc; } + + private static Map getFirstVc(Object vcs) { + + if(vcs instanceof Object[]) { + Object r = ((Object[]) vcs)[0]; + logger.info("r type: " + r.getClass()); + return (Map) r; + } + else if(vcs instanceof AbstractList) { + Object r = ((AbstractList) vcs).get(0); + logger.info("r type: " + r.getClass()); + return (Map) r; + } + else { + logger.info("vc type: " + vcs.getClass()); + return (Map) vcs; + } + } }