OpenSAML and Apache Santuario (xmlsec) 1.5.1
Stephanie Stroka
stephanie.stroka at adnovum.ch
Fri Apr 13 15:48:00 BST 2012
I found out that the problem is not in the registration of the id. The
document holds identifiers that point to its Elements, e.g.:
{_1ac9178abf0f99838fdcc574fea92179=[xenc:EncryptedKey: null],
Assertion_13253b842c2883ef5260df3bf0cc201013e9ac3d=[saml2:Assertion:
null], _cdf68c16b77735622330aca8b2e310ab=[xenc:EncryptedData: null],
Response_d52b993993f8cc6a004d3df24581d97f101d0e90=[saml2p:Response: null]}
But the resolving process fails when I use
doc.getElementById("Assertion_13253b842c2883ef5260df3bf0cc201013e9ac3d")
I printed the document shortly before
org.apache.xml.security.utils.resolver.implementations.ResolverFragment
requests the "element by id" (doc.getElementById(id) line 84 in
ResolverFragment). According to the identifier I should see a tag called
<saml2:Assertion> .. but it does not exist. Instead there are
<EncrptedAssertion> tags
Is it possible that something went wrong during the decryption process?
Here are the two methods that decrypt the XMLObject:
public XMLObject decryptWhereNeccessary(XMLObject obj) throws Exception {
if (obj instanceof EncryptedElementType) {
obj = decrypt(obj);
}
if (obj.getOrderedChildren() != null) {
for (XMLObject child : obj.getOrderedChildren()) {
if (child == null) continue;
XMLObject newChild = decryptWhereNeccessary(child);
if (newChild == child) continue;
if (newChild instanceof Assertion && obj instanceof Response &&
child instanceof EncryptedAssertion) {
((org.opensaml.saml2.core.Response)obj).getEncryptedAssertions().remove(child);
((org.opensaml.saml2.core.Response)obj).getAssertions().add((Assertion)
newChild);
}
else if (newChild instanceof NameID) {
obj.getClass().getMethod("setEncryptedID", new Class[]
{EncryptedID.class}).invoke(obj, new Object[]{null});
obj.getClass().getMethod("setNameID", new Class[]
{NameID.class}).invoke(obj, new Object[]{newChild});
}
else if (newChild instanceof Attribute && obj instanceof
AttributeStatement && child instanceof EncryptedAttribute) {
((AttributeStatement)obj).getEncryptedAttributes().remove(child);
((AttributeStatement)obj).getAttributes().add((Attribute)
newChild);
}
else {
throw new Exception("Do now know how to handle decrypted
element " + newChild + " in its parent " + obj);
}
}
}
return obj;
}
private XMLObject decrypt(XMLObject obj) throws Exception {
try {
if (obj instanceof EncryptedAssertion) {
obj = this.decrypter.decrypt((EncryptedAssertion)obj);
}
else if (obj instanceof EncryptedAttribute) {
obj = this.decrypter.decrypt((EncryptedAttribute)obj);
}
else if (obj instanceof EncryptedID) {
obj = this.decrypter.decrypt((EncryptedID)obj);
}
else {
throw new Exception("Do not know how to decrypt element of type "
+ obj.getElementQName().getLocalPart());
}
return obj;
catch (Exception e) {
throw new Exception("Failed to encrypt " + obj + ": " + e,e);
}
}
Sorry for all those mails and questions!
best wishes, Steffi :)
On 04/13/12 13:40, Stephanie Stroka wrote:
> Fun fact: When the ResponseUnmarshaller, but not the Decrypter calls
> attribute.getOwnerElement().setIdAttributeNode(attribute, true) in the
> same method (see stack trace below), the element can be resolved.
>
> That doesn't make sense, does it?
>
>
> Thread [main] (Suspended)
> AssertionUnmarshaller.processAttribute(XMLObject, Attr) line: 81
> AssertionUnmarshaller(AbstractXMLObjectUnmarshaller).unmarshallAttribute(XMLObject, Attr) line: 239
> AssertionUnmarshaller(AbstractXMLObjectUnmarshaller).unmarshall(Element) line: 108
> ResponseUnmarshaller(AbstractXMLObjectUnmarshaller).unmarshallChildElement(XMLObject, Element) line: 334
> ResponseUnmarshaller(AbstractXMLObjectUnmarshaller).unmarshall(Element)
> line: 121
> Toolbox.unmarshall(Element) line: 1339
> Toolbox.unmarshall(InputSource) line: 1318
> Toolbox.unmarshall(String) line: 1306
> Toolbox.resolveHttpPostBinding(AuthRequest) line: 787
> Toolbox.getSAMLMessage(AuthRequest, AuthResponse, Binding) line: 2521
> ServiceProviderState.authenticate(AuthRequest, AuthResponse) line: 876
> ServiceProviderState(AuthState).process(AuthRequest, AuthResponse)
> line: 91
> AuthStateHarness.process(TestContext) line: 154
> AuthStateHarness.authenticate(TestContext) line: 169
> tSAMLUnitTests.encryptChildren_post_symmetric_key() line: 375
> NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
> available [native method]
> NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
> DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
> Method.invoke(Object, Object...) line: 597
> FrameworkMethod$1.runReflectiveCall() line: 44
> FrameworkMethod$1(ReflectiveCallable).run() line: 15
> FrameworkMethod.invokeExplosively(Object, Object...) line: 41
> InvokeMethod.evaluate() line: 20
> BlockJUnit4ClassRunner(ParentRunner<T>).runLeaf(Statement, Description,
> RunNotifier) line: 263
> BlockJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 69
> BlockJUnit4ClassRunner.runChild(Object, RunNotifier) line: 48
> ParentRunner$3.run() line: 231
> ParentRunner$1.schedule(Runnable) line: 60
> BlockJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 229
> ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 50
> ParentRunner$2.evaluate() line: 222
> RunBefores.evaluate() line: 28
> RunAfters.evaluate() line: 31
> BlockJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 292
> JUnit4TestAdapter.run(TestResult) line: 39
> JUnitTestRunner.run() line: 421
> JUnitTestRunner.launch(JUnitTest, boolean, boolean, boolean, boolean,
> boolean, boolean, Properties) line: 912
> JUnitTestRunner.main(String[]) line: 766
>
>
>
> On 04/13/12 13:34, Stephanie Stroka wrote:
>> Hey Brent,
>>
>> thanks for testing and investing your time into that!
>> I may have figured out what causes the trouble.
>> Though I'm still not sure about how to resolve it.
>>
>> First of all: unmarshalling non encrypted messages seems to work fine,
>> except when the unmarshalled msg is marshalled again for
>> logging/debugging purposes: This causes the Id to be lost.
>>
>> The second problem may be caused by using
>> org.opensaml.saml2.encryption.Decrypter to decrypt an
>> org.opensaml.xml.XMLObject:
>>
>> There's the stack trace to where I figured out the problem:
>>
>> Thread [main] (Suspended)
>> AssertionUnmarshaller.processAttribute(XMLObject, Attr) line: 81
>> AssertionUnmarshaller(AbstractXMLObjectUnmarshaller).unmarshallAttribute(XMLObject, Attr) line: 239
>> AssertionUnmarshaller(AbstractXMLObjectUnmarshaller).unmarshall(Element) line: 108
>> Decrypter(Decrypter).decryptDataToList(EncryptedData, boolean) line: 467
>> Decrypter(Decrypter).decryptData(EncryptedData, boolean) line: 400
>> Decrypter.decryptData(EncryptedElementType) line: 141
>> Decrypter.decrypt(EncryptedAssertion) line: 69
>> Decrypter.decrypt(XMLObject) line: 152
>> Decrypter.decryptWhereNeccessary(XMLObject, EncryptionPass) line: 193
>> Decrypter.decryptWhereNeccessary(XMLObject, EncryptionPass) line: 209
>> Toolbox.verifySignature(SignableSAMLObject, String, AuthRequest,
>> AuthResponse) line: 1477
>> ServiceProviderState.consume(Response, AuthRequest, AuthResponse)
>> line: 223
>> ServiceProviderState.authenticate(AuthRequest, AuthResponse) line: 920
>> ServiceProviderState(AuthState).process(AuthRequest, AuthResponse)
>> line: 91
>> AuthStateHarness.process(TestContext) line: 154
>> AuthStateHarness.authenticate(TestContext) line: 169
>> tSAMLUnitTests.encryptAssertion_redirect_noKeyInfo() line: 148
>> NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not
>> available [native method]
>> NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
>> DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
>> Method.invoke(Object, Object...) line: 597
>> FrameworkMethod$1.runReflectiveCall() line: 44
>> FrameworkMethod$1(ReflectiveCallable).run() line: 15
>> FrameworkMethod.invokeExplosively(Object, Object...) line: 41
>> InvokeMethod.evaluate() line: 20
>> BlockJUnit4ClassRunner(ParentRunner<T>).runLeaf(Statement, Description,
>> RunNotifier) line: 263
>> BlockJUnit4ClassRunner.runChild(FrameworkMethod, RunNotifier) line: 69
>> BlockJUnit4ClassRunner.runChild(Object, RunNotifier) line: 48
>> ParentRunner$3.run() line: 231
>> ParentRunner$1.schedule(Runnable) line: 60
>> BlockJUnit4ClassRunner(ParentRunner<T>).runChildren(RunNotifier) line: 229
>> ParentRunner<T>.access$000(ParentRunner, RunNotifier) line: 50
>> ParentRunner$2.evaluate() line: 222
>> RunBefores.evaluate() line: 28
>> RunAfters.evaluate() line: 31
>> BlockJUnit4ClassRunner(ParentRunner<T>).run(RunNotifier) line: 292
>> JUnit4TestAdapter.run(TestResult) line: 39
>> JUnitTestRunner.run() line: 421
>> JUnitTestRunner.launch(JUnitTest, boolean, boolean, boolean, boolean,
>> boolean, boolean, Properties) line: 912
>> JUnitTestRunner.main(String[]) line: 766
>>
>>
>> processAttribute(..) calls
>> attribute.getOwnerElement().setIdAttributeNode(attribute, true)
>> which should register the ID attribute as an id.
>>
>> Here's the content of attribute:
>>
>> "attribute" (id=96)
>> flags 680
>> localName "ID"
>> name "ID"
>> namespaceURI null
>> ownerNode ElementNSImpl (id=100)
>> type null
>> value "Assertion_d0bd8dd5b6d9b37731d6df773b369fde83408f45"
>>
>> However, I wanted to verify that the ID is indeed registered, so I called
>> attribute.getOwnerElement().getOwnerDocument().getElementById("Assertion_d0bd8dd5b6d9b37731d6df773b369fde83408f45")
>> in the debugger and null is returned.
>>
>> Do you have any ideas what might have gone wrong?
>>
>> We are using xerces 2.9.1 and xalan 2.7.0.
>> To be honest, I've no idea how it has been endorsed into the JVM nor do
>> I know anything about you install instructions ;-).
>> This project that I'm working on is about 10 years old and I just
>> started 1 month ago.
>>
>> I am using Java hotspot 1.6.0 under Linux x86 32bit, but the testing
>> environment also (additionally) runs on 64bit Linux and under Solaris.
>>
>> Steffi
>>
>>
>>
>> On 04/12/12 23:18, Brent Putman wrote:
>>>
>>>
>>> On 4/12/12 1:12 PM, Brent Putman wrote:
>>>> I have not tried running OpenSAML v2 with the newer Santuario yet. I'll
>>>> do some quick tests later today or tomorrow to see if I experience the
>>>> same issue.
>>>
>>> I did some testing. I was not able to reproduce this by just switching
>>> OpenSAML 2 to use 1.5.1. All our signature signing and validation tests
>>> work fine for me.
>>>
>>> Your and Scott's comments about the SAML signature profile validator
>>> made me realize that the ID-ness of the attributes and their resolution
>>> can't be fundamentally broken in OpenSAML, and the Santuario IdResolver
>>> must be finding the ID's by DOM search and not by the fallback behavior
>>> that was removed in 1.5.0. If that were the case, we'd be seeing
>>> routine failures of things in the profile validator, which uses the DOM
>>> search exclusively, before it even attempted to validate the signature.
>>>
>>> I also confirmed this by turning on DEBUG logging level for category:
>>> org.apache.xml.security.utils.IdResolver. With 1.4.x, I see output
>>> similar to the following:
>>>
>>> DEBUG IdResolver - getElementByIdType() Search for ID
>>> _b32801700a13922734aeb359f296ddac
>>> DEBUG IdResolver - getElementByIdUsingDOM() Search for ID
>>> _b32801700a13922734aeb359f296ddac
>>> DEBUG IdResolver - I could find an Element using the simple
>>> getElementByIdUsingDOM method: saml2:Assertion
>>>
>>> The line about getElementByIdType() is a little misleading - looking at
>>> code, what that really does is attempt to resolve from the IdResolver
>>> cache, nothing more. The last line indicates a successful resolution
>>> via the DOM method (despite the slightly awkward English phrasing there).
>>>
>>> In order to troubleshoot what's going on in your environment, you might
>>> try reverting back to 1.4.x, and turning on the debug logging above. I
>>> suspect you'll see the first 2 lines, but not the "I could find..."
>>> line, which would mean the DOM search is failing. Unfortunately, it
>>> doesn't explicitly log anything when it then does the manual search
>>> against well-known namespaces, but the absence of the "I could find..."
>>> line in conjunction with a successful resolution and signature
>>> validation would confirm that is what it's doing.
>>>
>>> Also, if you are running the SAMLSignatureProfileValidator, it shouldn't
>>> matter what version of Santuario you are using. The DOM search there
>>> should fail if the ID-ness is lost, so that could be an indication of
>>> the problem.
>>>
>>> Since it's been working for a large number of people, I'd suspect
>>> either: 1) something you are doing after parsing but before validation
>>> is changing the DOM, as you earlier suggested or 2) an environment issue
>>> with your XML parsing environment. Can you check and confirm what
>>> version of Xerces and Xalan you are using, and that you have properly
>>> endorsed them in your JVM per our install instructions? If there is an
>>> issue with some combination of Xerces and Xalan, or a bug in some
>>> version of those libraries, we'd love to uncover that.
>>>
>>> Also, on what JRE vendor, version and OS platform are you seeing this error?
>>>
>>>
>>> --
>>> To unsubscribe from this list send an email to dev-unsubscribe at shibboleth.net
>> --
>> To unsubscribe from this list send an email to dev-unsubscribe at shibboleth.net
>
--
AdNovum Informatik AG
Stephanie Stroka
Dipl. Informatik-Ing. FH
Roentgenstrasse 22, CH-8005 Zurich
mailto:stephanie.stroka at adnovum.ch
phone: +41 44 272 6111, fax: +41 44 272 6312
http://www.adnovum.ch AdNovum Offices: Bern, Budapest, Singapore,
Zurich (HQ)
More information about the dev
mailing list