Я пытаюсь подключиться к приложению, установленному в Linux, с проверкой подлинности SAML с компьютера WIndows RDP.
В ответе мыла появляется сообщение «Криптографическая проверка подписи не удалась». Тот же код и запрос отлично работают в другом приложении при установке на серверах Linux.
Мы попробовали немало сценариев.
- Сгенерировал самоподписанный сертификат с нашей стороны и получил открытый ключразвернут на другом конце.
- Конечное приложение сгенерировало самозаверяющий сертификат, и они предоставили нам секретный ключ для развертывания на нашем конце.
Пожалуйста, дайте мне знать, если это SAMLсоздание проблемы с кодом или сертификата. Java SAML метод:
public OMElement createSAMLHeader() throws Exception {
OMElement securityHeader = null;
final OMFactory factory = new SOAP11Factory();
final OMNamespace wsseNS = factory.createOMNamespace(WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX);
try {
// create the Security header block
securityHeader = factory.createOMElement("Security", wsseNS);
securityHeader.addAttribute("mustUnderstand", "1", null);
// Get the builder factory
DefaultBootstrap.bootstrap();
final XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
final AssertionBuilder assertionBuilder = new AssertionBuilder();
// Create the assertion
Assertion assertion = assertionBuilder.buildObject();
final IssuerBuilder issuerBuilder = new IssuerBuilder();
final Issuer issuer = issuerBuilder.buildObject();
final String issuerName = "****";
// ConfigManager.getString(Constants.DMSConstants.DMS_CATEGORY,
// Constants.DMSConstants.DAAS_CERTIFICATE_ISSUER);
// issuer.setFormat("urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress");
issuer.setValue(issuerName);
assertion.setIssuer(issuer);
assertion.setID(UUID.randomUUID().toString());
final ConditionsBuilder conditionsBuilder = new ConditionsBuilder();
final Conditions conditions = conditionsBuilder.buildObject();
final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
final java.util.Date now = new Date(System.currentTimeMillis());
assertion.setIssueInstant(org.joda.time.DateTime.parse(df.format(now)));
// final java.util.Date now = SystemUtil.getSystemDateTime().getTime();
final long t = now.getTime();
final java.util.Date nowLess1minutes = new java.util.Date(t - (1 * ONE_MINUTE_IN_MILLIS));
final java.util.Date nowPlus3minutes = new java.util.Date(t + (300 * ONE_MINUTE_IN_MILLIS));
conditions.setNotBefore(org.joda.time.DateTime.parse(df.format(nowLess1minutes)));
final org.joda.time.DateTime highDate = org.joda.time.DateTime.parse(df.format(nowPlus3minutes));
conditions.setNotOnOrAfter(highDate);
final AudienceBuilder audienceBuilder = new AudienceBuilder();
final Audience audience = audienceBuilder.buildObject();
audience.setAudienceURI("***");
final AudienceRestrictionBuilder arBuilder = new AudienceRestrictionBuilder();
final AudienceRestriction audienceRestriction = arBuilder.buildObject();
audienceRestriction.getAudiences().add(audience);
conditions.getAudienceRestrictions().add(audienceRestriction);
assertion.setConditions(conditions);
AuthnStatement authStmt = new AuthnStatementBuilder().buildObject();
// authStmt.setAuthnInstant(new DateTime());
AuthnContext authContext = new AuthnContextBuilder().buildObject();
AuthnContextClassRef authCtxClassRef = new AuthnContextClassRefBuilder().buildObject();
authCtxClassRef.setAuthnContextClassRef("AuthnContextClassRef");
authContext.setAuthnContextClassRef(authCtxClassRef);
authStmt.setAuthnContext(authContext);
assertion.getAuthnStatements().add(authStmt);
final AttributeBuilder attributeBuilder = new AttributeBuilder();
final Attribute userIdAttribute = attributeBuilder.buildObject();
userIdAttribute.setName("LanId");
final AttributeBuilder attributeBuilder1 = new AttributeBuilder();
final Attribute repoAttribute = attributeBuilder1.buildObject();
repoAttribute.setName("RepositoryName");
final AttributeBuilder attributeBuilder2 = new AttributeBuilder();
final Attribute inputSystemAttribute = attributeBuilder2.buildObject();
inputSystemAttribute.setName("InputSystem");
@SuppressWarnings("unchecked")
final XMLObjectBuilder<AttributeValue> stringBuilder = (XMLObjectBuilder<AttributeValue>) builderFactory
.getBuilder(XSString.TYPE_NAME);
final XSString attrValueUserId = (XSString) stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
XSString.TYPE_NAME);
final XSString attrRepoId = (XSString) stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
XSString.TYPE_NAME);
final XSString attrinputSysId = (XSString) stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME,
XSString.TYPE_NAME);
// ORR 1302 starts
String userLanID = "***";
// LOG.info("Initial Value of userLanID = " + userLanID);
if (userLanID.indexOf('@') > 0) {
if (userLanID.contains(userDomain)) {
userLanID = new StringBuilder().append(userLanID.substring(0, userLanID.indexOf('@')).toLowerCase())
.toString();
} else {
userLanID = new StringBuilder().append(userDomain)
.append(userLanID.substring(0, userLanID.indexOf('@')).toLowerCase()).toString();
}
}
attrValueUserId.setValue("****");
attrRepoId.setValue("***");
repoAttribute.getAttributeValues().add(attrRepoId);
attrinputSysId.setValue("***");
inputSystemAttribute.getAttributeValues().add(attrinputSysId);
userIdAttribute.getAttributeValues().add(attrValueUserId);
final AttributeStatementBuilder asb = new AttributeStatementBuilder();
final AttributeStatement attributeStatement = asb.buildObject();
attributeStatement.getAttributes().add(userIdAttribute);
attributeStatement.getAttributes().add(repoAttribute);
attributeStatement.getAttributes().add(inputSystemAttribute);
assertion.getAttributeStatements().add(attributeStatement);
signAssertion(assertion);
final AssertionMarshaller assertionMarshaller = new AssertionMarshaller();
final Element assertionElement = assertionMarshaller.marshall(assertion);
final OMElement omElement = XMLUtils.toOM(assertionElement);
securityHeader.addChild(omElement);
} catch (ConfigurationException e) {
// throw new DMSException(e, EXCEPTION_MESSAGE_TOKEN);
} catch (MarshallingException e) {
// throw new DMSException(e, EXCEPTION_MESSAGE_TOKEN);
} catch (XMLStreamException e) {
//throw new DMSException(e, EXCEPTION_MESSAGE_TOKEN);
} catch (Exception e) {
//throw new DMSException(e, EXCEPTION_MESSAGE_TOKEN);
}
return securityHeader;
}
public static void signAssertion(final Assertion assertion) {
final PrivateKeyEntry pkEntry = retrievePrivateKey();
final PrivateKey pk = pkEntry.getPrivateKey();
final X509Certificate certificate = (X509Certificate) pkEntry.getCertificate();
final BasicX509Credential credential = new BasicX509Credential();
credential.setEntityCertificate(certificate);
credential.setPrivateKey(pk);
final Signature signature = (Signature) Configuration.getBuilderFactory()
.getBuilder(Signature.DEFAULT_ELEMENT_NAME).buildObject(Signature.DEFAULT_ELEMENT_NAME);
signature.setSigningCredential(credential);
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
final SecurityConfiguration secConfiguration = Configuration.getGlobalSecurityConfiguration();
final KeyInfoGeneratorManager keyInfoGeneratorManager = secConfiguration.getKeyInfoGeneratorManager()
.getDefaultManager();
final KeyInfoGeneratorFactory keyInfoGeneratorFactory = keyInfoGeneratorManager.getFactory(credential);
final KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance();
KeyInfo keyInfo = null;
try {
keyInfo = keyInfoGenerator.generate(credential);
signature.setKeyInfo(keyInfo);
assertion.setSignature(signature);
Configuration.getMarshallerFactory().getMarshaller(assertion).marshall(assertion);
Signer.signObject(signature);
} catch (SecurityException e) {
//throw new DMSException(e, EXCEPTION_MESSAGE_SIGNATURE);
} catch (MarshallingException e) {
//throw new DMSException(e, EXCEPTION_MESSAGE_SIGNATURE);
} catch (SignatureException e) {
// throw new DMSException(e, EXCEPTION_MESSAGE_SIGNATURE);
}
}
private static KeyStore.PrivateKeyEntry retrievePrivateKey() {
KeyStore.PrivateKeyEntry pkEntry = null;
try {
final String keyStoreLocation = "****";
final String keyStorePassword = "****";
final String signingCertAlias = "***";
// Get Private Key Entry From Certificate
final char[] password = keyStorePassword.toCharArray();
// Get Default Instance of KeyStore
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// Read Keystore as file Input Stream
FileInputStream fis = new FileInputStream(keyStoreLocation);
// Load KeyStore
ks.load(fis, password);
// Close InputFileStream
fis.close();
//ks.load(param);
pkEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(signingCertAlias,
new KeyStore.PasswordProtection(password));
} catch (IOException e) {
//throw new DMSException(e, EXCEPTION_MESSAGE_PRIV_KEY);
} catch (GeneralSecurityException e) {
// throw new DMSException(e, EXCEPTION_MESSAGE_PRIV_KEY);
}
return pkEntry;
}
Запрос на мыло:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header>
<ns1:Security xmlns:ns1="org.apache.axiom.om.impl.llom.OMNamespaceImpl@b901bce7" soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next" soapenv:mustUnderstand="0">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" mustUnderstand="1">
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="36a0b51e-cf95-42a9-94c1-8e6c9b1de555" IssueInstant="2019-10-07T22:22:16.000Z" Version="2.0">
<saml2:Issuer>****</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#36a0b51e-cf95-42a9-94c1-8e6c9b1de555">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="#default saml ds xs xsi" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>SxWFZ84sxmFzNrXDnHKkrqNcG8U=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>n9T5QB7Kwm4cMemRI3n8w7qbHVB7b91CAeKvRRBrFZAOsehKrVEUshc+ybUPDn3ccNnNWZ++FGcVnFtVdu/0C9ekqnxBKlK96tftIUnS3mvuWeOFLPAeqNuyPMlQB6+YkAERhKsUZkqR7uP2PxVGlsfsMFxLqfGccGTvU4cZ00BlwzHPnOzLAdil2K1KjRtUra8b9GIaUH7q78rFiXjB7J2k5uMmtD3t6HNNWiTp7FcBdbyd7y1ZT1XJwk1Y9v5nK2odsbsC6IXyLHiQrlFUhDSrfNsItAGjqe9OZO+6yT7HZlxtnfh7z/1RyYwyu+fV9xbpa60zyFBAIdECAObYSg==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDZzCCAk+gAwIBAgIEaa+o4TANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJBVTEMMAoGA1UE
CBMDTlNXMQ8wDQYDVQQHEwZTeWRuZXkxDDAKBgNVBAoTA0NCQTETMBEGA1UECxMKQ29tbUluc3Vy
ZTETMBEGA1UEAxMKRVNEUk9PVENBMzAeFw0xOTEwMDcwODMwMDhaFw0yMDAxMDUwODMwMDhaMGQx
CzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTEMMAoGA1UEChMDQ0JB
MRMwEQYDVQQLEwpDb21tSW5zdXJlMRMwEQYDVQQDEwpFU0RST09UQ0EzMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAvpO0o5FrjWkRPqTKaZYAkdcUc++6qgX0XgbTF6YND24p4qaJ9H8B
2oUXoN3Zq1Pc3BHejDWAVKxn7pOQ1EV03mG2duG+M2vpqVGOywNrHdSKipvcVWlh71hO3uzgcqjC
r7JvKt9XfMb07jqKxcWATB+qMBujUjy3yDlrv+wG7lwzxonuLLZXmdSldniTvX/FmfiGyYw8tbSQ
Rup8Ibzh+VB5JlpCECLLZAtQxkpFeF4XFjNMuio1QAKnYHGU6fEjFshNnwXQco8NsYoXea3Sv82V
H+ta60BFZ+HdPgLh2ZR4Ixs3uIf23teYWF5kI3yOldzO8ssyQ50QKJjEfDqoGwIDAQABoyEwHzAd
BgNVHQ4EFgQU/ve/Rf493EWmWmpWiU3Xs8pq/C8wDQYJKoZIhvcNAQELBQADggEBAIZBf+7ji2i0
rNWA0kSkjG9EdI6uL4c2GGJmTe1hDXxk1sKiDO7ckh2q/ZIyW3VpmEVRKIOMw7JlyIlcf3Q8SVBZ
vFLoregO/nia+3ZRr3mN3TFeuxVXitXsLwSDW83IjQIUM0vX7GwoVOqbNp1gwqWBM7yCvf/prcto
WFx5I9GpqV6TUekJEPFz7vcwwqbuvjBYiFMOn0kjjhVtGr8CiTnGtks0jJCplG5njzKPuevGrc10
Lveg9t7ZqbErjK1SNOd9E61sy/bjFC7U5pAirpkiKu/dfA/8c0j19qsjvM7oZmfBagSY5SK4qCeN
OgkL9Zm9qGv0/iDuPIQ1wwRuOXk=</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2:Conditions NotBefore="2019-09-27T12:22:16.000Z" NotOnOrAfter="2028-04-27T22:22:16.000Z">
<saml2:AudienceRestriction>
<saml2:Audience>***</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement>
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>AuthnContextClassRef</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
<saml2:AttributeStatement>
<saml2:Attribute Name="LanId">
<saml2:AttributeValue xsi:type="xs:string">****</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="RepositoryName">
<saml2:AttributeValue xsi:type="xs:string">***</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="InputSystem">
<saml2:AttributeValue xsi:type="xs:string">***</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
</saml2:Assertion>
</wsse:Security>
</ns1:Security>
</soapenv:Header>
<soapenv:Body>
<executeDQL xmlns="***">
<executeInfo xmlns="">
<DqlQuery>***</DqlQuery>
<RepositoryNames>***</RepositoryNames>
</executeInfo>
</executeDQL>
</soapenv:Body>
</soapenv:Envelope>
Обновление (9/11/2019): мы решили, что мы получаем несоответствие значения дайджеста, и я не уверен, каккак раз то, что произошло в этом URL