BackupResource { @Timed @ExceptionMetered @GET @Path("{key}/group/{group}") @Produces(APPLICATION_OCTET_STREAM) public byte[] backup( @Auth AutomationClient automationClient, @PathParam("group") String name, @PathParam("key") String key) { if (config.getBackupExportKey(key) == null) { throw new NotFoundException("Unknown key: " + key); } Optional<Group> groupOptional = groupDAO.getGroup(name); if (!groupOptional.isPresent()) { throw new NotFoundException("Unknown group: " + name); } Group group = groupOptional.get(); List<SecretDeliveryResponse> secrets = secretController.getSecretsForGroup(group).stream() .map(SecretDeliveryResponse::fromSecret) .collect(toList()); String serialized; try { serialized = objectMapper.writeValueAsString(secrets); } catch (JsonProcessingException e) { logger.error("Unable to backup secrets", e); throw new InternalServerErrorException("Unable to backup secrets, check logs for details"); } Map<String, String> auditInfo = secrets.stream() .collect(toMap(SecretDeliveryResponse::getName, SecretDeliveryResponse::getChecksum)); auditLog.recordEvent(new Event( now(), GROUP_BACKUP, automationClient.getName(), group.getName(), auditInfo)); try { Key exportKey = new Key(config.getBackupExportKey(key)); Encryptor encryptor = new Encryptor(exportKey); encryptor.setEncryptionAlgorithm(AES256); encryptor.setSigningAlgorithm(Unsigned); encryptor.setCompressionAlgorithm(ZIP); ByteArrayInputStream plaintext = new ByteArrayInputStream(serialized.getBytes(UTF_8)); ByteArrayOutputStream ciphertext = new ByteArrayOutputStream(); encryptor.encrypt(plaintext, ciphertext, new FileMetadata(format("%s.json", group), UTF8)); return ciphertext.toByteArray(); } catch (PGPException | IOException e) { logger.error("Unable to backup secrets", e); throw new InternalServerErrorException("Unable to backup secrets, check logs for details"); } } @Inject  BackupResource(
      GroupDAOFactory groupDAOFactory,
      @Readonly SecretController secretController,
      ObjectMapper objectMapper,
      KeywhizConfig config,
      AuditLog auditLog); @Timed @ExceptionMetered @GET @Path("{key}/group/{group}") @Produces(APPLICATION_OCTET_STREAM) byte[] backup(
      @Auth AutomationClient automationClient,
      @PathParam("group") String name,
      @PathParam("key") String key);  }
@Test public void backupInvalidKey() throws Exception { Response httpResponse = backup("asdf", "Blackops"); assertThat(httpResponse.code()).isEqualTo(404); }
@Test public void backupInvalidGroup() throws Exception { Response httpResponse = backup("test", "asdf"); assertThat(httpResponse.code()).isEqualTo(404); }
@Test public void backupSuccess() throws Exception { Response httpResponse = backup("test", "Blackops"); assertThat(httpResponse.code()).isEqualTo(200); InputStream ciphertext = httpResponse.body().byteStream(); ByteArrayOutputStream plaintext = new ByteArrayOutputStream(); Key key = new Key(TEST_EXPORT_KEY_PRIVATE, "password"); Decryptor decryptor = new Decryptor(key); decryptor.setVerificationRequired(false); decryptor.decrypt(ciphertext, plaintext); List<SecretDeliveryResponse> output = mapper.readValue( plaintext.toByteArray(), new TypeReference<List<SecretDeliveryResponse>>() {}); assertThat(output) .extracting(SecretDeliveryResponse::getName) .containsExactlyInAnyOrder("Hacking_Password", "General_Password"); assertThat(output) .extracting(SecretDeliveryResponse::getSecret) .allMatch(s -> !Strings.isNullOrEmpty(s)); }