WS Policy with Apache CXF 3.0 - soap

Trying to implement WS-Policy within WSDL.
There is my configurations:
WS-Policy within WSDL:
<wsp:Policy wsu:Id="Signature">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding>
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=
"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken=
"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
<wsp:Policy>
<sp:WssX509V3Token10 />
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:TripleDesRsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:LaxTsFirst />
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp />
<sp:OnlySignEntireHeadersAndBody />
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts>
<sp:Body />
</sp:SignedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
CXF configuration:
EndpointImpl endpoint = new EndpointImpl(bus, service);
endpoint.setWsdlLocation("classpath:/wsdl/ws.wsdl");
endpoint.setProperties(new HashMap<String, Object>() {
{
put("ws-security.signature.validator", customSignatureValidator);
put("ws-security.signature.properties", new Properties() {{
put("org.apache.ws.security.crypto.provider", "org.apache.ws.security.components.crypto.Merlin");
put("org.apache.ws.security.crypto.merlin.keystore.type", "jks");
put("org.apache.ws.security.crypto.merlin.keystore.password", keystorePassword);
put("org.apache.ws.security.crypto.merlin.file", keystorePath);
}});
put("ws-security.signature.username", privateKeyName);
put("ws-security.callback-handler", (CallbackHandler) callbacks -> {
WSPasswordCallback passwordCallback = (WSPasswordCallback) callbacks[0];
passwordCallback.setPassword(privateKeyPassword);
});
}
});
endpoint.publish("/ws");
Problem:
After sending SOAP request with timestamp, signature key information etc. I'm getting SOAP fault message:
These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}AsymmetricBinding: Received Timestamp does not match the requirements
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}InitiatorToken
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}RecipientToken
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}IncludeTimestamp
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}OnlySignEntireHeadersAndBody
Error appears even if I'm not sending timestamp. According logs (CXF) I see that signature is correct.

After some debugging and experiments figured out the problem: provided SOAP request was incorrect according WS-Policy: Timestamp and Body must be signed by the same signature. If signed only Body - will face listed errors (which are bit inaccurate).

Related

CamelCase resgitraiton of eureka app using REST API

I'm using eureka server,Config server and zuul server,and registering a rest service using Eureka REST API provided at
Eureka REST Operations
eureka url to register : http://localhost:8761/eureka/apps/DemoClient
with post body as below :
{
"instance": {
"instanceId":"localhost:DemoClient58181",
"hostName": "localhost",
"app": "DemoClient",
"ipAddr": "localhost",
"vipAddress": "DemoClient",
"secureVipAddress": "DemoClient",
"status": "UP",
"port": {"$": "58181", "#enabled": "true"},
"healthCheckUrl": "http://localhost:58181/healthcheck",
"statusPageUrl": "http://localhost:58181/status",
"homePageUrl": "http://localhost:58181",
"dataCenterInfo": {
"#class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
"name": "MyOwn"
}
}
}
i can see the app registered as below
<application>
<name>DEMOCLIENT</name>
<instance>
<instanceId>localhost:58181</instanceId>
<hostName>localhost</hostName>
<app>DEMOCLIENT</app>
<ipAddr>localhost</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">58181</port>
<securePort enabled="false">7002</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1523540991583</registrationTimestamp>
<lastRenewalTimestamp>1523540991583</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1523538580531</serviceUpTimestamp>
</leaseInfo>
<metadata class="java.util.Collections$EmptyMap"/>
<homePageUrl>http://localhost:58181</homePageUrl>
<statusPageUrl>http://localhost:58181/status</statusPageUrl>
<healthCheckUrl>http://localhost:58181/healthcheck</healthCheckUrl>
<vipAddress>DemoClient</vipAddress>
<secureVipAddress>DemoClient</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1523540991583</lastUpdatedTimestamp>
<lastDirtyTimestamp>1523540991075</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
when request with url http://localhost:58080/democlient/sayhello is accessed
but http://localhost:58080/DemoClient/sayhello is not accessed
when i add route configuration in zuul as
zuul:
ignoredServices: '*'
routes:
DemoClient:
path: /DemoClient/**
serviceId: DEMOCLIENT
then the CameCase route works.
Is there any way, how i can access route registering with CamelCase via REST api and not specifying route configuration in zuul.

CXF: Inbound policy verification failed: These policy alternatives can not be satisfied:

Wildfly10
CXF 3.1.6
SOAP Webservices
WSDL configuration of security policy is:
<wsp:Policy wsu:Id="UsernameTransportPolicy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:TextPassword />
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Handler configuration is:
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
<endpoint-config>
<config-name>Custom-JAXWS-WS-SecurityEndpoint</config-name>
<property>
<property-name>ws-security.validate.token</property-name>
<property-value>true</property-value>
</property>
<property>
<property-name>ws-security.callback-handler</property-name>
<property-value>com.xxx.xxxx.security.ServerPasswordHandler
</property-value>
</property>
</endpoint-config>
</jaxws-config>
Handler code:
public class ServerPasswordHandler implements CallbackHandler
{
private static final Logger logger = Logger.getInstance(ServerPasswordHandler.class);
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException
{
logger.debug("begin handle");
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
String userId = "wsuser";
String password = "wspassword";
logger.debug("userId is["+userId+"]");
if (userId.equals(pc.getIdentifier()))
{
pc.setPassword(password);
logger.info("User ["+userId+"] is familiar.");
}
else
logger.error("Unknown user ["+userId+"]");
logger.debug("end handle");
}
}
Sending xml request as:
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ser="http://service.dms.ctl.com/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<wsse:Security soap:mustUnderstand='true'
xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'
xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'>
<wsse:UsernameToken wsu:Id='UsernameToken-3DAJDJSKJDHFJASDKJFKJ234JL2K3H2K3J42'>
<wsse:Username>wsuser</wsse:Username>
<wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>wspassword</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
</soapenv:Header>
<soapenv:Body>
.....
</soapenv:Body>
I am getting following error:
15:22:54,541 DEBUG [c.c.i.s.MessageInterceptor] handleMessage
15:22:56,684 DEBUG [c.c.i.s.ServerPasswordHandler] begin handle
15:22:56,685 DEBUG [c.c.i.s.ServerPasswordHandler] userId is[wsuser]
15:22:56,685 INFO [c.c.i.s.ServerPasswordHandler] User [wsuser] is familiar.
15:22:56,685 DEBUG [c.c.i.s.ServerPasswordHandler] end handle
15:23:18,609 SEVERE [o.a.c.w.p.PolicyVerificationInInterceptor] Inbound policy verification failed: These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}TextPassword
15:23:18,609 WARNING [o.a.c.p.PhaseInterceptorChain] Interceptor for {http://service.xxx.xxx.com/}Adapter#{http://service.dms.ctl.com/}findAvailableCustomers has thrown exception, unwinding now: org.apache.cxf.ws.policy.PolicyException: These policy alternatives can not be satisfied:
{http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702}TextPassword
at org.apache.cxf.ws.policy.AssertionInfoMap.checkEffectivePolicy(AssertionInfoMap.java:179)
at org.apache.cxf.ws.policy.PolicyVerificationInInterceptor.handle(PolicyVerificationInInterceptor.java:102)
at org.apache.cxf.ws.policy.AbstractPolicyInterceptor.handleMessage(AbstractPolicyInterceptor.java:44)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:254)
at org.jboss.wsf.stack.cxf.RequestHandlerImpl.handleHttpRequest(RequestHandlerImpl.java:108)
at org.jboss.wsf.stack.cxf.transport.ServletHelper.callRequestHandler(ServletHelper.java:134)
at org.jboss.wsf.stack.cxf.CXFServletExt.invoke(CXFServletExt.java:88)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299)
at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doPost(AbstractHTTPServlet.java:218)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at org.jboss.wsf.stack.cxf.CXFServletExt.service(CXFServletExt.java:136)
at org.jboss.wsf.spi.deployment.WSFServlet.service(WSFServlet.java:140)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
Looking at the source code, i see the exception being thrown at following :
try {
//Exception here
List<List<Assertion>> usedAlternatives = aim.checkEffectivePolicy(effectivePolicy.getPolicy());
if (usedAlternatives != null && !usedAlternatives.isEmpty() && message.getExchange() != null) {
message.getExchange().put("ws-policy.validated.alternatives", usedAlternatives);
}
} catch (PolicyException ex) {
LOG.log(Level.SEVERE, "Inbound policy verification failed: " + ex.getMessage());
//To check if there is ws addressing policy violation and throw WSA specific
//exception to pass jaxws2.2 tests
if (ex.getMessage().indexOf("Addressing") > -1) {
throw new Fault("A required header representing a Message Addressing Property "
+ "is not present", LOG)
.setFaultCode(new QName("http://www.w3.org/2005/08/addressing",
"MessageAddressingHeaderRequired"));
}
throw ex;
EDIT: Fixed minor debug message
I was able to fix this with information from various websites. First off, as mentioned in oasis-open, i removed following element as passwords are mandatory.
<wsp:Policy>
<sp:TextPassword />
</wsp:Policy>
But due to a bug that was mentioned cxf issue, UsernameToken needed a policy element so workaround was to keep an empty policy under usernametoken
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
That fixed it.
"sp:TextPassword" is not a valid policy.

NullPointerException in my client of axis 2 web service with rampart security

I've created axs 2 web service with rampart ws security in eclipse (here s the tutorial I follow TUTORIAL PAGE - 18-21
I've aplied the policy in service.xml by adding this code AND ENGAGED RAMPART MODULE
<wsp:Policy wsu:Id="UTOverTransport"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:SignedSupportingTokens
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
<wsp:Policy>
<sp:UsernameToken
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient" />
</wsp:Policy>
</sp:SignedSupportingTokens>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:passwordCallbackClass>axis2wstest.PWCBHandler</ramp:passwordCallbackClass>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
Then I create web service client - here is the code
public static void main(String[] args) throws RemoteException {
ConfigurationContext ctx;
ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem("C:/Users/Tanya/workspace/testlnclient/WebContent/WEB-INF", null);
TestlnStub stub = new TestlnStub(ctx);
Testws cl = new Testws();
cl.setX(5);
ServiceClient client = stub._getServiceClient();
client.engageModule("rampart");
//client.addHeader(omSecurityElement);
org.apache.axis2.client.Options o = client.getOptions();
o.setPassword("pass");
o.setUserName("test");
TestwsResponse resp = stub.testws(cl);
System.out.println("Response" + resp.get_return());
// TODO Auto-generated method stub
}
}
but it gives me an excetion
exception in thread "main" org.apache.axis2.AxisFault: java.lang.NullPointerException
at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:531)
at org.apache.axis2.description.OutInAxisOperationClient.handleResponse(OutInAxisOperation.java:375)
at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:421)
at org.apache.axis2.description.OutInAxisOperationClient.executeImpl(OutInAxisOperation.java:229)
at org.apache.axis2.client.OperationClient.execute(OperationClient.java:165)
at axis2wstest.TestlnStub.testws(TestlnStub.java:191)
at axis2wstest.testlnclient.main(testlnclient.java:35)
The presence of Utils.getInboundFaultFromMessageContext in the stack trace indicates that the NullPointerException is actually coming from the service and not thrown by the client. Check the server logs to see where the NullPointerException occurs.

What is the correct format for SAML 2.0 Assertions?

We have a customer trying to use ADFS to SSO on to our web application. We are using the ComponentSpace SAML 2.0 library. The assertion being sent to us looks like:
<Assertion ID="_b8a24809-ab6b-4acd-ad6a-8bcb97bb1889" IssueInstant="2012-05-24T13:30:33.917Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<Issuer>http://example.com/adfs/services/trust</Issuer>
<Subject>
<NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">mail#example.com</NameID>
<SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<SubjectConfirmationData NotOnOrAfter="2012-05-24T13:35:33.920Z" Recipient="https://example.com/default.aspx" />
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="2012-05-24T13:30:33.907Z" NotOnOrAfter="2012-05-24T14:30:33.907Z">
<AudienceRestriction>
<Audience>https://example.com</Audience>
</AudienceRestriction>
</Conditions>
<AttributeStatement>
<Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
<AttributeValue>mail#example.com</AttributeValue>
</Attribute>
</AttributeStatement>
<AuthnStatement AuthnInstant="2012-05-24T13:30:33.756Z" SessionIndex="_b8a24809-ab6b-4acd-ad6a-8bcb97bb1889">
<AuthnContext>
<AuthnContextClassRef>urn:federation:authentication:windows</AuthnContextClassRef>
</AuthnContext>
</AuthnStatement>
</Assertion>
The ComponentSpace library is pulling the full SamlResponse from the HTTP post but it reports no Assertions (ie samlResponse.GetAssertions().Count == 0). If I use the ComponentSpace examples it works but I notice all of the elements I build with the ComponentSpace library are prefixed with "saml:" (as I believe it should be).
Should the ComponentSpace library be able to find the Assertion without the saml: prefix or is there a way to configure ADFS to send it correctly?
A correct SAML response should contain namespace-qualified elements
<saml2p:Response Destination="https://www.google.com/a/squaresquare.biz/acs" IssueInstant="2010-08-04T17:47:20.956Z" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" InResponseTo="djfnhepndikoonjjkeomgplmkjofobhdbdieihpa" Version="2.0" ID="_bd24b4a3514fd93800d2a43cafc98edb">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://my.ssodemo.url.demo.google.com/idp/shibboleth</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:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference URI="#_bd24b4a3514fd93800d2a43cafc98edb">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
<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="dssaml2saml2p"></ec:InclusiveNamespaces>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>m/lUCS3nvfGuSJFKAtIz+ZrfxTU=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>PLdYgU9u5KirVrMHNSwYvk6fQ401dMbpuiDXpapKf0eOKC6pN3g7tnTEzvfOaXhkDNXVmGN+lXQ6iUDppWpdO2MbvPVZabOBPU1aAO+CWI53ciC0rYsxpFzQLLMC/7x9Wk7VFFmYEecxAJV+lTWvp8ZKXvwqZbhiTO/23EC0xconGhnwSvKjJWQuLnMMaFWSjDFYyzgsp34cR7aX/eqhhJyA/rr2uFdmgEdagAl+/17ppgHgthgK+PJtX16AALtsoXonv6uybRCX/YiDRvM1VsdwusVq5tXh9V+bTMZcgi/3Eh+Em/OZp0En8pqOngvL19U4LfqG0yJZjoDGkpHuhA==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIDgjCCAmqgAwIBAgIVAKgIqbzZl7+0p2qjxJFVJs3DE/jxMA0GCSqGSIb3DQEBBQUAMDAxLjAsBgNVBAMTJWh0dHA6Ly93cGgtdWJpcTI3LmhvdC5jb3JwLmdvb2dsZS5jb20wHhcNMTAwNzIxMTcxNTA5WhcNMzAwNzIxMTcxNTA5WjAwMS4wLAYDVQQDEyVodHRwOi8vd3BoLXViaXEyNy5ob3QuY29ycC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAioQsJycRmjPjB2xlH0iSGn14lNbO/jIVgiGIlzZwlPkH1s2TTdwoTKKQBSe2s8AnJ4LliXlne/qWun3peYht0+RhejtB20L+Bw/I+iKQBGpHzgIKdkPGZnemWl9KqWQ/ZYKnY2x6qMEBmhUfYZcawzs26em5a+iaYlrTJNVEZ+QwWvg2/EOJvJNyBkSfXyxia5eAHV38Uy7xn0G5Zc9ge4ckCYj6b8a/UxpPJM61KztzY5coDwReQsDBq+DciGALJPbFk4783TW...etc.etc</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></saml2p:StatusCode>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" IssueInstant="2010-08-04T17:47:20.956Z" ID="_73fe28bcbb68e93df954d8e2f25097b1">
<saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://my.ssodemo.url.demo.google.com/idp/shibboleth</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">my_username</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData NotOnOrAfter="2010-08-04T17:52:20.956Z" InResponseTo="djfnhepndikoonjjkeomgplmkjofobhdbdieihpa" Recipient="https://www.google.com/a/squaresquare.biz/acs" Address="172.24.6.38"></saml2:SubjectConfirmationData>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotOnOrAfter="2010-08-04T17:52:20.956Z" NotBefore="2010-08-04T17:47:20.956Z">
<saml2:AudienceRestriction>
<saml2:Audience>google.com</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AuthnStatement SessionIndex="f306dd2bff4e9b3ba9218bd70fbaa87404d38a4c79547ac1edc9436a9f222213" AuthnInstant="2010-08-04T17:47:20.953Z">
<saml2:SubjectLocality Address="172.24.6.38"></saml2:SubjectLocality>
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
</saml2:Assertion>
</saml2p:Response>
Namespace qualifications are optional.
It turns out that the above XML is valid (ADFS adds the namespace to the overall XML but not each element). The problem was that the ComponentSpace library has different methods for getting Signed or Encrypted Assertions and I was just calling the generic GetAssertions. ADFS was generating signed assertions and I needed to call the other function.
Here is the code we ended up with:
IList<EncryptedAssertion> encryptedAssertions = samlResponse.GetEncryptedAssertions();
if (encryptedAssertions.Count > 0 && x509Certificate != null) {
// Decrypt the assertion
EncryptedAssertion encryptedAssertion = encryptedAssertions[0];
XmlElement decryptedElement = encryptedAssertion.DecryptToXml(x509Certificate, null);
LogMessage("Decrypted assertion: " + decryptedElement.OuterXml);
// Then verify the signature.
VerifySignature(x509Certificate, decryptedElement);
samlAssertion = new SAMLAssertion(decryptedElement);
} else {
if (samlResponse.GetSignedAssertions().Count > 0) {
// Get the signed assertion and verify the signature.
XmlElement signedAssertionElement = samlResponse.GetSignedAssertions()[0];
LogMessage("Signed assertion: " + signedAssertionElement.OuterXml);
VerifySignature(x509Certificate, signedAssertionElement);
samlAssertion = new SAMLAssertion(signedAssertionElement);
} else {
// Assertion is not encrypted or signed.
if (samlResponse.GetAssertions().Count > 0) {
samlAssertion = samlResponse.GetAssertions()[0];
LogMessage("Assertion: " + samlAssertion.ToXml().OuterXml);
} else {
LogFatalError("No assertions in response");
}
}
}

How do I validate a SAML assertion in Perl?

I need to validate a SAML assertion of this kind:
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ID="Assertion-uuide824d44-0134-14b1-8e70-f85c710cb043" IssueInstant="2011-12-05T13:55:47Z" Version="2.0">
<saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">MPS</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="uuide824d48-0134-18fe-b37b-f85c710cb043">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference URI="#Assertion-uuide824d44-0134-14b1-8e70-f85c710cb043">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<xc14n:InclusiveNamespaces xmlns:xc14n="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs saml xsi"></xc14n:InclusiveNamespaces>
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>p02xKMDUYCR5xpppYUOQgsGBR5c=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>R9YHo8TK/wYkGkTP3QrnnM8U6TKf9vu+ElpRjDPgpg4O88oARZSb9OhlVn2sXJGEaQ5i0ORrofbKwOI+D/jFgz3Hz/g/h4yt2aqIFxLpOTFb448bDvFsHHWAoWc0DUPYf1AjW7Peu1ICSCdR3EaVLqtgdsUsVWoA7oXbWyAyVLM=</ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>iZ0D1X6rk8+ZwNBTVZt7C85m421a8A52Ksjw40t+jNvbLYDp/W66AMMYD7rB5qgniZ5K1p9W8ivM9WbPxc2u/60tFPg0e/Q/r/fxegW1K1umnay+5MaUvN3p4XUCRrfg79OvurvXQ7GZa1/wOp5vBIdXzg6i9CVAqL29JGi6GYU=</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:ibm:names:ITFIM:5.1:accessmanager">J006068</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"></saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2011-12-05T13:45:47Z" NotOnOrAfter="2011-12-05T14:05:47Z">
<saml:AudienceRestriction>
<saml:AttributeValue xsi:type="xs:string">1030</saml>
I did not find a library on CPAN that can take the SAML as argument and can validate it.
Someone can help me with how to reach my goal?
Ok, better late than never... how to use it...
When you say 'validate' I'm not sure if you mean 'check the assertion', or 'verify the signature'.
my $assertion = Net::SAML2::Protocol::Assertion->new_from_xml(
xml => decode_base64($saml_response)
);
then you just check the validity of the Assertion object created via the accessors. I'm assuming you understand SAML semantics.
To verify the signature, you need access to the private key:
my $sig = Net::SAML2::XML::Sig->new( { key =>'/private.key' } );
$sig->verify( $xml );
See the XML::Sig perldoc for variations on the source of the key (x509, certs).
Note that Net::SAML2 doesn't cover encrypted SAML assertions () but you didn't ask about that.
The Net::SAML2 CPAN module would help you out here
http://metacpan.org/pod/Net::SAML2