Skip to content

Commit

Permalink
Merge pull request #180 from onc-healthit/develop
Browse files Browse the repository at this point in the history
Merge from Develop to Master for release 3.1.71
  • Loading branch information
bgirishrao authored Sep 26, 2023
2 parents 4176ae6 + 99cbda9 commit 6f2c2af
Show file tree
Hide file tree
Showing 12 changed files with 368 additions and 77 deletions.
24 changes: 12 additions & 12 deletions configuration/ccdaReferenceValidatorConfig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -865,12 +865,12 @@
Consol CE SHOULD contain zero or more [0..*] translation, which SHALL be selected from ValueSet Medication Route 2.16.840.1.113762.1.4.1099.12 DYNAMIC (CONF:1198-32960, DSTU:1276) -->
<expression xpathExpression="//v3:substanceAdministration/v3:templateId[@root='2.16.840.1.113883.10.20.22.4.52' and @extension='2015-08-01']/ancestor::v3:substanceAdministration[1]/v3:routeCode/v3:translation[not(@nullFlavor) and ancestor::v3:section[not(@nullFlavor)]]">
<validator>
<name>CodeSystemCodeValidator</name>
<validationResultSeverityLevels>
<codeSeverityLevel>SHALL</codeSeverityLevel>
</validationResultSeverityLevels>
<allowedCodesystemNames>SNOMED-CT</allowedCodesystemNames>
</validator>
<name>ValueSetCodeValidator</name>
<validationResultSeverityLevels>
<codeSeverityLevel>SHALL</codeSeverityLevel>
</validationResultSeverityLevels>
<allowedValuesetOids>2.16.840.1.113762.1.4.1099.12</allowedValuesetOids>
</validator>
</expression>

<!--11. MAY contain zero or one [0..1] approachSiteCode, where the code SHALL be selected from ValueSet Body Site urn:oid:2.16.840.1.113883.3.88.12.3221.8.9 DYNAMIC (CONF:1198-8840).-->
Expand Down Expand Up @@ -997,11 +997,11 @@
Consol CE SHOULD contain zero or more [0..*] translation, which SHALL be selected from ValueSet Medication Route 2.16.840.1.113762.1.4.1099.12 DYNAMIC (CONF:1098-32950, DSTU:1276) -->
<expression xpathExpression="//v3:substanceAdministration/v3:templateId[@root='2.16.840.1.113883.10.20.22.4.16' and @extension='2014-06-09']/ancestor::v3:substanceAdministration[1]/v3:routeCode/v3:translation[not(@nullFlavor) and ancestor::v3:section[not(@nullFlavor)]]">
<validator>
<name>CodeSystemCodeValidator</name>
<name>ValueSetCodeValidator</name>
<validationResultSeverityLevels>
<codeSeverityLevel>SHALL</codeSeverityLevel>
</validationResultSeverityLevels>
<allowedCodesystemNames>SNOMED-CT</allowedCodesystemNames>
<allowedValuesetOids>2.16.840.1.113762.1.4.1099.12</allowedValuesetOids>
</validator>
</expression>

Expand Down Expand Up @@ -1193,11 +1193,11 @@
Consol CE SHOULD contain zero or more [0..*] translation, which SHALL be selected from ValueSet Medication Route 2.16.840.1.113762.1.4.1099.12 DYNAMIC (CONF:1098-32951, DSTU:1276) -->
<expression xpathExpression="//v3:substanceAdministration/v3:templateId[@root='2.16.840.1.113883.10.20.22.4.120']/ancestor::v3:substanceAdministration[1]/v3:routeCode/v3:translation[not(@nullFlavor) and ancestor::v3:section[not(@nullFlavor)]]">
<validator>
<name>CodeSystemCodeValidator</name>
<name>ValueSetCodeValidator</name>
<validationResultSeverityLevels>
<codeSeverityLevel>SHALL</codeSeverityLevel>
</validationResultSeverityLevels>
<allowedCodesystemNames>SNOMED-CT</allowedCodesystemNames>
<allowedValuesetOids>2.16.840.1.113762.1.4.1099.12</allowedValuesetOids>
</validator>
</expression>

Expand Down Expand Up @@ -1240,11 +1240,11 @@
Consol CE SHOULD contain zero or more [0..*] translation, which SHALL be selected from ValueSet Medication Route 2.16.840.1.113762.1.4.1099.12 DYNAMIC (CONF:1098-32952, DSTU:1276) -->
<expression xpathExpression="//v3:substanceAdministration/v3:templateId[@root='2.16.840.1.113883.10.20.22.4.42' and @extension='2014-06-09']/ancestor::v3:substanceAdministration[1]/v3:routeCode/v3:translation[not(@nullFlavor) and ancestor::v3:section[not(@nullFlavor)]]">
<validator>
<name>CodeSystemCodeValidator</name>
<name>ValueSetCodeValidator</name>
<validationResultSeverityLevels>
<codeSeverityLevel>SHALL</codeSeverityLevel>
</validationResultSeverityLevels>
<allowedCodesystemNames>SNOMED-CT</allowedCodesystemNames>
<allowedValuesetOids>2.16.840.1.113762.1.4.1099.12</allowedValuesetOids>
</validator>
</expression>

Expand Down
16 changes: 12 additions & 4 deletions configuration/referenceccdaservice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@ Save a backup of this completed configuration file

<Context reloadable="true">
<Parameter name="vocabulary.localCodeRepositoryDir" value="path/to/your/code_repository" override="true"/>
<Parameter name="vocabulary.localValueSetRepositoryDir" value="path/to/your/valueset_repository" override="true"/>
<Parameter name="referenceccda.configFile" value="path/to/your/configs_folder/ccdaReferenceValidatorConfig.xml" override="true"/>
<Parameter name="vocabulary.localValueSetRepositoryDir" value="path/to/your/valueset_repository" override="true"/>
<Parameter name="referenceccda.configFile" value="path/to/your/configs_folder/ccdaReferenceValidatorConfig.xml" override="true"/>
<Parameter name="referenceccda.isDynamicVocab" value="false" override="true"/>
<Parameter name="referenceccda.configFolder" value="path/to/your/configs_folder" override="true"/>
<Parameter name="content.scenariosDir" value="path/to/your/scenarios_directory" override="true"/>
</Context>
<Parameter name="content.scenariosDir" value="path/to/your/scenarios_directory" override="true"/>

<Parameter name="keycloak.enabled" value="false" override="true"/>
<Parameter name="keycloak.auth.server" value="Replace with KeyCloak auth URL" override="true"/>
<Parameter name="keycloak.realm" value="Replace with KeyCloak Realm" override="true"/>
<Parameter name="keycloak.client.id" value="Replace with KeyCloak client id for introspect" override="true"/>
<Parameter name="keycloak.client.secret" value="Replace with KeyCloak client secret for introspect" override="true"/>


</Context>
19 changes: 17 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<groupId>org.sitenv</groupId>
<artifactId>referenceccdavalidator</artifactId>
<version>1.0.69</version>
<version>1.0.70</version>
<packaging>war</packaging>
<name>Reference CCDA Validator</name>

Expand All @@ -16,7 +16,7 @@
<content.validator.version>latestVersion</content.validator.version>
<!-- MDHT SITE properties -->
<mdht.models.groupid>mdht.openhealthtools.mdht.cda</mdht.models.groupid>
<mdht.models.version>3.0.0.20220923</mdht.models.version>
<mdht.models.version>3.0.0.20230823</mdht.models.version>
<ds4pcontent.groupId>mdht.hl7.ds4p</ds4pcontent.groupId>
<ds4pcontent.version>${mdht.models.version}</ds4pcontent.version>
<mdht.plugins.groupId>mdht.eclipse.mdht</mdht.plugins.groupId>
Expand Down Expand Up @@ -261,6 +261,21 @@
<version>4.13.1</version>
<scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20230227</version>
</dependency>

</dependencies>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.sitenv.referenceccda.configuration;

import okhttp3.*;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
* KeycloakTokenValidationClient class used for validating token
*/
@Component("keycloakTokenValidationClient")
public class KeycloakTokenValidationClient {

/** The LOGGERGER */
private static final Logger LOGGER = LoggerFactory.getLogger(KeycloakTokenValidationClient.class);
private static final String APPLICATION_URL_FORM_ENCODED = "application/x-www-form-urlencoded";

/**
*
* @param request
* @param authUrl : Auth base URL for keycloak
* @param realm : keycloak realm for introspect
* @param clientId : client id for authenticating token
* @param clientSecret
* @return
*/
public boolean validateToken(HttpServletRequest request, String authUrl, String realm, String clientId, String clientSecret) {

LOGGER.info("Entry - validateToken Method in KeyCloakTokenValidationClient ");
boolean validationResponse = false;
final String authorizationHeaderValue = request.getHeader("Authorization");
if (authorizationHeaderValue != null && authorizationHeaderValue.startsWith("Bearer"));
String token = authorizationHeaderValue.substring(7, authorizationHeaderValue.length());

String url = authUrl + "/realms/" + realm + "/protocol/openid-connect/token/introspect";
LOGGER.info("KeyCloakTokenValidationClient URL = "+url );

OkHttpClient client = new OkHttpClient().newBuilder().hostnameVerifier(new HostnameVerifier()
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
}).build();

MediaType mediaType = MediaType.parse(APPLICATION_URL_FORM_ENCODED);

RequestBody body = RequestBody.create(mediaType, "token="+token+"&client_id="+clientId+"&client_secret="+clientSecret);

Request requestOne = new Request.Builder()
.url(url)
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response clientResponse;
try {
clientResponse = client.newCall(requestOne).execute();
clientResponse.body();
if (!clientResponse.isSuccessful()) {
LOGGER.error("Failed to authenticate");
}
String response = clientResponse.body().string();
JSONObject jsonObj = new JSONObject(response);
validationResponse = (boolean) jsonObj.get("active");
LOGGER.info("Access Token Validation Status ::::" + validationResponse);
} catch (IOException e) {
LOGGER.info("Exception - validateToken Method in KeyCloakTokenValidationClient",e);
e.printStackTrace();
}
LOGGER.info("Exit - validateToken Method in KeyCloakTokenValidationClient ");
return validationResponse;

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.sitenv.referenceccda.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* Filter class for intercepting incoming request
*/
@Component
@WebFilter(urlPatterns = "/*")
public class TokenFilter implements Filter {

/** The LOGGERGER */
private static final Logger LOGGER = LoggerFactory.getLogger(TokenFilter.class);
private String authUrl;
private String realm;
private String clientId;
private String clientSecret;
private String authEnabled;

@Override
public void init(FilterConfig filterConfig) throws ServletException {
ServletContext servletContext = filterConfig.getServletContext();
authEnabled = servletContext.getInitParameter("keycloak.enabled");
authUrl = servletContext.getInitParameter("keycloak.auth.server");
realm = servletContext.getInitParameter("keycloak.realm");
clientId = servletContext.getInitParameter("keycloak.client.id");
clientSecret = servletContext.getInitParameter("keycloak.client.secret");
LOGGER.info("authEnabled"+authEnabled+"authUrl == "+authUrl +"\nrealm == "+realm+"\nclientId == "+clientId+"\nclientSecret == "+clientSecret);
//System.out.println("authEnabled == "+authEnabled+"\nauthUrl == "+authUrl +"\nrealm == "+realm+"\nclientId == "+clientId+"\nclientSecret == "+clientSecret);
}

/**
* (non-Javadoc) Details of the APIs and the request types that can be used with
* this application
*
* @param req
* @param res
* @param chain
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
LOGGER.info("Entry - doFilter Method in TokenFilter ");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;

String referrer = request.getHeader("Referer");
String path = request.getRequestURL().toString();

if (path.contains("/static/") || path.contains("/ui") || (referrer != null && referrer.contains("/referenceccdaservice/static/validationui.html") )) {
chain.doFilter(request, response);
LOGGER.info("Exit - doFilter Method in TokenFilter -- CCDA UI endpoint");
}else if ("true".equals(authEnabled)) {
KeycloakTokenValidationClient keyCloakTokenValidationClient = new KeycloakTokenValidationClient();
boolean responseStatus = keyCloakTokenValidationClient.validateToken(request, authUrl, realm, clientId, clientSecret);
LOGGER.info("RESPONSE STATUS :: " + responseStatus);
if (responseStatus) {
chain.doFilter(request, response);
LOGGER.info("Exit - doFilter Method in TokenFilter ");
} else {
response.sendError(401, "UnAuthorized User");
LOGGER.error("Error in doFilter TokenFilter - UnAuthorized User ");
}
} else {
chain.doFilter(request, response);
LOGGER.info("Exit - doFilter Method in TokenFilter -- Keycloak authentication not enabled");
}
}

/**
* Destroy method
*/
@Override
public void destroy() {
LOGGER.info("Entry - destroy Method in Web Filter ");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public ValidationResultsDto doValidation(
@RequestParam(value = "ccdaFile", required = true) MultipartFile ccdaFile,
@RequestParam(value = "curesUpdate", required = false) boolean curesUpdate,
@RequestParam(value = "svap2022", required = false) boolean svap2022,
@RequestParam(value = "svap2023", required = false) boolean svap2023,
@RequestParam(defaultValue = VocabularyConstants.Config.DEFAULT, required = false) String vocabularyConfig,
@RequestParam(defaultValue = DEFAULT_SEVERITY_LEVEL, required = false) String severityLevel) {

Expand All @@ -59,7 +60,7 @@ public ValidationResultsDto doValidation(
logger.info("Final severityLevelEnum.name() " + severityLevelEnum.name());

return referenceCcdaValidationService.validateCCDA(validationObjective, referenceFileName, ccdaFile,
curesUpdate, svap2022, vocabularyConfig, severityLevelEnum);
curesUpdate, svap2022, svap2023, vocabularyConfig, severityLevelEnum);
}

@RequestMapping(value = "/getvaluesetsbyoids", method = RequestMethod.GET)
Expand Down
Loading

0 comments on commit 6f2c2af

Please sign in to comment.