Skip to content

Commit ac7c835

Browse files
committed
add kerberos retry with krb5config EBCDIC charset on z/os
1 parent ae763f2 commit ac7c835

File tree

1 file changed

+68
-2
lines changed

1 file changed

+68
-2
lines changed

dev/com.ibm.ws.security.spnego_fat/fat/src/com/ibm/ws/security/spnego/fat/ContainerKDCCommonTest.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2024 IBM Corporation and others.
2+
* Copyright (c) 2024, 2025 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -16,7 +16,12 @@
1616
import static org.junit.Assert.assertNull;
1717

1818
import java.io.BufferedReader;
19+
import java.io.FileOutputStream;
1920
import java.io.FileReader;
21+
import java.io.IOException;
22+
import java.io.OutputStreamWriter;
23+
import java.nio.charset.Charset;
24+
import java.nio.file.Files;
2025
import java.nio.file.Path;
2126
import java.nio.file.Paths;
2227
import java.text.DateFormat;
@@ -209,20 +214,34 @@ public static void createNewSpnegoToken(boolean setAsCommonSpnegoToken, boolean
209214
* @throws InterruptedException
210215
*/
211216
private static void createSpnegoToken(String thisMethod, String user, String password) throws Exception, InterruptedException {
217+
boolean retriedWithEbcdic = false;
212218
for (int i = 1; i <= 3; i++) {
213219
try {
214220
spnegoTokenForTestClass = createToken(user, password, TARGET_SERVER, null, null, configFile, krb5Helper, true, Krb5Helper.SPNEGO_MECH_OID, null);
215221
break;
216222
} catch (LoginException e) {
223+
Log.info(c, thisMethod, "Login still failed after " + i + " attempts");
217224
if (i == 3) {
218-
Log.info(c, thisMethod, "Login still failed after " + i + " attempts");
219225
String errorMsg = "Exception was caught while trying to create a SPNEGO token. Due to LoginException: " + e.getMessage();
220226
Log.error(c, thisMethod, e, errorMsg);
221227
e.printStackTrace();
222228
throw (new Exception(errorMsg, e));
223229
}
224230
Thread.sleep(2000);
225231
} catch (Exception e2) {
232+
// Check if this is a KrbException with status code 0 on z/OS
233+
if (!retriedWithEbcdic && isZOS() && isKrbExceptionWithStatusCode0(e2)) {
234+
Log.info(c, thisMethod, "Caught KrbException with status code 0 on z/OS. Attempting to convert krb5 config to EBCDIC and retry.");
235+
try {
236+
convertKrb5ConfigToEbcdic(configFile);
237+
retriedWithEbcdic = true;
238+
// Retry the token creation after conversion
239+
continue;
240+
} catch (IOException ioEx) {
241+
Log.error(c, thisMethod, ioEx, "Failed to convert krb5 config file to EBCDIC: " + ioEx.getMessage());
242+
// Fall through to throw the original exception
243+
}
244+
}
226245
String errorMsg = "Exception was caught while trying to create a SPNEGO token. Ensuing tests requiring use of this token might fail. " + e2.getMessage();
227246
Log.error(c, thisMethod, e2, errorMsg);
228247
e2.printStackTrace();
@@ -231,6 +250,53 @@ private static void createSpnegoToken(String thisMethod, String user, String pas
231250
}
232251
}
233252

253+
/**
254+
* Check if the current OS is z/OS
255+
*/
256+
private static boolean isZOS() {
257+
String osName = System.getProperty("os.name");
258+
return osName != null && osName.toLowerCase().contains("z/os");
259+
}
260+
261+
/**
262+
* Check if the exception is a com.ibm.security.krb5.KrbException with status code 0
263+
*/
264+
private static boolean isKrbExceptionWithStatusCode0(Exception e) {
265+
Throwable cause = e;
266+
while (cause != null) {
267+
String className = cause.getClass().getName();
268+
if ("com.ibm.security.krb5.KrbException".equals(className)) {
269+
String message = cause.getMessage();
270+
// Check if the message contains "status code: 0"
271+
if (message != null && message.contains("status code: 0")) {
272+
return true;
273+
}
274+
}
275+
cause = cause.getCause();
276+
}
277+
return false;
278+
}
279+
280+
/**
281+
* Convert the krb5 config file from ASCII to EBCDIC (IBM1047) charset
282+
*/
283+
private static void convertKrb5ConfigToEbcdic(String krb5ConfigPath) throws IOException {
284+
String method = "convertKrb5ConfigToEbcdic";
285+
Log.info(c, method, "Converting krb5 config file to EBCDIC: " + krb5ConfigPath);
286+
287+
Path configPath = Paths.get(krb5ConfigPath);
288+
289+
// Read the file content as ASCII
290+
String content = new String(Files.readAllBytes(configPath), Charset.forName("US-ASCII"));
291+
292+
// Write the content back using EBCDIC charset
293+
try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(configPath.toFile()), Charset.forName("IBM1047"))) {
294+
writer.write(content);
295+
}
296+
297+
Log.info(c, method, "Successfully converted krb5 config file to EBCDIC");
298+
}
299+
234300
public static String createToken(String username, String password, String targetServer, String realm, String kdcHostName, String krb5ConfPath,
235301
Krb5Helper krb5Helper, boolean includeClientGSSCredentialInSubject, Oid mechOid, String jaasLoginContextEntry) throws Exception {
236302
String method = "createToken";

0 commit comments

Comments
 (0)