[Libwebsockets] Libwebsocket with Keycloak Integration

Andy Green andy at warmcat.com
Thu Apr 11 11:41:07 CEST 2019



On 11/04/2019 15:58, Marcel Isenbügel wrote:
> Yes im implementing a client and a server.
> 
> The clients add a token. It is now working when I add  an authorization token in the header
> 
> 	";
> 	 	if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_AUTHORIZATION,
> 	 			(const unsigned char*)secret.c_str(), secret.length(), p, end))
> 	 		return -1;	
> 
> the custom name didn’t work but the Authorization tag is fine.
> 
> 
> The server checks the token
> 
> The only thing I didn't know on the server side
> LWS_CALLBACK_HTTP_CONFIRM_UPGRADE when I return 1. The Http Status is 502. There would be nice a http status of 401.
> 
> Then everything is well prepared for my use.

I'm glad you're working, but I can't see anything in lws returning a 502.

			n = user_callback_handle_rxflow(wsi->protocol->callback,
					wsi, LWS_CALLBACK_HTTP_CONFIRM_UPGRADE,
					wsi->user_space, (char *)up, 0);

			/* just hang up? */

			if (n < 0)
				goto bail_nuke_ah;

			/* callback returned headers already, do t_c? */

			if (n > 0) {
				if (lws_http_transaction_completed(wsi))
					goto bail_nuke_ah;

				/* continue on */

				return 0;
			}

It takes the 1 to mean you already sent the headers you wanted for the 
failure case in your callback handler.

-Andy

> Thanks for your help :)
> 
> 
> Marcel
> 
> 
> -----Ursprüngliche Nachricht-----
> Von: Andy Green [mailto:andy at warmcat.com]
> Gesendet: Mittwoch, 10. April 2019 18:43
> An: Marcel Isenbügel; libwebsockets at ml.libwebsockets.org
> Betreff: Re: AW: [Libwebsockets] Libwebsocket with Keycloak Integration
> 
> 
> 
> On 10/04/2019 23:10, Marcel Isenbügel wrote:
>> Thank you :)
>>
>> You helped me a little bit. First I printed all reason numbers which will be called on an ws connection.
>>
>> Then I saw I can use:
>>
>> LWS_CALLBACK_HTTP_CONFIRM_UPGRADE
> 
> Right... but it doesn't help if you need to return to the event loop
> before you can judge if he is authorized or not.  If you can tell just
> from the sent headers, that's great.
> 
>> LWS_CALLBACK_CHECK_ACCESS_RIGHTS is not called on a normal connection.
>>
>> Then I printed everything from the header and can check something and decline the connection if something wrong. I don’t know if I can set the http response code to 401 instead of 502. But that is not so important.
>>
>>
>> One thing is that the client should send a custom header. I looked on the examples for this and added to the ws client
>>
>> 	case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
>>           {
>>                   std::cout << "Append Handshake Header" << std::endl;
>> 		unsigned char **p = (unsigned char **)in, *end = (*p) + len;
>>
>>                    if (lws_add_http_header_by_name(wsi,
>>                                    (const unsigned char *)"dnt",
>>                                    (const unsigned char *)"1", 1, p, end))
>>                            return -1;
>> 		
>>                   break;
>>           }
>>
>> But on the server I didn’t see that header flag dnt. Not on the HTTP Connection and also not in the upgraded connection.
>>
>> Is this this to late ? I want use this custom header in LWS_CALLBACK_HTTP_CONFIRM_UPGRADE to check something.
> 
> The code you pasted is from minimal-client-http-custom-headers, which is
> good... you pasted the original case as well for
> CLIENT_APPEND_HANDSHAKE_HEADERS which is also good.
> 
> But I'm a bit confused we're also discussing
> LWS_CALLBACK_HTTP_CONFIRM_UPGRADE which is a server-side callback.
> 
> You mean you want to emit the header clientside using
> CLIENT_APPEND_HANDSHAKE_HEADER and also separately check for it on the
> server side?
> 
> The best thing is try the related minimal example as it is and see if it
> works for you... if there's a problem we can both look at the same thing.
> 
> Note that custom header reading only works on h1 and needs the special
> apis as shown in the LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP part of the
> same minimal example.
> 
> -Andy
> 
>> Best Regards
>>
>> Marcel
>>
>> -----Ursprüngliche Nachricht-----
>> Von: Andy Green [mailto:andy at warmcat.com]
>> Gesendet: Mittwoch, 10. April 2019 10:17
>> An: Marcel Isenbügel; libwebsockets at ml.libwebsockets.org
>> Betreff: Re: [Libwebsockets] Libwebsocket with Keycloak Integration
>>
>>
>>
>> On 10/04/2019 15:04, Marcel Isenbügel wrote:
>>> Hey everyone,
>>>
>>> I’m interested to implement an authentication system to Websockets.
>>>
>>> So they are two different ways.
>>>
>>> 1.After upgrading to ws conncetion start an authorisation
>>>
>>> 2.On the HTTP Request test the authorization
>>
>> Lws natively supports Basic Auth using the http mount stuff... URLs that
>> match the mount (so /secret/anything/etc if the mount was at /secret)
>> cause the browser to prompt the user for credentials that must exist in
>> a text file outside the served part of the filesystem.  It's "Basic" as
>> the name says, but combined with TLS, it's better than nothing.
>>
>> https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/http-server/minimal-http-server-basicauth
>>
>> The Basic Auth support also covers ws upgrades on master, you need to
>> add a pvo to the related vhost attached to the protocol name and with
>> name "basic-auth" and value "path" where "path" is the path to the
>> credentials file on the server.
>>
>> See eg
>>
>> https://libwebsockets.org/git/libwebsockets/tree/minimal-examples/ws-server/minimal-ws-server-echo/minimal-ws-server-echo.c#n29-48
>>
>> for how to add pvos.
>>
>>> So I want to implement the second way. A Bearer Token will be send in
>>> the http request. Is there a easy way to catch that token and check it
>>> against a keycloak server.
>>>
>>> I think I have to extract the http header when
>>>
>>> LWS_CALLBACK_HTTP  is called ?
>>>
>>> The Token is in the header => Authorization: Bearer <token>
>>>
>>> How can I get this token ?
>>
>> You should be able to get the headers for a non-upgrade HTTP request at
>> LWS_CALLBACK_HTTP, but it might be worth trying
>> LWS_CALLBACK_CHECK_ACCESS_RIGHTS
>>
>> 	/**< This gives the user code a chance to forbid an http access.
>> 	 * `in` points to a `struct lws_process_html_args`, which
>> 	 * describes the URL, and a bit mask describing the type of
>> 	 * authentication required.  If the callback returns nonzero,
>> 	 * the transaction ends with HTTP_STATUS_UNAUTHORIZED. */
>>
>> in this case.  You would check the Authorization: header the usual way
>> using token index WSI_TOKEN_HTTP_AUTHORIZATION with the api
>> lws_hdr_copy()
>>
>> https://libwebsockets.org/git/libwebsockets/tree/include/libwebsockets/lws-http.h#n371-386
>>
>>> On Success upgrade to ws
>>>
>>> On Error decline connection
>>>
>>> Is this a right and good way to implement this ? If someone has an
>>> example it would be nice to see how it can works.
>>
>> I'm not really clear what Keycloak is... if it's a network service
>> itself, you will have to create an onward client connection and await
>> the results before proceeding.  Lws only has the idea that you can
>> immediately tell at the callbacks if it should proceed or not, as is the
>> case with Basic Auth it either gave you valid credentials in the request
>> header already, or it didn't... it doesn't have a way atm to defer
>> judgement until later.  For ws upgrade, if you need an onward client
>> connection, atm you'd need to take the approach to accept the connection
>> but in the protocol don't do anything until the validity of the
>> credential is known from the external service, or it times out waiting.
>>
>> It probably needs a little more something in lws to support this
>> deferred credential validity testing cleanly.
>>
>> -Andy
>>
>>> Best regards
>>>
>>> Marcel
>>>
>>>
>>> _______________________________________________
>>> Libwebsockets mailing list
>>> Libwebsockets at ml.libwebsockets.org
>>> https://libwebsockets.org/mailman/listinfo/libwebsockets
>>>
>>
>>
> 
> 


More information about the Libwebsockets mailing list