Skip to content

Commit 8ff0840

Browse files
authored
Merge pull request #25 from ZenWave360/feature/authentication
fix: $RefParser.java replaceWith$Ref keep references when posible adds improves authentication settings
2 parents b49e7d5 + 454ffd1 commit 8ff0840

File tree

6 files changed

+153
-9
lines changed

6 files changed

+153
-9
lines changed

pom.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@
105105
<version>1.2.13</version>
106106
<scope>test</scope>
107107
</dependency>
108+
<dependency>
109+
<groupId>com.github.tomakehurst</groupId>
110+
<artifactId>wiremock-jre8</artifactId>
111+
<version>2.35.0</version>
112+
<scope>test</scope>
113+
</dependency>
108114
</dependencies>
109115

110116
<build>

src/main/java/io/zenwave360/jsonrefparser/$RefParser.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,20 @@ public class $RefParser {
113113
return this;
114114
}
115115

116+
public $RefParser withAuthenticationValues(AuthenticationValue... authenticationValue) {
117+
if(authenticationValue != null) {
118+
Arrays.stream(authenticationValue).forEach(this::withAuthentication);
119+
}
120+
return this;
121+
}
122+
123+
public $RefParser withAuthenticationValues(List<AuthenticationValue> authenticationValue) {
124+
if(authenticationValue != null) {
125+
authenticationValue.forEach(this::withAuthentication);
126+
}
127+
return this;
128+
}
129+
116130
public $RefParser withResolver(RefFormat refFormat, Resolver resolver) {
117131
this.resolvers.put(refFormat, resolver);
118132
return this;
@@ -304,8 +318,8 @@ private void dereference(ExtendedJsonContext jsonContext, Object value, String[]
304318
throw e;
305319
}
306320
} else if(value instanceof Map) {
307-
// visit
308-
((Map<String, Object>) value).entrySet().forEach(e -> {
321+
// visit - use ArrayList to avoid ConcurrentModificationException
322+
new ArrayList<>(((Map<String, Object>) value).entrySet()).forEach(e -> {
309323
dereference(jsonContext, e.getValue(), ArrayUtils.add(paths, e.getKey()), currentFileURL);
310324
});
311325
} else if(value instanceof List) {
@@ -318,6 +332,28 @@ private void dereference(ExtendedJsonContext jsonContext, Object value, String[]
318332
}
319333

320334
private void replaceWith$Ref(ExtendedJsonContext jsonContext, String jsonPath, Object resolved) {
335+
Map<String, Object> original = jsonContext.read(jsonPath);
336+
if(original.containsKey("$ref") && original.size() == 1) {
337+
mergeResolvedIntoOriginal(jsonContext, jsonPath, resolved);
338+
} else {
339+
mergeResolvedAndReplaceOriginal(jsonContext, jsonPath, resolved);
340+
}
341+
}
342+
343+
private void mergeResolvedIntoOriginal(ExtendedJsonContext jsonContext, String jsonPath, Object resolved) {
344+
Map<String, Object> original = jsonContext.read(jsonPath);
345+
if (resolved instanceof Map) {
346+
for (Map.Entry<String, Object> entry : (original).entrySet()) {
347+
if(!entry.getKey().equals("$ref")) {
348+
((Map) resolved).put(entry.getKey(), entry.getValue());
349+
}
350+
}
351+
}
352+
jsonContext.set(jsonPath, resolved);
353+
}
354+
355+
private void mergeResolvedAndReplaceOriginal(ExtendedJsonContext jsonContext, String jsonPath, Object resolved) {
356+
// losing original reference, they will become different objects
321357
Map<String, Object> original = jsonContext.read(jsonPath);
322358
Map<String, Object> replacement = new LinkedHashMap<>();
323359
replacement.putAll(original);

src/main/java/io/zenwave360/jsonrefparser/AuthenticationValue.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public static enum AuthenticationType {
2121
private String value;
2222
private AuthenticationType type = AuthenticationType.HEADER;
2323

24+
private List<String> urlPatterns = Arrays.asList("*");
2425
private Predicate<URL> urlMatcher = ANY_MATCH;
2526

2627
public AuthenticationValue() {
@@ -60,6 +61,20 @@ public AuthenticationValue withUrlMatcher(Predicate<URL> urlMatcher) {
6061
return this;
6162
}
6263

64+
public AuthenticationValue withUrlPattern(String urlPattern) {
65+
this.urlPatterns = List.of(urlPattern);
66+
return this;
67+
}
68+
69+
public boolean matches(URL url) {
70+
if(urlMatcher != null) {
71+
return urlMatcher.test(url);
72+
} else if(urlPatterns != null) {
73+
return urlPatterns.stream().anyMatch(url.toString()::matches);
74+
}
75+
return ANY_MATCH.test(url);
76+
}
77+
6378
public String getKey() {
6479
return this.key;
6580
}
@@ -72,10 +87,6 @@ public AuthenticationType getType() {
7287
return this.type;
7388
}
7489

75-
public Predicate<URL> getUrlMatcher() {
76-
return this.urlMatcher;
77-
}
78-
7990
public void setKey(String key) {
8091
this.key = key;
8192
}
@@ -91,4 +102,22 @@ public void setType(AuthenticationType type) {
91102
public void setUrlMatcher(Predicate<URL> urlMatcher) {
92103
this.urlMatcher = urlMatcher;
93104
}
94-
}
105+
106+
public void setUrlPattern(String urlPattern) {
107+
this.urlPatterns = List.of(urlPattern);
108+
}
109+
110+
public void setUrlPatterns(List<String> urlPatterns) {
111+
this.urlPatterns = urlPatterns;
112+
}
113+
114+
public String toString() {
115+
return "AuthenticationValue{" +
116+
"key='" + key + '\'' +
117+
", value='" + value + '\'' +
118+
", type=" + type +
119+
", urlPatterns=" + urlPatterns +
120+
", urlMatcher=" + urlMatcher +
121+
'}';
122+
}
123+
}

src/main/java/io/zenwave360/jsonrefparser/resolver/HttpResolver.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.zenwave360.jsonrefparser.$Ref;
44
import io.zenwave360.jsonrefparser.AuthenticationValue;
5+
import org.apache.commons.lang3.builder.ToStringBuilder;
56
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
78

@@ -70,7 +71,7 @@ protected String downloadUrlToString(String url, List<AuthenticationValue> auths
7071
final List<AuthenticationValue> header = new ArrayList<>();
7172
if (auths != null && auths.size() > 0) {
7273
for (AuthenticationValue auth : auths) {
73-
if (auth.getUrlMatcher() == null || auth.getUrlMatcher().test(inUrl)) {
74+
if (auth.matches(inUrl)) {
7475
if (AuthenticationValue.AuthenticationType.HEADER == auth.getType()) {
7576
header.add(auth);
7677
}

src/test/java/io/zenwave360/jsonrefparser/GH18.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ public void test() throws Exception {
1313
refParser.withOptions(new $RefParserOptions().withOnCircular($RefParserOptions.OnCircular.SKIP));
1414
$Refs refs = refParser.parse().dereference().getRefs();
1515
String schema = refs.schema().toString();
16+
System.out.println("Actual schema output:");
17+
System.out.println(schema);
18+
System.out.println("Contains 'lorem={title=lorem': " + schema.contains("lorem={title=lorem"));
19+
System.out.println("Contains 'ipsum={title=ipsum': " + schema.contains("ipsum={title=ipsum"));
1620
Assert.assertTrue(schema.contains("lorem={title=lorem"));
1721
Assert.assertTrue(schema.contains("ipsum={title=ipsum"));
18-
System.out.println(refs.schema());
1922
}
2023
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package io.zenwave360.jsonrefparser.resolver;
2+
3+
import com.github.tomakehurst.wiremock.WireMockServer;
4+
import com.github.tomakehurst.wiremock.client.WireMock;
5+
import io.zenwave360.jsonrefparser.$Ref;
6+
import io.zenwave360.jsonrefparser.AuthenticationValue;
7+
import org.junit.After;
8+
import org.junit.Before;
9+
import org.junit.Test;
10+
11+
import java.net.URI;
12+
13+
import static com.github.tomakehurst.wiremock.client.WireMock.*;
14+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
15+
16+
public class HttpResolverHeaderTest {
17+
18+
private WireMockServer wireMockServer;
19+
private HttpResolver httpResolver;
20+
21+
@Before
22+
public void setup() {
23+
wireMockServer = new WireMockServer(options().port(8089));
24+
wireMockServer.start();
25+
WireMock.configureFor("localhost", 8089);
26+
27+
httpResolver = new HttpResolver();
28+
}
29+
30+
@After
31+
public void teardown() {
32+
wireMockServer.stop();
33+
}
34+
35+
@Test
36+
public void testHeadersAreSent() throws Exception {
37+
// Setup mock response
38+
stubFor(get(urlEqualTo("/test.json"))
39+
.willReturn(aResponse()
40+
.withStatus(200)
41+
.withHeader("Content-Type", "application/json")
42+
.withBody("{\"test\": \"data\"}")));
43+
44+
httpResolver.withAuthentication(new AuthenticationValue()
45+
.withHeader("Authorization", "Bearer test-token")
46+
.withUrlMatcher(url -> url.getHost().equals("localhost")));
47+
48+
httpResolver.withAuthentication(new AuthenticationValue()
49+
.withHeader("API-Key", "test-key")
50+
.withUrlPattern("local*"));
51+
52+
httpResolver.withAuthentication(new AuthenticationValue()
53+
.withHeader("OTHER", "other")
54+
.withUrlPattern("other"));
55+
56+
// Make request
57+
$Ref ref = $Ref.of("http://localhost:8089/test.json", null);
58+
String result = httpResolver.resolve(ref);
59+
60+
// Verify headers were sent
61+
verify(getRequestedFor(urlEqualTo("/test.json"))
62+
.withHeader("Authorization", equalTo("Bearer test-token"))
63+
.withHeader("API-Key", equalTo("test-key"))
64+
.withHeader("Accept", equalTo("application/json, application/yaml, */*"))
65+
.withHeader("User-Agent", equalTo("Apache-HttpClient/$JSONSchemaRefParserJVM")));
66+
67+
System.out.println("Response: " + result);
68+
}
69+
}

0 commit comments

Comments
 (0)