Using SAML Assertion in XSD - java

I have a webservice operation where i'll be getting SAML Assertion as part of the request Body.
I have following XSD:
<xsd:element name="CreateRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="info" type="SomeRequestObj"/>
<xsd:element ref="saml:Assertion" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
The saml:Assertion refers to:
<xsd:import namespace="urn:oasis:names:tc:SAML:2.0:assertion"schemaLocation="../samlv2_0/saml-schema-assertion-2.0.xsd"/>
This saml schema is copied from SAML 2.0.
This generates classes with name *Type.java.
And i am having a hard time creating a unit test for this (which is a separate application with UI).
My Request requires a SAML AssertionType element in the request Body.
So, i cannot use OpneSaml for generating that as it gives me a SAML Assertion object and not AssertionType.
I tried generating the AssertionType object manually but i am having a hard time doing so.
Is there a way to use OpenSaml for generating this?
As i see the xml is going to be the same that i would get in case i just use OpenSaml to generate Assertion object.
Is there a way to simplify this?
EDIT: Added XSD snippet of Assertion
<element name="Assertion" type="saml:AssertionType"/>
<complexType name="AssertionType">
<sequence>
<element ref="saml:Issuer"/>
<element ref="ds:Signature" minOccurs="0"/>
<element ref="saml:Subject" minOccurs="0"/>
<element ref="saml:Conditions" minOccurs="0"/>
<element ref="saml:Advice" minOccurs="0"/>
<choice minOccurs="0" maxOccurs="unbounded">
<element ref="saml:Statement"/>
<element ref="saml:AuthnStatement"/>
<element ref="saml:AuthzDecisionStatement"/>
<element ref="saml:AttributeStatement"/>
</choice>
</sequence>
<attribute name="Version" type="string" use="required"/>
<attribute name="ID" type="ID" use="required"/>
<attribute name="IssueInstant" type="dateTime" use="required"/>
</complexType>
This generates AssertionType Object.

SAML Assertions are of complex type "AssertionType", but the element name is "Assertion". The <Assertion> element generated by OpenSaml should be just fine.
The element is defined in section 2.3.3 in the SAML core spec.

Try to use an external binding file when generating the classes from the XSD with JAXB. See this topic (I guess the second answer of it is what you're looking for): JAXB: How to change XJC-generated classes names when attr type is specified in XSD?

Related

Why is this XML Validation failing on NameIDFormat from an extended type?

I recently encountered an issue with SAML metadata validation from a customer.
The relevant part of metadata that is failing:
<IDPSSODescriptor protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
<Extensions>
<shibmd:Scope regexp="false">...</shibmd:Scope>
</Extensions>
<KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
...
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="..." index="1"/>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="..." index="2"/>
<SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="h..."/>
<NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
</IDPSSODescriptor>
This fails with the folowing error:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'NameIDFormat'. One of '{"urn:oasis:names:tc:SAML:2.0:metadata":SingleSignOnService, "urn:oasis:names:tc:SAML:2.0:metadata":NameIDMappingService, "urn:oasis:names:tc:SAML:2.0:metadata":AssertionIDRequestService, "urn:oasis:names:tc:SAML:2.0:metadata":AttributeProfile, "urn:oasis:names:tc:SAML:2.0:assertion":Attribute}' is expected.
The following is the relevant portion of saml-schema-metadata-2.0.xsd:
<complexType name="SSODescriptorType" abstract="true">
<complexContent>
<extension base="md:RoleDescriptorType">
<sequence>
<element ref="md:ArtifactResolutionService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:SingleLogoutService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:ManageNameIDService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="ArtifactResolutionService" type="md:IndexedEndpointType"/>
<element name="SingleLogoutService" type="md:EndpointType"/>
<element name="ManageNameIDService" type="md:EndpointType"/>
<element name="NameIDFormat" type="anyURI"/>
<element name="IDPSSODescriptor" type="md:IDPSSODescriptorType"/>
<complexType name="IDPSSODescriptorType">
<complexContent>
<extension base="md:SSODescriptorType">
<sequence>
<element ref="md:SingleSignOnService" maxOccurs="unbounded"/>
<element ref="md:NameIDMappingService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AssertionIDRequestService" minOccurs="0" maxOccurs="unbounded"/>
<element ref="md:AttributeProfile" minOccurs="0" maxOccurs="unbounded"/>
<element ref="saml:Attribute" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
<attribute name="WantAuthnRequestsSigned" type="boolean" use="optional"/>
</extension>
</complexContent>
</complexType>
<element name="SingleSignOnService" type="md:EndpointType"/>
<element name="NameIDMappingService" type="md:EndpointType"/>
<element name="AssertionIDRequestService" type="md:EndpointType"/>
<element name="AttributeProfile" type="anyURI"/>
I notice that the error message only specifies elements from the IDPSSODescriptorType and not the base SSODescriptorType. Maybe that's by design?
Regardless, I receive no errors for ArtifactResolutionService which also happens to be define in the base type.
In fact, if I move <element ref="md:NameIDFormat" minOccurs="0" maxOccurs="unbounded"/> in the schema file from the base SSODescriptorType to the IDPSSODescriptorType, and leave everything else, the metadata file passes validation.
I'm using Java 8 with the default implementation of javax.xml.validation.*
private static String[] schemas = {
"/schema/xml.xsd",
"/schema/XMLSchema.xsd",
"/schema/xmldsig-core-schema.xsd",
"/schema/xenc-schema.xsd",
"/schema/saml-schema-assertion-2.0.xsd",
"/schema/saml-schema-metadata-2.0.xsd",
};
public boolean validateXMLSchema(Document document) {
try {
SchemaFactory factory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(getSources().toArray(new Source[0]));
Validator validator = schema.newValidator();
validator.validate(new DOMSource(document));
return true;
} catch (SAXException e) {
log.error("Exception: " + e.getMessage());
} catch (Exception ex) {
log.debug("Exception: ", ex);
}
return false;
}
At this point I'm unsure what would be causing the NameIDFormat element to fail validation, or why the validator isn't finding it in the base type but does seem to find ArtifactResolutionService.
How this element is produced it is generated without its minOccurs= attribute while other elements of the same set type do have it. , so there is a malformation much as the parser error says.
<element ref="md:SingleSignOnService" maxOccurs="unbounded"/>
I figured out what's going on. The customer metadata is indeed invalid (according to this schema).
The complexTypes in the schema are specifying sequences. This means the elements MUST be specified in that particular order.
According to the schema, the NameIDFormat elements defined in the SSODescriptorType must be specified before any of the elements defined by the IDPSSODescriptorType. Changing the metadata to the following works:
<IDPSSODescriptor protocolSupportEnumeration="urn:mace:shibboleth:1.0 urn:oasis:names:tc:SAML:1.1:protocol urn:oasis:names:tc:SAML:2.0:protocol">
<Extensions>
<shibmd:Scope regexp="false">...</shibmd:Scope>
</Extensions>
<KeyDescriptor>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
...
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:1.0:bindings:SOAP-binding" Location="..." index="1"/>
<ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="..." index="2"/>
<NameIDFormat>urn:mace:shibboleth:1.0:nameIdentifier</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<SingleSignOnService Binding="urn:mace:shibboleth:1.0:profiles:AuthnRequest" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="..."/>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="h..."/>
</IDPSSODescriptor>
Now to figure out how I'm going to handle this since it's unlikely I'll be able to get the customer to fix their metadata...

MULE ESB Simple SOAP service create mandatory fields

I want to expose a Simple SOAP web service in Mule 3.4 Community.
Some fields of the service need to be mandatory/required. How can that be done?
Here is the web service method:
public String methodname(String field1, String field2, String field3);
Here is the resulting wsdl:
<xsd:element minOccurs="0" name="field1" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="field2" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="field3" nillable="true" type="xsd:string"/>
How can I make these fields minOccurs="1" and nillable="false"
Please note #XmlElement(required=true) doesn't work with my Java version 1.6
minOccurs="1" makes the element mandatory and minOccurs="0" makes it optional
So make the following change to make it mandatory:-
<xsd:element minOccurs="1" name="field1" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="1" name="field2" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="1" name="field3" nillable="true" type="xsd:string"/>
For your reference :- https://social.msdn.microsoft.com/Forums/en-US/f59a3ee2-5997-4ee7-8c09-8d371c923267/creating-required-elements-in-xsd?forum=xmlandnetfx
and
How to tell if XML element is marked as required in the XSD file
and nillable is specifies whether an explicit null value can be assigned to the element
reference:-http://www.w3schools.com/schema/el_element.asp
So you need to make change in your WSDL so that the Java class generated from to implements those properties of attributes
I'm afraid you can't do this with a simple service (as it's simple by definition, it would probably work latter versions of java as you point).
You should switch to a fullfeatured jaxws service without autogenerated wdsl.

Wsdl optional params become mandatory in generated java stub code

I am newbie to webservices.
I have generated the stub from the provided wsdl.
What I have observed is the stub generated code asking me to provide the optional parameters mandatory.
For example this is one of the method in wsdl file.
<complexType name="OPP_BOOK_FACT">
<sequence>
<element form="unqualified" name="Descriptions" type="tns:Descriptions" minOccurs="0"/>
<element form="unqualified" name="CustomerID" type="tns:CustomerConfirmationID" minOccurs="0"/>
<element form="unqualified" name="UID" type="tns:UPRID" minOccurs="0"/>
<element form="unqualified" name="Ext" type="tns:ExtAuth" minOccurs="0"/>
<element form="unqualified" name="Partner" type="tns:Partner"/>
<element form="unqualified" name="Subscriber" type="tns:Subscriber"/>
<element form="unqualified" name="FactBook" type="tns:FactBook"/>
<element form="unqualified" name="FactAuth" type="tns:FactAuth"/>
<element form="unqualified" name="Price" type="tns:Price"/>
<element form="unqualified" name="SubseReqData" type="tns:SubseReqData" minOccurs="0"/>
<element form="unqualified" name="FactBundleTemplate" type="tns:FactBundleTemplate" minOccurs="0"/>
<element form="unqualified" name="ContentInfo" type="tns:ContentInfo" minOccurs="0"/>
<element form="unqualified" name="Discount" type="tns:Discount" minOccurs="0"/>
<element form="unqualified" name="FactShoppingBasket" type="tns:FactShoppingBasket" minOccurs="0"/>
</sequence>
</complexType>
Here if you notice for example "CustomerID", "UID" and "Ext" are optional param as the minOccurs="0".
But the generated stub api is as below.
com.xstg.www.soap.schemas.services.v80.Xaction80Stateful_wsdl.Xaction80StatefulPortType.OPP_BOOK_F
ACT(Description[] arg0, Long arg1, String arg2, ExtAuthElement[] arg3, Partner arg4, Subscriber arg5,
FactBook arg6, FactAuth arg7, Price arg8, SubseReqData arg9, FactBundleTemplate arg10, ContentInfo
arg11, Discount arg12, FactShoppingBasket arg13) throws RemoteException
It is clear that to invoke this method from client, I have to definitely supply all optional param variables also.
I have used <axis-wsdl2java> ant call to generate the stub.
May I know the reason for this? According to me, client stub should not expect me to provide all optional params also.
Please let me know if you need any additional info.
Update:
We are using axis-1.4. The above stub was generated using axis-1.4.
I tried the same with axis2. The generated stub is different in axis2. But I need to use axis-1.4 as the old client code was already developed using this version
Would you mind to try adding nillable="true".
Like:
<element form="unqualified" name="Ext" type="tns:ExtAuth" nillable="true" minOccurs="0"/>

XSD declaration of a complex type with repeating attribute outside a list

I have a provider that outputs something like this
<Result rawScore="623">
<Target>http://myUrl.com/test1</Target>
<Domain name="myUrl.search.com" />
<Property name="Language">en</Property>
<Property name="Teaser">This is the description</Property>
<Property name="LVCategory">Help</Property>
<Property name="Title">ProductTitle</Property>
<Property name="Last Modified">2012-04-06T21:44:11Z</Property>
</Result>
I'm trying to create an xsd to leverage jaxb, but I'm not sure how to handle the Property attribute appearing several times but not inside a list, so a sequence won't work. Any ideas?
This is a complete XML Schema, and compiles to Java code
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsd:element name="Result" type="ResultType"/>
<xsd:complexType name="ResultType">
<xsd:sequence>
<xsd:element name="Target" type="xsd:string"/>
<xsd:element name="Domain" type="xsd:string"/>
<xsd:element name="Property" type="PropertyType"
minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="rawScore" type="xsd:int"/>
<!-- xsd:integer => BigDecimal/PITA -->
</xsd:complexType>
<!-- I prefer explicit types to avoid nested class definitions -->
<xsd:complexType name="PropertyType">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="name" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:schema>
A few lines of Java code:
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Unmarshaller m = jc.createUnmarshaller();
try {
File source = new File( XMLIN );
JAXBElement<ResultType> jbe = (JAXBElement<ResultType>)m.unmarshal( source );
ResultType result = (ResultType)jbe.getValue();
} catch( Exception e ){
}
You could do something like the following:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="Result">
<complexType>
<sequence>
...
<element name="Property" minOccurs="0" maxOccurs="unbounded">
<complexType>
<simpleContent>
<extension base="string">
<attribute name="name" type="string"/>
</extension>
</simpleContent>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
Note the following things about the XML Schema:
The Property element has the attribute maxOccurs="unbounded". This indicates that it is a repeating element.
The Property element is a complex type with simple content. This means it can have a text value and XML attributes.
Declare the type of Result using something like this:
<xsd:complexType name="ResultType">
<xsd:sequence>
<xsd:element ref="Target"/>
<xsd:element ref="Domain"/>
<xsd:element ref="Property"
minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="rawScore" type="xsd:integer"/>
</xsd:complexType>
And learn the difference between elements and attributes, OK?

get Jboss 7 to use custom top down WSDL definition of your choosing, without having CXF generate a wsdl

we are moving a topdown (wsdl first) ws from jboss4 to jboss7 and are having some difficulties with CXF. I am noticing that the large wsdl file located in
standalone\data\wsdl\x.ear\x.war\x.wsdl
is not generated off the supplied xsd set, it seems to be generating off the classes. For instance our definition from JBoss4 reads (obfuscated)
<element name="x">
<complexType>
<sequence>
<element minOccurs="0" name="x" type="x"/>
<choice>
<element name="x" type="x"/>
<element name="x" type="x"/>
<element name="x" type="x"/>
<element name="x" type="x"/>
<element name="x" type="x"/>
</choice>
</sequence>
</complexType>
</element>
and the one generated by CXF has all the coice element replaced with minoccurs = 0, totally invalid for our actual use.
<xs:element name="x">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="x" type="xs:string"/>
<xs:element minOccurs="0" name="x" type="ns1:x"/>
<xs:element minOccurs="0" name="x" type="ns1:x"/>
<xs:element minOccurs="0" name="x" type="ns1:x"/>
<xs:element minOccurs="0" name="x" type="ns1:x"/>
<xs:element minOccurs="0" name="x" type="ns1:x"/>
</xs:sequence>
</xs:complexType>
</xs:element>
This is because wsconsume builds our java classes and annotates them well enough to be parsed by cxf, but not well enough to actually present the initial intent of the complexTypes, so after much looking, how do you get Jboss 7 to use the WSDL definition of your choosing, without having CXF generate a wsdl? We will not be using Spring to make this happen, so... Discuss!
so setting the wsdlLocation in the #webservice annotation lead to the error described here
http://mail-archives.apache.org/mod_mbox/cxf-users/200806.mbox/%3C1932ACF3-DCD2-4073-83DD-981FC0F68F53#apache.org%3E
so it turned way simpler after reading it
the directions there list two options:
1) Update the #WebService annotation on the FooDocumentImpl class to
have the serviceName/portName attributes that match the values in the
wsdl.
2) Update the element in your config to add the
qnames for the service name and portname.
the first is if you are not using Spring, so after explicitly bringing the #WebService annotation to:
#WebService(endpointInterface = "main.package.InterfaceWS", serviceName = "InterfaceWSService", name = "InterfaceWS", targetNamespace = "http://Interface.namespace.main", wsdlLocation = "WEB-INF/wsdl/InterfaceWS.wsdl" ,portName="InterfaceWSPort")
to match the service description in the InterfaceWS.wsdl:
<service name="InterfaceWSService">
<port binding="tns:InterfaceWSSOAPBinding" name="InterfaceWSPort">
<soap:address location="http://localhost:8080/publishedLocationOfInterface />
</port>
</service>
it worked like a charm

Categories