* * *

Author Topic: [SOLVED] Ouath 2 with LinkedIn and TFPHTTPServer  (Read 630 times)

tudi_x

  • Full Member
  • ***
  • Posts: 208
[SOLVED] Ouath 2 with LinkedIn and TFPHTTPServer
« on: July 11, 2017, 02:38:36 pm »
hi All,
i am getting a 'Missing HTTP protocol version in request' when trying to extract the values (code and state) from the HTTP request from the LinkedIn server with the code attached.

as per the request i see http protocol it is 1.1.
please advise what i am missing.

when i am making the request to my code with a rest client (Insomnia) i do not get an error.
i also analyzed the request from LinkedIn with requestb.in and it was parsed with no issues by them.

thank you

using Lazarus 1.6.4 on Windows 7 64 bit
you would need libeay32.dll and ssleay32.dll in same directory as exe
« Last Edit: July 11, 2017, 05:28:04 pm by tudi_x »

rvk

  • Hero Member
  • *****
  • Posts: 2566
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #1 on: July 11, 2017, 03:30:48 pm »
I'm not sure what you are expecting but you can't retrieve the access-token with just one "get".

I see you do the t.AGet() and directly try to access the html from it.
But OAuth2 doesn't work that way.
If you look closely you'll see that your code runs through the t.AGet() before asking the user for permission.

It shows you an access-page in the browser.
The users needs to allow the access first and after that the browser is redirected to the redirect_uri.
AFTER that you need to read the URI to extract the code it gives you.
(you can see that after pressing allow you get redirected to localhost with a code in the URL)

You can proceed with that after that.

(This should be the same with Google OAuth2).

The only way to monitor the URL is to open a browser and wait for the browsers-title page to change.
You can see here how I did that with Google OAuth2: https://github.com/rvk01/google-oauth2
Look at TGoogleOAuth2.GetAuthorize_token_interactive in https://github.com/rvk01/google-oauth2/blob/master/google_oauth2.pas#L474
« Last Edit: July 11, 2017, 03:34:03 pm by rvk »

tudi_x

  • Full Member
  • ***
  • Posts: 208
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #2 on: July 11, 2017, 04:01:34 pm »
i actually started from your repository some days ago. it was very helpful
! thank you rvk.

unfortunately your code is not cross platform.

my idea is to have a socket opened on localhost so the redirect URL would actually do a GET to this URL. this socket starts with form create in a separate thread.
this way on redirect (after the user provides the ALLOW) the browser is doing a GET on my socket with the parameters i need.
during the synchronize i catch these parameters and i use them in the next steps of the ouath 2 process in order to get the access and refresh token.

so to answer i am not trying to get with this code the access token.
what i am trying to get is the authorize code.

yes, the code runs through because i do not have access to the browser. i just start the browser and it is on it's own - this is different than your solution where you control the browser.

please note that there is no AFTER that for me - it is just a listening socket that is always there and gets a request. because i do not control the browser i do not know when the user pressed ALLOW, what i know is just when the redirect hits my socket.

besides this ouath 2 issues please advise on the missing protocol error if possible.

thank you
 

rvk

  • Hero Member
  • *****
  • Posts: 2566
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #3 on: July 11, 2017, 04:13:54 pm »
Woops, yeah, I missed the server part you were doing  :-[

The problem you are having is that you get 2 request right after each other.
And in the HandleHTTPRequest() you do a Memo1.Clear;

Change the following and you'll see the redirect:
Code: Pascal  [Select]
  1.   // Memo1.Clear;
  2.   Memo1.Append('------');
  3.   Memo1.Append('starting...');
  4.   Memo1.Append('request URI: ' + trim(ARequest.URI));
  5.   Memo1.Append('request URL: ' + trim(ARequest.URL));
  6.   Memo1.Append('request: ' + trim(ARequest.ContentFields.Text));
  7.   Memo1.Append('http version: ' + ARequest.HttpVersion);
  8.   Memo1.Append('protocol version: ' + ARequest.ProtocolVersion);

Gives me this:
Code: [Select]
starting...
request URI: /?code=AQT-iDkodSGx4O7SoiZ3nZd5_Qkwj6xxx3pN0WbrAZI-ixkAJVfTcm5KBJ1QBtx0gqQZ2I3XqSE8pZD-3J1Wvc-ZHRjSu3jhMW6KEBLwkh5ciJSa4Vk&state=T1499789434
request URL: /?code=AQT-iDkodSGx4O7SoiZ3nZd5_Qkwj6xxx3pN0WbrAZI-ixkAJVfTcm5KBJ1QBtx0gqQZ2I3XqSE8pZD-3J1Wvc-ZHRjSu3jhMW6KEBLwkh5ciJSa4Vk&state=T1499789434
request:
http version: 1.1
protocol version: 1.1
server error: nil
stopping...
------
starting...
request URI: /favicon.ico
request URL: /favicon.ico
request:
http version: 1.1
protocol version: 1.1
server error: nil
stopping...
See the request URI in the first request? You can extract the code from that.
The second request is for /favicon.ico (for which you don't have any use)  :D :D

tudi_x

  • Full Member
  • ***
  • Posts: 208
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #4 on: July 11, 2017, 04:28:59 pm »
thanks a lot!

please advise how i could actually extract the values from the valued GET.
i see that ARequest.ContentFields.Count is zero.

i can of course parse directly the ARequest.URL but i thought i could use some help from the http methods.

molly

  • Hero Member
  • *****
  • Posts: 1695
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #5 on: July 11, 2017, 04:44:54 pm »
i can of course parse directly the ARequest.URL but i thought i could use some help from the http methods.
Isn't that what QueryFields (TRequest/THTTPHeader) was meant for ?

I'm (wrongfully?) assuming that the used field is always named code ?

rvk

  • Hero Member
  • *****
  • Posts: 2566
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #6 on: July 11, 2017, 04:45:11 pm »
please advise how i could actually extract the values from the valued GET.
i see that ARequest.ContentFields.Count is zero.
I think the ContentFields are only filled if you get a POST request. Synapse will extract from FORM-DATA or X-WWW-FORM-URLENCODED.
At least, I only see the filling of ContentFields in InitPostVars in HTTPDefs.pas.

And:
Code: Pascal  [Select]
  1.   if (CompareText(R,'POST')=0) or (CompareText(R,'PUT')=0) or (ContentLength>0) then
  2.     InitPostVars;

So you don't get a POST but just a redirect with GET.
Synapse does extract these in the Request in QueryFields.

So the only thing you need to change is this:
Code: Pascal  [Select]
  1.   setlength(_HTTPRequestInfo, ARequest.QueryFields.Count);
  2.   for i := 0 to ARequest.QueryFields.Count - 1 do
  3.   begin
  4.     _HTTPRequestInfo[i].FieldName := Copy(ARequest.QueryFields[i], 1, Pos('=', ARequest.QueryFields[i]) - 1);
  5.     _HTTPRequestInfo[i].FieldValue := Copy(ARequest.QueryFields[i], Pos('=', ARequest.QueryFields[i]) + 1, length(ARequest.QueryFields[i]));
  6.   end;

edit: molly just beat me by seconds. That's what you get for typing a whole solution  :P

Do note that the second pass (for favicon.ico) to HandleHTTPRequest will delete your own array again in setlength(_HTTPRequestInfo); So you need to save it or build in a check for Count > 0.
Code: Pascal  [Select]
  1. if ARequest.QueryFields.Count > 0 then
  2. begin
  3.   setlength(_HTTPRequestInfo, ARequest.QueryFields.Count);
  4.   for i := 0 to ARequest.QueryFields.Count - 1 do
  5.   begin
  6.     _HTTPRequestInfo[i].FieldName := Copy(ARequest.QueryFields[i], 1, Pos('=', ARequest.QueryFields[i]) - 1);
  7.     _HTTPRequestInfo[i].FieldValue := Copy(ARequest.QueryFields[i], Pos('=', ARequest.QueryFields[i]) + 1, length(ARequest.QueryFields[i]));
  8.   end;
  9. end;
« Last Edit: July 11, 2017, 04:48:29 pm by rvk »

tudi_x

  • Full Member
  • ***
  • Posts: 208
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #7 on: July 11, 2017, 04:51:54 pm »
much obliged

i guess 'Missing HTTP protocol version in request' could just be ignored ...


rvk

  • Hero Member
  • *****
  • Posts: 2566
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #8 on: July 11, 2017, 04:54:08 pm »
i guess 'Missing HTTP protocol version in request' could just be ignored ...
I'm not getting that.
Is that a message from your browser in Linux?

In that case it might be useful to send a full header-set in your httpserver to the browser.
Maybe with a message in html that granting access is successful (or is not successful).
Now the user gets a blank page.

molly

  • Hero Member
  • *****
  • Posts: 1695
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #9 on: July 11, 2017, 04:58:58 pm »
edit: molly just beat me by seconds. That's what you get for typing a whole solution  :P
Sorry. it was not mean to intrude on your conversation. I just happen to cross the subject on a recent project i worked on.

Your answer is by miles better than what i was able to come up with, as i'm (still) exploring fcl http classes, so thank you very much for the elaborated/illustrated answer.


tudi_x

  • Full Member
  • ***
  • Posts: 208
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #10 on: July 11, 2017, 05:00:59 pm »
i am getting the message when debugging the app. please see the screen capture.
there is something similar reported in


http://lists.freepascal.org/pipermail/fpc-pascal/2014-April/041701.html


i think it is the same because they are speaking of a localhost socket.

rvk

  • Hero Member
  • *****
  • Posts: 2566
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #11 on: July 11, 2017, 05:07:34 pm »
edit: molly just beat me by seconds. That's what you get for typing a whole solution  :P
Sorry. it was not mean to intrude on your conversation. I just happen to cross the subject on a recent project i worked on.
No problem at all.

I've expanded the request handler somewhat to also output success or failure to the browser so the user can see what's going on:

Code: Pascal  [Select]
  1. procedure TForm1.HandleHTTPRequest(Sender: TObject; var ARequest: TFPHTTPConnectionRequest; var AResponse: TFPHTTPConnectionResponse);
  2. var
  3.   i: integer;
  4.   match: boolean;
  5. begin
  6.   // Memo1.Clear;
  7.   Memo1.Append('------');
  8.   Memo1.Append('starting...');
  9.   Memo1.Append('request URI: ' + trim(ARequest.URI));
  10.   Memo1.Append('request URL: ' + trim(ARequest.URL));
  11.   Memo1.Append('request Queryfields: ' + trim(ARequest.QueryFields.Text));
  12.   Memo1.Append('http version: ' + ARequest.HttpVersion);
  13.   Memo1.Append('protocol version: ' + ARequest.ProtocolVersion);
  14.  
  15.   if ARequest.QueryFields.Count > 0 then
  16.   begin
  17.     setlength(_HTTPRequestInfo, ARequest.QueryFields.Count);
  18.     for i := 0 to ARequest.QueryFields.Count - 1 do
  19.     begin
  20.       _HTTPRequestInfo[i].FieldName := Copy(ARequest.QueryFields[i], 1, Pos('=', ARequest.QueryFields[i]) - 1);
  21.       _HTTPRequestInfo[i].FieldValue := Copy(ARequest.QueryFields[i], Pos('=', ARequest.QueryFields[i]) + 1, length(ARequest.QueryFields[i]));
  22.     end;
  23.   end;
  24.  
  25.   _HTTPServer.Synchronize(nil, @HandleHTTPInfo);
  26.  
  27.   // here you give a response back to the browser
  28.   match := false;
  29.   for i := 0 to length(_HTTPRequestInfo) - 1 do
  30.     if _HTTPRequestInfo[i].FieldName = 'code' then match := true;
  31.  
  32.   if match then
  33.     AResponse.Content := 'Yeah.........' // Only if successful :)
  34.   else
  35.     AResponse.Content := 'Noooooo .....';
  36.  
  37. end;

Of course the AResponse.Content needs to be a complete HTML so it's a but prettier then only one line.
It might be that the server also sends the HTTP-version automatically.

tudi_x, do you still get the error when using AResponse.Content?
At what point do you get the error.
After pressing Allow or before that?

tudi_x

  • Full Member
  • ***
  • Posts: 208
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #12 on: July 11, 2017, 05:11:20 pm »
i get the error after pressing the ALLOW.
i can also see by then the redirect has taken place.

sorry there is no HTML for the user, this is just a prototype for ouath 2.
only after reaching the end of ouath i would be thinking about the user experience :).

rvk

  • Hero Member
  • *****
  • Posts: 2566
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #13 on: July 11, 2017, 05:14:54 pm »
sorry there is no HTML for the user, this is just a prototype for ouath 2.
only after reaching the end of ouath i would be thinking about the user experience :).
Well, adding the few lines I showed already gives the user some feedback. You can paste in some more HTML later on.

Does the Memo1 show the HTTP version and protocol for the request?

The link you gave talks about Windows and I'm on Windows and don't have the error.
(although my version is 1.8RC2 with FPC 3.1.1)

It looks like your browser doesn't send HTTP/1.1 or 1.0.
(maybe only for localhost)

You could try 127.0.0.1 as redirect instead of localhost?
« Last Edit: July 11, 2017, 05:18:02 pm by rvk »

tudi_x

  • Full Member
  • ***
  • Posts: 208
Re: Ouath 2 with LinkedIn and TFPHTTPServer
« Reply #14 on: July 11, 2017, 05:23:08 pm »
i am in 1.6.4. the contents of my memo is below.
i am using Firefox Developer Edition as browser.

Code: Pascal  [Select]
  1. ------
  2. starting...
  3. request URI: /?code=AQT1TPhn7tWtHGVTx-pnoomAEL4uFYY0B4k7c70BqRzBKrmrsChEeG2yjUuRCQOtkYOwxcBjjI0YXO0s1xXOWJJLvceo1XxlQTZpgxgf7mpN2mH1Zcg&state=T1499797252
  4. request URL: /?code=AQT1TPhn7tWtHGVTx-pnoomAEL4uFYY0B4k7c70BqRzBKrmrsChEeG2yjUuRCQOtkYOwxcBjjI0YXO0s1xXOWJJLvceo1XxlQTZpgxgf7mpN2mH1Zcg&state=T1499797252
  5. request Queryfields: code=AQT1TPhn7tWtHGVTx-pnoomAEL4uFYY0B4k7c70BqRzBKrmrsChEeG2yjUuRCQOtkYOwxcBjjI0YXO0s1xXOWJJLvceo1XxlQTZpgxgf7mpN2mH1Zcg
  6. state=T1499797252
  7. http version: 1.1
  8. protocol version: 1.1
  9. field name:state value:T1499797252
  10. ------
  11. starting...
  12. request URI: /favicon.ico
  13. request URL: /favicon.ico
  14. request Queryfields:
  15. http version: 1.1
  16. protocol version: 1.1
  17.  

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus