2017-01-09 20 views
-1

Я зашел в тупик, используя поддержку OpenSAML для подготовки полезной нагрузки SAML для выполнения транзакции единого входа с другой службой, с которой я работаю. Я получаю исключение NullPointerException, которое возникает после использования процедуры SecurityHelper.prepareSignatureParams(). У меня есть Stacktrace, но это было довольно уродливо, чтобы добавить.java.lang.NullPointerException Ошибка во время SecurityHelper.prepareSignatureParams() OpenSAML-вызов

Позвольте мне сказать, что я был в состоянии сделать ...

Для целей обучения технологии и убедиться, что она будет работать, я был в состоянии успешно построить полезную нагрузку SAML, подписать его с помощью Сертификат и закрытый ключ, который был сохранен в файле хранилища Java-файлов, который я создал локально на своей рабочей станции, используя программу Keytool с опцией -genkeypair.

Как я понимаю, мой файл JKS содержит самоподписанный сертификат и закрытый ключ. Я смог открыть файл JKS, собрать сертификат и закрытый ключ для создания сертификата подписи. Сертификат подписи использовался для подписи полезной нагрузки SAML, которую я создал. Вы увидите, как я это сделал, если вы посмотрите на примеры кода, которые я добавлю.

Что не работает ...

Я хочу использовать ту же самую поддержку SAML подписать мой SAML Payload используя доверенный сертификат, который у меня есть на моем сайте, что я получил от GoDaddy. Для этого я установил доверенный сертификат в хранилище ключей веб-сервера по адресу: '\ Program Files \ Java \ jre1.8.0_102 \ lib \ security \ cacerts'. Я понимаю, что файл cacerts является KeyStore для нашего веб-сервера. Я установил доверенный сертификат с помощью команды Keytool -importcert. Одно большое различие заключается в том, что у доверенного сертификата нет личного ключа. Поэтому при подготовке сертификата подписи с использованием поддержки Open SAML я не могу добавить закрытый ключ к объекту Credential (потому что у меня его нет).

При попытке вышеуказанного для доверенного сертификата я могу добраться до той части, где я готовлю подписи Parms (SecurityHelper.prepareSignatureParams()). Вот где я получаю нулевой указатель.

Если вы можете взглянуть на код, который я использую. Я включаю код (который успешно подписывает мою полезную нагрузку), который читает из локального файла JKS, а также код (который получает исключение Null Pointer), когда я пытаюсь использовать доверенный сертификат на сервере (оба случая). Там не сильно отличаются между этими двумя случаями:

// Signing process using OpenSAML 

// Get instance of an OpenSAML 'KeyStore' object... 
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); 

// Read KeyStore as File Input Stream. This is either the local JKS 
// file or the server's cacerts file. 
File ksFile = new File(keyStoreFileName); 

// Open an Input Stream with the Key Store File 
FileInputStream ksfInputStream = new FileInputStream(ksFile); 

// Load KeyStore. The keyStorePassord is the password assigned to the keystore, Usually 'changeit' 
// before being changed. 
keyStore.load(ksfInputStream, keyStorePassword); 

// Close InputFileStream. No longer needed. 
ksfInputStream.close(); 


// Used to get Entry objects from the Key Store 
KeyStore.PrivateKeyEntry pkEntry = null; 
KeyStore.TrustedCertificateEntry tcEntry = null; 

PrivateKey pk     = null; 
X509Certificate x509Certificate = null; 

BasicX509Credential credential = null; 

// The Java Key Store specific code... 
// Get Key Entry From the Key Store. CertificateAliasName identifies the 
// Entry in the KeyStore. KeyPassword is assigned to the Private Key. 
pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(certificateAliasName, new KeyStore.PasswordProtection(keyPassword)); 

// Get the Private Key from the Entry 
pk = pkEntry.getPrivateKey(); 

// Get the Certificate from the Entry 
x509Certificate = (X509Certificate) pkEntry.getCertificate(); 

// Create the Credential. Assign the X509Certificate and the Privatekey 
credential = new BasicX509Credential(); 
credential.setEntityCertificate(x509Certificate); 
credential.setPrivateKey(pk); 


// The Trusted Certificate specific code... 
// Accessing a Certificate that was issued from a trusted source - like GoDaddy.com 
// 
// Get Certificate Entry From the Key Store. CertificateAliasName identifies the Entry in the KeyStore. 
// There is NO password as there is no Private Key associate with this Certificate 

tcEntry = (TrustedCertificateEntry) keyStore.getEntry(certificateAliasName, null); 

// Get the Certificate from the Entry 
x509Certificate = (X509Certificate) tcEntry.getTrustedCertificate(); 

// Create the Credential. There is no Provate Ley to assign into the Credential 
credential = new BasicX509Credential(); 
credential.setEntityCertificate(x509Certificate); 


// Back to code that is not specific to either method... 
// 
// Assign the X509Credential object into a Credential Object. The BasicX509Credential object 
// that has a Certificate and a Private Key OR just a Certificate added to it is now saved as a 
// Cendential object. 
Credential signingCredential = credential; 


// Use the OpenSAML builder to create a signature object. 
Signature signingSignature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME).build Object(Signature.DEFAULT_ELEMENT_NAME); 

// Set the previously created signing credential 
signingSignature.setSigningCredential(signingCredential); 

// Get a Global Security Configuration object. 
SecurityConfiguration secConfig = Configuration.getGlobalSecurityConfiguration(); 

// KeyInfoGenerator. Not sure what this is, but the example I am working from shows 
// this being passed as null. 
String keyInfoGeneratorProfile = "XMLSignature"; 

// Prepare the Signature Parameters. 
// 
// This works fine for the JKS version of the KeyStore, but gets a Null Pointer exception when I run to the cacerts file. 
SecurityHelper.prepareSignatureParams(signingSignature, signingCredential, secConfig, keyInfoGeneratorProfile <or null>); 

// I need to set into the SigningSignature object the signing algorithm. This is required when using the TrustedCertificate 
signingSignature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); 



// This is my code that builds a SAML Response. The SAML Payload contains data 
// about the SSO session that I will be creating... 
Response samlResponse = createSamlResponse.buildSamlResponseMessage(); 

// Sign the Response using the Certificate that was created earlier 
samlResponse.setSignature(signingSignature); 



// Get the marshaller factory to marshall the SamlResponse 
MarshallerFactory marshallerFactory = Configuration.getMarshallerFactory(); 
Marshaller responseMarshaller = marshallerFactory.getMarshaller(samlResponse); 

// Marshall the Response 
Element responseElement = responseElement =  responseMarshaller.marshall(samlResponse); 

// Sign the Object... 
Signer.signObject(signingSignature); 

Примечание: Моя попытка подписать SAML Payload была смоделирована после примера OPENSAML, что я нашел здесь: https://narendrakadali.wordpress.com/2011/06/05/sign-assertion-using-opensaml/

Надеясь, что кто-то может показать мне ошибку мои пути или то, что мне не хватает.

Спасибо за любые предложения.

EDIT (01/26/2016)

я смог пройти мимо NULL указателя я получал при подготовке Signature Params (SecurityHelper.prepareSignatureParams()). Изменения кода включали обновление моего файла xmlsec.jar до версии 2.0.8 (xmlsec-2.0.8.jar), и я явно устанавливал алгоритм подписи для SHA256 при использовании доверенного сертификата (из GoDaddy). Смотрите мой пример кода для использования:

signingSignature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); 

Вышеуказанные изменения позволяет полезной SAML быть построены и отправлены в связи конечной точке.

Однако я все еще не устанавливаю соединение SSO с моей конечной точкой.

Вот что я вижу, что происходит:

Во время обработки, а полезная нагрузка SAML строится и, в частности, подпись SAML полезной нагрузки является подписываются:

Signer.signObject(signature); 

Я получаю сообщение об ошибке от SAML:

ERROR: org.opensaml.xml.signature.Signer - An error occured computing the digital signature 

трассировка стека (только окончание участка):

org.apache.xml.security.signature.XMLSignatureException: Sorry, you supplied the wrong key type for this operation! You supplied a null but a java.security.PrivateKey is needed. 
at org.apache.xml.security.algorithms.implementations.SignatureBaseRSA.engineInitSign(SignatureBaseRSA.java:149) 
at org.apache.xml.security.algorithms.implementations.SignatureBaseRSA.engineInitSign(SignatureBaseRSA.java:165) 
at org.apache.xml.security.algorithms.SignatureAlgorithm.initSign(SignatureAlgorithm.java:238) 
at org.apache.xml.security.signature.XMLSignature.sign(XMLSignature.java:631) 
at org.opensaml.xml.signature.Signer.signObject(Signer.java:77) 

Я искал сообщения об ошибках, но я не очень много придумываю.

Я не понимаю корень сообщения об ошибке - что был указан неправильный тип ключа (null), и что OpenSAML, похоже, ожидает java.Security.PrivateKey.

При использовании доверенного сертификата у меня нет закрытого ключа, правильно? Как я могу предоставить закрытый ключ? В случае доверенного сертификата я читаю доверенный сертификат (TrustedCertificateEntry) из KeyStore. Объект TrustedCertificateEntry позволяет мне получить доступ к сертификату, но нет способа получить закрытый ключ (также не должно быть).

Однако, когда я использую самоподписанный сертификат для выполнения операции подписи, я понимаю, что у меня есть как сертификат (открытый ключ), так и закрытый ключ, содержащийся в файле JKS (KeyStore). Я думаю, именно поэтому, когда я читал из файла JKS, я могу прочитать личную запись ключа (KeyStore.PrivateKeyEntry), которая имеет методы для доступа к открытому ключу (сертификату) и к закрытому ключу.

Что мне не хватает в деле доверенного сертификата? Кажется, что поддержка OpenSAML ожидает, что секретный ключ сможет вычислить подпись.

В случае доверенного сертификата есть ли способ упаковать оригинальный секретный ключ в мой магазин ключей (вместе с доверенным сертификатом)? Я не уверен, что это то, что обычно делается или даже возможно.

Надеюсь, некоторые указания относительно того, что я здесь делаю, пожалуйста!

EDIT (01/26/2017) - 2 для дополнительной информации.

Я поделюсь частью полезной нагрузки SAML, которая отправляется ...

В случае самоподписывающегося сертификат, я вижу SignatureValue тег и тег X509Certificate. Оба имеют двоичные данные, включенные в начало и конец тега.

В случае Доверенный сертификат, я получил пустую подпись Значение тега, который выглядит как:

<ds:SignatureValue/> 

Сертификат тег по-прежнему присутствует и содержит байты сертификата.

Итак, глядя на ошибку, которую я вижу из OpenSAML, более очевидно, что она не может вычислить подпись, используя данные, доступные в доверенном сертификате.

+0

Вопрос был не в обработке исключения Null Pointer, а в том, что я делал в пакете OpenSAML, который вызывал Null Pointer. Возможно, я мог бы повторить этот вопрос, чтобы быть более точным? Я знаю, что вопрос длительный, но, вероятно, что-то полезно для других, которые работают с поддержкой OpenSAML. – SBParks

ответ

1

Хорошо, это довольно длинный вопрос. Насколько я понимаю, корень проблемы - это сообщение «Извините, вы указали неправильный тип ключа для этой операции! Вы предоставили нуль, но java.security.PrivateKey необходим». Вы пытаетесь подписать сообщение с использованием открытого ключа. Это невозможно. Просто глядя на него логично, подписание с использованием открытого ключа не даст никаких доказательств того, что подписант предназначен, поскольку он доступен для всех.

Что вам нужно сделать, это подписать с помощью закрытого ключа. в вашем случае вы создали открытый и закрытый ключ на вашем компьютере, а затем отправили CSR в ЦС и получили сертификат, подписанный ЦС. Вы должны использовать приватный ключ с вашего локального компьютера, чтобы подписать сообщение и отправить сертификат, подписанный CA, получателю, чтобы он мог использовать его для подтверждения вашей подписи.

В this blog post of mine Я объясню, как получить учетные данные, включая закрытый ключ из хранилища ключей Java.

+0

Стефан, спасибо за ответ. Извините, я признаю, что вышеупомянутый вопрос был долгим. – SBParks

+0

Однако все еще есть что-то, что я не понимаю ... Как использовать доверенный сертификат, который я получил из CA (GoDaddy в этом случае), чтобы подписать мою полезную нагрузку SAML? Вы говорите, что мне нужно будет использовать оригинальный самоподписанный сертификат JKS, содержащий сертификат (открытый ключ) и закрытый ключ, который был сгенерирован и использован для запроса доверенного сертификата (CSR) из ЦС? Если это так, то какой сертификат я могу поделиться с стороной, с которой я пытаюсь подключиться к ... доверенному сертификату или сертификату, который содержится в файле JKS? – SBParks

+0

Se обновлено answere –

 Смежные вопросы

  • Нет связанных вопросов^_^