HttpClient with Basic Authentication of some sort...

Posted by Simon de Kraa on 02-Jan-2017 06:53

Hi,

I found the documentation on Basic Authentication.

documentation.progress.com/.../index.html

But I am not sure how to implement the following using the HttpClient.

Any ideas where to start? Thanks.

url=https://myurl/api

clientid=myid

clientsecret=mysecret

username=myusername

password=mypassword

scope=myscope

auth64=`echo -n $clientid:$clientsecret|base64 --wrap=0`

curl "$url/oauth/token" \

-H "Accept: application/json" \

-H "Authorization: Basic $auth64" \

-H "Content-Type: application/x-www-form-urlencoded" \

--data "grant_type=password&username=$username&password=$password&scope=$scope" \

--compressed

Posted by Peter Judge on 05-Jan-2017 13:54

You don’t need to. The HTTP client will do it for you. if you care how it’s done, it’s below (the source code is also available in $DLC/src/netlib/OpenEdge.Net.pl).
 
 
class OpenEdge.Net.HTTP.Filter.Auth.BasicAuthenticationFilter inherits AuthenticationRequestFilter:
    constructor public BasicAuthenticationFilter (input poRequest as IAuthenticatedRequest ):
        super (input poRequest).
    end constructor.
 
    /** Build the actual authentication. To be implemented by concrete classes. */
    method override protected void AddAuthentication():
        define variable cRealm as character no-undo.
        define variable cCredentials as character no-undo.
        define variable mCredentials as memptr no-undo.
        define variable mShortCredentials as memptr no-undo.
        define variable oCredentials as Credentials no-undo.
        define variable ilength as integer no-undo.
        define variable oRequest as IAuthenticatedRequest no-undo.
       
        /* cast for comfort */
        assign oRequest = cast(this-object:Message, IAuthenticatedRequest)
               cRealm = entry(2, oRequest:AuthenticationChallenge, '=':u)
               cRealm = trim(cRealm, '"':u).
        Assert:NotNull(cRealm, 'Realm').
       
        assign oCredentials = GetCredentials(cRealm).
        if not valid-object(oCredentials) then
            return error new AppError(substitute('Missing credentials for realm ~"&1~"', cRealm), 0).
       
        assign cCredentials = substitute('&1:&2':u,
                                oCredentials:UserName,
                                oCredentials:Password)
               iLength = length(cCredentials, 'RAW':u).
 
        set-size(mCredentials) = iLength + 1. /* for the null terminator */
        put-string(mCredentials, 1) = cCredentials.
        /* jiggery-pokery with lengths because there's a null at the end of the
           memptr, which we do not want */
        set-size(mShortCredentials) = iLength.
        put-bytes(mShortCredentials, 1) = get-bytes(mCredentials, 1, iLength).
        
        assign cCredentials = substitute('Basic &1':u, base64-encode(mShortCredentials)).
        /* add to the request */
        oRequest:SetHeader(
            HttpHeaderBuilder:Build('Authorization':u):Value(cCredentials):Header).
       
        finally:
            set-size(mShortCredentials) = 0.
            set-size(mCredentials) = 0.
        end finally.
    end method.
           
end class.
 

All Replies

Posted by Simon de Kraa on 02-Jan-2017 06:55

Any idea why my posts are always in one big line? This happens to me on Chrome, Edge, ... on Windows 10.

Never mind I have added some html paragraph code ... not very friendly...

Posted by Peter Judge on 05-Jan-2017 12:57

Simon,

I've added some examples/samples at github.com/.../http_authentication .

Posted by Simon de Kraa on 05-Jan-2017 13:45

Thanks, but I'm still not sure how to handle the $auth64 (see example) in combination with username/password?

Posted by Peter Judge on 05-Jan-2017 13:54

You don’t need to. The HTTP client will do it for you. if you care how it’s done, it’s below (the source code is also available in $DLC/src/netlib/OpenEdge.Net.pl).
 
 
class OpenEdge.Net.HTTP.Filter.Auth.BasicAuthenticationFilter inherits AuthenticationRequestFilter:
    constructor public BasicAuthenticationFilter (input poRequest as IAuthenticatedRequest ):
        super (input poRequest).
    end constructor.
 
    /** Build the actual authentication. To be implemented by concrete classes. */
    method override protected void AddAuthentication():
        define variable cRealm as character no-undo.
        define variable cCredentials as character no-undo.
        define variable mCredentials as memptr no-undo.
        define variable mShortCredentials as memptr no-undo.
        define variable oCredentials as Credentials no-undo.
        define variable ilength as integer no-undo.
        define variable oRequest as IAuthenticatedRequest no-undo.
       
        /* cast for comfort */
        assign oRequest = cast(this-object:Message, IAuthenticatedRequest)
               cRealm = entry(2, oRequest:AuthenticationChallenge, '=':u)
               cRealm = trim(cRealm, '"':u).
        Assert:NotNull(cRealm, 'Realm').
       
        assign oCredentials = GetCredentials(cRealm).
        if not valid-object(oCredentials) then
            return error new AppError(substitute('Missing credentials for realm ~"&1~"', cRealm), 0).
       
        assign cCredentials = substitute('&1:&2':u,
                                oCredentials:UserName,
                                oCredentials:Password)
               iLength = length(cCredentials, 'RAW':u).
 
        set-size(mCredentials) = iLength + 1. /* for the null terminator */
        put-string(mCredentials, 1) = cCredentials.
        /* jiggery-pokery with lengths because there's a null at the end of the
           memptr, which we do not want */
        set-size(mShortCredentials) = iLength.
        put-bytes(mShortCredentials, 1) = get-bytes(mCredentials, 1, iLength).
        
        assign cCredentials = substitute('Basic &1':u, base64-encode(mShortCredentials)).
        /* add to the request */
        oRequest:SetHeader(
            HttpHeaderBuilder:Build('Authorization':u):Value(cCredentials):Header).
       
        finally:
            set-size(mShortCredentials) = 0.
            set-size(mCredentials) = 0.
        end finally.
    end method.
           
end class.

Posted by Simon de Kraa on 05-Jan-2017 14:01

Right! I will give it a try. Thanks.

Posted by Simon de Kraa on 09-Jan-2017 02:10

Using basic_preemptive.p.

What domain should I use? If I leave it empty I get the following error message: Domain cannot be empty.

I my case I only have a clientid (username?) and clientsecret (password?).

I am also not sure how to add the following curl parameter?

--data "grant_type=password&username=$username&password=$password&scope=$scope" \ -

Any ideas?

Edit: do I need to use WithData()?

Posted by Peter Judge on 09-Jan-2017 10:12

You can use any domain you like (or none): the constructor requires a non-null, non-empty value but all three properties are settable to whatever you’d like.
 
 
 

Posted by Simon de Kraa on 10-Jan-2017 00:30

EDIT: NEVER MIND. IT SHOULD HAVE BEEN A POST INSTEAD OF A GET. PROBLEM SOLVED.

Thanks, any idea how to translate the curl --data param? Is the following code in the right direction?

Unfortunately I get the following error message:

HTTP status code: 400 { "errors": [ { "code": "2.5", "field": null, "description": "Request method not supported" } ] }

creds = new Credentials('abc', 'clientid', 'clientsecret').

oRequestBody = new String('grant_type=password&username=myuser&password=mypasswd&scope=myscope').

req = RequestBuilder:Get('partner.transfollow.com/.../', oRequestBody) // Add credentials to the request :UsingBasicAuthentication(creds) :ContentType('application/x-www-form-urlencoded') :AcceptJson() :Request.

resp = httpClient:Execute(req).

DEFINE VARIABLE oJsonEntity AS JsonObject NO-UNDO. DEFINE VARIABLE JsonString AS LONGCHAR NO-UNDO.

oJsonEntity = CAST(resp:Entity, JsonObject). oJsonEntity:Write(JsonString, TRUE).

Posted by Peter Judge on 10-Jan-2017 08:16

Your approach looks fine (for the message body/entity). Maybe the endpoint is expecting a PUT or a POST? GET’s don’t typically have bodies.
 

Posted by Simon de Kraa on 10-Jan-2017 08:18

Yes, I found out this morning that it should have been a POST. Thank you for your help.

This thread is closed