001package ca.uhn.fhir.test.utilities; 002 003/*- 004 * #%L 005 * HAPI FHIR Test Utilities 006 * %% 007 * Copyright (C) 2014 - 2023 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.context.FhirContext; 024import ca.uhn.fhir.i18n.Msg; 025import ca.uhn.fhir.rest.client.api.IGenericClient; 026import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; 027import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; 028import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; 029import ca.uhn.fhir.rest.server.IResourceProvider; 030import ca.uhn.fhir.rest.server.IServerAddressStrategy; 031import ca.uhn.fhir.tls.KeyStoreType; 032import org.eclipse.jetty.http.HttpVersion; 033import org.eclipse.jetty.server.HttpConfiguration; 034import org.eclipse.jetty.server.HttpConnectionFactory; 035import org.eclipse.jetty.server.Server; 036import org.eclipse.jetty.server.ServerConnector; 037import org.eclipse.jetty.server.SslConnectionFactory; 038import org.eclipse.jetty.servlet.ServletContextHandler; 039import org.eclipse.jetty.servlet.ServletHolder; 040import org.eclipse.jetty.util.ssl.SslContextFactory; 041import org.hl7.fhir.instance.model.api.IBaseResource; 042import org.hl7.fhir.instance.model.api.IIdType; 043import org.junit.jupiter.api.extension.RegisterExtension; 044 045import javax.servlet.Servlet; 046import java.security.KeyStore; 047import java.util.List; 048 049public abstract class BaseRestServerHelper { 050 051 private final String SERVER_KEYSTORE_PATH = "/tls/server-keystore.p12"; 052 private final String SERVER_TRUSTSTORE_PATH = "/tls/server-truststore.p12"; 053 private final String PASSWORD = "changeit"; 054 055 protected final FhirContext myFhirContext; 056 protected int myListenerPort; 057 protected int myHttpsListenerPort; 058 protected Server myListenerServer; 059 protected String myBase; 060 protected String mySecureBase; 061 protected IGenericClient myClient; 062 063 @RegisterExtension 064 public TlsAuthenticationTestHelper myTlsAuthenticationTestHelper = new TlsAuthenticationTestHelper(); 065 066 public BaseRestServerHelper(FhirContext theFhirContext) { 067 myFhirContext = theFhirContext; 068 } 069 070 protected void afterEach() throws Exception { 071 stop(); 072 } 073 074 public IGenericClient getClient() { 075 return myClient; 076 } 077 078 protected void startServer(Servlet theServlet) throws Exception { 079 myListenerServer = new Server(0); 080 081 myFhirContext.getRestfulClientFactory().setSocketTimeout(120000); 082 083 ServletContextHandler proxyHandler = new ServletContextHandler(); 084 proxyHandler.setContextPath("/"); 085 086 ServletHolder targetServletHolder = new ServletHolder(); 087 targetServletHolder.setServlet(theServlet); 088 proxyHandler.addServlet(targetServletHolder, "/target/*"); 089 090 myListenerServer.setHandler(proxyHandler); 091 092 SslContextFactory.Server sslContextFactory = getSslContextFactory(); 093 094 HttpConfiguration httpsConfig = new HttpConfiguration(); 095 httpsConfig.setSecureScheme("https"); 096 httpsConfig.setSecurePort(0); 097 098 ServerConnector sslConnector = new ServerConnector(myListenerServer, 099 new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), 100 new HttpConnectionFactory(httpsConfig)); 101 sslConnector.setPort(0); 102 103 myListenerServer.addConnector(sslConnector); 104 myListenerServer.start(); 105 106 assignHttpAndHttpsPorts(); 107 108 myBase = "http://localhost:" + myListenerPort + "/target"; 109 mySecureBase = "https://localhost:" + myHttpsListenerPort + "/target"; 110 111 myFhirContext.getRestfulClientFactory().setConnectTimeout(60000); 112 myFhirContext.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); 113 114 myClient = myFhirContext.newRestfulGenericClient(myBase); 115 myClient.registerInterceptor(new LoggingInterceptor(false)); 116 } 117 118 private void assignHttpAndHttpsPorts() { 119 myListenerPort = ((ServerConnector)myListenerServer.getConnectors()[0]).getLocalPort(); 120 myHttpsListenerPort = ((ServerConnector)myListenerServer.getConnectors()[1]).getLocalPort(); 121 } 122 123 private SslContextFactory.Server getSslContextFactory() throws Exception{ 124 try { 125 SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); 126 127 KeyStore keyStore = KeyStore.getInstance(KeyStoreType.PKCS12.toString()); 128 keyStore.load(BaseRestServerHelper.class.getResourceAsStream(SERVER_KEYSTORE_PATH), PASSWORD.toCharArray()); 129 sslContextFactory.setKeyStore(keyStore); 130 sslContextFactory.setKeyStorePassword(PASSWORD); 131 132 KeyStore trustStore = KeyStore.getInstance(KeyStoreType.PKCS12.toString()); 133 trustStore.load(BaseRestServerHelper.class.getResourceAsStream(SERVER_TRUSTSTORE_PATH), PASSWORD.toCharArray()); 134 sslContextFactory.setTrustStore(trustStore); 135 136 return sslContextFactory; 137 } 138 catch(Exception e){ 139 throw new RuntimeException(Msg.code(2123)+"Failed to obtain SslContextFactory", e); 140 } 141 } 142 143 public String getBase() { 144 return myBase; 145 } 146 147 public String getSecureBase() { 148 return mySecureBase; 149 } 150 151 public void stop() throws Exception { 152 JettyUtil.closeServer(myListenerServer); 153 } 154 155 public abstract void clearDataAndCounts(); 156 157 public abstract void setFailNextPut(boolean theFailNextPut); 158 159 public abstract List<Object> getInterceptors(); 160 161 public abstract void unregisterInterceptor(Object theNext); 162 163 public abstract void clearCounts(); 164 165 public abstract long getPatientCountSearch(); 166 167 public abstract long getPatientCountDelete(); 168 169 public abstract long getPatientCountUpdate(); 170 171 public abstract long getPatientCountRead(); 172 173 public abstract long getObservationCountSearch(); 174 175 public abstract long getObservationCountDelete(); 176 177 public abstract long getObservationCountUpdate(); 178 179 public abstract long getObservationCountRead(); 180 181 public abstract boolean registerInterceptor(Object theInterceptorAdapter); 182 183 public abstract IResourceProvider getObservationResourceProvider(); 184 185 public abstract IResourceProvider getPatientResourceProvider(); 186 187 public abstract IResourceProvider getConceptMapResourceProvider(); 188 189 public abstract IIdType createPatientWithId(String theId); 190 191 public abstract IIdType createPatient(IBaseResource theBaseResource); 192 193 public abstract IIdType createObservationForPatient(IIdType theFirstTargetPatientId); 194 195 public abstract IIdType createObservation(IBaseResource theBaseResource); 196 197 public void setServerAddressStrategy(boolean theUseHttps){ 198 String path = theUseHttps ? mySecureBase : myBase; 199 HardcodedServerAddressStrategy strategy = new HardcodedServerAddressStrategy(path); 200 setServerAddressStrategy(strategy); 201 } 202 203 protected abstract void setServerAddressStrategy(IServerAddressStrategy theServerAddressStrategy); 204}