1111import java .util .ArrayList ;
1212import java .util .Arrays ;
1313import java .util .Collections ;
14+ import java .util .HashMap ;
1415import java .util .List ;
16+ import java .util .Map ;
1517
1618import io .kubernetes .client .openapi .models .V1EnvVar ;
1719import io .kubernetes .client .openapi .models .V1HTTPIngressPath ;
3032import oracle .weblogic .kubernetes .actions .impl .Cluster ;
3133import oracle .weblogic .kubernetes .actions .impl .NginxParams ;
3234import oracle .weblogic .kubernetes .actions .impl .Service ;
35+ import oracle .weblogic .kubernetes .actions .impl .primitive .Command ;
36+ import oracle .weblogic .kubernetes .actions .impl .primitive .CommandParams ;
3337import oracle .weblogic .kubernetes .actions .impl .primitive .WitParams ;
3438import oracle .weblogic .kubernetes .annotations .IntegrationTest ;
3539import oracle .weblogic .kubernetes .annotations .Namespaces ;
4044import org .junit .jupiter .api .DisplayName ;
4145import org .junit .jupiter .api .Tag ;
4246import org .junit .jupiter .api .Test ;
47+ import org .junit .jupiter .api .condition .DisabledIfEnvironmentVariable ;
4348
4449import static java .net .InetAddress .getLocalHost ;
4550import static oracle .weblogic .kubernetes .TestConstants .ADMIN_PASSWORD_DEFAULT ;
7782import static oracle .weblogic .kubernetes .utils .CommonTestUtils .testUntil ;
7883import static oracle .weblogic .kubernetes .utils .DomainUtils .createDomainAndVerify ;
7984import static oracle .weblogic .kubernetes .utils .FileUtils .copyFileToPod ;
85+ import static oracle .weblogic .kubernetes .utils .FileUtils .generateFileFromTemplate ;
8086import static oracle .weblogic .kubernetes .utils .ImageUtils .createTestRepoSecret ;
8187import static oracle .weblogic .kubernetes .utils .LoadBalancerUtils .createIngressAndRetryIfFail ;
8288import static oracle .weblogic .kubernetes .utils .LoadBalancerUtils .installAndVerifyNginx ;
@@ -118,6 +124,7 @@ class ItCrossDomainTransactionSecurity {
118124 private static String domain2ManagedServerPrefix = domainUid2 + "-managed-server" ;
119125 private static LoggingFacade logger = null ;
120126 private static int replicaCount = 2 ;
127+ private static String clusterName = "cluster-2" ;
121128 private static int t3ChannelPort1 = getNextFreePort ();
122129 private static int t3ChannelPort2 = getNextFreePort ();
123130 private static String domain1AdminExtSvcRouteHost = null ;
@@ -126,6 +133,11 @@ class ItCrossDomainTransactionSecurity {
126133 private static String nginxNamespace = null ;
127134 private static NginxParams nginxHelmParams = null ;
128135 private static int nginxNodePort ;
136+ private static Path tlsCertFile ;
137+ private static Path tlsKeyFile ;
138+ private static Path jksTrustFile ;
139+ private static String tlsSecretName = domainUid2 + "-test-tls-secret" ;
140+ private static String hostAddress = K8S_NODEPORT_HOST ;
129141
130142
131143
@@ -135,7 +147,7 @@ class ItCrossDomainTransactionSecurity {
135147 * JUnit engine parameter resolution mechanism
136148 */
137149 @ BeforeAll
138- public static void initAll (@ Namespaces (3 ) List <String > namespaces ) {
150+ public static void initAll (@ Namespaces (3 ) List <String > namespaces ) throws UnknownHostException {
139151 logger = getLogger ();
140152
141153 // get a new unique opNamespace
@@ -152,6 +164,7 @@ public static void initAll(@Namespaces(3) List<String> namespaces) {
152164 assertNotNull (namespaces .get (2 ), "Namespace list is null" );
153165 nginxNamespace = namespaces .get (2 );
154166
167+
155168 // Create the repo secret to pull the image
156169 // this secret is used only for non-kind cluster
157170 createTestRepoSecret (domainNamespace );
@@ -167,25 +180,6 @@ public static void initAll(@Namespaces(3) List<String> namespaces) {
167180
168181 buildDomains ();
169182
170- }
171-
172- /**
173- * Configure two domains d1 and d2 with CrossDomainSecurityEnabled set to true
174- * On both domains create a user (cross-domain) with group CrossDomainConnectors
175- * Add required Credential Mapping
176- * Deploy a JSP on d1's admin server that takes 2 parameteers
177- * a. The tx aaction b. the d2's cluster service url
178- * Starts a User transcation
179- * Send 10 messgaes to a distributed destination (jms.testUniformQueue) on d2 that has 2 members
180- * Send a message to local destination (jms.admin.adminQueue) on d1
181- * Commit/rollback the transation
182- * Receive the messages from the distributed destination (jms.testUniformQueue) on d2
183- * Receive the message from the local destination (jms.admin.adminQueue) on d1
184- */
185- @ Test
186- @ DisplayName ("Check cross domain transaction works" )
187- void testCrossDomainTransactionCommitSecurityEnable () throws UnknownHostException {
188-
189183 logger .info ("2 domains with crossDomainSecurity enabled start up!" );
190184 int domain1AdminServiceNodePort
191185 = getServiceNodePort (domainNamespace , getExternalServicePodName (domain1AdminServerPodName ), "default" );
@@ -212,7 +206,25 @@ void testCrossDomainTransactionCommitSecurityEnable() throws UnknownHostExceptio
212206 }
213207 logger .info ("hostHeader1 for domain1 is: " + hostHeader1 );
214208 logger .info ("hostAndPort1 for domain1 is: " + hostAndPort1 );
209+ }
215210
211+ /**
212+ * Configure two domains d1 and d2 with CrossDomainSecurityEnabled set to true
213+ * On both domains create a user (cross-domain) with group CrossDomainConnectors
214+ * Add required Credential Mapping
215+ * Deploy a JSP on d1's admin server that takes 2 parameteers
216+ * a. The tx action b. the d2's cluster service url
217+ * Starts a User transcation
218+ * Using t3 send 10 messgaes to a distributed destination (jms.testUniformQueue) on d2 that has 2 members
219+ * Using t3 Send a message to local destination (jms.admin.adminQueue) on d1
220+ * Commit/rollback the transation
221+ * Using t3 receive the messages from the distributed destination (jms.testUniformQueue) on d2
222+ * Using t3 receive the message from the local destination (jms.admin.adminQueue) on d1
223+ */
224+ @ Test
225+ @ DisplayName ("Check cross domain transaction works" )
226+ void testCrossDomainTxWithCrossDomainSecurityEnabled () throws UnknownHostException {
227+
216228 // build the standalone JMS Client on Admin pod
217229 String destLocation = "/u01/JmsSendReceiveClient.java" ;
218230 assertDoesNotThrow (() -> copyFileToPod (domainNamespace ,
@@ -294,6 +306,122 @@ void testCrossDomainTransactionCommitSecurityEnable() throws UnknownHostExceptio
294306 "Wait for JMS Client to send/recv msg" );
295307 }
296308
309+ /**
310+ * Configure two domains d1 and d2 with CrossDomainSecurityEnabled set to true
311+ * On both domains create a user (cross-domain) with group CrossDomainConnectors
312+ * Add required Credential Mapping
313+ * Deploy a JSP on d1's admin server that takes 2 parameteers
314+ * a. The tx action b. the d2's cluster service url
315+ * Starts a User transcation
316+ * Using t3s send 10 messgaes to a distributed destination (jms.testUniformQueue) on d2 that has 2 members
317+ * Using t3s Send a message to local destination (jms.admin.adminQueue) on d1
318+ * Commit/rollback the transation
319+ * Using t3s receive the messages from the distributed destination (jms.testUniformQueue) on d2
320+ * Using t3s Receive the message from the local destination (jms.admin.adminQueue) on d1
321+ */
322+ @ Test
323+ @ DisplayName ("Check cross domain transaction works when SSL enabled" )
324+ @ DisabledIfEnvironmentVariable (named = "OKE_CLUSTER" , matches = "true" )
325+ void testCrossDomainTxWithCrossDomainSecurityAndSSLEnabled () throws UnknownHostException {
326+
327+ // Create SSL certificate and key using openSSL with SAN extension
328+ createCertKeyFiles (hostAddress );
329+ // Create kubernates secret using genereated certificate and key
330+ createSecretWithTLSCertKey (tlsSecretName );
331+ // Import the tls certificate into a JKS truststote to be used while
332+ // running the standalone client.
333+ importKeytoTrustStore ();
334+
335+ //In a UserTransaction send 10 msg to remote udq and 1 msg to local queue and commit the tx
336+ StringBuffer curlCmd1 = new StringBuffer ("curl -skg --show-error --noproxy '*' " );
337+ if (TestConstants .KIND_CLUSTER
338+ && !TestConstants .WLSIMG_BUILDER .equals (TestConstants .WLSIMG_BUILDER_DEFAULT )) {
339+ curlCmd1 .append (" -H 'host: " + hostHeader1 + "' " );
340+ }
341+ String url1 = "\" http://" + hostAndPort1
342+ + "/sample_war/dtx.jsp?remoteurl=t3s://domain2-cluster-cluster-2:8500&action=commit\" " ;
343+ curlCmd1 .append (url1 );
344+ logger .info ("Executing curl command: {0}" , curlCmd1 );
345+ assertTrue (getCurlResult (curlCmd1 .toString ()).contains ("Message sent in a commit User Transation" ),
346+ "Didn't send expected msg " );
347+
348+ //receive msg from the udq that has 2 memebers
349+ StringBuffer curlCmd2 = new StringBuffer ("curl -j --show-error --noproxy '*' " );
350+ if (TestConstants .KIND_CLUSTER
351+ && !TestConstants .WLSIMG_BUILDER .equals (TestConstants .WLSIMG_BUILDER_DEFAULT )) {
352+ curlCmd2 .append (" -H 'host: " + hostHeader1 + "' " );
353+ }
354+ String url2 = "\" http://" + hostAndPort1
355+ + "/sample_war/get.jsp?remoteurl="
356+ + "t3s://domain2-cluster-cluster-2:8500&action=recv&dest=jms.testUniformQueue\" " ;
357+ curlCmd2 .append (url2 );
358+ logger .info ("Executing curl command: {0}" , curlCmd2 );
359+ for (int i = 0 ; i < 2 ; i ++) {
360+ assertTrue (getCurlResult (curlCmd2 .toString ()).contains ("Total Message(s) Received : 5" ),
361+ "Didn't receive expected msg count from remote queue" );
362+ }
363+
364+ // receive 1 msg from the local queue
365+ logger .info ("Receiving 1 msg from the local queue" );
366+ StringBuffer curlCmdx = new StringBuffer ("curl -j --show-error --noproxy '*' " );
367+ if (TestConstants .KIND_CLUSTER
368+ && !TestConstants .WLSIMG_BUILDER .equals (TestConstants .WLSIMG_BUILDER_DEFAULT )) {
369+ curlCmdx .append (" -H 'host: " + hostHeader1 + "' " );
370+ }
371+ String urlx = "\" http://" + hostAndPort1
372+ + "/sample_war/get.jsp?remoteurl="
373+ + "t3s://domain1-admin-server:7002&action=recv&dest=jms.admin.adminQueue\" " ;
374+ curlCmdx .append (urlx );
375+ logger .info ("Executing curl command for local queue: {0}" , curlCmdx );
376+ assertTrue (getCurlResult (curlCmdx .toString ()).contains ("Total Message(s) Received : 1" ),
377+ "Didn't receive expected msg count from local queue" );
378+
379+ //In a UserTransaction send 10 msg to remote udq and 1 msg to local queue and rollback the tx
380+ StringBuffer curlCmd3 = new StringBuffer ("curl -skg --show-error --noproxy '*' " );
381+ if (TestConstants .KIND_CLUSTER
382+ && !TestConstants .WLSIMG_BUILDER .equals (TestConstants .WLSIMG_BUILDER_DEFAULT )) {
383+ curlCmd3 .append (" -H 'host: " + hostHeader1 + "' " );
384+ }
385+ String url3 = "\" http://" + hostAndPort1
386+ + "/sample_war/dtx.jsp?remoteurl=t3s://domain2-cluster-cluster-2:8500&action=rollback\" " ;
387+ curlCmd3 .append (url3 );
388+ logger .info ("Executing curl command: {0}" , curlCmd3 );
389+ assertTrue (getCurlResult (curlCmd3 .toString ()).contains ("Message sent in a rolled-back User Transation" ),
390+ "Didn't send expected msg " );
391+
392+ //receive 0 msg from the udq that has 2 memebers
393+ StringBuffer curlCmd4 = new StringBuffer ("curl -j --show-error --noproxy '*' " );
394+ if (TestConstants .KIND_CLUSTER
395+ && !TestConstants .WLSIMG_BUILDER .equals (TestConstants .WLSIMG_BUILDER_DEFAULT )) {
396+ curlCmd4 .append (" -H 'host: " + hostHeader1 + "' " );
397+ }
398+ String url4 = "\" http://" + hostAndPort1
399+ + "/sample_war/get.jsp?remoteurl="
400+ + "t3s://domain2-cluster-cluster-2:8500&action=recv&dest=jms.testUniformQueue\" " ;
401+ curlCmd4 .append (url4 );
402+ logger .info ("Executing curl command: {0}" , curlCmd4 );
403+ for (int i = 0 ; i < 2 ; i ++) {
404+ assertTrue (getCurlResult (curlCmd4 .toString ()).contains ("Total Message(s) Received : 0" ),
405+ "Didn't receive expected msg count from remote queue" );
406+ }
407+
408+ // receive 0 msg from the local queue
409+ logger .info ("Receiving 0 msg from the local queue" );
410+ StringBuffer curlCmdy = new StringBuffer ("curl -j --show-error --noproxy '*' " );
411+ if (TestConstants .KIND_CLUSTER
412+ && !TestConstants .WLSIMG_BUILDER .equals (TestConstants .WLSIMG_BUILDER_DEFAULT )) {
413+ curlCmdy .append (" -H 'host: " + hostHeader1 + "' " );
414+ }
415+ String urly = "\" http://" + hostAndPort1
416+ + "/sample_war/get.jsp?remoteurl="
417+ + "t3s://domain1-admin-server:7002&action=recv&dest=jms.admin.adminQueue\" " ;
418+ curlCmdy .append (urly );
419+ logger .info ("Executing curl command for local queue: {0}" , curlCmdy );
420+ assertTrue (getCurlResult (curlCmdx .toString ()).contains ("Total Message(s) Received : 0" ),
421+ "Didn't receive expected msg count from local queue" );
422+
423+ }
424+
297425 private static String createAuxImage (String imageName , String imageTag , List <String > wdtModelFile ,
298426 String wdtVariableFile ) {
299427
@@ -630,5 +758,63 @@ private static void createNginxIngressPathRoutingRules() {
630758 assertTrue (callWebAppAndWaitTillReady (curlCmd , 60 ));
631759 }
632760
761+ // Create and display SSL certificate and key using openSSL with SAN extension
762+ private static void createCertKeyFiles (String cn ) {
763+
764+ Map <String , String > sanConfigTemplateMap = new HashMap <>();
765+ sanConfigTemplateMap .put ("INGRESS_HOST" , hostAddress );
766+
767+ Path srcFile = Paths .get (RESOURCE_DIR ,
768+ "tunneling" , "san.config.template.txt" );
769+ Path targetFile = assertDoesNotThrow (
770+ () -> generateFileFromTemplate (srcFile .toString (),
771+ "san.config.txt" , sanConfigTemplateMap ));
772+ logger .info ("Generated SAN config file {0}" , targetFile );
773+
774+ tlsKeyFile = Paths .get (RESULTS_ROOT , domainNamespace + "-tls.key" );
775+ tlsCertFile = Paths .get (RESULTS_ROOT , domainNamespace + "-tls.cert" );
776+ String opcmd = "openssl req -x509 -nodes -days 365 -newkey rsa:2048 "
777+ + "-keyout " + tlsKeyFile + " -out " + tlsCertFile
778+ + " -subj \" /CN=" + cn + "\" -extensions san"
779+ + " -config " + Paths .get (RESULTS_ROOT , "san.config.txt" );
780+ assertTrue (
781+ Command .withParams (new CommandParams ()
782+ .command (opcmd )).execute (), "openssl req command fails" );
783+
784+ String opcmd2 = "openssl x509 -in " + tlsCertFile + " -noout -text " ;
785+ assertTrue (
786+ Command .withParams (new CommandParams ()
787+ .command (opcmd2 )).execute (), "openssl list command fails" );
788+ }
789+
790+ // Import the certificate into a JKS TrustStore to be used while running
791+ // external JMS client to send message to WebLogic.
792+ private static void importKeytoTrustStore () {
793+
794+ jksTrustFile = Paths .get (RESULTS_ROOT , domainNamespace + "-trust.jks" );
795+ String keycmd = "keytool -import -file " + tlsCertFile
796+ + " --keystore " + jksTrustFile
797+ + " -storetype jks -storepass password -noprompt " ;
798+ assertTrue (
799+ Command .withParams (new CommandParams ()
800+ .command (keycmd )).execute (), "keytool import command fails" );
801+
802+ String keycmd2 = "keytool -list -keystore " + jksTrustFile
803+ + " -storepass password -noprompt" ;
804+ assertTrue (
805+ Command .withParams (new CommandParams ()
806+ .command (keycmd2 )).execute (), "keytool list command fails" );
807+ }
808+
809+ // Create kubernetes secret from the ssl key and certificate
810+ private static void createSecretWithTLSCertKey (String tlsSecretName ) {
811+ String kcmd = KUBERNETES_CLI + " create secret tls " + tlsSecretName + " --key "
812+ + tlsKeyFile + " --cert " + tlsCertFile + " -n " + domainNamespace ;
813+ assertTrue (
814+ Command .withParams (new CommandParams ()
815+ .command (kcmd )).execute (), KUBERNETES_CLI + " create secret command fails" );
816+ }
817+
818+
633819}
634820
0 commit comments