Skip to content

Commit

Permalink
RESTful Forward Rule: Replace Target Base URL and Keycloak Server ID …
Browse files Browse the repository at this point in the history
…by Web Application name #1924
  • Loading branch information
vrindanayak committed Apr 12, 2019
1 parent 42f526c commit f23c766
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 115 deletions.
Expand Up @@ -2071,8 +2071,9 @@ objectclass ( 1.2.40.0.13.1.15.110.4.25 NAME 'dcmRSForwardRule'
SUP top STRUCTURAL
MUST (
cn $
dcmURI )
dcmWebAppName )
MAY (
dcmURI $
dcmKeycloakServerID $
dcmTLSAllowAnyHostname $
dcmTLSDisableTrustManager $
Expand Down
Expand Up @@ -700,9 +700,8 @@ private static void writeRSForwardRules(JsonWriter writer, Collection<RSForwardR
for (RSForwardRule rule : rules) {
writer.writeStartObject();
writer.writeNotNullOrDef("cn", rule.getCommonName(), null);
writer.writeNotNullOrDef("dcmURI", rule.getBaseURI(), null);
writer.writeNotNullOrDef("dcmWebAppName", rule.getWebAppName(), null);
writer.writeNotEmpty("dcmRSOperation", rule.getRSOperations());
writer.writeNotNullOrDef("dcmKeycloakServerID", rule.getKeycloakServerID(), null);
writer.writeNotDef("dcmTLSAllowAnyHostname", rule.isTlsAllowAnyHostname(), false);
writer.writeNotDef("dcmTLSDisableTrustManager", rule.isTlsDisableTrustManager(), false);
writer.writeNotNullOrDef("dcmURIPattern", rule.getRequestURLPattern(), null);
Expand Down Expand Up @@ -2323,15 +2322,12 @@ private static void loadRSForwardRules(Collection<RSForwardRule> rules, JsonRead
case "cn":
rule.setCommonName(reader.stringValue());
break;
case "dcmURI":
rule.setBaseURI(reader.stringValue());
case "dcmWebAppName":
rule.setWebAppName(reader.stringValue());
break;
case "dcmRSOperation":
rule.setRSOperations(reader.enumArray(RSOperation.class));
break;
case "dcmKeycloakServerID":
rule.setKeycloakServerID(reader.stringValue());
break;
case "dcmTLSAllowAnyHostname":
rule.setTlsAllowAnyHostname(reader.booleanValue());
break;
Expand Down
Expand Up @@ -2796,9 +2796,8 @@ private static Attributes storeTo(ConfigurationChanges.ModifiedObject ldapObj, H
private Attributes storeTo(ConfigurationChanges.ModifiedObject ldapObj, RSForwardRule rule, BasicAttributes attrs) {
attrs.put("objectclass", "dcmRSForwardRule");
attrs.put("cn", rule.getCommonName());
LdapUtils.storeNotNullOrDef(ldapObj, attrs, "dcmURI", rule.getBaseURI(), null);
LdapUtils.storeNotNullOrDef(ldapObj, attrs, "dcmWebAppName", rule.getWebAppName(), null);
LdapUtils.storeNotEmpty(ldapObj, attrs, "dcmRSOperation", rule.getRSOperations());
LdapUtils.storeNotNullOrDef(ldapObj, attrs, "dcmKeycloakServerID", rule.getKeycloakServerID(), null);
LdapUtils.storeNotDef(ldapObj, attrs, "dcmTLSAllowAnyHostname", rule.isTlsAllowAnyHostname(), false);
LdapUtils.storeNotDef(ldapObj, attrs, "dcmTLSDisableTrustManager", rule.isTlsDisableTrustManager(), false);
LdapUtils.storeNotNullOrDef(ldapObj, attrs, "dcmURIPattern", rule.getRequestURLPattern(), null);
Expand Down Expand Up @@ -2966,9 +2965,8 @@ private void loadRSForwardRules(Collection<RSForwardRule> rules, String parentDN
SearchResult sr = ne.next();
Attributes attrs = sr.getAttributes();
RSForwardRule rule = new RSForwardRule(LdapUtils.stringValue(attrs.get("cn"), null));
rule.setBaseURI(LdapUtils.stringValue(attrs.get("dcmURI"), null));
rule.setWebAppName(LdapUtils.stringValue(attrs.get("dcmWebAppName"), null));
rule.setRSOperations(LdapUtils.enumArray(RSOperation.class, attrs.get("dcmRSOperation")));
rule.setKeycloakServerID(LdapUtils.stringValue(attrs.get("dcmKeycloakServerID"), null));
rule.setTlsAllowAnyHostname(LdapUtils.booleanValue(attrs.get("dcmTLSAllowAnyHostname"), false));
rule.setTlsDisableTrustManager(LdapUtils.booleanValue(attrs.get("dcmTLSDisableTrustManager"), false));
rule.setRequestURLPattern(LdapUtils.stringValue(attrs.get("dcmURIPattern"), null));
Expand Down Expand Up @@ -3375,10 +3373,8 @@ private static List<ModificationItem> storeDiffs(
private List<ModificationItem> storeDiffs(
ConfigurationChanges.ModifiedObject ldapObj, RSForwardRule prev, RSForwardRule rule,
ArrayList<ModificationItem> mods) {
LdapUtils.storeDiffObject(ldapObj, mods, "dcmURI", prev.getBaseURI(), rule.getBaseURI(), null);
LdapUtils.storeDiffObject(ldapObj, mods, "dcmWebAppName", prev.getWebAppName(), rule.getWebAppName(), null);
LdapUtils.storeDiff(ldapObj, mods, "dcmRSOperation", prev.getRSOperations(), rule.getRSOperations());
LdapUtils.storeDiffObject(ldapObj, mods, "dcmKeycloakServerID", prev.getKeycloakServerID(),
rule.getKeycloakServerID(), null);
LdapUtils.storeDiffObject(ldapObj, mods, "dcmURIPattern", prev.getRequestURLPattern(),
rule.getRequestURLPattern(), null);
LdapUtils.storeDiff(ldapObj, mods, "dcmTLSAllowAnyHostname",
Expand Down
Expand Up @@ -17,7 +17,7 @@
*
* The Initial Developer of the Original Code is
* J4Care.
* Portions created by the Initial Developer are Copyright (C) 2016
* Portions created by the Initial Developer are Copyright (C) 2016-2019
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
Expand Down Expand Up @@ -54,12 +54,10 @@ public class RSForwardRule {

private String commonName;

private String baseURI;
private String webAppName;

private EnumSet<RSOperation> rsOperations = EnumSet.noneOf(RSOperation.class);

private String keycloakServerID;

private boolean ifNotRequestURLPattern;

private Pattern requestURLPattern;
Expand All @@ -83,12 +81,12 @@ public void setCommonName(String commonName) {
this.commonName = commonName;
}

public String getBaseURI() {
return baseURI;
public String getWebAppName() {
return webAppName;
}

public void setBaseURI(String baseURI) {
this.baseURI = baseURI;
public void setWebAppName(String webAppName) {
this.webAppName = webAppName;
}

public RSOperation[] getRSOperations() {
Expand All @@ -100,14 +98,6 @@ public void setRSOperations(RSOperation[] rsOperations) {
this.rsOperations.addAll(Arrays.asList(rsOperations));
}

public String getKeycloakServerID() {
return keycloakServerID;
}

public void setKeycloakServerID(String keycloakServerID) {
this.keycloakServerID = keycloakServerID;
}

public boolean isTlsAllowAnyHostname() {
return tlsAllowAnyHostname;
}
Expand Down Expand Up @@ -159,7 +149,7 @@ public boolean match(RSOperation rsOperation, HttpServletRequest request) {
public String toString() {
return "RSForwardRule{" +
"cn='" + commonName + '\'' +
", baseURI='" + baseURI + '\'' +
", webAppName='" + webAppName + '\'' +
", ops=" + rsOperations +
'}';
}
Expand Down
Expand Up @@ -346,7 +346,7 @@ public void mergePatients(@PathParam("patientID") IDWithIssuer patientID, InputS
for (Attributes otherPID : attrs.getSequence(Tag.OtherPatientIDsSequence))
mergePatient(patientID, otherPID);

rsForward.forwardMergeMultiplePatients(RSOperation.MergePatients, arcAE, baos.toByteArray(), request);
rsForward.forward(RSOperation.MergePatients, arcAE, baos.toByteArray(), null, request);
} catch (JsonParsingException e) {
throw new WebApplicationException(
errResponse(e.getMessage() + " at location : " + e.getLocation(),
Expand Down
Expand Up @@ -17,7 +17,7 @@
*
* The Initial Developer of the Original Code is
* J4Care.
* Portions created by the Initial Developer are Copyright (C) 2015-2018
* Portions created by the Initial Developer are Copyright (C) 2015-2019
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
Expand All @@ -42,8 +42,7 @@
package org.dcm4chee.arc.keycloak;

import org.dcm4che3.net.Device;
import org.dcm4chee.arc.conf.ArchiveDeviceExtension;
import org.dcm4chee.arc.conf.KeycloakServer;
import org.dcm4che3.net.KeycloakClient;
import org.dcm4chee.arc.event.ArchiveServiceEvent;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.admin.client.Keycloak;
Expand Down Expand Up @@ -71,8 +70,8 @@ public void onArchiveServiceEvent(@Observes ArchiveServiceEvent event) {
cachedKeycloak = null;
}

public String getAccessTokenString(String keycloakServerID) throws Exception {
return getAccessTokenString(toCachedKeycloak(keycloakServerID));
public String getAccessTokenString(String keycloakClientID) throws Exception {
return getAccessTokenString(toCachedKeycloak(keycloakClientID));
}

private String getAccessTokenString(CachedKeycloak tmp) {
Expand All @@ -86,23 +85,25 @@ public AccessToken getAccessToken(String keycloakServerID) throws Exception {
tmp.keycloak.tokenManager().getAccessToken().getExpiresIn());
}

private CachedKeycloak toCachedKeycloak(String keycloakServerID) throws Exception {
private CachedKeycloak toCachedKeycloak(String keycloakClientID) throws Exception {
CachedKeycloak tmp = cachedKeycloak;
if (tmp == null || !tmp.keycloakServerID.equals(keycloakServerID)) {
KeycloakServer server = device.getDeviceExtensionNotNull(ArchiveDeviceExtension.class)
.getKeycloakServerNotNull(keycloakServerID);
cachedKeycloak = tmp = new CachedKeycloak(keycloakServerID, KeycloakBuilder.builder()
.serverUrl(server.getServerURL())
.realm(server.getRealm())
.clientId(server.getClientID())
.clientSecret(server.getClientSecret())
.username(server.getUserID())
.password(server.getPassword())
.grantType(server.getGrantType().name())
if (tmp == null || !tmp.keycloakClientID.equals(keycloakClientID)) {
KeycloakClient keycloakClient = device.getKeycloakClient(keycloakClientID);
if (keycloakClient == null)
throw new IllegalArgumentException("No Keycloak Client configured with ID:" + keycloakClientID);

cachedKeycloak = tmp = new CachedKeycloak(keycloakClientID, KeycloakBuilder.builder()
.serverUrl(keycloakClient.getKeycloakServerURL())
.realm(keycloakClient.getKeycloakRealm())
.clientId(keycloakClient.getKeycloakClientID())
.clientSecret(keycloakClient.getKeycloakClientSecret())
.username(keycloakClient.getUserID())
.password(keycloakClient.getPassword())
.grantType(keycloakClient.getKeycloakGrantType().name())
.resteasyClient(resteasyClientBuilder(
server.getServerURL(),
server.isTlsAllowAnyHostname(),
server.isTlsDisableTrustManager())
keycloakClient.getKeycloakServerURL(),
keycloakClient.isTLSAllowAnyHostname(),
keycloakClient.isTLSDisableTrustManager())
.build())
.build());
}
Expand All @@ -124,11 +125,11 @@ public ResteasyClientBuilder resteasyClientBuilder(
}

private static class CachedKeycloak {
final String keycloakServerID;
final String keycloakClientID;
final Keycloak keycloak;

CachedKeycloak(String keycloakServerID, Keycloak keycloak) {
this.keycloakServerID = keycloakServerID;
CachedKeycloak(String keycloakClientID, Keycloak keycloak) {
this.keycloakClientID = keycloakClientID;
this.keycloak = keycloak;
}
}
Expand Down
Expand Up @@ -58,14 +58,14 @@ void scheduleRequest(
String method,
String uri,
byte[] content,
String keycloakServerID,
String keycloakClientID,
boolean tlsAllowAnyHostName,
boolean tlsDisableTrustManager) throws QueueSizeLimitExceededException;

Outcome request(
String method,
String uri,
String keycloakServerID,
String keycloakClientID,
boolean tlsAllowAnyHostname,
boolean tlsDisableTrustManager,
byte[] content) throws Exception;
Expand Down
Expand Up @@ -17,7 +17,7 @@
*
* The Initial Developer of the Original Code is
* J4Care.
* Portions created by the Initial Developer are Copyright (C) 2017
* Portions created by the Initial Developer are Copyright (C) 2017-2019
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
Expand All @@ -40,12 +40,13 @@

package org.dcm4chee.arc.rs.client;

import org.dcm4che3.conf.api.IWebApplicationCache;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.IDWithIssuer;
import org.dcm4che3.json.JSONWriter;
import org.dcm4che3.net.WebApplication;
import org.dcm4che3.util.ByteUtils;
import org.dcm4chee.arc.conf.ArchiveAEExtension;
import org.dcm4chee.arc.conf.RSForwardRule;
import org.dcm4chee.arc.conf.RSOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -56,7 +57,6 @@
import javax.json.stream.JsonGenerator;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.util.List;

/**
* @author Vrinda Nayak <vrinda.nayak@j4care.com>
Expand All @@ -71,51 +71,45 @@ public class RSForward {
@Inject
private RSClient rsClient;

@Inject
private IWebApplicationCache iWebAppCache;

public void forward(RSOperation rsOp, ArchiveAEExtension arcAE, Attributes attrs, HttpServletRequest request) {
List<RSForwardRule> rules = arcAE.findRSForwardRules(rsOp, request);
for (RSForwardRule rule : rules) {
try {
String targetURI = mkForwardURI(rule.getBaseURI(), rsOp, request);
if (!targetURI.equals(request.getRequestURL().toString())) {
if (rsOp == RSOperation.CreatePatient)
targetURI += IDWithIssuer.pidOf(attrs);
rsClient.scheduleRequest(
getMethod(rsOp),
targetURI,
toContent(attrs),
rule.getKeycloakServerID(),
rule.isTlsAllowAnyHostname(),
rule.isTlsDisableTrustManager());
}
} catch (Exception e) {
LOG.warn("Failed to apply {}:\n", rule, e);
}
}
forward(rsOp, arcAE, toContent(attrs),
rsOp == RSOperation.CreatePatient ? IDWithIssuer.pidOf(attrs) : null, request);
}

public void forwardMergeMultiplePatients(RSOperation rsOp, ArchiveAEExtension arcAE, byte[] in, HttpServletRequest request) {
List<RSForwardRule> rules = arcAE.findRSForwardRules(rsOp, request);
for (RSForwardRule rule : rules) {
public void forward(
RSOperation rsOp, ArchiveAEExtension arcAE, byte[] in, IDWithIssuer patientID, HttpServletRequest request) {
LOG.info("Restful Service Forward {} {} from {}@{}", request.getMethod(), request.getRequestURI(),
request.getRemoteUser(), request.getRemoteHost());
String requestURI = request.getRequestURI();
String appendURI = requestURI.substring(requestURI.indexOf("/rs/") + 4);

arcAE.findRSForwardRules(rsOp, request).forEach(rule -> {
try {
String targetURI = mkForwardURI(rule.getBaseURI(), rsOp, request);
if (!targetURI.equals(request.getRequestURL().toString()))
WebApplication webApplication = iWebAppCache.findWebApplication(rule.getWebAppName());
String serviceURL = webApplication.getServiceURL().toString();
String targetURI = serviceURL + (serviceURL.endsWith("rs/") ? "" : "/") + appendURI;
if (!targetURI.equals(request.getRequestURL().toString())) {
if (rsOp == RSOperation.CreatePatient)
targetURI += patientID;
rsClient.scheduleRequest(
getMethod(rsOp),
targetURI,
in,
rule.getKeycloakServerID(),
webApplication.getKeycloakClientID(),
rule.isTlsAllowAnyHostname(),
rule.isTlsDisableTrustManager());
LOG.info("Forwarded {} {} from {}@{} using RSForward rule {} to device {}. Target URL is {}",
request.getMethod(), request.getRequestURI(), request.getRemoteUser(),
request.getRemoteHost(), rule, webApplication.getDevice().getDeviceName(), targetURI);
}
} catch (Exception e) {
LOG.warn("Failed to apply {}:\n", rule, e);
LOG.warn("Failed to apply RSForwardRule {} to {} {} from {}@{} for RSOperation {} :\n",
rule, request, rsOp, e);
}
}
}

private static String mkForwardURI(String baseURI, RSOperation rsOp, HttpServletRequest request) {
String requestURI = request.getRequestURI();
return baseURI + requestURI.substring(requestURI.indexOf(
rsOp == RSOperation.ApplyRetentionPolicy ? "expire/series" : "rs/"));
});
}

private static byte[] toContent(Attributes attrs) {
Expand Down

0 comments on commit f23c766

Please sign in to comment.