Consuming WebServices in combination with oAuth2.0

Cecil

19+ years progress programming and still learning.
#1
Working on a new project that requires consuming WebServices (WSDL, not REST). However, I need to include some extra information in the HTTP Headers for the access token. But the ABL does not expose any methods with adding extra HTTP headers.

Apart from using sockets or OPENEDGE.HTTP.NET.PL and posting the SOAP payload myself, what are the alternatives??
 

RealHeavyDude

Well-Known Member
#2
Since the ABL does not support the SSL client certificate I use the .NET HttpWebRequest object. Obviously our client is running on Windoze.

On Solaris we use wget.
 

Cecil

19+ years progress programming and still learning.
#3
Since the ABL does not support the SSL client certificate I use the .NET HttpWebRequest object. Obviously our client is running on Windoze.

On Solaris we use wget.

Can you explain a bit more about SSL client Certificate support issue, is that about using CA x.509 certificates??

Do you have any sample ABL code which uses NET HttpWebRequest>
 

RealHeavyDude

Well-Known Member
#4
The ABl (at least with OE 11.6) does not support the SSL client certificate except for WebService calls. With standard HTTPS get and post requests you cannot use it. Here @ my employer we all login to our Windows 7 systems with a smartcard. During login to Windows the SSL client certificate residing on the smartcard is copied into Windows certificate store. Our single-sign-on infrastructure is based in CAs SiteMinder and each web server requests the SSL client certificate to be present for authentication.

Code:
define input authenticationUrl  as character   no-undo.  /* Authentication URL */
define input hostName           as character   no-undo.  /* Name of the host (DNS alias) */

define variable cookieContainer   as class CookieContainer    no-undo.
define variable cookieCollection  as class CookieCollection   no-undo.
define variable cookie            as class Cookie             no-undo.
define variable requestUri        as class Uri                no-undo.
define variable request           as class HttpWebRequest     no-undo.
define variable response          as class HttpWebResponse    no-undo.
define variable responseReader    as class StreamReader       no-undo.
define variable enumHelper1       as class System.Enum        no-undo.
define variable enumHelper2       as class System.Enum        no-undo.
define variable certificate        as class auth.ClientCertificate  no-undo.
define variable issoEndpoint       as class auth.ISSOEndpoint       no-undo.
define variable xmlContent         as longchar    no-undo.
define variable contentType        as character   no-undo.
define variable statusCode         as character   no-undo.
define variable statusDescription  as character   no-undo.
define variable debugFileName      as character   no-undo.
define variable cookieCount        as integer     no-undo.
define variable okay               as logical     no-undo.
/* Get the certificate */
assign certificate = auth.ClientCertificate:getInstance ( ).
assign x509Certificate = certificate:getCetificate ( ).
/* The Cookie container which will hold the C<X>SESSION cookie */
assign cookieContainer = new CookieContainer ( ).
/* Security protocols */
assign enumHelper1 = Progress.Util.EnumHelper:or ( SecurityProtocolType:Tls, SecurityProtocolType:Tls11 ).
assign enumHelper2 = Progress.Util.EnumHelper:or ( cast ( enumHelper1, SecurityProtocolType ), SecurityProtocolType:Tls12 ).
assign ServicePointManager:SecurityProtocol = cast ( enumHelper2, SecurityProtocolType ).
/* This is the request */
assign requestUri = new Uri ( issoEndPointURL )
       request    = cast ( WebRequest:Create ( requestUri ), HttpWebRequest ).
assign request:Method            = 'GET'
       request:AllowAutoRedirect = true
       request:CookieContainer   = cookieContainer.
/* Add the certificate to the request */
request:ClientCertificates:Add ( x509Certificate ).
           
/* This is the response */
assign response = cast ( request:GetResponse ( ), HttpWebResponse ).
/* Check the HTTP status code whether the reqeust succeeded */
assign statusCode = response:StatusCode:ToString ( ).
/* Fetch the response in any case */
assign responseReader = new StreamReader ( response:GetResponseStream ( ), Encoding:ASCII ).
assign xmlContent = responseReader:ReadToEnd ( ).
HTH - RealHeavyDude.
 

RealHeavyDude

Well-Known Member
#5
Ooops, forgot

Code:
using System.*.
using System.Text.*.
using System.IO.*.
using System.Net.*.
using System.Security.Cryptography.X509Certificates.*.
using System.Security.Cryptography.*.
 

Cecil

19+ years progress programming and still learning.
#6
:(
1516091659739.png
Is there something extra I need to add to the assemblies .xml file?

I've added Sytem,Security just to "suck it and see", but that did not work.
 

RealHeavyDude

Well-Known Member
#7
The auth.ClientCertificate is a class which I developed to wrap the logic which fetches the SSL certificate from the Windows certificate store. I did not include it. Do you need a sample on how to get the certificate from the Windows certificate store?
 

Cecil

19+ years progress programming and still learning.
#9
The auth.ClientCertificate is a class which I developed to wrap the logic which fetches the SSL certificate from the Windows certificate store. I did not include it. Do you need a sample on how to get the certificate from the Windows certificate store?
Quite possibly yes. The service I’m consuming has/will issue me a CA x.905 file. Not quite shure how to utilise the file yet. Does .NET need access these files from some sort of repository I.e. ‘Windows certificate store’? Or can .NET reference this file directly using a file path?
 
Last edited:

Cecil

19+ years progress programming and still learning.
#10
Just to prove I'm not freeloading off your hard work RHD, I have actually attempted to try an write my own GetClientCertificate() method, but I'm lacking in the required skills in trying to interact with .NET and the ABL. Side Note: I find the OpenEdge Documentation quite bloated and overwhelming to understand.

Code:
using System.*.
USING System.Security.Cryptography.*.
USING System.Security.Cryptography.X509Certificates.*.

 
CLASS X509Certificate2:

  
    
    METHOD PRIVATE STATIC CHARACTER GetClientCertificate():
        DEFINE VARIABLE userCaStore AS CLASS X509Store NO-UNDO.
        DEFINE VARIABLE certificatesInStore  AS CLASS   X509Certificate2Collection  NO-UNDO.
        DEFINE VARIABLE findResult           AS CLASS   "X509Certificate2Collection[]"  NO-UNDO.
        
        userCaStore = NEW X509Store( StoreName:My, StoreLocation:CurrentUser).
        
         userCaStore:OPEN( OpenFlags:ReadOnly ).
        
         certificatesInStore = userCaStore:Certificates.
        
         DO i = 0 TO certificatesInStore:LENGTH - 1:
            findResult = CAST().
         END.
        
         findResult          = certificatesInStore:Find(X509FindType:FindBySubjectName, "localtestclientcert", true).

         IF findResult:COUNT = 1 THEN
            clientCertificate = findResult[0].   
        
        
         userCaStore:Close().
        
         RETURN clientCertificate.
    END METHOD.
    
END CLASS.
 

RealHeavyDude

Well-Known Member
#11
Code:
routine-level on error undo, throw.
using System.Security.Cryptography.X509Certificates.*.
using System.Security.Cryptography.*.
using System.Security.Permissions.*.
class auth.ClientCertificate final inherits AoSBase:
   
    &scoped-define sub-system 'CLNT_CERT'
    &scoped-define certificate-issuer 'CN=*** your CN ***'
    /* XCN_OID_PKIX_KP_CLIENT_AUTH - 1.3.6.1.5.5.7.3.2: The certificate can be used for authenticating a client. */
    &scoped-define certificate-oid '1.3.6.1.5.5.7.3.2'
    &scoped-define http-status-code-def '{&package}/HTTP_status_codes.xml'
   
    define private variable x509Certificate  as class X509Certificate2  no-undo.
    define private static variable instance  as class auth.ClientCertificate  no-undo.
   
    define public property certificateString  as character   no-undo get. private set.
   
    method public System.Security.Cryptography.X509Certificates.X509Certificate2 getCetificate ( ):
       
        /*------------------------------------------------------------------------------
           Purpose:  Get the certificate from the certificate store
             Notes:  
        ------------------------------------------------------------------------------*/
       
        &scoped-define bail-out do: assign x509Certificate = ?. leave get-cetificate-blk. end
       
         /* ------------------------------ .NET classes ------------------------------ */
        define variable myStore               as class X509Store                      no-undo.
        define variable readOnly              as class OpenFlags                      no-undo.
        define variable openExistinOnly       as class OpenFlags                      no-undo.
        define variable certificates          as class X509Certificate2Collection     no-undo.
        define variable certificate           as class X509Certificate2               no-undo.
         define variable asymmetricAlgorythm   as class AsymmetricAlgorithm            no-undo.
        define variable extensions            as class X509ExtensionCollection        no-undo.
        define variable extension             as class X509Extension                  no-undo.
        define variable keyUsageExtension     as class X509EnhancedKeyUsageExtension  no-undo.
        define variable oids                  as class OidCollection                  no-undo.
        define variable oid                   as class Oid                            no-undo.
        /* ------------------------------ .NET classes ------------------------------ */
       
        define variable certNumber            as integer     no-undo.
        define variable certCount             as integer     no-undo.
        define variable extensionNumber       as integer     no-undo.
        define variable oidNumber             as integer     no-undo.
        define variable confirmation          as logical     no-undo.
       
        define buffer CertificateCollectionBuffer for CertificateCollection.
        get-cetificate-blk:
        do on error undo get-cetificate-blk, leave get-cetificate-blk
            on stop undo get-cetificate-blk, retry get-cetificate-blk:
               
            /* STOP Conditon trapped */
            if retry then do:
                errorMessage ( substitute ( 'Exception getting X509 certificate from DTP Smartcard [&1].', stopCondition ), {&sub-system} ) no-error.
                {&bail-out}.
            end.                
       
            /* Only necessary if the certificate is not valid ( has not been retrieved yet ) */
            if not valid-object ( x509Certificate ) then do:
       
                /* Access the certificate store */
                assign myStore = new X509Store ( StoreName:My, StoreLocation:CurrentUser ).
                myStore:Open ( cast ( Progress.Util.EnumHelper:And ( OpenFlags:ReadOnly, OpenFlags:OpenExistingOnly ), OpenFlags ) ).
       
                /* Fetch the certificates */
                assign certificates = myStore:Certificates.
   
                /* Loop through the certificates until we've got the one we need */
                do certNumber = 0 to certificates:Count - 1:
   
                    assign certificate = certificates:Item [ certNumber ].
   
                    /* Does the certificate have a private key and is it issued by one of the know issuers of
                       smartcard certificates */
                    if certificate:HasPrivateKey and certificate:Issuer begins {&certificate-issuer} then do:
                         /* This will enforce the access to the private key on the certificate and thus ask the user
                            for the PIN whenever there is a problem with the smartcard middleware ... */
                         assign asymmetricAlgorythm = certificate:PrivateKey.
   
                        /* Loop through the cetificate's extension and check if the key usae extension carries the
                           client authentication OID */
                        assign extensions = certificate:Extensions.
                        do extensionNumber = 0 to extensions:Count - 1:
   
                            assign extension = extensions:Item [ extensionNumber ].
                            assign keyUsageExtension = cast ( extension, X509EnhancedKeyUsageExtension ) no-error.
                            if valid-object ( keyUsageExtension ) then do:
   
                                assign oids = keyUsageExtension:EnhancedKeyUsages.
                                do oidNumber = 0 to oids:Count - 1:
   
                                    assign oid = oids:Item [ oidNumber ].
   
                                    /* Finally, that's the one */
                                    if oid:Value = {&certificate-oid} then do:
                                        assign x509Certificate   = certificate
                                               certificateString = certificate:ToString ( ).
                                        /* In case there is more than one certificate in the Windows store ... */
                                        do for CertificateCollectionBuffer:
                                            create CertificateCollectionBuffer.
                                            assign CertificateCollectionBuffer.certificateNumber = certNumber
                                                   CertificateCollectionBuffer.issuedToProperty  = getProperty ( certificate:Subject )
                                                   CertificateCollectionBuffer.issuedByProperty  = getProperty ( certificate:Issuer )
                                                   CertificateCollectionBuffer.serialNumber      = certificate:SerialNumber.
                                            infoMessage ( substitute ( 'X509 certificate for &1 successfuly fetched form DTP Smartcard.', CertificateCollectionBuffer.issuedToProperty ), {&sub-system} ).
                                            assign certCount = certCount + 1.
                                        end.
                                    end.
                                end.
   
                            end.  /* Loop through the cetificate's extension */
   
                        end. /* Loop through the cetificate's extension */
   
                    end. /* Certificate has a private key and is it issued by one of the know issuers of smartcard certificates */
   
                end. /* Loop through the certificates until we've got the one we need */
                /* Close the certificate store */
                myStore:Close ( ).
            end. /* Only necessary if the certificate is not valid ( has not been retrieved yet ) */
            /* Error handling */
            catch anyError as Progress.Lang.Error:
                assign x509Certificate = ?.
                errorMessage ( substitute ( 'Exception getting X509 certificate from DTP Smartcard [&1].', anyError:getMessage ( 1 ) ), {&sub-system} ) no-error.
                delete object anyError.
            end catch.
            finally:
                empty temp-table CertificateCollection.
            end finally.
       
        end. /* get-cetificate-blk */
       
        return x509Certificate.
       
        &undefine bail-out
   
    end method. /* getCetificate */
   
    method public static auth.ClientCertificate getInstance ( ):
       
        /*------------------------------------------------------------------------------
           Purpose:  Return the reference to the one and only instance
             Notes:  
        ------------------------------------------------------------------------------*/
       
        if not valid-object ( instance ) then
            assign instance = new auth.ClientCertificate ( ).
       
        return instance.
       
    end method. /* getInstance */
end class.
 

Cecil

19+ years progress programming and still learning.
#12
Thanks for all the sample code. I not going to be able to test it until next week. Got it to compile with a few tweaks but out of curiosity, do you think you could have archived the same thing with just using a curl command?
 
Top