Skip to content

Commit 70b918c

Browse files
committed
Pull request #167: Support for authentication in user-provided remote artifacts (OAuth2.0, HTTP basic, HTTP header)
Merge in ITB/json-validator from development to master * commit '0c64acc10af66345d2e7249f5c4aa2f988e45697': Support for authentication in user-provided remote artifacts (OAuth2.0, HTTP basic, HTTP header)
2 parents 2846a48 + 0c64acc commit 70b918c

3 files changed

Lines changed: 42 additions & 20 deletions

File tree

jsonvalidator-common/src/main/java/eu/europa/ec/itb/json/validation/JSONValidator.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
import java.math.BigInteger;
5353
import java.nio.charset.StandardCharsets;
5454
import java.nio.file.Files;
55-
import java.nio.file.Path;
5655
import java.util.ArrayList;
5756
import java.util.LinkedList;
5857
import java.util.List;
@@ -251,14 +250,14 @@ private List<Message> validateAgainstSetOfSchemas(List<FileInfo> schemaFileInfos
251250
if (combinationApproach == ValidationArtifactCombinationApproach.ALL) {
252251
// All schema validations must result in success.
253252
for (FileInfo fileInfo: schemaFileInfos) {
254-
aggregatedMessages.addAll(validateAgainstSchema(fileInfo.getFile()));
253+
aggregatedMessages.addAll(validateAgainstSchema(fileInfo));
255254
}
256255
} else if (combinationApproach == ValidationArtifactCombinationApproach.ONE_OF) {
257256
// All schemas need to be validated but only one should validate successfully.
258257
int successCount = 0;
259258
int branchCounter = 1;
260259
for (FileInfo fileInfo: schemaFileInfos) {
261-
var latestErrors = validateAgainstSchema(fileInfo.getFile());
260+
var latestErrors = validateAgainstSchema(fileInfo);
262261
if (latestErrors.isEmpty()) {
263262
successCount += 1;
264263
} else {
@@ -277,7 +276,7 @@ private List<Message> validateAgainstSetOfSchemas(List<FileInfo> schemaFileInfos
277276
// Any of the schemas should validate successfully.
278277
int branchCounter = 1;
279278
for (FileInfo fileInfo: schemaFileInfos) {
280-
List<Message> latestErrors = validateAgainstSchema(fileInfo.getFile());
279+
List<Message> latestErrors = validateAgainstSchema(fileInfo);
281280
if (latestErrors.isEmpty()) {
282281
aggregatedMessages.clear();
283282
break;
@@ -312,12 +311,12 @@ private void addBranchErrors(List<Message> aggregatedMessages, List<Message> bra
312311
* The schema loading in this case extends what the official spec foresees, allowing to read definitions
313312
* from local files (and reuse schemas).
314313
*
315-
* @param path The schema path.
314+
* @param schemaInfo The schema information.
316315
* @return The parsed schema and JSON node reader to use.
317316
*/
318-
private Pair<Schema, NodeReader> readSchema(Path path) {
317+
private Pair<Schema, NodeReader> readSchema(FileInfo schemaInfo) {
319318
try {
320-
var jsonNode = objectMapper.readTree(path.toFile());
319+
var jsonNode = objectMapper.readTree(schemaInfo.getFile());
321320
var jsonReader = getJsonReader();
322321
var registryConfig = SchemaRegistryConfig.builder()
323322
.cacheRefs(false)
@@ -330,7 +329,7 @@ private Pair<Schema, NodeReader> readSchema(Path path) {
330329
.schemaRegistryConfig(registryConfig)
331330
.schemaCacheEnabled(false)
332331
.nodeReader(jsonReader)
333-
.resourceLoaders(builder -> builder.add(new LocalSchemaResolver(specs.getDomainConfig(), localSchemaCache)))
332+
.resourceLoaders(builder -> builder.add(new LocalSchemaResolver(specs.getDomainConfig(), localSchemaCache, schemaInfo)))
334333
.build();
335334
return Pair.of(registry.getSchema(jsonNode), jsonReader);
336335
} catch (IOException e) {
@@ -372,8 +371,8 @@ private Function<Error, String> getLocationMapper() {
372371
* @param schemaFile The schema file to use.
373372
* @return The resulting error messages.
374373
*/
375-
private List<Message> validateAgainstSchema(File schemaFile) {
376-
var schemaInfo = readSchema(schemaFile.toPath());
374+
private List<Message> validateAgainstSchema(FileInfo schemaFile) {
375+
var schemaInfo = readSchema(schemaFile);
377376
var locationMapper = getLocationMapper();
378377
return schemaInfo.getLeft().validate(getContentNode(schemaInfo.getRight())).stream().map(error -> {
379378
String pathPrefix = null;

jsonvalidator-common/src/main/java/eu/europa/ec/itb/json/validation/LocalSchemaResolver.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717

1818
import com.networknt.schema.AbsoluteIri;
1919
import com.networknt.schema.resource.InputStreamSource;
20-
import com.networknt.schema.resource.IriResourceLoader;
2120
import com.networknt.schema.resource.ResourceLoader;
21+
import com.networknt.schema.utils.AbsoluteIris;
2222
import eu.europa.ec.itb.json.DomainConfig;
23+
import eu.europa.ec.itb.validation.commons.FileInfo;
24+
import eu.europa.ec.itb.validation.commons.URLReader;
2325
import org.apache.commons.lang3.Strings;
2426
import org.slf4j.Logger;
2527
import org.slf4j.LoggerFactory;
2628

29+
import java.net.URI;
2730
import java.nio.file.Files;
2831

2932
/**
@@ -35,16 +38,20 @@ public class LocalSchemaResolver implements ResourceLoader {
3538

3639
private final DomainConfig domain;
3740
private final LocalSchemaCache localSchemaCache;
41+
private final FileInfo schemaInfo;
42+
private URLReader urlReader;
3843

3944
/**
4045
* Constructor.
4146
*
4247
* @param domain The configuration domain.
4348
* @param localSchemaCache The cache of locally-defined schemas.
49+
* @param schemaInfo The schema information.
4450
*/
45-
public LocalSchemaResolver(DomainConfig domain, LocalSchemaCache localSchemaCache) {
51+
public LocalSchemaResolver(DomainConfig domain, LocalSchemaCache localSchemaCache, FileInfo schemaInfo) {
4652
this.domain = domain;
4753
this.localSchemaCache = localSchemaCache;
54+
this.schemaInfo = schemaInfo;
4855
}
4956

5057
/**
@@ -59,11 +66,23 @@ public InputStreamSource getResource(AbsoluteIri absoluteIri) {
5966
var schema = localSchemaCache.getSchemaForId(domain, idToCheck);
6067
if (schema.isEmpty()) {
6168
LOG.debug("Schema with URI {} not found locally. Looking up remotely.", absoluteIri);
62-
return IriResourceLoader.getInstance().getResource(absoluteIri);
69+
return () -> getUrlReader().stream(URI.create(AbsoluteIris.toUri(absoluteIri)), null, domain.getHttpVersion(), schemaInfo.getRequestDecorator()).stream();
6370
} else {
6471
LOG.debug("Schema with URI {} found locally.", absoluteIri);
6572
return () -> Files.newInputStream(schema.get());
6673
}
6774
}
6875

76+
/**
77+
* Get the URL reader to use.
78+
*
79+
* @return The reader.
80+
*/
81+
private URLReader getUrlReader() {
82+
if (urlReader == null) {
83+
urlReader = new URLReader();
84+
}
85+
return urlReader;
86+
}
87+
6988
}

jsonvalidator-web/src/main/java/eu/europa/ec/itb/json/web/UploadController.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
import java.io.IOException;
5959
import java.io.InputStream;
6060
import java.net.http.HttpClient;
61+
import java.net.http.HttpRequest;
6162
import java.util.*;
63+
import java.util.function.Consumer;
6264

6365
import static eu.europa.ec.itb.validation.commons.web.Constants.*;
6466

@@ -213,7 +215,7 @@ public UploadResult<Translations> handleUpload(@PathVariable("domain") String do
213215
List<FileInfo> externalSchemas = new ArrayList<>();
214216
boolean proceedToValidate = true;
215217
try {
216-
externalSchemas = getExternalFiles(externalSchemaContentType, externalSchemaFiles, externalSchemaUri, externalSchemaString, config.getSchemaInfo(validationType), tempFolderForRequest, config.getHttpVersion());
218+
externalSchemas = getExternalFiles(externalSchemaContentType, externalSchemaFiles, externalSchemaUri, externalSchemaString, config.getSchemaInfo(validationType), tempFolderForRequest, config.getHttpVersion(), config);
217219
} catch (IOException e) {
218220
logger.error("Error while reading uploaded file [{}]", e.getMessage(), e);
219221
result.setMessage(localisationHelper.localise("validator.label.exception.errorInUpload", e.getMessage()));
@@ -374,13 +376,15 @@ private ValidationArtifactCombinationApproach getSchemaCombinationApproach(Strin
374376
* @param schemaInfo The schema information from the domain.
375377
* @param parentFolder The temporary folder to use for file system storage.
376378
* @param httpVersion The HTTP version to use.
379+
* @param domainConfig The domain configuration.
377380
* @return The list of user-provided artifacts.
378381
* @throws IOException If an IO error occurs.
379382
*/
380383
private List<FileInfo> getExternalFiles(String[] externalContentType, MultipartFile[] externalFiles, String[] externalUri, String[] externalString,
381-
ValidationArtifactInfo schemaInfo, File parentFolder, HttpClient.Version httpVersion) throws IOException {
384+
ValidationArtifactInfo schemaInfo, File parentFolder, HttpClient.Version httpVersion, DomainConfig domainConfig) throws IOException {
382385
List<FileInfo> lis = new ArrayList<>();
383386
if (externalContentType != null) {
387+
Consumer<HttpRequest.Builder> requestDecorator = fileManager.createRemoteFileRequestDecorator(domainConfig, schemaInfo);
384388
for (int i=0; i<externalContentType.length; i++) {
385389
if (StringUtils.isNotBlank(externalContentType[i])) {
386390
File inputFile;
@@ -396,10 +400,9 @@ private List<FileInfo> getExternalFiles(String[] externalContentType, MultipartF
396400
if (externalString != null && externalString.length > i) {
397401
currentExtString = externalString[i];
398402
}
399-
400-
inputFile = getInputFile(externalContentType[i], currentExtFile, currentExtUri, currentExtString, parentFolder, httpVersion);
403+
inputFile = getInputFile(externalContentType[i], currentExtFile, currentExtUri, currentExtString, parentFolder, httpVersion, requestDecorator);
401404
if (inputFile != null) {
402-
lis.add(new FileInfo(inputFile));
405+
lis.add(new FileInfo(inputFile, null, null, requestDecorator));
403406
}
404407
}
405408
}
@@ -452,10 +455,11 @@ private boolean validateExternalFiles(List<FileInfo> lis, ValidationArtifactInfo
452455
* @param inputString The provided direct input string to load the content from.
453456
* @param parentFolder The temporary folder to use.
454457
* @param httpVersion The HTTP version to use.
458+
* @param requestDecorator The request decorator to use.
455459
* @return The input content's file.
456460
* @throws IOException If an error occurs.
457461
*/
458-
private File getInputFile(String contentType, MultipartFile inputFile, String inputUri, String inputString, File parentFolder, HttpClient.Version httpVersion) throws IOException {
462+
private File getInputFile(String contentType, MultipartFile inputFile, String inputUri, String inputString, File parentFolder, HttpClient.Version httpVersion, Consumer<HttpRequest.Builder> requestDecorator) throws IOException {
459463
File file = null;
460464
if (CONTENT_TYPE_FILE.equals(contentType)) {
461465
if (inputFile!=null && !inputFile.isEmpty()) {
@@ -465,7 +469,7 @@ private File getInputFile(String contentType, MultipartFile inputFile, String in
465469
}
466470
} else if (CONTENT_TYPE_URI.equals(contentType)) {
467471
if (StringUtils.isNotBlank(inputUri)) {
468-
file = this.fileManager.getFileFromURL(parentFolder, inputUri, httpVersion);
472+
file = this.fileManager.getFileFromURL(parentFolder, inputUri, null, null, null, null, null, null, httpVersion, requestDecorator).getFile();
469473
}
470474
} else if (CONTENT_TYPE_STRING.equals(contentType)) {
471475
if (StringUtils.isNotBlank(inputString)) {

0 commit comments

Comments
 (0)