Wsdl optional params become mandatory in generated java stub code - java

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"/>

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...

How 'minOccurs' and 'maxOccurs' attribute value will generated inside the `element` tag of the WSDL file?

We have custom java code that deployed in the JBoss. We are firing the webservice call and the WSDL file is generating by using the Apache Axis framework.
My question is for some of the tag, minOccurs and maxOccurs attribute is present, but for some other tag, those attributes are not present.
If I want minOccurs and maxOccurs attribute inside the element tag, then where I have to configure? How this Apache Axis framework will generate these attribute.
Sample WSDL :
<wsdl:definitions xmlns:apachesoap="http://xml.apache.org/xml-soap"
xmlns:impl="urn:sif.siperian.com" xmlns:intf="urn:sif.siperian.com"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:sif.siperian.com">
<!--
WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)
-->
<wsdl:types>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" targetNamespace="urn:sif.siperian.com">
<complexType name="Account">
<sequence>
<element name="accountNumber" nillable="true" type="xsd:string"/>
<element name="accountType" nillable="true" type="xsd:string"/>
<element name="cardholderName" nillable="true" type="xsd:string"/>
<element name="city" nillable="true" type="xsd:string"/>
<element name="expirationMonth" nillable="true" type="xsd:string"/>
<element name="expirationYear" nillable="true" type="xsd:string"/>
<element name="hubStateInd" nillable="true" type="xsd:string"/>
<element name="issuingCompany" nillable="true" type="xsd:string"/>
<element name="pkeySrcObject" nillable="true" type="xsd:string"/>
<element name="postalCode" nillable="true" type="xsd:string"/>
<element name="rowidObject" nillable="true" type="xsd:string"/>
<element name="securityCode" nillable="true" type="xsd:string"/>
<element name="source" nillable="true" type="xsd:string"/>
<element name="stateProvince" nillable="true" type="xsd:string"/>
<element name="streetName" nillable="true" type="xsd:string"/>
</sequence>
</complexType>
<complexType name="ArrayOfAccount">
<sequence>
<element maxOccurs="unbounded" minOccurs="0" name="item"
type="impl:Account"/>
</sequence>
</complexType>
</schema>
</wsdl:types>
</wsdl:definitions>
In the above WSDL, the <complexType name="Account"> is not having property minOccurs and maxOccurs.
Where as, the <complexType name="ArrayOfAccount"> is having both the properties.
The following is a Java Code sample on how to build the following element:
<element maxOccurs="1" minOccurs="0" name="Test" nillable="true" type="xsd:string"/>
Java Code:
elemField = new org.apache.axis.description.ElementDesc();
elemField.setFieldName("test");
elemField.setXmlName(new javax.xml.namespace.QName("http://www.test.com", "Test"));
elemField.setXmlType(new javax.xml.namespace.QName("http://www.w3.org/2001/XMLSchema", "string"));
elemField.setMinOccurs(0);
elemField.setNillable(true);
Hope this helps.

Why spring wrong generate java classes from xsd

I have xsd schema below describe the
<xs:element name="ReqStartTest">
<xs:complexType>
<xs:sequence>
<xs:element name="Version" >
<xs:simpleType>
<xs:restriction base="xs:string" />
</xs:simpleType>
</xs:element>
<xs:element name="Time" >
<xs:simpleType>
<xs:restriction base="xs:string" />
</xs:simpleType>
</xs:element>
<xs:element ref="tns:StartTestRequest" minOccurs="1" maxOccurs="1"></xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="StartTestRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="Name" >
<xs:simpleType>
<xs:restriction base="xs:string" />
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
After i generate java classes from xsd file, and recieve *.wsdl file. After i testing *.wsdl file in SOAPUI, I see just "StartTestRequest" request. My question, why/where my input data ("Version","Time") in request?
Thanks in advance.
Spring only generates request/response for the elements that has the postfixes "request" and "response". In this case, you are referencing "StartTestRequest" from "ReqStartTest". So, you will only see "StartTestRequest" which only has the name field in it. You should extend or reference "ReqStartTest" in your "StartTestRequest"
Following should work fine.
<complexType name="ReqStartTest">
<sequence>
<element name="Version" type="string"/>
<element name="Time" type="string"/>
</sequence>
</complexType>
<element name="StartTestRequest">
<complexType>
<complexContent>
<extension base="tns:ReqStartTest">
<sequence>
<element name="Name" type="string"/>
</sequence>
</extension>
</complexContent>
</complexType>
</element>
Update:
Spring requires predefined suffixes to identify elements that are requests or responses of a web service. Default suffixes are "Request" and "Response". You can change it in the configuration. This thread might help you: Spring-ws: How to create Wsdl from an xsd with no "Request" element
Also this is the closest you will get without changing suffixes:
<element name="ReqStartTestRequest">
<complexType>
<sequence>
<element name="version" type="string"/>
<element name="time" type="string"/>
<element name="startTestRequest" type="tns:StartTestRequest"/>
</sequence>
</complexType>
</element>
<complexType name="StartTestRequest">
<sequence>
<element name="name" type="string"/>
</sequence>
</complexType>
I highly advise you to follow naming conventions. For example, first letter of a variable or non constant field should be lower case (camelcase notation).

Using SAML Assertion in XSD

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?

Create a nested element with blank namespace in a schema definition

I have a remote system that returns an XML similar to the one below.
<BalanceResponse xmlns="http://example.com/balance">
<BalanceResult>
<Balance xmlns="">
<amount>10</amount>
<Balance>
</BalanceResult>
</BalanceResponse>
I created an xsd to match it
<s:schema elementFormDefault="qualified" targetNamespace="http://example.com/balance">
<s:element name="BalanceResponse">
<s:complexType>
<s:element minOccurs="0" maxOccurs="1" name="BalanceResult">
<s:complexType>
<s:element minOccurs="0" maxOccurs="1" name="Balance">
<s:complexType>
<s:element minOccurs="0" maxOccurs="1" name="amount" type="s:decimal" />
</s:complexType>
</s:element>
</s:complexType>
</s:element>
</s:complexType>
</s:schema>
I use JAXB to generate the stub classes. However, I know that my (un/)marshaller cannot bind the Balance element because the namespace is different.
Question is, how can i declare a different (blank)namespace for my element Balance?
You could do something like the following. Since elementFormDefault is unqualified all global elements (BalanceResponse and BalanceResult will be namespace qualified and all local elements (Balance and amount) won't be.
<?xml version="1.0" encoding="UTF-8"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.com/balance"
xmlns:tns="http://example.com/balance"
elementFormDefault="unqualified">
<element name="BalanceResponse">
<complexType>
<sequence>
<element ref="tns:BalanceResult"/>
</sequence>
</complexType>
</element>
<element name="BalanceResult">
<complexType>
<sequence>
<element name="Balance">
<complexType>
<sequence>
<element name="amount" type="int"/>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
If as in the XML Schema in your question put elementFormDefault as qualified then it would expect all of the XML elements to be namespace qualified.

Categories