8257858: [macOS]: Remove JNF dependency from libosxsecurity/KeystoreImpl.m
8257860: [macOS]: Remove JNF dependency from libosxkrb5/SCDynamicStoreConfig.m Reviewed-by: erikj, prr, ihse, valeriep
This commit is contained in:
parent
472bf629cd
commit
4a8b5c1602
@ -81,7 +81,7 @@ define SetupTestFilesCompilationBody
|
||||
|
||||
# Locate all files with the matching prefix
|
||||
$1_FILE_LIST := \
|
||||
$$(call FindFiles, $$($1_SOURCE_DIRS), $$($1_PREFIX)*.c $$($1_PREFIX)*.cpp)
|
||||
$$(call FindFiles, $$($1_SOURCE_DIRS), $$($1_PREFIX)*.c $$($1_PREFIX)*.cpp $$($1_PREFIX)*.m)
|
||||
|
||||
$1_EXCLUDE_PATTERN := $$(addprefix %/, $$($1_EXCLUDE))
|
||||
$1_FILTERED_FILE_LIST := $$(filter-out $$($1_EXCLUDE_PATTERN), $$($1_FILE_LIST))
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -110,9 +110,9 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS := \
|
||||
-lobjc \
|
||||
-framework JavaNativeFoundation \
|
||||
-framework CoreServices \
|
||||
-framework Security \
|
||||
-framework Foundation \
|
||||
$(JDKLIB_LIBS), \
|
||||
))
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -80,8 +80,8 @@ ifneq ($(BUILD_CRYPTO), false)
|
||||
DISABLED_WARNINGS_clang := deprecated-declarations, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS := -framework JavaNativeFoundation -framework Cocoa \
|
||||
-framework SystemConfiguration -framework Kerberos, \
|
||||
LIBS := -framework Cocoa -framework SystemConfiguration \
|
||||
-framework Kerberos, \
|
||||
))
|
||||
|
||||
TARGETS += $(BUILD_LIBOSXKRB5)
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -77,13 +77,15 @@ endif
|
||||
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
BUILD_JDK_JTREG_EXCLUDE += exelauncher.c
|
||||
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libTestMainKeyWindow := -ObjC
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTestMainKeyWindow := \
|
||||
-framework Cocoa -framework JavaNativeFoundation
|
||||
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJniInvocationTest := -ljli
|
||||
BUILD_JDK_JTREG_LIBRARIES_LIBS_libTestDynamicStore := \
|
||||
-framework Cocoa -framework SystemConfiguration
|
||||
else
|
||||
BUILD_JDK_JTREG_EXCLUDE += libTestMainKeyWindow.c
|
||||
BUILD_JDK_JTREG_EXCLUDE += libTestMainKeyWindow.m
|
||||
BUILD_JDK_JTREG_EXCLUDE += exeJniInvocationTest.c
|
||||
BUILD_JDK_JTREG_EXCLUDE += libTestDynamicStore.m
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, linux), true)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -815,8 +815,8 @@ public final class KeychainStore extends KeyStoreSpi {
|
||||
* Callback method from _scanKeychain. If an identity is found, this method will be called to create Java certificate
|
||||
* and private key objects from the keychain data.
|
||||
*/
|
||||
private void createKeyEntry(String alias, long creationDate, long secKeyRef, long[] secCertificateRefs, byte[][] rawCertData)
|
||||
throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
private void createKeyEntry(String alias, long creationDate, long secKeyRef,
|
||||
long[] secCertificateRefs, byte[][] rawCertData) {
|
||||
KeyEntry ke = new KeyEntry();
|
||||
|
||||
// First, store off the private key information. This is the easy part.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,16 +25,10 @@
|
||||
|
||||
#import "apple_security_KeychainStore.h"
|
||||
#import "jni_util.h"
|
||||
|
||||
#import <Security/Security.h>
|
||||
#import <Security/SecImportExport.h>
|
||||
#import <CoreServices/CoreServices.h> // (for require() macros)
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
|
||||
|
||||
static JNF_CLASS_CACHE(jc_KeychainStore, "apple/security/KeychainStore");
|
||||
static JNF_MEMBER_CACHE(jm_createTrustedCertEntry, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
|
||||
static JNF_MEMBER_CACHE(jm_createKeyEntry, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
static jstring getLabelFromItem(JNIEnv *env, SecKeychainItemRef inItem)
|
||||
{
|
||||
@ -290,6 +284,10 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
|
||||
SecIdentityRef theIdentity = NULL;
|
||||
OSErr searchResult = noErr;
|
||||
|
||||
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
|
||||
CHECK_NULL(jc_KeychainStore);
|
||||
jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V");
|
||||
CHECK_NULL(jm_createKeyEntry);
|
||||
do {
|
||||
searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity);
|
||||
|
||||
@ -359,7 +357,8 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore)
|
||||
|
||||
// Call back to the Java object to create Java objects corresponding to this security object.
|
||||
jlong nativeKeyRef = ptr_to_jlong(privateKeyRef);
|
||||
JNFCallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
|
||||
(*env)->CallVoidMethod(env, keyStore, jm_createKeyEntry, alias, creationDate, nativeKeyRef, certRefArray, javaCertArray);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
} while (searchResult == noErr);
|
||||
|
||||
@ -377,6 +376,11 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
|
||||
SecKeychainItemRef theItem = NULL;
|
||||
OSErr searchResult = noErr;
|
||||
|
||||
jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore");
|
||||
CHECK_NULL(jc_KeychainStore);
|
||||
jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID(
|
||||
env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;JJ[B)V");
|
||||
CHECK_NULL(jm_createTrustedCertEntry);
|
||||
do {
|
||||
searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem);
|
||||
|
||||
@ -402,7 +406,8 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore)
|
||||
|
||||
// Call back to the Java object to create Java objects corresponding to this security object.
|
||||
jlong nativeRef = ptr_to_jlong(certRef);
|
||||
JNFCallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
|
||||
(*env)->CallVoidMethod(env, keyStore, jm_createTrustedCertEntry, alias, nativeRef, creationDate, certData);
|
||||
JNU_CHECK_EXCEPTION(env);
|
||||
}
|
||||
} while (searchResult == noErr);
|
||||
|
||||
@ -500,6 +505,20 @@ JNIEXPORT void JNICALL Java_apple_security_KeychainStore__1scanKeychain
|
||||
|
||||
}
|
||||
|
||||
NSString* JavaStringToNSString(JNIEnv *env, jstring jstr) {
|
||||
if (jstr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
jsize len = (*env)->GetStringLength(env, jstr);
|
||||
const jchar *chars = (*env)->GetStringChars(env, jstr, NULL);
|
||||
if (chars == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
NSString *result = [NSString stringWithCharacters:(UniChar *)chars length:len];
|
||||
(*env)->ReleaseStringChars(env, jstr, chars);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: apple_security_KeychainStore
|
||||
* Method: _addItemToKeychain
|
||||
@ -511,95 +530,97 @@ JNIEXPORT jlong JNICALL Java_apple_security_KeychainStore__1addItemToKeychain
|
||||
OSStatus err;
|
||||
jlong returnValue = 0;
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
|
||||
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
|
||||
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
|
||||
if (rawData == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
|
||||
CFArrayRef createdItems = NULL;
|
||||
|
||||
SecKeychainRef defaultKeychain = NULL;
|
||||
SecKeychainCopyDefault(&defaultKeychain);
|
||||
|
||||
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
|
||||
|
||||
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
|
||||
SecKeyImportExportParameters paramBlock;
|
||||
CFStringRef passwordStrRef = NULL;
|
||||
|
||||
jsize passwordLen = 0;
|
||||
jchar *passwordChars = NULL;
|
||||
|
||||
if (passwordObj) {
|
||||
passwordLen = (*env)->GetArrayLength(env, passwordObj);
|
||||
|
||||
if (passwordLen > 0) {
|
||||
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
|
||||
if (passwordChars == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);
|
||||
if (passwordStrRef == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
||||
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
|
||||
paramBlock.flags = 0;
|
||||
paramBlock.passphrase = passwordStrRef;
|
||||
paramBlock.alertTitle = NULL;
|
||||
paramBlock.alertPrompt = NULL;
|
||||
paramBlock.accessRef = NULL;
|
||||
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
|
||||
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
|
||||
|
||||
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
|
||||
0, ¶mBlock, defaultKeychain, &createdItems);
|
||||
if (cfDataToImport != NULL) {
|
||||
CFRelease(cfDataToImport);
|
||||
}
|
||||
|
||||
if (err == noErr) {
|
||||
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
|
||||
|
||||
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
|
||||
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
|
||||
setLabelForItem(JNFJavaToNSString(env, alias), anItem);
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
|
||||
@try {
|
||||
jsize dataSize = (*env)->GetArrayLength(env, rawDataObj);
|
||||
jbyte *rawData = (*env)->GetByteArrayElements(env, rawDataObj, NULL);
|
||||
if (rawData == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
// Retain the item, since it will be released once when the array holding it gets released.
|
||||
CFRetain(anItem);
|
||||
returnValue = ptr_to_jlong(anItem);
|
||||
} else {
|
||||
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
|
||||
CFDataRef cfDataToImport = CFDataCreate(kCFAllocatorDefault, (UInt8 *)rawData, dataSize);
|
||||
CFArrayRef createdItems = NULL;
|
||||
|
||||
SecKeychainRef defaultKeychain = NULL;
|
||||
SecKeychainCopyDefault(&defaultKeychain);
|
||||
|
||||
SecExternalFormat dataFormat = (isCertificate == JNI_TRUE ? kSecFormatX509Cert : kSecFormatWrappedPKCS8);
|
||||
|
||||
// Convert the password obj into a CFStringRef that the keychain importer can use for encryption.
|
||||
SecKeyImportExportParameters paramBlock;
|
||||
CFStringRef passwordStrRef = NULL;
|
||||
|
||||
jsize passwordLen = 0;
|
||||
jchar *passwordChars = NULL;
|
||||
|
||||
if (passwordObj) {
|
||||
passwordLen = (*env)->GetArrayLength(env, passwordObj);
|
||||
|
||||
if (passwordLen > 0) {
|
||||
passwordChars = (*env)->GetCharArrayElements(env, passwordObj, NULL);
|
||||
if (passwordChars == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
|
||||
passwordStrRef = CFStringCreateWithCharactersNoCopy(NULL, passwordChars, passwordLen, kCFAllocatorNull);
|
||||
if (passwordStrRef == NULL) {
|
||||
goto errOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
paramBlock.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
|
||||
// Note that setting the flags field **requires** you to pass in a password of some kind. The keychain will not prompt you.
|
||||
paramBlock.flags = 0;
|
||||
paramBlock.passphrase = passwordStrRef;
|
||||
paramBlock.alertTitle = NULL;
|
||||
paramBlock.alertPrompt = NULL;
|
||||
paramBlock.accessRef = NULL;
|
||||
paramBlock.keyUsage = CSSM_KEYUSE_ANY;
|
||||
paramBlock.keyAttributes = CSSM_KEYATTR_RETURN_DEFAULT;
|
||||
|
||||
err = SecKeychainItemImport(cfDataToImport, NULL, &dataFormat, NULL,
|
||||
0, ¶mBlock, defaultKeychain, &createdItems);
|
||||
if (cfDataToImport != NULL) {
|
||||
CFRelease(cfDataToImport);
|
||||
}
|
||||
|
||||
if (err == noErr) {
|
||||
SecKeychainItemRef anItem = (SecKeychainItemRef)CFArrayGetValueAtIndex(createdItems, 0);
|
||||
|
||||
// Don't bother labeling keys. They become part of an identity, and are not an accessible part of the keychain.
|
||||
if (CFGetTypeID(anItem) == SecCertificateGetTypeID()) {
|
||||
setLabelForItem(JavaStringToNSString(env, alias), anItem);
|
||||
}
|
||||
|
||||
// Retain the item, since it will be released once when the array holding it gets released.
|
||||
CFRetain(anItem);
|
||||
returnValue = ptr_to_jlong(anItem);
|
||||
} else {
|
||||
cssmPerror("_addItemToKeychain: SecKeychainItemImport", err);
|
||||
}
|
||||
|
||||
if (createdItems != NULL) {
|
||||
CFRelease(createdItems);
|
||||
}
|
||||
|
||||
errOut:
|
||||
if (rawData) {
|
||||
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
|
||||
}
|
||||
|
||||
if (passwordStrRef) CFRelease(passwordStrRef);
|
||||
if (passwordChars) {
|
||||
// clear the password and release
|
||||
memset(passwordChars, 0, passwordLen);
|
||||
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
|
||||
JNI_ABORT);
|
||||
}
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"%@", [e callStackSymbols]);
|
||||
} @finally {
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
if (createdItems != NULL) {
|
||||
CFRelease(createdItems);
|
||||
}
|
||||
|
||||
errOut:
|
||||
if (rawData) {
|
||||
(*env)->ReleaseByteArrayElements(env, rawDataObj, rawData, JNI_ABORT);
|
||||
}
|
||||
|
||||
if (passwordStrRef) CFRelease(passwordStrRef);
|
||||
if (passwordChars) {
|
||||
// clear the password and release
|
||||
memset(passwordChars, 0, passwordLen);
|
||||
(*env)->ReleaseCharArrayElements(env, passwordObj, passwordChars,
|
||||
JNI_ABORT);
|
||||
}
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,110 +24,40 @@
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaNativeFoundation/JavaNativeFoundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
|
||||
@interface JNFVectorCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFVectorCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_Vector, "java/util/Vector");
|
||||
static JNF_CTOR_CACHE(jm_Vector_ctor, jc_Vector, "(I)V");
|
||||
static JNF_MEMBER_CACHE(jm_Vector_add, jc_Vector, "add", "(Ljava/lang/Object;)Z");
|
||||
|
||||
NSArray *nsArray = (NSArray *)obj;
|
||||
jobject javaArray = JNFNewObject(env, jm_Vector_ctor, (jint)[nsArray count]);
|
||||
|
||||
for (id obj in nsArray) {
|
||||
jobject jobj = [coercer coerceNSObject:obj withEnv:env usingCoercer:coercer];
|
||||
JNFCallBooleanMethod(env, javaArray, jm_Vector_add, jobj);
|
||||
if (jobj != NULL) (*env)->DeleteLocalRef(env, jobj);
|
||||
}
|
||||
|
||||
return javaArray;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface JNFHashtableCoercion : NSObject <JNFTypeCoercion> { }
|
||||
@end
|
||||
|
||||
@implementation JNFHashtableCoercion
|
||||
|
||||
- (jobject) coerceNSObject:(id)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
static JNF_CLASS_CACHE(jc_Hashtable, "java/util/Hashtable");
|
||||
static JNF_CTOR_CACHE(jm_Hashtable_ctor, jc_Hashtable, "()V");
|
||||
static JNF_MEMBER_CACHE(jm_Hashtable_put, jc_Hashtable, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
|
||||
NSDictionary *nsDict = (NSDictionary *)obj;
|
||||
NSEnumerator *keyEnum = [nsDict keyEnumerator];
|
||||
|
||||
jobject jHashTable = JNFNewObject(env, jm_Hashtable_ctor);
|
||||
|
||||
id key = nil;
|
||||
while ((key = [keyEnum nextObject]) != nil) {
|
||||
jobject jkey = [coercer coerceNSObject:key withEnv:env usingCoercer:coercer];
|
||||
|
||||
id value = [nsDict objectForKey:key];
|
||||
jobject jvalue = [coercer coerceNSObject:value withEnv:env usingCoercer:coercer];
|
||||
|
||||
JNFCallObjectMethod(env, jHashTable, jm_Hashtable_put, jkey, jvalue);
|
||||
|
||||
if (jkey != NULL) (*env)->DeleteLocalRef(env, jkey);
|
||||
if (jvalue != NULL) (*env)->DeleteLocalRef(env, jvalue);
|
||||
}
|
||||
|
||||
return jHashTable;
|
||||
}
|
||||
|
||||
- (id) coerceJavaObject:(jobject)obj withEnv:(JNIEnv *)env usingCoercer:(JNFTypeCoercion *)coercer {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
NSDictionary *realmConfigsForRealms(SCDynamicStoreRef store, NSArray *realms) {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
|
||||
for (NSString *realm in realms) {
|
||||
CFTypeRef realmInfo = SCDynamicStoreCopyValue(store, (CFStringRef) [NSString stringWithFormat:@"Kerberos:%@", realm]);
|
||||
|
||||
if (realmInfo == NULL || CFGetTypeID(realmInfo) != CFDictionaryGetTypeID()) {
|
||||
if (realmInfo) CFRelease(realmInfo);
|
||||
return nil;
|
||||
}
|
||||
|
||||
[dict setObject:(NSArray *)realmInfo forKey:realm];
|
||||
CFRelease(realmInfo);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
#import "jni_util.h"
|
||||
|
||||
#define KERBEROS_DEFAULT_REALMS @"Kerberos-Default-Realms"
|
||||
#define KERBEROS_DEFAULT_REALM_MAPPINGS @"Kerberos-Domain-Realm-Mappings"
|
||||
#define KERBEROS_REALM_INFO @"Kerberos:%@"
|
||||
|
||||
JavaVM *localVM;
|
||||
|
||||
void _SCDynamicStoreCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) {
|
||||
NSArray *keys = (NSArray *)changedKeys;
|
||||
NSArray *keys = (NSArray *)changedKeys;
|
||||
if ([keys count] == 0) return;
|
||||
if (![keys containsObject:KERBEROS_DEFAULT_REALMS] && ![keys containsObject:KERBEROS_DEFAULT_REALM_MAPPINGS]) return;
|
||||
|
||||
JNFPerformEnvBlock(JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon, ^(JNIEnv *env) {
|
||||
static JNF_CLASS_CACHE(jc_Config, "sun/security/krb5/Config");
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_Config_refresh, jc_Config, "refresh", "()V");
|
||||
JNFCallStaticVoidMethod(env, jm_Config_refresh);
|
||||
});
|
||||
JNIEnv *env;
|
||||
bool createdFromAttach = FALSE;
|
||||
jint status = (*localVM)->GetEnv(localVM, (void**)&env, JNI_VERSION_1_2);
|
||||
if (status == JNI_EDETACHED) {
|
||||
status = (*localVM)->AttachCurrentThreadAsDaemon(localVM, (void**)&env, NULL);
|
||||
createdFromAttach = TRUE;
|
||||
}
|
||||
if (status == 0) {
|
||||
jclass jc_Config = (*env)->FindClass(env, "sun/security/krb5/Config");
|
||||
CHECK_NULL(jc_Config);
|
||||
jmethodID jm_Config_refresh = (*env)->GetStaticMethodID(env, jc_Config, "refresh", "()V");
|
||||
CHECK_NULL(jm_Config_refresh);
|
||||
(*env)->CallStaticVoidMethod(env, jc_Config, jm_Config_refresh);
|
||||
if ((*env)->ExceptionOccurred(env) != NULL) {
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
if (createdFromAttach) {
|
||||
(*localVM)->DetachCurrentThread(localVM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -135,89 +65,109 @@ void _SCDynamicStoreCallBack(SCDynamicStoreRef store, CFArrayRef changedKeys, vo
|
||||
* Method: installNotificationCallback
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_installNotificationCallback(JNIEnv *env, jclass klass) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
|
||||
@try {
|
||||
(*env)->GetJavaVM(env, &localVM);
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java"), _SCDynamicStoreCallBack, NULL);
|
||||
if (store == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
NSArray *keys = [NSArray arrayWithObjects:KERBEROS_DEFAULT_REALMS, KERBEROS_DEFAULT_REALM_MAPPINGS, nil];
|
||||
SCDynamicStoreSetNotificationKeys(store, (CFArrayRef) keys, NULL);
|
||||
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java"), _SCDynamicStoreCallBack, NULL);
|
||||
if (store == NULL) {
|
||||
return;
|
||||
CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
|
||||
if (rls != NULL) {
|
||||
CFRunLoopAddSource(CFRunLoopGetMain(), rls, kCFRunLoopDefaultMode);
|
||||
CFRelease(rls);
|
||||
}
|
||||
|
||||
CFRelease(store);
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"%@", [e callStackSymbols]);
|
||||
} @finally {
|
||||
[pool drain];
|
||||
}
|
||||
|
||||
NSArray *keys = [NSArray arrayWithObjects:KERBEROS_DEFAULT_REALMS, KERBEROS_DEFAULT_REALM_MAPPINGS, nil];
|
||||
SCDynamicStoreSetNotificationKeys(store, (CFArrayRef) keys, NULL);
|
||||
|
||||
CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
|
||||
if (rls != NULL) {
|
||||
CFRunLoopAddSource(CFRunLoopGetMain(), rls, kCFRunLoopDefaultMode);
|
||||
CFRelease(rls);
|
||||
}
|
||||
|
||||
CFRelease(store);
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
|
||||
}
|
||||
|
||||
#define ADD(list, str) { \
|
||||
jobject localeObj = (*env)->NewStringUTF(env, [str UTF8String]); \
|
||||
(*env)->CallBooleanMethod(env, list, jm_listAdd, localeObj); \
|
||||
(*env)->DeleteLocalRef(env, localeObj); \
|
||||
}
|
||||
|
||||
#define ADDNULL(list) (*env)->CallBooleanMethod(env, list, jm_listAdd, NULL)
|
||||
|
||||
/*
|
||||
* Class: sun_security_krb5_SCDynamicStoreConfig
|
||||
* Method: getKerberosConfig
|
||||
* Signature: ()Ljava/util/Hashtable;
|
||||
* Signature: ()Ljava/util/List;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_sun_security_krb5_SCDynamicStoreConfig_getKerberosConfig(JNIEnv *env, jclass klass) {
|
||||
jobject jHashTable = NULL;
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
jobject newList = 0;
|
||||
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java-kerberos"), NULL, NULL);
|
||||
if (store == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
SCDynamicStoreRef store = NULL;
|
||||
CFTypeRef realms = NULL;
|
||||
CFTypeRef realmMappings = NULL;
|
||||
CFTypeRef realmInfo = NULL;
|
||||
|
||||
CFTypeRef realms = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALMS);
|
||||
if (realms == NULL || CFGetTypeID(realms) != CFArrayGetTypeID()) {
|
||||
if (realms) CFRelease(realms);
|
||||
CFRelease(store);
|
||||
return NULL;
|
||||
}
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
|
||||
@try {
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java-kerberos"), NULL, NULL);
|
||||
if (store == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFTypeRef realmMappings = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS);
|
||||
CFTypeRef realms = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALMS);
|
||||
if (realms == NULL || CFGetTypeID(realms) != CFArrayGetTypeID()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (realmMappings == NULL || CFGetTypeID(realmMappings) != CFArrayGetTypeID()) {
|
||||
// This methods returns a ArrayList<String>:
|
||||
// (realm kdc* null) null (mapping-domain mapping-realm)*
|
||||
jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
|
||||
CHECK_NULL_RETURN(jc_arrayListClass, NULL);
|
||||
jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "<init>", "()V");
|
||||
CHECK_NULL_RETURN(jm_arrayListCons, NULL);
|
||||
jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
||||
CHECK_NULL_RETURN(jm_listAdd, NULL);
|
||||
newList = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons);
|
||||
CHECK_NULL_RETURN(newList, NULL);
|
||||
|
||||
for (NSString *realm in (NSArray*)realms) {
|
||||
if (realmInfo) CFRelease(realmInfo); // for the previous realm
|
||||
realmInfo = SCDynamicStoreCopyValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, realm]);
|
||||
if (realmInfo == NULL || CFGetTypeID(realmInfo) != CFDictionaryGetTypeID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ADD(newList, realm);
|
||||
NSDictionary* ri = (NSDictionary*)realmInfo;
|
||||
for (NSDictionary* k in (NSArray*)ri[@"kdc"]) {
|
||||
ADD(newList, k[@"host"]);
|
||||
}
|
||||
ADDNULL(newList);
|
||||
}
|
||||
ADDNULL(newList);
|
||||
|
||||
CFTypeRef realmMappings = SCDynamicStoreCopyValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS);
|
||||
if (realmMappings != NULL && CFGetTypeID(realmMappings) == CFArrayGetTypeID()) {
|
||||
for (NSDictionary* d in (NSArray *)realmMappings) {
|
||||
for (NSString* s in d) {
|
||||
ADD(newList, s);
|
||||
ADD(newList, d[s]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"%@", [e callStackSymbols]);
|
||||
} @finally {
|
||||
[pool drain];
|
||||
if (realmInfo) CFRelease(realmInfo);
|
||||
if (realmMappings) CFRelease(realmMappings);
|
||||
CFRelease(realms);
|
||||
CFRelease(store);
|
||||
return NULL;
|
||||
if (realms) CFRelease(realms);
|
||||
if (store) CFRelease(store);
|
||||
}
|
||||
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
|
||||
if (CFArrayGetCount(realms) > 0) {
|
||||
NSDictionary *defaultRealmsDict = [NSDictionary dictionaryWithObject:[(NSArray *)realms objectAtIndex:0] forKey:@"default_realm"];
|
||||
[dict setObject:defaultRealmsDict forKey:@"libdefaults"];
|
||||
|
||||
NSDictionary *realmConfigs = realmConfigsForRealms(store, (NSArray *)realms);
|
||||
[dict setObject:realmConfigs forKey:@"realms"];
|
||||
}
|
||||
CFRelease(realms);
|
||||
CFRelease(store);
|
||||
|
||||
if (CFArrayGetCount(realmMappings) > 0) {
|
||||
[dict setObject:[(NSArray *)realmMappings objectAtIndex:0] forKey:@"domain_realm"];
|
||||
}
|
||||
CFRelease(realmMappings);
|
||||
|
||||
|
||||
// create and load a coercer with all of the different coercions to convert each type of object
|
||||
JNFTypeCoercer *coercer = [[[JNFTypeCoercer alloc] init] autorelease];
|
||||
[JNFDefaultCoercions addStringCoercionTo:coercer];
|
||||
[JNFDefaultCoercions addNumberCoercionTo:coercer];
|
||||
[coercer addCoercion:[[[JNFHashtableCoercion alloc] init] autorelease] forNSClass:[NSDictionary class] javaClass:@"java/util/Map"];
|
||||
[coercer addCoercion:[[[JNFVectorCoercion alloc] init] autorelease] forNSClass:[NSArray class] javaClass:@"java/util/List"];
|
||||
|
||||
// convert Cocoa graph to Java graph
|
||||
jHashTable = [coercer coerceNSObject:dict withEnv:env];
|
||||
|
||||
JNF_COCOA_EXIT(env);
|
||||
|
||||
return jHashTable;
|
||||
return newList;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,14 +26,20 @@
|
||||
package sun.security.krb5;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
|
||||
public class SCDynamicStoreConfig {
|
||||
private static native void installNotificationCallback();
|
||||
private static native Hashtable<String, Object> getKerberosConfig();
|
||||
|
||||
/**
|
||||
* Returns the dynamic store setting for kerberos in a string array.
|
||||
* (realm kdc* null) null (mapping-domain mapping-realm)*
|
||||
*/
|
||||
private static native List<String> getKerberosConfig();
|
||||
private static boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
|
||||
|
||||
static {
|
||||
@ -51,49 +57,6 @@ public class SCDynamicStoreConfig {
|
||||
if (isMac) installNotificationCallback();
|
||||
}
|
||||
|
||||
private static Vector<String> unwrapHost(
|
||||
Collection<Hashtable<String, String>> c) {
|
||||
Vector<String> vector = new Vector<String>();
|
||||
for (Hashtable<String, String> m : c) {
|
||||
vector.add(m.get("host"));
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* convertRealmConfigs: Maps the Object graph that we get from JNI to the
|
||||
* object graph that Config expects. Also the items inside the kdc array
|
||||
* are wrapped inside Hashtables
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Hashtable<String, Object>
|
||||
convertRealmConfigs(Hashtable<String, ?> configs) {
|
||||
Hashtable<String, Object> realmsTable = new Hashtable<String, Object>();
|
||||
|
||||
for (String realm : configs.keySet()) {
|
||||
// get the kdc
|
||||
Hashtable<String, Collection<?>> map =
|
||||
(Hashtable<String, Collection<?>>) configs.get(realm);
|
||||
Hashtable<String, Vector<String>> realmMap =
|
||||
new Hashtable<String, Vector<String>>();
|
||||
|
||||
// put the kdc into the realmMap
|
||||
Collection<Hashtable<String, String>> kdc =
|
||||
(Collection<Hashtable<String, String>>) map.get("kdc");
|
||||
if (kdc != null) realmMap.put("kdc", unwrapHost(kdc));
|
||||
|
||||
// put the admin server into the realmMap
|
||||
Collection<Hashtable<String, String>> kadmin =
|
||||
(Collection<Hashtable<String, String>>) map.get("kadmin");
|
||||
if (kadmin != null) realmMap.put("admin_server", unwrapHost(kadmin));
|
||||
|
||||
// add the full entry to the realmTable
|
||||
realmsTable.put(realm, realmMap);
|
||||
}
|
||||
|
||||
return realmsTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls down to JNI to get the raw Kerberos Config and maps the object
|
||||
* graph to the one that Kerberos Config in Java expects
|
||||
@ -102,45 +65,64 @@ public class SCDynamicStoreConfig {
|
||||
* @throws IOException
|
||||
*/
|
||||
public static Hashtable<String, Object> getConfig() throws IOException {
|
||||
Hashtable<String, Object> stanzaTable = getKerberosConfig();
|
||||
if (stanzaTable == null) {
|
||||
List<String> list = getKerberosConfig();
|
||||
if (list == null) {
|
||||
throw new IOException(
|
||||
"Could not load configuration from SCDynamicStore");
|
||||
}
|
||||
if (DEBUG) System.out.println("Raw map from JNI: " + stanzaTable);
|
||||
return convertNativeConfig(stanzaTable);
|
||||
}
|
||||
if (DEBUG) System.out.println("Raw map from JNI: " + list);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Hashtable<String, Object> convertNativeConfig(
|
||||
Hashtable<String, Object> stanzaTable) throws IOException {
|
||||
// convert SCDynamicStore realm structure to Java realm structure
|
||||
Hashtable<String, ?> realms =
|
||||
(Hashtable<String, ?>) stanzaTable.get("realms");
|
||||
if (realms == null || realms.isEmpty()) {
|
||||
throw new IOException(
|
||||
"SCDynamicStore contains an empty Kerberos setting");
|
||||
}
|
||||
stanzaTable.remove("realms");
|
||||
Hashtable<String, Object> realmsTable = convertRealmConfigs(realms);
|
||||
stanzaTable.put("realms", realmsTable);
|
||||
WrapAllStringInVector(stanzaTable);
|
||||
if (DEBUG) System.out.println("stanzaTable : " + stanzaTable);
|
||||
return stanzaTable;
|
||||
}
|
||||
Hashtable<String,Object> v = new Hashtable<>();
|
||||
Hashtable<String,Object> realms = new Hashtable<>();
|
||||
Iterator<String> iterator = list.iterator();
|
||||
String defaultRealm = null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void WrapAllStringInVector(
|
||||
Hashtable<String, Object> stanzaTable) {
|
||||
for (String s: stanzaTable.keySet()) {
|
||||
Object v = stanzaTable.get(s);
|
||||
if (v instanceof Hashtable) {
|
||||
WrapAllStringInVector((Hashtable<String,Object>)v);
|
||||
} else if (v instanceof String) {
|
||||
Vector<String> vec = new Vector<>();
|
||||
vec.add((String)v);
|
||||
stanzaTable.put(s, vec);
|
||||
while (true) {
|
||||
String nextRealm = iterator.next();
|
||||
if (nextRealm == null) {
|
||||
break;
|
||||
}
|
||||
if (defaultRealm == null) {
|
||||
defaultRealm = nextRealm;
|
||||
Hashtable<String,Object> dr = new Hashtable<>();
|
||||
dr.put("default_realm", v1(defaultRealm));
|
||||
v.put("libdefaults", dr);
|
||||
}
|
||||
Vector<String> kdcs = new Vector<>();
|
||||
while (true) {
|
||||
String nextKdc = iterator.next();
|
||||
if (nextKdc == null) {
|
||||
break;
|
||||
}
|
||||
kdcs.add(nextKdc);
|
||||
}
|
||||
if (!kdcs.isEmpty()) {
|
||||
Hashtable<String,Object> ri = new Hashtable<>();
|
||||
ri.put("kdc", kdcs);
|
||||
realms.put(nextRealm, ri);
|
||||
}
|
||||
}
|
||||
if (!realms.isEmpty()) {
|
||||
v.put("realms", realms);
|
||||
}
|
||||
Hashtable<String,Object> mapping = new Hashtable<>();
|
||||
while (true) {
|
||||
if (!iterator.hasNext()) {
|
||||
break;
|
||||
}
|
||||
mapping.put(iterator.next(), v1(iterator.next()));
|
||||
}
|
||||
if (!mapping.isEmpty()) {
|
||||
v.put("domain_realm", mapping);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Make a single value Vector. Config's stanzaTable always
|
||||
// use Vector as end values.
|
||||
private static Vector<String> v1(String s) {
|
||||
Vector<String> out = new Vector<>();
|
||||
out.add(s);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7184246
|
||||
* @summary Simplify Config.get() of krb5
|
||||
* @modules java.security.jgss/sun.security.krb5:+open
|
||||
*/
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Vector;
|
||||
import sun.security.krb5.Config;
|
||||
import sun.security.krb5.SCDynamicStoreConfig;
|
||||
|
||||
public class SCDynamicConfigTest {
|
||||
|
||||
static Vector<Hashtable<String,String>>hosts() {
|
||||
Vector <Hashtable<String,String>> result = new Vector<>();
|
||||
Hashtable<String,String> pair = new Hashtable<>();
|
||||
pair.put("host", "127.0.0.1");
|
||||
result.add(pair);
|
||||
pair = new Hashtable<>();
|
||||
pair.put("host", "127.0.0.2");
|
||||
result.add(pair);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Reconstruct a typical SCDynamicConfig.getKerberosConfig() output
|
||||
Hashtable<String, Object> conf = new Hashtable<>();
|
||||
|
||||
Hashtable<String, Object> libdefaults = new Hashtable<>();
|
||||
libdefaults.put("default_realm", "REALM.COM");
|
||||
conf.put("libdefaults", libdefaults);
|
||||
|
||||
Hashtable<String, Object> realms = new Hashtable<>();
|
||||
Hashtable<String, Object> thisRealm = new Hashtable<>();
|
||||
realms.put("REALM.COM", thisRealm);
|
||||
thisRealm.put("kpasswd", hosts());
|
||||
thisRealm.put("kadmin", hosts());
|
||||
thisRealm.put("kdc", hosts());
|
||||
conf.put("realms", realms);
|
||||
|
||||
Hashtable<String, Object> domain_realm = new Hashtable<>();
|
||||
domain_realm.put(".realm.com", "REALM.COM");
|
||||
domain_realm.put("realm.com", "REALM.COM");
|
||||
conf.put("domain_realm", domain_realm);
|
||||
|
||||
System.out.println("SCDynamicConfig:\n");
|
||||
System.out.println(conf);
|
||||
|
||||
// Simulate SCDynamicConfig.getConfig() output
|
||||
Method m = SCDynamicStoreConfig.class.getDeclaredMethod(
|
||||
"convertNativeConfig", Hashtable.class);
|
||||
m.setAccessible(true);
|
||||
conf = (Hashtable)m.invoke(null, conf);
|
||||
|
||||
System.out.println("\nkrb5.conf:\n");
|
||||
System.out.println(conf);
|
||||
|
||||
// Feed it into a Config object
|
||||
System.setProperty("java.security.krb5.conf", "not-a-file");
|
||||
Config cf = Config.getInstance();
|
||||
Field f = Config.class.getDeclaredField("stanzaTable");
|
||||
f.setAccessible(true);
|
||||
f.set(cf, conf);
|
||||
|
||||
System.out.println("\nConfig:\n");
|
||||
System.out.println(cf);
|
||||
|
||||
if (!cf.getDefaultRealm().equals("REALM.COM")) {
|
||||
throw new Exception();
|
||||
}
|
||||
if (!cf.getKDCList("REALM.COM").equals("127.0.0.1 127.0.0.2")) {
|
||||
throw new Exception();
|
||||
}
|
||||
if (!cf.get("domain_realm", ".realm.com").equals("REALM.COM")) {
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8257860
|
||||
* @summary SCDynamicStoreConfig works
|
||||
* @modules java.security.jgss/sun.security.krb5
|
||||
* @library /test/lib
|
||||
* @run main/manual/native TestDynamicStore
|
||||
* @requires (os.family == "mac")
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import sun.security.krb5.Config;
|
||||
|
||||
public class TestDynamicStore {
|
||||
|
||||
native static int actionInternal(char what, char whom);
|
||||
|
||||
// what: 'a' for add, 'r' for remove
|
||||
// whom: 'a' for all, 'r' for realm, 'm' for mapping
|
||||
static int action(char what, char whom) throws Exception {
|
||||
int out = actionInternal(what, whom);
|
||||
System.out.println("Run " + what + whom + " " + out);
|
||||
Thread.sleep(1000); // wait for callback called
|
||||
return out;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
System.loadLibrary("TestDynamicStore");
|
||||
|
||||
Config cfg = Config.getInstance();
|
||||
if (cfg.exists("libdefaults") || cfg.exists("realms")) {
|
||||
System.out.println("Already have krb5 config. Will not touch");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
System.out.println("Fill in dynamic store");
|
||||
action('a', 'a');
|
||||
Asserts.assertTrue(Config.getInstance().get("libdefaults", "default_realm").equals("A.COM"));
|
||||
Asserts.assertTrue(Config.getInstance().exists("domain_realm"));
|
||||
|
||||
System.out.println("Remove mapping");
|
||||
action('r', 'm');
|
||||
Asserts.assertTrue(!Config.getInstance().exists("domain_realm"));
|
||||
|
||||
System.out.println("Re-add mapping");
|
||||
action('a', 'm');
|
||||
Asserts.assertTrue(Config.getInstance().exists("domain_realm"));
|
||||
|
||||
System.out.println("Remove realm info");
|
||||
action('r', 'r');
|
||||
// Realm info is not watched, so no change detected
|
||||
Asserts.assertTrue(Config.getInstance().get("libdefaults", "default_realm").equals("A.COM"));
|
||||
|
||||
System.out.println("Remove mapping");
|
||||
action('r', 'm');
|
||||
// But mapping is watched, so realm info is not re-read
|
||||
Asserts.assertTrue(Config.getInstance().get("libdefaults", "default_realm").equals("B.COM"));
|
||||
} finally {
|
||||
System.out.println("Remove everything");
|
||||
action('r', 'a');
|
||||
Asserts.assertTrue(!Config.getInstance().exists("libdefault"));
|
||||
}
|
||||
}
|
||||
}
|
111
test/jdk/sun/security/krb5/config/native/libTestDynamicStore.m
Normal file
111
test/jdk/sun/security/krb5/config/native/libTestDynamicStore.m
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import <jni.h>
|
||||
|
||||
#define KERBEROS_DEFAULT_REALMS @"Kerberos-Default-Realms"
|
||||
#define KERBEROS_DEFAULT_REALM_MAPPINGS @"Kerberos-Domain-Realm-Mappings"
|
||||
#define KERBEROS_REALM_INFO @"Kerberos:%@"
|
||||
|
||||
int removeAll(SCDynamicStoreRef store) {
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreRemoveValue(store, (CFStringRef) KERBEROS_DEFAULT_REALMS));
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreRemoveValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, @"A.COM"]));
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreRemoveValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, @"B.COM"]));
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreRemoveValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int removeRealm(SCDynamicStoreRef store) {
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreRemoveValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, @"A.COM"]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int removeMapping(SCDynamicStoreRef store) {
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreRemoveValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int addMapping(SCDynamicStoreRef store) {
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"a", @"A",
|
||||
@"b", @"B",
|
||||
@"c", @"C",
|
||||
@"d", @"D",
|
||||
nil];
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreSetValue(store, (CFStringRef) KERBEROS_DEFAULT_REALM_MAPPINGS, [NSArray arrayWithObjects: dict, nil]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int addAll(SCDynamicStoreRef store) {
|
||||
NSArray *keys = [NSArray arrayWithObjects:@"A.COM", @"B.COM", nil];
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreSetValue(store, (CFStringRef) KERBEROS_DEFAULT_REALMS, keys));
|
||||
|
||||
NSDictionary *k1 = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"kdc1.a.com", @"host", nil];
|
||||
NSDictionary *k2 = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"kdc2.a.com", @"host", nil];
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSArray arrayWithObjects: k1, k2, nil], @"kdc",
|
||||
nil];
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreSetValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, @"A.COM"], dict));
|
||||
|
||||
k1 = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"kdc1.b.com", @"host", nil];
|
||||
k2 = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"kdc2.b.com", @"host", nil];
|
||||
dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSArray arrayWithObjects: k1, k2, nil], @"kdc",
|
||||
nil];
|
||||
fprintf(stderr, "%d\n", SCDynamicStoreSetValue(store, (CFStringRef) [NSString stringWithFormat:KERBEROS_REALM_INFO, @"B.COM"], dict));
|
||||
addMapping(store);
|
||||
return 1;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_TestDynamicStore_actionInternal(JNIEnv *env, jclass clazz, jchar what, jchar whom) {
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("java-kerberos"), NULL, NULL);
|
||||
fprintf(stderr, ">>> action: %c %c\n", what, whom);
|
||||
@try {
|
||||
switch (what) {
|
||||
case 'a':
|
||||
switch (whom) {
|
||||
case 'a': return addAll(store);
|
||||
case 'm': return addMapping(store);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
switch (whom) {
|
||||
case 'a': return removeAll(store);
|
||||
case 'r': return removeRealm(store);
|
||||
case 'm': return removeMapping(store);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} @finally {
|
||||
CFRelease(store);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user