2

I am trying to implement Amadeus Soap4 web services . Created the Header entries as recommended by the Implementation document. But Always receives 12|Presentation|Soap Message header incorrect error.I have tried the generated soap header in SOAP UI and it works without any changes to it. So I am looking for a solution to pin down the issue happening with in the application .

anu Joseph
  • 21
  • 2
  • Welcome to Stack Overflow! Always try to post code. Even if wrong - that will show that you're really trying at least! – Jensd Feb 15 '16 at 13:33

2 Answers2

0

There are several steps needed to take when implementing WS-Security in OpenEdge since there basically isn't any built in support!

First you will need to be able to create a password digest. There are several pitfalls here to avoid (character transformation between different types of charsets, handling binary data etc).

This procedure will take a pointer to a "Nonce", a date and a password and return a "digest".

PROCEDURE generatePasswordDigest :

    DEFINE INPUT  PARAMETER mNonce     AS MEMPTR      NO-UNDO.
    DEFINE INPUT  PARAMETER pcCreated  AS CHARACTER   NO-UNDO.
    DEFINE INPUT  PARAMETER pcPassword AS CHARACTER   NO-UNDO.

    DEFINE OUTPUT PARAMETER pcHash     AS CHARACTER   NO-UNDO.

    DEFINE VARIABLE mBytes        AS MEMPTR      NO-UNDO.
    DEFINE VARIABLE mSHA1         AS MEMPTR      NO-UNDO.

    /*
    Set size of mempointer, created + 36 because of all data that should fit.
    */
    SET-SIZE(mBytes) = 36 + LENGTH(pcCreated).

    /* Put the decoded nonce first */
    PUT-BYTES(mBytes, 1) = mNonce.

    /* Add create time */
    PUT-STRING(mBytes, 1 + 16) = pcCreated.

    /* Set SHA1 returns a 20 byte raw string. */
    SET-SIZE(mSHA1) = 20.
    mSHA1 = SHA1-DIGEST(pcPassword).

    /* Add password, SHA1-digested (so we need to put bytes instead of a string */
    PUT-BYTES(mBytes, 17 + LENGTH(pcCreated)) = mSHA1.

    /* Create out-data in B64-encoded format */
    pcHash = STRING(BASE64-ENCODE(SHA1-DIGEST(mBytes))).

    /* Clean up mempointers */
    SET-SIZE(mBytes) = 0.
    SET-SIZE(mSHA1)  = 0.
    SET-SIZE(mNonce) = 0.

END PROCEDURE.

Once you have your digest you will have to do a quite large job of putting the SOAP-headers together. There's most likely are more effective way of doing this, you could create procedures to have a more modular way of coding this etc. But this actually works. Needless to say, you need to change quite a lot below. At least all the "XXXYYY"s should be customized to your needs.

PROCEDURE setRequestSessionHeader :
    DEFINE OUTPUT PARAMETER phHeader    AS HANDLE.
    DEFINE INPUT  PARAMETER pcNamespace AS CHARACTER.
    DEFINE INPUT  PARAMETER pcLocalNS   AS CHARACTER.
    DEFINE OUTPUT PARAMETER plDeleteOnDone AS LOGICAL.

    DEFINE VARIABLE hSoapHeaderEntryref1    AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hSoapHeaderEntryref2    AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hSoapHeaderEntryref3    AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hSoapHeaderEntryref4    AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hSoapHeaderEntryref5    AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hXDocument              AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hOASSecurity            AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hOASUsernameToken       AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hOASUserName            AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hOASPassword            AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hOASPasswordType        AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hOASNonce               AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hWSUCreated             AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hADDMessageID           AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hADDTo                  AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hADDAction              AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hAMA_SecurityHostedUser AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hUserId                 AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hTxt                    AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hAttr                   AS HANDLE      NO-UNDO.
    DEFINE VARIABLE hRootNode               AS HANDLE      NO-UNDO.

   /* Namespaces */
    DEFINE VARIABLE cNSAddressing           AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cNSSecurity             AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cNSSecurityUtils        AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cNSAmaSec               AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cMessageId              AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cUserName               AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cPasswordClear          AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cPasswordDigest         AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cCreated                AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cAction                 AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cTo                     AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cNonceB64               AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE cOfficeId               AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE mNonce                  AS MEMPTR      NO-UNDO.


    /* Changes might be needed here depending on what service is called */
    ASSIGN
        cNSAddressing     = "http://www.w3.org/2005/08/addressing"
        cNSSecurity       = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
        cNSSecurityUtils  = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        cNSAmaSec         = "http://xml.amadeus.com/2010/06/Security_v1"
        cAction           = "http://webservices.amadeus.com/XXXYYY"
        cTo               = "https://noded1.production.webservices.amadeus.com/XXXYYY".

    /* Set your username, office ID and password */
    ASSIGN
        cUserName         = "XXXYYY"
        cOfficeId         = "XXXYYY"
        cPasswordClear    = "XXXYYY".


    /* Delete header when done! */
    ASSIGN
        plDeleteOnDone = TRUE.


    CREATE SOAP-HEADER ghSoapHeader.
    CREATE SOAP-HEADER-ENTRYREF hSoapHeaderEntryref1.
    CREATE SOAP-HEADER-ENTRYREF hSoapHeaderEntryref2.
    CREATE SOAP-HEADER-ENTRYREF hSoapHeaderEntryref3.
    CREATE SOAP-HEADER-ENTRYREF hSoapHeaderEntryref4.
    CREATE SOAP-HEADER-ENTRYREF hSoapHeaderEntryref5.


    CREATE X-DOCUMENT hXDocument.
    CREATE X-NODEREF hRootNode.
    CREATE X-NODEREF hOASSecurity.
    CREATE X-NODEREF hTxt.
    CREATE X-NODEREF hOASUsernameToken.
    CREATE X-NODEREF hOASPassword.
    CREATE X-NODEREF hOASUserName.
    CREATE X-NODEREF hOASNonce.
    CREATE X-NODEREF hADDMessageID.
    CREATE X-NODEREF hADDTo.
    CREATE X-NODEREF hADDAction.
    CREATE X-NODEREF hWSUCreated.
    CREATE X-NODEREF hAMA_SecurityHostedUser.
    CREATE X-NODEREF hUserId.


    /* Not DATETIME-TZ! */
    DEFINE VARIABLE dtZuluNow AS DATETIME    NO-UNDO.

    /* Genereate a random key and base64-encode it */
    SET-SIZE(mNonce) = 16.
    mNonce = GENERATE-RANDOM-KEY.
    cNonceB64 = BASE64-ENCODE(mNonce).

    /* Get time in UTC/GMT/ZULU/Timezone 0 */
    dtZuluNow = DATETIME-TZ(NOW,0).

    /* Manipulate the date string to fit specs... */
    ASSIGN
        cMessageId = LC(SUBSTRING(STRING(GENERATE-UUID), 8, 20))
        cCreated = STRING(dtZuluNow, "9999-99-99THH:MM:SS") + ":000Z".

    /* Genereate digest */
    RUN generatePasswordDigest( mNonce, cCreated, cPasswordClear, OUTPUT cPasswordDigest).


    /* Root node */
    hXDocument:CREATE-NODE-NAMESPACE(hRootNode, "", "root", "element").
    hXDocument:INSERT-BEFORE(hRootNode, ?).

    /**** Addressing ****/
    /* MessageID */
    ghSoapHeader:ADD-HEADER-ENTRY(hSoapHeaderEntryref1).
    hXDocument:CREATE-NODE-NAMESPACE(hADDMessageID, cNSAddressing, "MessageID", "ELEMENT").
    hRootNode:APPEND-CHILD(hAddMessageID).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cMessageId.
    hADDMessageId:APPEND-CHILD(hTxt).
    hSoapHeaderEntryref1:SET-NODE(hADDMessageID).

    /* Action */
    ghSoapHeader:ADD-HEADER-ENTRY(hSoapHeaderEntryref2).
    hXDocument:CREATE-NODE-NAMESPACE(hADDAction, cNSAddressing, "Action", "ELEMENT").
    hRootNode:APPEND-CHILD(hADDAction).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cAction.
    hADDAction:APPEND-CHILD(hTxt).
    hSoapHeaderEntryref2:SET-NODE(hADDAction).

    /* To */
    ghSoapHeader:ADD-HEADER-ENTRY(hSoapHeaderEntryref3).
   hXDocument:CREATE-NODE-NAMESPACE(hADDTo, cNSAddressing, "To", "ELEMENT").
    hRootNode:APPEND-CHILD(hADDTo).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cTo.
    hADDTo:APPEND-CHILD(hTxt).
    hSoapHeaderEntryref3:SET-NODE(hADDTo).

    /**** Security ****/
    /* Root node */
    ghSoapHeader:ADD-HEADER-ENTRY(hSoapHeaderEntryref4).
    hXDocument:CREATE-NODE-NAMESPACE(hOASSecurity, cNSSecurity, "Security", "ELEMENT").
    hRootNode:APPEND-CHILD(hOASSecurity).

    /* UserNameToken node */
    hXDocument:CREATE-NODE-NAMESPACE(hOASUsernameToken, cNSSecurity, "UsernameToken", "ELEMENT").
    hOASUsernameToken:SET-ATTRIBUTE("Id", "UsernameToken-1").
    hOASSecurity:INSERT-BEFORE(hOASUsernameToken, ?).

    /* Username */
    hXDocument:CREATE-NODE-NAMESPACE(hOASUserName, cNSSecurity, "Username", "ELEMENT").
    hRootNode:APPEND-CHILD(hOASUserName).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cUserName.
    hOASUserName:APPEND-CHILD(hTxt).
    hOASUsernameToken:APPEND-CHILD(hOASUserName).

    /* Nonce */
    hXDocument:CREATE-NODE-NAMESPACE(hOASNonce, cNSSecurity, "Nonce", "ELEMENT").
    hOASNonce:SET-ATTRIBUTE("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary").
    hOASUsernameToken:APPEND-CHILD(hOASNonce).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cNonceB64.
    hOASNonce:APPEND-CHILD(hTxt).
    /* Password hash */
    hXDocument:CREATE-NODE-NAMESPACE(hOASPassword, cNSSecurity, "Password", "ELEMENT").
    hOASPassword:SET-ATTRIBUTE("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest").
    hOASUsernameToken:APPEND-CHILD(hOASPassword).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cPasswordDigest.
    hOASPassword:APPEND-CHILD(hTxt).

    /* Created - timestamp */
    hXDocument:CREATE-NODE-NAMESPACE(hWSUCreated, cNSSecurityUtils, "Created", "ELEMENT").
    hOASUsernameToken:APPEND-CHILD(hWSUCreated).
    hXDocument:CREATE-NODE(hTxt, "", "TEXT").
    hTxt:NODE-VALUE = cCreated.
    hWSUCreated:APPEND-CHILD(hTxt).
    hSoapHeaderEntryref4:SET-NODE(hOASSecurity).

    /**** AMA_SecurityHostedUser ****/
    /* Root node */
    ghSoapHeader:ADD-HEADER-ENTRY(hSoapHeaderEntryref5).
    hXDocument:CREATE-NODE-NAMESPACE(hAMA_SecurityHostedUser, cNSAMASec, "AMA_SecurityHostedUser", "ELEMENT").
    hRootNode:APPEND-CHILD(hAMA_SecurityHostedUser).


    /* UserID */
    hXDocument:CREATE-NODE-NAMESPACE(hUserID, cNSAMASec, "UserID", "ELEMENT").

    hUserID:SET-ATTRIBUTE("AgentDutyCode", "SU").
    hUserID:SET-ATTRIBUTE("RequestorType", "U").
    hUserID:SET-ATTRIBUTE("PseudoCityCode", cOfficeId).
    hUserID:SET-ATTRIBUTE("POS_Type", "1").

    hAMA_SecurityHostedUser:APPEND-CHILD(hUserID).
    hSoapHeaderEntryref5:SET-NODE(hAMA_SecurityHostedUser).

    /* Output the header */
    phHeader = ghSoapHeader.

    /* Cleanup */
    IF VALID-HANDLE(hOASSecurity) THEN
        DELETE OBJECT hOASSecurity.
    IF VALID-HANDLE(hOASUsernameToken) THEN
        DELETE OBJECT hOASUsernameToken.
    IF VALID-HANDLE(hOASUserName) THEN
        DELETE OBJECT hOASUserName.
    IF VALID-HANDLE(hOASPassword) THEN
        DELETE OBJECT hOASPassword.
    IF VALID-HANDLE(hADDMessageID) THEN
        DELETE OBJECT hADDMessageID.
    IF VALID-HANDLE(hOASNonce) THEN
        DELETE OBJECT hOASNonce.
    IF VALID-HANDLE(hTxt) THEN
        DELETE OBJECT hTxt.
    IF VALID-HANDLE(hADDTo) THEN
        DELETE OBJECT hADDTo.
    IF VALID-HANDLE(hWSUCreated) THEN
        DELETE OBJECT hWSUCreated.
    IF VALID-HANDLE(hADDAction) THEN
        DELETE OBJECT hADDAction.
    IF VALID-HANDLE(hXDocument) THEN
        DELETE OBJECT hXDocument.
    IF VALID-HANDLE(hRootNode) THEN
        DELETE OBJECT hRootNode.
    IF VALID-HANDLE(hSoapHeaderEntryRef1) THEN
        DELETE OBJECT hSoapHeaderEntryRef1.
    IF VALID-HANDLE(hSoapHeaderEntryRef2) THEN
        DELETE OBJECT hSoapHeaderEntryRef2.
    IF VALID-HANDLE(hSoapHeaderEntryRef3) THEN
        DELETE OBJECT hSoapHeaderEntryRef3.
    IF VALID-HANDLE(hSoapHeaderEntryRef4) THEN
        DELETE OBJECT hSoapHeaderEntryRef4.
    IF VALID-HANDLE(hSoapHeaderEntryRef5) THEN
        DELETE OBJECT hSoapHeaderEntryRef5.
    IF VALID-HANDLE(hAMA_SecurityHostedUser) THEN
        DELETE OBJECT hAMA_SecurityHostedUser.
    IF VALID-HANDLE(hUserId) THEN
        DELETE OBJECT hUserId.

END PROCEDURE.

Finally, before calling the actual web service you will need to attach the procedure above so it creates headers on the fly:

XXXYYY-handle:SET-CALLBACK-PROCEDURE( "REQUEST-HEADER", "setRequestSessionHeader" ).

That should basically be it. A rough example that works but perhaps isn't very beautiful...

Jensd
  • 7,886
  • 2
  • 28
  • 37
  • The soap header still creates the error 12|Presentation|Soap Header message incorrect.I assume the issue is because there are many additional namespaces in soapenv:envelope which I am not able to do programmatically.When I use the soapenv:header created using the program in soapUI with additional namespaces ,it works fine. So I assume you might have faced the same issue during implementation.Any idea how to resolve this issue..?Is it possible to create soapenv:envelope as required in call back procedure along with the soap:body ? – anu Joseph Feb 17 '16 at 11:10
  • The code i posted works, in production. Use a tool like Telerik Fiddler to debug what you are actually sending! – Jensd Feb 17 '16 at 11:12
  • It's quite likely that you've got something like namespace, "to" or "action" wrong. Also the correct case can be a problem. I had problems with "nodeD1" vs "noded1" for instance. – Jensd Feb 17 '16 at 13:50
  • i see the same question to be asked under this link : https://community.progress.com/community_groups/openedge_development/f/19/t/13193 .But i didn't quite understand the Solution . – anu Joseph Feb 17 '16 at 19:22
  • The solution is above! The question you linked to is actually mine but never really got answered. Remove your comments and update your original question instead - that is unreadable... – Jensd Feb 17 '16 at 20:50
0

This is due to webservice URL of Amadeus. Be sure that the url of the web request matches the value of the tag "add:To", including letter case.the request will be sent to the address in lowercase like noded1 instead of nodeD1

For Reference please refere below link Amadeus webservice address point Issue

Community
  • 1
  • 1