From 6d83f5614a5273ff53f1ddc5f4c614460e228993 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 30 Jan 2019 16:40:15 +0300 Subject: fix user deletion flow when invalid key is present --- .../java/com/juick/server/SignatureManager.java | 45 +++++++++++----------- .../com/juick/server/api/activity/Profile.java | 4 +- .../HTTPSignatureAuthenticationFilter.java | 25 ++++++------ .../java/com/juick/server/tests/ServerTests.java | 7 +++- 4 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/juick/server/SignatureManager.java b/src/main/java/com/juick/server/SignatureManager.java index 032f71ee..c863ae0f 100644 --- a/src/main/java/com/juick/server/SignatureManager.java +++ b/src/main/java/com/juick/server/SignatureManager.java @@ -86,32 +86,33 @@ public class SignatureManager { public User verifySignature(String method, String path, Map headers) { String signatureString = headers.get("signature"); - if (StringUtils.isNotEmpty(signatureString)) { - logger.info("Signature: {}", signatureString); - Signature signature = Signature.fromString(signatureString); - Optional context = getContext(URI.create(signature.getKeyId())); - if (context.isPresent() && context.get() instanceof Person) { - Person person = (Person) context.get(); - Key key = KeystoreManager.publicKeyOf(person); + logger.info("Signature: {}", signatureString); + Signature signature = Signature.fromString(signatureString); + Optional context = getContext(UriComponentsBuilder.fromUriString(signature.getKeyId()) + .fragment(null).build().toUri()); + if (context.isPresent() && context.get() instanceof Person) { + Person person = (Person) context.get(); + Key key = KeystoreManager.publicKeyOf(person); - Verifier verifier = new Verifier(key, signature); - try { - boolean result = verifier.verify(method, path, headers); - logger.info("signature of {} is valid: {}", signature.getKeyId(), result); - if (result) { - User user = new User(); - user.setUri(URI.create(person.getId())); - if (key.equals(keystoreManager.getPublicKey())) { - return userService.getUserByName(person.getName()); - } - return user; - } else { - return AnonymousUser.INSTANCE; + Verifier verifier = new Verifier(key, signature); + try { + boolean result = verifier.verify(method, path, headers); + logger.info("signature of {} is valid: {}", signature.getKeyId(), result); + if (result) { + User user = new User(); + user.setUri(URI.create(person.getId())); + if (key.equals(keystoreManager.getPublicKey())) { + return userService.getUserByName(person.getName()); } - } catch (NoSuchAlgorithmException | SignatureException | IOException e) { - logger.warn("Invalid signature {}", signatureString); + return user; + } else { + return AnonymousUser.INSTANCE; } + } catch (NoSuchAlgorithmException | SignatureException | IOException e) { + logger.warn("Invalid signature {}", signatureString); } + } else { + logger.warn("Unknown keyId"); } return AnonymousUser.INSTANCE; } diff --git a/src/main/java/com/juick/server/api/activity/Profile.java b/src/main/java/com/juick/server/api/activity/Profile.java index ff9df4fc..bd8b9ea8 100644 --- a/src/main/java/com/juick/server/api/activity/Profile.java +++ b/src/main/java/com/juick/server/api/activity/Profile.java @@ -358,9 +358,7 @@ public class Profile { if (activity.getObject() instanceof String) { // Delete gone user if (activity.getActor().equals(activity.getObject())) { - if (signatureManager.getContext(URI.create(activity.getActor())).isEmpty()) { - return new ResponseEntity<>(HttpStatus.ACCEPTED); - } + return new ResponseEntity<>(HttpStatus.ACCEPTED); } } } diff --git a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java index 3fb16dce..22dc3b9c 100644 --- a/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java +++ b/src/main/java/com/juick/service/security/HTTPSignatureAuthenticationFilter.java @@ -4,6 +4,7 @@ import com.juick.User; import com.juick.server.SignatureManager; import com.juick.service.UserService; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -40,17 +41,19 @@ public class HTTPSignatureAuthenticationFilter extends OncePerRequestFilter { Map headers = Collections.list(request.getHeaderNames()) .stream() .collect(Collectors.toMap(String::toLowerCase, request::getHeader)); - User user = signatureManager.verifySignature(request.getMethod(), request.getRequestURI(), headers); - if (!user.isAnonymous()) { - String userUri = user.getUri().toString(); - if (userUri.length() == 0) { - User userWithPassword = userService.getUserByName(user.getName()); - userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid())); - Authentication authentication = new UsernamePasswordAuthenticationToken(userWithPassword.getName(), userWithPassword.getCredentials()); - SecurityContextHolder.getContext().setAuthentication(authentication); - } else { - Authentication authentication = new AnonymousAuthenticationToken(userUri, user, Collections.singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS"))); - SecurityContextHolder.getContext().setAuthentication(authentication); + if (StringUtils.isNotEmpty(headers.get("signature"))) { + User user = signatureManager.verifySignature(request.getMethod(), request.getRequestURI(), headers); + if (!user.isAnonymous()) { + String userUri = user.getUri().toString(); + if (userUri.length() == 0) { + User userWithPassword = userService.getUserByName(user.getName()); + userWithPassword.setAuthHash(userService.getHashByUID(userWithPassword.getUid())); + Authentication authentication = new UsernamePasswordAuthenticationToken(userWithPassword.getName(), userWithPassword.getCredentials()); + SecurityContextHolder.getContext().setAuthentication(authentication); + } else { + Authentication authentication = new AnonymousAuthenticationToken(userUri, user, Collections.singletonList(new SimpleGrantedAuthority("ROLE_ANONYMOUS"))); + SecurityContextHolder.getContext().setAuthentication(authentication); + } } } } diff --git a/src/test/java/com/juick/server/tests/ServerTests.java b/src/test/java/com/juick/server/tests/ServerTests.java index 5ee8b1f4..1e56668d 100644 --- a/src/test/java/com/juick/server/tests/ServerTests.java +++ b/src/test/java/com/juick/server/tests/ServerTests.java @@ -1896,12 +1896,17 @@ public class ServerTests { Delete delete = jsonMapper.readValue(deleteJsonStr, Delete.class); ClientHttpRequestFactory originalRequestFactory = apClient.getRequestFactory(); MockRestServiceServer restServiceServer = MockRestServiceServer.createServer(apClient); - restServiceServer.expect(times(1), requestTo((String)delete.getObject())) + restServiceServer.expect(times(2), requestTo((String)delete.getObject())) .andRespond(withStatus(HttpStatus.GONE)); mockMvc.perform(post("/api/inbox") .contentType(ACTIVITY_MEDIA_TYPE) .content(deleteJsonStr)) .andExpect(status().isAccepted()); + mockMvc.perform(post("/api/inbox") + .contentType(ACTIVITY_MEDIA_TYPE) + .content(deleteJsonStr) + .header("Signature", "keyId=\"https://example.com/users/deleted#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"wHoU91JJBsIYcR1W1/57B0oG98t5Aa/TvGPw1B8KQlAp5KhpePnOzD1MZRgivBx7YKO6eYwDx+AX9dn6tjlAvzRLygv21H6UoDZFihWzeE1HM8pY2Pe4EhUgYBN0YuiKUi7W4TS9bDRAJ5vGNPUWATe+2o5Jcbux5cZYXFKKYbLBLD+/IlqPdHA2IXLZ52HFVVfBkPH5sSklV6XJtD/PHLK9R/I9w/mUpj9moUPQu44rR7KvxiGNuHla3vfDtJbkBqLMdScX91EG8373AulXPUiCCF7R2lJB0fFQedm2nSbcwBoJ32GEyOyOPFgPKG5zd9Fd5TfB1pmA8ZIE0sChfA==\"")) + .andExpect(status().isAccepted()); apClient.setRequestFactory(originalRequestFactory); } } -- cgit v1.2.3