Skip to content

Commit 3871cc6

Browse files
committed
Rework authorization providers in ManagedWebAccess
1 parent bab506b commit 3871cc6

19 files changed

Lines changed: 289 additions & 465 deletions

RELEASE_NOTES.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## Security Notices
1+
## Security Notices
22

33
* TODO: HTTP Authentication Notes
44
* This release of the Validator supports scoped packages (see [security advisory note](todo))
@@ -13,20 +13,20 @@
1313
* Fix bugs in expansion and validation when valueset includes two different versions of the same code system
1414
* Various Performance Improvements
1515
* Package Regenerator
16-
* Performance Improvements
17-
* more robust against errors in FHIRPath expressions
18-
* Don't produce duplicate value sets
16+
* Performance Improvements
17+
* more robust against errors in FHIRPath expressions
18+
* Don't produce duplicate value sets
1919
* Fix bug parsing with multiple profiles for a type
2020
* fix bug validating codes with no server
2121

2222
## Other code changes
2323

2424
* The IWorkerContext has been changed, which impacts on all uses of the HAPI core library:
2525
* Introduce VersionResolutionRules when resolving versions for canonical references
26-
* Add Identifier when resolving References to support logical references
26+
* Add Identifier when resolving References to support logical references
2727
* Add the methods storeAnalysis/retrieveAnalysis for caching analysis of the loaded resources - caches are wiped when loaded content changes
2828
* Remove the NamingSystem related function in preference to using the analysis methods
29-
* Fix NPE rendering Questionnaires
29+
* Fix NPE rendering Questionnaires
3030
* Expansion bugs: imported valueSet excludes ignored + expansion.total inconsistent
3131
* Remove FTPClient, tests, and supporting dependencies
3232
* Fix rendering bug where naming system resolution was a little random

org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/terminologies/TerminologyCacheManager.java

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -143,24 +143,4 @@ private void zipDirectory(OutputStream outputStream) throws IOException {
143143
});
144144
}
145145
}
146-
147-
public void commit(String token) throws IOException {
148-
// create a zip of all the files
149-
ByteArrayOutputStream bs = new ByteArrayOutputStream();
150-
zipDirectory(bs);
151-
152-
// post it to
153-
String url = "https://tx.fhir.org/post/tx-cache/" + ghOrg + "/" + ghRepo + "/" + ghBranch + ".zip";
154-
log.info("Sending tx-cache to " + url + " (" + Utilities.describeSize(bs.toByteArray().length) + ")");
155-
156-
HTTPResult res = ManagedWebAccess.accessor(Arrays.asList("web"))
157-
.withBasicAuth(token.substring(0, token.indexOf(':')), token.substring(token.indexOf(':') + 1))
158-
.put(url, bs.toByteArray(), null, "application/zip");
159-
if (res.getCode() >= 300) {
160-
log.error("sending cache failed: " + res.getCode());
161-
} else {
162-
log.info("Sent cache");
163-
}
164-
}
165-
166146
}

org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/TerminologyCacheManager.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ private void zipDirectory(OutputStream outputStream) throws IOException {
144144
}
145145
}
146146

147-
147+
/*FIXME delete this if need be or implement basic auth
148148
public void commit(String token) throws IOException {
149149
// create a zip of all the files
150150
ByteArrayOutputStream bs = new ByteArrayOutputStream();
@@ -163,5 +163,5 @@ public void commit(String token) throws IOException {
163163
log.info("Sent cache");
164164
}
165165
}
166-
166+
*/
167167
}

org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/HTTPAuthProvider.java

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.hl7.fhir.utilities.http;
2+
3+
import java.net.URL;
4+
import java.util.Map;
5+
6+
/**
7+
* Provides necessary information for authenticating HTTP requests for specific URLs.
8+
*/
9+
public interface IHTTPAuthenticationProvider {
10+
11+
public boolean canProvideHeaders(URL url);
12+
13+
public Map<String, String> getHeaders(URL url);
14+
15+
}

org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedFhirWebAccessor.java

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public ManagedFhirWebAccessor withLogger(ToolingClientLogger logger) {
4444
return this;
4545
}
4646

47-
public ManagedFhirWebAccessor(String userAgent, List<ServerDetailsPOJO> serverAuthDetails) {
48-
super(Arrays.asList("fhir"), userAgent, serverAuthDetails);
47+
public ManagedFhirWebAccessor(String userAgent, IHTTPAuthenticationProvider authenticationProvider) {
48+
super(Arrays.asList("fhir"), userAgent, authenticationProvider);
4949
this.timeout = 5000;
5050
this.timeoutUnit = TimeUnit.MILLISECONDS;
5151
}
@@ -70,40 +70,9 @@ protected HTTPRequest requestWithAuthorizationHeaders(HTTPRequest httpRequest) {
7070
headers.add(new HTTPHeader(entry.getKey(), entry.getValue()));
7171
}
7272

73-
if (getAuthenticationMode() != null) {
74-
if (getAuthenticationMode() != HTTPAuthenticationMode.NONE) {
75-
switch (getAuthenticationMode()) {
76-
case BASIC:
77-
final String basicCredential = Credentials.basic(getUsername(), getPassword());
78-
headers.add(new HTTPHeader("Authorization", basicCredential));
79-
break;
80-
case TOKEN:
81-
String tokenCredential = "Bearer " + getToken();
82-
headers.add(new HTTPHeader("Authorization", tokenCredential));
83-
break;
84-
case APIKEY:
85-
String apiKeyCredential = getToken();
86-
headers.add(new HTTPHeader("Api-Key", apiKeyCredential));
87-
break;
88-
}
89-
}
90-
} else {
91-
ServerDetailsPOJO settings = ManagedWebAccessUtils.getServer(getServerTypes(), httpRequest.getUrl().toString(), getServerAuthDetails());
92-
if (settings != null) {
93-
switch (settings.getAuthenticationType()) {
94-
case "basic":
95-
final String basicCredential = Credentials.basic(settings.getUsername(), settings.getPassword());
96-
headers.add(new HTTPHeader("Authorization", basicCredential));
97-
break;
98-
case "token":
99-
String tokenCredential = "Bearer " + settings.getToken();
100-
headers.add(new HTTPHeader("Authorization", tokenCredential));
101-
break;
102-
case "apikey":
103-
String apiKeyCredential = settings.getApikey();
104-
headers.add(new HTTPHeader("Api-Key", apiKeyCredential));
105-
break;
106-
}
73+
if (getHttpAuthHeaderProvider() != null && getHttpAuthHeaderProvider().canProvideHeaders(httpRequest.getUrl())) {
74+
for (Map.Entry<String, String> entry : getHttpAuthHeaderProvider().getHeaders(httpRequest.getUrl()).entrySet()) {
75+
headers.add(new HTTPHeader(entry.getKey(), entry.getValue()));
10776
}
10877
}
10978
return httpRequest.withHeaders(headers);

org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccess.java

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ public enum WebAccessPolicy {
8282

8383
@Getter
8484
private static String userAgent;
85-
private static List<ServerDetailsPOJO> serverAuthDetails;
85+
86+
private static List<ServerDetailsPOJO> serverDetailsList;
87+
private static IHTTPAuthenticationProvider defaultAuthenticationProvider;
8688

8789
public static WebAccessPolicy getAccessPolicy() {
8890
return accessPolicy;
@@ -109,11 +111,19 @@ public static void setUserAgent(String userAgent) {
109111
}
110112

111113
public static ManagedWebAccessor accessor(Iterable<String> serverTypes) {
112-
return new ManagedWebAccessor(serverTypes, userAgent, serverAuthDetails);
114+
return new ManagedWebAccessor(serverTypes, userAgent, defaultAuthenticationProvider);
115+
}
116+
117+
public static ManagedWebAccessor accessor(Iterable<String> serverTypes, IHTTPAuthenticationProvider authenticationProvider) {
118+
return new ManagedWebAccessor(serverTypes, userAgent, authenticationProvider);
113119
}
114120

115121
public static ManagedFhirWebAccessor fhirAccessor() {
116-
return new ManagedFhirWebAccessor(userAgent, serverAuthDetails);
122+
return new ManagedFhirWebAccessor(userAgent, defaultAuthenticationProvider);
123+
}
124+
125+
public static ManagedFhirWebAccessor fhirAccessor(IHTTPAuthenticationProvider authenticationProvider) {
126+
return new ManagedFhirWebAccessor(userAgent, authenticationProvider);
117127
}
118128

119129
public static HTTPResult get(Iterable<String> serverTypes, String url) throws IOException {
@@ -139,15 +149,8 @@ public static HTTPResult httpCall(HTTPRequest httpRequest) throws IOException {
139149
public static void loadFromFHIRSettings() {
140150
setAccessPolicy(FhirSettings.isProhibitNetworkAccess() ? WebAccessPolicy.PROHIBITED : WebAccessPolicy.DIRECT);
141151
setUserAgent("hapi-fhir-tooling-client");
142-
serverAuthDetails = new ArrayList<>();
143-
serverAuthDetails.addAll(FhirSettings.getServers());
144-
}
145-
146-
public static void loadFromFHIRSettings(FhirSettings settings) {
147-
setAccessPolicy(settings.isProhibitNetworkAccess() ? WebAccessPolicy.PROHIBITED : WebAccessPolicy.DIRECT);
148-
setUserAgent("hapi-fhir-tooling-client");
149-
serverAuthDetails = new ArrayList<>();
150-
serverAuthDetails.addAll(settings.getServers());
152+
serverDetailsList = FhirSettings.getServers();
153+
defaultAuthenticationProvider = new ServerDetailsPOJOHTTPAuthProvider(serverDetailsList);
151154
}
152155

153156
public static String makeSecureRef(String url) {
@@ -165,8 +168,8 @@ private static boolean isLocal(String url) {
165168

166169
// Check if this URL matches a configured server with allowHttp: true
167170
// This allows HTTP for trusted internal servers (e.g., Docker service names)
168-
if (serverAuthDetails != null) {
169-
for (ServerDetailsPOJO server : serverAuthDetails) {
171+
if (serverDetailsList != null) {
172+
for (ServerDetailsPOJO server : serverDetailsList) {
170173
if (server.getAllowHttp() != null && server.getAllowHttp() && server.getUrl() != null && !server.getUrl().isEmpty()) {
171174
// Match if the URL starts with the configured server URL
172175
if (url.startsWith(server.getUrl())) {

org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/http/ManagedWebAccessUtils.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,42 @@
22

33
import org.hl7.fhir.utilities.settings.ServerDetailsPOJO;
44

5+
import java.nio.charset.StandardCharsets;
6+
import java.util.Base64;
7+
58
public class ManagedWebAccessUtils {
69

710
public static ServerDetailsPOJO getServer(Iterable<String> serverTypes, String url, Iterable<ServerDetailsPOJO> serverAuthDetails) {
811
if (serverAuthDetails != null) {
912
for (ServerDetailsPOJO serverDetails : serverAuthDetails) {
1013
for (String serverType : serverTypes) {
11-
if (url.startsWith(serverDetails.getUrl()) && typesMatch(serverType, serverDetails.getType())) {
12-
return serverDetails;
13-
}
14+
if (url.startsWith(serverDetails.getUrl()) && typesMatch(serverType, serverDetails.getType())) {
15+
return serverDetails;
16+
}
1417
}
1518
}
1619
}
1720
return null;
1821
}
1922

23+
public static ServerDetailsPOJO getServer(String url, Iterable<ServerDetailsPOJO> serverAuthDetails) {
24+
if (serverAuthDetails != null) {
25+
for (ServerDetailsPOJO serverDetails : serverAuthDetails) {
26+
if (url.startsWith(serverDetails.getUrl())) {
27+
return serverDetails;
28+
}
29+
}
30+
}
31+
return null;
32+
}
33+
2034
private static boolean typesMatch(String criteria, String value) {
2135
return criteria == null || value == null || criteria.equals(value);
2236
}
2337

38+
public static byte[] getEncodedBasicAuth(String providedUsername, String providedPassword) {
39+
String auth = providedUsername + ":" + providedPassword;
40+
return Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8));
41+
}
42+
2443
}

0 commit comments

Comments
 (0)