Skip to content

Commit 9b06be4

Browse files
Merge pull request #3 from openmrs/master
Update
2 parents 679b709 + 40e5fac commit 9b06be4

File tree

11 files changed

+123
-99
lines changed

11 files changed

+123
-99
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* This Source Code Form is subject to the terms of the Mozilla Public License,
3+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
4+
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5+
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6+
*
7+
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8+
* graphic logo is a trademark of OpenMRS Inc.
9+
*/
10+
package org.openmrs.module.smartonfhir.util;
11+
12+
import java.io.BufferedInputStream;
13+
import java.io.File;
14+
import java.io.FileInputStream;
15+
import java.io.FileNotFoundException;
16+
import java.io.InputStream;
17+
import java.nio.file.Paths;
18+
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import lombok.SneakyThrows;
21+
import lombok.extern.slf4j.Slf4j;
22+
import org.openmrs.module.smartonfhir.web.KeycloakConfig;
23+
import org.openmrs.util.OpenmrsUtil;
24+
import org.springframework.core.io.Resource;
25+
import org.springframework.core.io.ResourceLoader;
26+
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
27+
28+
@Slf4j
29+
public class KeycloakConfigHolder {
30+
31+
private static final ObjectMapper objectMapper = new ObjectMapper();
32+
33+
private static volatile KeycloakConfig keycloakConfig;
34+
35+
public static KeycloakConfig getKeycloakConfig() {
36+
if (keycloakConfig == null) {
37+
synchronized (KeycloakConfigHolder.class) {
38+
if (keycloakConfig == null) {
39+
loadKeycloakConfig();
40+
}
41+
}
42+
}
43+
44+
return keycloakConfig;
45+
}
46+
47+
@SneakyThrows
48+
private static void loadKeycloakConfig() {
49+
final File f = Paths.get(OpenmrsUtil.getApplicationDataDirectory(), "config", "smart-keycloak.json").toFile();
50+
51+
if (f.canRead()) {
52+
try (InputStream keycloakConfigStream = new BufferedInputStream(new FileInputStream(f))) {
53+
keycloakConfig = objectMapper.readValue(keycloakConfigStream, KeycloakConfig.class);
54+
return;
55+
}
56+
catch (FileNotFoundException e) {
57+
log.error("Could not load file [{}]", f.getPath(), e);
58+
}
59+
}
60+
61+
final ResourceLoader resolver = new PathMatchingResourcePatternResolver();
62+
final Resource resource = resolver.getResource("classpath:smart-keycloak.json");
63+
64+
if (resource != null && resource.isReadable()) {
65+
try (InputStream keycloakConfigStream = resource.getInputStream()) {
66+
keycloakConfig = objectMapper.readValue(keycloakConfigStream, KeycloakConfig.class);
67+
}
68+
}
69+
}
70+
71+
}

omod/src/main/java/org/openmrs/module/smartonfhir/util/SmartSecretKeyHolder.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
*/
1010
package org.openmrs.module.smartonfhir.util;
1111

12+
import java.io.BufferedInputStream;
1213
import java.io.File;
14+
import java.io.FileInputStream;
1315
import java.io.FileNotFoundException;
1416
import java.io.InputStream;
17+
import java.nio.file.Paths;
1518
import java.util.Base64;
1619

1720
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -44,24 +47,21 @@ public static byte[] getSecretKey() {
4447
@SneakyThrows
4548
private static void loadSecretKey() {
4649
final Base64.Decoder decoder = Base64.getDecoder();
47-
final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
48-
49-
Resource resource = resolver
50-
.getResource(OpenmrsUtil.getDirectoryInApplicationDataDirectory("config").getAbsolutePath() + File.separator
51-
+ "smart-secret-key.json");
50+
final File f = Paths.get(OpenmrsUtil.getApplicationDataDirectory(), "config", "smart-secret-key.json").toFile();
5251

53-
if (resource != null && resource.isReadable()) {
54-
try (InputStream secretKeyStream = resource.getInputStream()) {
52+
if (f.canRead()) {
53+
try (InputStream secretKeyStream = new BufferedInputStream(new FileInputStream(f))) {
5554
secretKey = decoder
5655
.decode(objectMapper.readValue(secretKeyStream, SmartSecretKey.class).getSmartSharedSecretKey());
5756
return;
5857
}
5958
catch (FileNotFoundException e) {
60-
log.error("Could not load file [{}]", resource.getFilename(), e);
59+
log.error("Could not load file [{}]", f.getAbsolutePath(), e);
6160
}
6261
}
6362

64-
resource = resolver.getResource("classpath:smart-secret-key.json");
63+
final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
64+
final Resource resource = resolver.getResource("classpath:smart-secret-key.json");
6565

6666
if (resource != null && resource.isReadable()) {
6767
try (InputStream secretKeyStream = resource.getInputStream()) {

omod/src/main/java/org/openmrs/module/smartonfhir/web/KeycloakConfig.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212
import com.fasterxml.jackson.annotation.JsonInclude;
1313
import com.fasterxml.jackson.annotation.JsonProperty;
1414
import lombok.Data;
15+
import lombok.EqualsAndHashCode;
16+
import org.keycloak.representations.adapters.config.AdapterConfig;
1517

18+
@EqualsAndHashCode(callSuper = true)
1619
@Data
1720
@JsonInclude(JsonInclude.Include.NON_EMPTY)
18-
public class KeycloakConfig {
21+
public class KeycloakConfig extends AdapterConfig {
1922

2023
@JsonProperty(value = "realm", required = true)
2124
private String realm;

omod/src/main/java/org/openmrs/module/smartonfhir/web/filter/CORSFilter.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,24 @@ public class CORSFilter extends OncePerRequestFilter {
2828
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
2929
throws ServletException, IOException {
3030
// CORS "pre-flight" request
31-
31+
3232
response.addHeader("Access-Control-Allow-Origin", "*");
33-
33+
3434
if ("OPTIONS".equals(request.getMethod())) {
3535
response.addHeader("Access-Control-Allow-Credentials", "true");
3636
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
3737
response.addHeader("Access-Control-Allow-Headers", "Authorization");
3838
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
3939
response.addHeader("Access-Control-Max-Age", "600");
40-
40+
4141
response.setStatus(HttpServletResponse.SC_OK);
4242
return;
4343
}
4444

45+
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
46+
return;
47+
}
48+
4549
filterChain.doFilter(request, response);
4650
}
4751
}

omod/src/main/java/org/openmrs/module/smartonfhir/web/filter/SmartAuthenticationFilter.java

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import javax.servlet.http.HttpServletRequest;
1818
import javax.servlet.http.HttpServletResponse;
1919

20-
import java.io.File;
2120
import java.io.IOException;
2221
import java.util.regex.Matcher;
2322
import java.util.regex.Pattern;
@@ -33,10 +32,9 @@
3332
import org.openmrs.api.context.Authenticated;
3433
import org.openmrs.api.context.Context;
3534
import org.openmrs.api.context.ContextAuthenticationException;
35+
import org.openmrs.module.smartonfhir.util.KeycloakConfigHolder;
36+
import org.openmrs.module.smartonfhir.web.KeycloakConfig;
3637
import org.openmrs.module.smartonfhir.web.smart.SmartTokenCredentials;
37-
import org.openmrs.util.OpenmrsUtil;
38-
import org.springframework.core.io.Resource;
39-
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
4038

4139
@Slf4j
4240
public class SmartAuthenticationFilter extends KeycloakOIDCFilter {
@@ -45,20 +43,13 @@ public class SmartAuthenticationFilter extends KeycloakOIDCFilter {
4543

4644
@Override
4745
public void init(FilterConfig filterConfig) {
48-
final Resource keycloakConfig = getKeycloakConfig();
46+
final KeycloakConfig keycloakConfig = KeycloakConfigHolder.getKeycloakConfig();
4947

5048
if (keycloakConfig == null) {
5149
log.error("Could not find Keycloak configuration file");
5250
this.deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
5351
} else {
54-
try {
55-
this.deploymentContext = new AdapterDeploymentContext(
56-
KeycloakDeploymentBuilder.build(keycloakConfig.getInputStream()));
57-
}
58-
catch (IOException e) {
59-
log.error("Error while trying to load Keycloak configuration", e);
60-
this.deploymentContext = new AdapterDeploymentContext(new KeycloakDeployment());
61-
}
52+
this.deploymentContext = new AdapterDeploymentContext(KeycloakDeploymentBuilder.build(keycloakConfig));
6253
}
6354

6455
String skipPatternDefinition = filterConfig.getInitParameter(SKIP_PATTERN_PARAM);
@@ -126,15 +117,4 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
126117

127118
chain.doFilter(req, res);
128119
}
129-
130-
private Resource getKeycloakConfig() {
131-
final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
132-
Resource resource = resolver.getResource(
133-
OpenmrsUtil.getDirectoryInApplicationDataDirectory("config") + File.separator + "smart-keycloak.json");
134-
if (resource != null) {
135-
resource = resolver.getResource("classpath:smart-keycloak.json");
136-
}
137-
138-
return resource;
139-
}
140120
}

omod/src/main/java/org/openmrs/module/smartonfhir/web/filter/SmartForwardingFilter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
4242
req.getRequestDispatcher("/ms/smartPatientSelected").forward(req, res);
4343
return;
4444
}
45+
4546
if (request.getRequestURI().contains("/ms/smartEhrLaunchServlet")) {
4647
req.getRequestDispatcher("/ms/smartEhrLaunchServlet").forward(req, res);
4748
return;

omod/src/main/java/org/openmrs/module/smartonfhir/web/servlet/SmartConfigServlet.java

Lines changed: 3 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,17 @@
99
*/
1010
package org.openmrs.module.smartonfhir.web.servlet;
1111

12-
import javax.servlet.ServletException;
1312
import javax.servlet.http.HttpServlet;
1413
import javax.servlet.http.HttpServletRequest;
1514
import javax.servlet.http.HttpServletResponse;
1615

17-
import java.io.File;
18-
import java.io.FileNotFoundException;
1916
import java.io.IOException;
20-
import java.io.InputStream;
2117

2218
import com.fasterxml.jackson.databind.ObjectMapper;
2319
import lombok.extern.slf4j.Slf4j;
20+
import org.openmrs.module.smartonfhir.util.KeycloakConfigHolder;
2421
import org.openmrs.module.smartonfhir.web.KeycloakConfig;
2522
import org.openmrs.module.smartonfhir.web.SmartConformance;
26-
import org.openmrs.util.OpenmrsUtil;
27-
import org.springframework.core.io.Resource;
28-
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
2923

3024
@Slf4j
3125
public class SmartConfigServlet extends HttpServlet {
@@ -34,16 +28,9 @@ public class SmartConfigServlet extends HttpServlet {
3428

3529
private SmartConformance smartConformance;
3630

37-
private KeycloakConfig keycloakConfig;
38-
3931
@Override
40-
public void init() throws ServletException {
41-
try {
42-
this.keycloakConfig = getKeycloakConfig();
43-
}
44-
catch (IOException e) {
45-
throw new ServletException("Error creating SmartConfigServlet", e);
46-
}
32+
public void init() {
33+
final KeycloakConfig keycloakConfig = KeycloakConfigHolder.getKeycloakConfig();
4734

4835
smartConformance = new SmartConformance();
4936
smartConformance.setAuthorizationEndpoint(
@@ -65,31 +52,4 @@ public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOExce
6552
res.setStatus(200);
6653
objectMapper.writerFor(SmartConformance.class).writeValue(res.getWriter(), smartConformance);
6754
}
68-
69-
private KeycloakConfig getKeycloakConfig() throws IOException {
70-
final PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
71-
Resource resource = resolver
72-
.getResource(OpenmrsUtil.getDirectoryInApplicationDataDirectory("config").getAbsolutePath() + File.separator
73-
+ "smart-keycloak.json");
74-
75-
if (resource != null && resource.isReadable()) {
76-
try (InputStream keycloakConfigStream = resource.getInputStream()) {
77-
keycloakConfig = objectMapper.readValue(keycloakConfigStream, KeycloakConfig.class);
78-
return keycloakConfig;
79-
}
80-
catch (FileNotFoundException e) {
81-
log.error("Could not load file [{}]", resource.getFilename(), e);
82-
}
83-
}
84-
85-
resource = resolver.getResource("classpath:smart-keycloak.json");
86-
87-
if (resource != null && resource.isReadable()) {
88-
try (InputStream keycloakConfigStream = resource.getInputStream()) {
89-
keycloakConfig = objectMapper.readValue(keycloakConfigStream, KeycloakConfig.class);
90-
}
91-
}
92-
93-
return keycloakConfig;
94-
}
9555
}

omod/src/main/java/org/openmrs/module/smartonfhir/web/servlet/SmartEhrLaunchServlet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class SmartEhrLaunchServlet extends HttpServlet {
2323
@Override
2424
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
2525
String patientId = req.getParameter("patientId");
26-
String url = "http://127.0.0.1:9090/launch-standalone.html?iss=http://localhost:8080/openmrs/ws/fhir2/R4&launch="
26+
String url = "http://localhost:9090/launch-standalone.html?iss=http://localhost:8080/openmrs/ws/fhir2/R4&launch="
2727
+ patientId;
2828

2929
if (StringUtils.isBlank(url)) {
Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
[
22
{
3-
"id": "smartapps.smartPatientChartRedirect",
4-
"description": "Smart App launch",
3+
"id": "smartonfhir.search",
4+
"description": "Basic patient search, by ID or Name (using OpenMRS's standard patient search)",
55
"order": 2,
6-
"extensions": [
7-
{
8-
"id": "smartapps.smartAppPatientChartLaunch",
9-
"extensionPointId": "patientDashboard.overallActions",
10-
"type": "link",
11-
"label": "Demo SMART App",
12-
"url": "ms/smartEhrLaunchServlet?app=smart_client&patientId={{patient.uuid}}",
13-
"icon": "icon-hdd",
14-
"requiredPrivilege": "App: smartonfhir:smartAppPatientChartLaunch"
15-
}
16-
]
6+
"config": {
7+
"afterSelectedUrl": "/ms/smartPatientSelected?app=smart_client&patientId={{patientId}}",
8+
"heading": "",
9+
"label": "coreapps.findPatient.app.label",
10+
"showLastViewedPatients": "true"
11+
}
1712
}
1813
]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"id": "smart.search",
4+
"instanceOf": "coreapps.template.findPatient",
5+
"description": "Basic patient search, by ID or Name (using OpenMRS's standard patient search)",
6+
"config": {
7+
"afterSelectedUrl": "/ms/smartPatientSelected?patientId={{patientId}}"
8+
}
9+
}
10+
]

0 commit comments

Comments
 (0)