Layer7 API Management

Expand all | Collapse all

validate full soap request against wsdl (with multiple schemas)

Jump to Best Answer
  • 1.  validate full soap request against wsdl (with multiple schemas)

    Posted 05-16-2017 08:40 AM

    Hi,

     

    I am looking for a generic way to validate all soap requests against the corresponding wsdl on the API Gateway.

     

    Of course, the assertion 'Validate XML Schema' should do this, but it only works with wsdls having one schema inside. As soon as there are multiple schemas inside the wsdl which refer each other and have imports from external xsd files on top, this assertion cannot handle it, because only one schema can be selected.

     

    I am aware of the fact, that I could write my own xsd file for each wsdl by hand, but with more than 100 soap services which are updated almost weekly, this is not a good idea.

     

    Therefore, I tried to write an encapsulated assertion which should be called in each soap service and does the following:

    1. obtain the corresponding wsdl and its dependencies with the ${service.oid} --> No problem
    2. extract all internal and external schemas with xslt and flatten it to one xsd --> Difficult to implement (I am not an xslt pro)
    3. validate the incoming soap request against this xsd --> This is also impossible with the 'Validate XML Schema' assertion, because it only takes manually tiped in xsd and no context variables

     

    So is my aproach the right one? And if so, how can I make it work?

     

    Thanks and regards,

    Andi



  • 2.  Re: validate full soap request against wsdl (with multiple schemas)

    Posted 05-16-2017 09:07 PM

    Andi,

     

    Good afternoon. The Validate XML Schema assertion can take a schema from multiple locations either static in the assertion, from a URL that is monitored and cached and refreshed at a set interval (interval controlled through cluster-wide properties), or schemas loaded through the Manage Global Resources. In each instance when the schema is loaded all import and include statements need to be resolvable and are used in the assertion to validate the schema. When the WSDL is pulled in the schema is pulled in the XSD and supporting XSD files are stored in a table on the gateway and stored in cache for usage throughout the policy. When you utilize the Manage Global Resources, each of the XSD files outlined in the main XSD and sub XSD files needs to be accessible so they can be imported into the Global Resources.

     

    For the scenario you have outlined, I would look at either using the Monitor from URL option which can have static or context variable passed into it or use some programatic means to load the XSD files through RESTMAN into the Global Resources.

     

    Sincerely,

     

    Stephen Hughes

    Director, CA Support



  • 3.  Re: validate full soap request against wsdl (with multiple schemas)

    Posted 05-17-2017 07:48 AM

    Hi Stephen,

     

    Thank you, but I don't really see how this should work now.

    The problem, that I don't have a flatten xsd remains the same, no matter from where I load it into the Validate XML Schema assertion. So as I already pointed out I don't want to use a static self written xsd. I want to generate an xsd based on the wsdl at runtime in order to be flexible. How can I do this?

     

    And the other two suggestions aren't really satisfying as well. Assumed I could generate an xsd schema, I don't want to manually save it at some 3rd party url which the apigw can point to, because if there is a change in the wsdl, i have to update this too. The same for storing the xsd in the global resources: everything is static...

     

    Again: The target is to be dynamic and flexible, because we have a lot of changes in our wsdls (especially while developing new services). Thus, every static solution e.g.: 3rd party url or global resource is no solution.

    All I want, is to generate an xsd from the given wsdl and validate the incoming soap request against it.

     

    In my opinion this must be possible, because tools such as SoapUi or XmlSpy can do this easily. 

     

    Kind regards,

    Andi



  • 4.  Re: validate full soap request against wsdl (with multiple schemas)

    Posted 05-17-2017 06:09 PM

    Andi,

     

    I apologize if my statement did not help to clarify your request. The main point I was raising is that the expectation is that we don't expect that the XSD is flatten to work for general operation. In your outline and your response, the option of using the Monitor URL which we see as the primary method of tracking and monitoring changes to XSD files is not going to work. When we update the WSDL in the gateway it does not update the policy to reflect the schemas in the WSDL. I've been trying to see if I can build a solution using policy logic to make the usage of the Validate XML Schema using Monitor a URL where the URL is a local service pulling data from the WSDL. I've been able to get a few scenarios to work but I need to know if your XSD have any flattening already so that two schema entries exist in the WSDL for different namespaces or multiple imports in the same WSDL for different namespaces. Any guidance will help be figure out the best approach.

     

    Sincerely,

     

    Stephen Hughes

    Director, CA Support



  • 5.  Re: validate full soap request against wsdl (with multiple schemas)

    Posted 05-18-2017 03:15 AM

    Hi Stephen,

     

    Thanks a lot for your investigations.

    I created an example wsdl (plus xsd) for you:

     

    File: adressSearchService.wsdl

    <?xml version="1.0" encoding="UTF-8"?>
    <wsdl:definitions
    xmlns:tns="http://com/example/searchService/"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:dto="http://com/example/searchService/dto/"
    xmlns:exc="http://com/example/searchService/exc/"
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
    name="PartnerSuchen"
    targetNamespace="http://com/example/searchService/">
    <wsdl:types>
    <xs:schema
    xmlns:tns="http://com/example/searchService/" elementFormDefault="unqualified" targetNamespace="http://com/example/searchService/" version="1.0">
    <xs:element name="searchAdressRequest" type="tns:searchAdressRequest"/>
    <xs:element name="searchAdressResponse" type="tns:searchAdressResponse"/>
    <xs:complexType name="searchAdressRequest">
    <xs:sequence>
    <xs:element name="searchAdressParameter" type="dto:searchAdressParameter"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="searchAdressResponse">
    <xs:sequence>
    <xs:element name="return" type="dto:searchAdressReturn"/>
    </xs:sequence>
    </xs:complexType>
    </xs:schema>
    <xs:schema xmlns:tns="http://com/example/searchService/dto/" targetNamespace="http://com/example/searchService/dto/" version="1.0" xmlns:external="http://com/example/login/">
    <xs:import namespace="http://com/example/login/" schemaLocation="external_login_schema.xsd"/>
    <xs:element name="searchAdressParameter" type="tns:searchAdressParameter"/>
    <xs:element name="searchAdressReturn" type="tns:searchAdressReturn"/>
    <xs:element name="AdressRequest" type="tns:AdressRequest"/>
    <xs:element name="RequestDate" type="tns:RequestDate"/>
    <xs:element name="MaxAmountOfResults" type="tns:MaxAmountOfResults"/>
    <xs:element name="FormattedAddress" type="tns:FormattedAddress"/>
    <xs:complexType name="searchAdressParameter">
    <xs:sequence>
    <xs:element ref="external:login"/>
    <xs:element name="clientId" type="xs:int"/>
    <xs:element name="adressRequest" type="tns:AdressRequest"/>
    <xs:element name="maxAmountOfResults" type="tns:MaxAmountOfResults"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="searchAdressReturn">
    <xs:sequence>
    <xs:element name="adressResponse" type="tns:Adress" maxOccurs="unbounded"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="AdressRequest">
    <xs:sequence>
    <xs:element name="id" type="xs:int" minOccurs="0"/>
    <xs:element name="name" type="xs:string" minOccurs="0"/>
    <xs:element name="surname" type="xs:string" minOccurs="0"/>
    <xs:element name="street" type="xs:string" minOccurs="0"/>
    <xs:element name="number" type="xs:string" minOccurs="0"/>
    <xs:element name="city" type="xs:string" minOccurs="0"/>
    <xs:element name="code" type="xs:string" minOccurs="0"/>
    <xs:element name="country" type="xs:string" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="Adress">
    <xs:sequence>
    <xs:element name="id" type="xs:int" minOccurs="0"/>
    <xs:element name="name" type="xs:string" minOccurs="0"/>
    <xs:element name="surname" type="xs:string" minOccurs="0"/>
    <xs:element name="street" type="xs:string" minOccurs="0"/>
    <xs:element name="number" type="xs:string" minOccurs="0"/>
    <xs:element name="city" type="xs:string" minOccurs="0"/>
    <xs:element name="code" type="xs:string" minOccurs="0"/>
    <xs:element name="country" type="xs:string" minOccurs="0"/>
    <xs:element name="formattedAddress" type="tns:FormattedAddress" minOccurs="0"/>
    </xs:sequence>
    </xs:complexType>
    <xs:simpleType name="MaxAmountOfResults">
    <xs:restriction base="xs:int">
    <xs:minInclusive value="1"/>
    <xs:maxInclusive value="2000"/>
    </xs:restriction>
    </xs:simpleType>
    <xs:simpleType name="RequestDate">
    <xs:restriction base="xs:string">
    <xs:pattern value="\d{2}.\d{2}.\d{4}"/>
    </xs:restriction>
    </xs:simpleType>
    <xs:complexType name="FormattedAddress">
    <xs:sequence>
    <xs:element name="id" type="xs:int"/>
    <xs:element name="requestDate" type="tns:RequestDate"/>
    <xs:element name="address" type="tns:AddressListType"/>
    </xs:sequence>
    </xs:complexType>
    <xs:complexType name="AddressListType">
    <xs:sequence>
    <xs:element name="line" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
    </xs:complexType>
    </xs:schema>
    <xs:schema xmlns:tns="http://com/example/searchService/exc/" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://com/example/searchService/exc/">
    <xs:element name="BusinessException" type="tns:BusinessException"/>
    <xs:complexType name="BusinessException">
    <xs:sequence>
    <xs:element name="message" nillable="true" type="xs:string"/>
    </xs:sequence>
    </xs:complexType>
    </xs:schema>
    </wsdl:types>
    <wsdl:message name="searchAdressRequest">
    <wsdl:part name="parameters" element="tns:searchAdressRequest">
    </wsdl:part>
    </wsdl:message>
    <wsdl:message name="searchAdressResponse">
    <wsdl:part name="parameters" element="tns:searchAdressResponse">
    </wsdl:part>
    </wsdl:message>
    <wsdl:message name="BusinessException">
    <wsdl:part name="BusinessException" element="exc:BusinessException">
    </wsdl:part>
    </wsdl:message>
    <wsdl:portType name="SearchAdress">
    <wsdl:operation name="searchAdress">
    <wsdl:input name="searchAdressRequest" message="tns:searchAdressRequest">
    </wsdl:input>
    <wsdl:output name="searchAdressResponse" message="tns:searchAdressResponse">
    </wsdl:output>
    <wsdl:fault name="BusinessException" message="tns:BusinessException">
    </wsdl:fault>
    </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="SearchAdressServiceSoapBinding" type="tns:SearchAdress">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="searchAdress">
    <soap:operation soapAction="" style="document"/>
    <wsdl:input name="searchAdressRequest">
    <soap:body use="literal"/>
    </wsdl:input>
    <wsdl:output name="searchAdressResponse">
    <soap:body use="literal"/>
    </wsdl:output>
    <wsdl:fault name="BusinessException">
    <soap:fault name="BusinessException" use="literal"/>
    </wsdl:fault>
    </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="SearchAdress">
    <wsdl:port name="SearchAdressPort" binding="tns:SearchAdressServiceSoapBinding">
    <soap:address location="http://localhost:9090/SearchAdressPort"/>
    </wsdl:port>
    </wsdl:service>
    </wsdl:definitions>

    File: external_login_schema.xsd

    <?xml version="1.0" encoding="UTF-8"?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:external="http://com/example/login/" targetNamespace="http://com/example/login/">
    <element name="login" type="external:login"/>
    <complexType name="login">
    <sequence>
    <element name="username" type="string"/>
    <element name="password" type="string"/>
    </sequence>
    </complexType>
    </schema>

     

    This is a typical wsdl (usually generated with apache cxf). 

    As you can see, there are several schemas with different namespaces in the wsdl which are referncing each other and we have one include from an external schema.

     

    I hope this helps.

     

    Kind regards,

    Andi



  • 6.  Re: validate full soap request against wsdl (with multiple schemas)

    Posted 05-23-2017 11:48 AM

    Andi,

     

    Thank you for the WSDL file. I've tried several different methods but the amount of complexity in getting the schemas parsed out of the WSDL and treat each one as a import along with namespace alignment is not going to work. This will need to be a new feature of the XML schema assertion to dynamically and cache the value for a period of time. Please log an idea through our community so that our product management team can review.

     

    Sincerely,

     

    Stephen Hughes

    Director, CA Support



  • 7.  Re: validate full soap request against wsdl (with multiple schemas)
    Best Answer

    Posted 05-24-2017 02:48 AM

    Thank you for your investigations.

     

    I added the following idea: validate complex xml schema dinamically 

     

    Regards,

    Andi