[Libwebsockets] Libwebsocket with Keycloak Integration

Marcel Isenbügel M.Isenbuegel at smart4energy.com
Thu Apr 11 09:58:24 CEST 2019

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.

Thanks for your help :)


-----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:

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
>          {
>                  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 

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.


> 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
> 	/**< 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