public static AccountabilityManager getAccountabilityManager(Properties accountabilityConfiguration) throws AccountabilityException { boolean requiresRecreation = false; // if any of the relevant configurations is changed, we need a new instance! if (activeProperties != null) { requiresRecreation = checkIfChanged(accountabilityConfiguration); } if (Objects.isNull(accountabilityManager) || requiresRecreation) { BlockchainFactory.reset(); ImmutableStorageProviderFactory.reset(); // if there is an older accountability manager, we should shut it down if (!Objects.isNull(accountabilityManager)) { accountabilityManager.close(); } try { BlockchainAccess blockchain = BlockchainFactory.getBlockchainAccess(BlockchainFactory.AvailableBlockchains.ETHEREUM, accountabilityConfiguration); ImmutableStorageProvider storageProvider = ImmutableStorageProviderFactory.getStorageProvider(ImmutableStorageProviderFactory.AvailableImmutableStorages.SWARM, accountabilityConfiguration); accountabilityManager = new AccountabilityManagerImpl(blockchain, storageProvider); copyProperties(accountabilityConfiguration); } catch (BlockchainException e) { String msg = "Could not instantiate accountability layer: " + e.getMessage(); LOGGER.error(msg, e); throw new AccountabilityException(msg, e); } } return accountabilityManager; }
private List<ModelProvenanceElement> enhanceHistoryElements(List<ModelProvenanceElement> historyElements, AuthorizationInfo authorizationInfo) { historyElements.forEach(element -> { element.setAuthorizedFlag(authorizationInfo); element.setAuthorName( authorizationInfo != null ? authorizationInfo.getRealWorldIdentity( element.getAuthorAddress()).orElseGet(String::new) : "" ); this.fillFilesOfModel(element); }); return historyElements; }
protected Map<String, ProvenanceVerification> validateBlockchainInput(List<ModelProvenanceElement> historyElements, String manifestId, Map<String, File> files, AuthorizationInfo authorizationInfo) throws IOException, NoSuchAlgorithmException { LOGGER.info("Start validating..."); Map<String, ProvenanceVerification> verificationMap = new HashMap<>(); ModelProvenanceElement validHistoryElement = verifyManifest(historyElements, manifestId, files, verificationMap, authorizationInfo); if (Objects.nonNull(validHistoryElement) && verificationMap.get(manifestId) == VERIFIED) { verifyFiles(validHistoryElement, files, verificationMap); } LOGGER.info("Completed validation."); return verificationMap; }
@Override public CompletableFuture<List<FileProvenanceElement>> getHistory(String processIdentifier, String fileId) { CompletableFuture<AuthorizationInfo> authorizationTree = this.blockchain.getAuthorizationTree(processIdentifier); return this.blockchain .getProvenance(processIdentifier) .thenCombine(authorizationTree, (provenanceElements, authorizationInfo) -> { List<FileProvenanceElement> result; if (authorizationInfo != null) { result = getHistoryOfSingleFile(provenanceElements, fileId, authorizationInfo); } else { LOGGER.info(NO_AUTHORIZATION_DATA); FileProvenanceElement historyElement = new FileProvenanceElement("", 0, NO_AUTHORIZATION_DATA); historyElement.setAuthorized(false); historyElement.setFileName(fileId); result = Collections.singletonList(historyElement); } return result; }); }
@POST @Path("authorize") @Consumes(MediaType.APPLICATION_JSON) public String addParticipant(AuthorizationNode participant) { try { return getAccountabilityManager() .authorize(Util.URLdecode(Util.URLdecode(provenanceId)), participant.getAddress(), participant.getIdentity()) .exceptionally(error -> null) .get(); } catch (InterruptedException | ExecutionException | AccountabilityException e) { LOGGER.error("Cannot authorize participant {}. Reason: {}", participant.getAddress(), e.getMessage()); throw createException(e); } }
private boolean isValid(ImportMetaInformation metaInformation, Map<String, File> fileMap) throws ExecutionException, InterruptedException, AccountabilityException { ServiceTemplateId entryServiceTemplate = metaInformation.entryServiceTemplate; metaInformation.verificationMap = new HashMap<>(); if (Objects.nonNull(entryServiceTemplate)) { Properties props = RepositoryFactory.getRepository().getAccountabilityConfigurationManager().properties; AccountabilityManager accountabilityManager = AccountabilityManagerFactory.getAccountabilityManager(props); String provenanceIdentifier = VersionUtils.getQNameWithComponentVersionOnly(entryServiceTemplate); metaInformation.verificationMap = accountabilityManager .verify(provenanceIdentifier, "TOSCA-Metadata/TOSCA.meta", fileMap) .exceptionally(e -> { LOGGER.debug("accountabilityManager.verify completed exceptionally", e); return null; }) .get(); return metaInformation.verificationMap.values().stream().allMatch(v -> v == ProvenanceVerification.VERIFIED); } return false; }
/** * Stores all files listed in the map in the immutable file storage, and updates the CsarContentProperties of each * file to contain its address in the aforementioned storage. * * @param filesToStore a map of the CsarContentProperties of all files to be stored in the CSAR and their contents. */ private void immutablyStoreRefFiles(Map<CsarContentProperties, CsarEntry> filesToStore, IRepository repository) throws AccountabilityException, ExecutionException, InterruptedException, IOException { Properties props = repository.getAccountabilityConfigurationManager().properties; AccountabilityManager manager = AccountabilityManagerFactory.getAccountabilityManager(props); Map<String, InputStream> filesMap = new HashMap<>(); for (Map.Entry<CsarContentProperties, CsarEntry> entry : filesToStore.entrySet()) { filesMap.put(entry.getKey().getPathInsideCsar(), entry.getValue().getInputStream()); } // store all files in immutable storage (already stored files will get their same old address) Map<String, String> addressMap = manager .storeState(filesMap) .get(); filesToStore.keySet().forEach((CsarContentProperties properties) -> { properties.setImmutableAddress(addressMap.get(properties.getPathInsideCsar())); }); }
public CompletableFuture<String> writeCsarAndSaveManifestInProvenanceLayer(IRepository repository, DefinitionsChildId entryId, OutputStream out) throws IOException, RepositoryCorruptException, AccountabilityException, InterruptedException, ExecutionException { LocalDateTime start = LocalDateTime.now(); Properties props = repository.getAccountabilityConfigurationManager().properties; AccountabilityManager accountabilityManager = AccountabilityManagerFactory.getAccountabilityManager(props); Map<String, Object> exportConfiguration = new HashMap<>(); exportConfiguration.put(CsarExportConfiguration.INCLUDE_HASHES.name(), null); exportConfiguration.put(CsarExportConfiguration.STORE_IMMUTABLY.name(), null); String manifestString = this.writeCsar(repository, entryId, out, exportConfiguration); String qNameWithComponentVersionOnly = VersionUtils.getQNameWithComponentVersionOnly(entryId); LOGGER.debug("Preparing CSAR export (provenance) lasted {}", Duration.between(LocalDateTime.now(), start).toString()); return accountabilityManager.storeFingerprint(qNameWithComponentVersionOnly, manifestString); }
@Override public CompletableFuture<Map<String, ProvenanceVerification>> verify(String processIdentifier, String manifestId, Map<String, File> files) { Objects.requireNonNull(processIdentifier); Objects.requireNonNull(manifestId); Objects.requireNonNull(files); LOGGER.info("Verifying process id: " + processIdentifier); CompletableFuture<AuthorizationInfo> authorizationTree = this.blockchain.getAuthorizationTree(processIdentifier); return this.blockchain .getProvenance(processIdentifier) .thenCombine(authorizationTree, (provenanceElements, authorizationInfo) -> { // TODO: extract into one method and write test cases Map<String, ProvenanceVerification> map = null; try { if (authorizationInfo == null) { LOGGER.info(NO_AUTHORIZATION_DATA); map = new HashMap<>(); map.put(manifestId, NO_AUTHORIZATION_DATA_AVAILABLE); } else { map = this.validateBlockchainInput(provenanceElements, manifestId, files, authorizationInfo); } } catch (NoSuchAlgorithmException e) { LOGGER.error("Could not find the hashing algorithm.", e); } catch (IOException e) { LOGGER.error("Could not transform file to byte array.", e); } catch (SerializationException e) { LOGGER.error("Could not deserialize stored manifest file.", e); } return map; }); }
private static AccountabilityManager getAccountabilityManager() throws AccountabilityException { Properties props = RepositoryFactory.getRepository().getAccountabilityConfigurationManager().properties; return AccountabilityManagerFactory.getAccountabilityManager(props); }
@GET @Path("authenticate") @Produces(MediaType.APPLICATION_JSON) public List<AuthorizationNode> getAuthentication(@QueryParam("participantAddress") String participantAddress) { AuthorizationInfo authorizationInfo; try { authorizationInfo = getAccountabilityManager() .getAuthorization(provenanceId) .exceptionally(error -> null) .get(); } catch (InterruptedException | ExecutionException | AccountabilityException e) { LOGGER.error("Cannot authenticate participant {}. Reason: {}", participantAddress, e.getMessage()); throw createException(e); } if (Objects.nonNull(authorizationInfo)) { return authorizationInfo .getAuthorizationLineage(participantAddress) .orElseGet(ArrayList::new); } return new ArrayList<>(); }
@GET @Path("modelHistory") @Produces(MediaType.APPLICATION_JSON) public List<ModelProvenanceElement> getModelHistory() { ServiceTemplateId serviceTemplateId = new ServiceTemplateId(new QName(provenanceId)); String qNameWithComponentVersionOnly = VersionUtils.getQNameWithComponentVersionOnly(serviceTemplateId); try { return getAccountabilityManager() .getHistory(qNameWithComponentVersionOnly) .exceptionally(error -> null) .get(); } catch (InterruptedException | ExecutionException | AccountabilityException e) { LOGGER.error("Cannot get history of model. Reason: {}", e.getMessage()); throw createException(e); } }
@GET @Path("retrieveFile") @Produces(MediaType.TEXT_PLAIN) public Response retrieveFileFromImmutableStorage(@QueryParam("address") String address) { try (InputStream data = getAccountabilityManager().retrieveState(address).get()) { String fileAsString = IOUtils.toString(data, Charset.defaultCharset().toString()); return Response .ok(fileAsString, MediaType.TEXT_PLAIN) .build(); } catch (IOException | InterruptedException | ExecutionException | AccountabilityException e) { LOGGER.error("Cannot retrieve file ({}) from immutable storage. Reason: {}", address, e.getMessage()); throw createException(e); } } }
protected void verifyFiles(ModelProvenanceElement validHistoryElement, Map<String, File> files, Map<String, ProvenanceVerification> verificationMap) throws SerializationException, IOException, NoSuchAlgorithmException { LOGGER.info("Start validating files..."); for (Map.Entry<String, File> entry : files.entrySet()) { String fileId = entry.getKey(); LOGGER.info("Validating \"" + fileId + "\""); String checksum = HashingUtil.getChecksum(entry.getValue(), TOSCAMetaFileAttributes.HASH); ProvenanceVerification verified = verifyFileInManifest(validHistoryElement, fileId, checksum); verificationMap.put(entry.getKey(), verified); LOGGER.info("\"" + entry.getKey() + "\" " + verified); } LOGGER.info("Completed files validation."); }
@GET @Path("fileHistory") @Produces(MediaType.APPLICATION_JSON) public List<FileProvenanceElement> getFileHistory(@QueryParam("fileId") String fileId) { ServiceTemplateId serviceTemplateId = new ServiceTemplateId(new QName(provenanceId)); String qNameWithComponentVersionOnly = VersionUtils.getQNameWithComponentVersionOnly(serviceTemplateId); Objects.requireNonNull(fileId); String fileIdDecoded = Util.URLdecode(fileId); try { return getAccountabilityManager() .getHistory(qNameWithComponentVersionOnly, fileIdDecoded) .exceptionally(error -> null) .get(); } catch (InterruptedException | ExecutionException | AccountabilityException e) { LOGGER.error("Cannot history of file {}. Reason: {}", fileId, e.getMessage()); throw createException(e); } }
@GET @Path("downloadFile") @Produces(MediaType.APPLICATION_OCTET_STREAM) public Response downloadFileFromImmutableStorage(@QueryParam("address") String address, @QueryParam("filename") String filename) { StreamingOutput fileStream = output -> { try (InputStream data = getAccountabilityManager().retrieveState(address).get()) { IOUtils.copy(data, output); output.flush(); } catch (Exception e) { LOGGER.error("Cannot download file ({}) from immutable storage. Reason: {}", address, e.getMessage()); throw createException(e); } }; return Response .ok(fileStream, MediaType.APPLICATION_OCTET_STREAM) .header("content-disposition", "attachment; filename = " + filename) .build(); }