Is there any support of client authentication on websocket connections?
Setting up ssl-websocket/https servers in Go is working fine, but is
there a way to enable client authentication, too? As far as i have seen
TLS does support client authentication.
In my use case, clients (or their certificates) could be added to the
server manually, so there would no need for a special first-time
authentication.
I would like to avoid a self-constructed client authentication and use
existing authentication schemes.
bye
Norbert
Hi Norbert,
As-is, there are no convenience methods in package http for enabling
TLS client auth. You can do it fairly easily yourself, though.
1. Set up an appropriate tls.Config (and set AuthenticateClient = true)
2. Create a tls listener with tls.Listen("tcp", ":443", &cfg)
3. You should probably create a special http ClientAuthMuxer that
checks the TLS (a tls.ConnectionState) field of incoming http.Requests
for an accepted certificate and send an appropriate HTTP error code if
they're denied access. If that's too much of a hassle, you could just
do it in your regular handlers. It doesn't really matter.
4. Once you're ready to go, you can call http.Serve() on the
tls.Listener you created earlier, and all should be running.
One problem with TLS client auth is that it's host-wide, so you can't
really do things serve a /help page that doesn't require
authentication (the certificate picker will pop up if the client has
any client certificates in its local store -- not really a problem per
se, but a nuisance for the user, definitely) and serve an /admin page
that does. That may or may not be relevant for your use case though.
Another problem is that the current client auth code in package tls
doesn't really allow you to "decline" a given certificate in a way
that browsers will understand (I think! I haven't actually tried --
maybe sending a 403 will make the browser pop up the certificate
picker if the server has client auth enabled...). Apache's mod_ssl
sends a handshake failure message when it declines a certificate.
Presumably this means that browsers will show a new picker in that
situation.
The reason it's important is that the current crypto/tls client auth
logic defers the decision to the application layer. (All valid client
certificates are gladly accepted). But if a browser gets an OK from
the TLS handshake, it might remember that certificate as being OK for
the whole host, and be stuck there until the user forces the browser
to forget the certificate for that host.
If the 403 approach works, good. If not, it'll probably require a
hook into the crypto/tls's handshake (or perhaps just a list of
accepted client certs in tls.Config).
WRT WebSockets, I don't know. I'd imagine WebSockets would just use
the remembered certificate for the host (maybe pop up the picker?)...
If certificate authentication works for WebSockets at all, all you
should need to do is to register the WebSocket handler like you would
if you weren't using client auth.
Mikkel
> As-is, there are no convenience methods in package http for enabling
> TLS client auth. You can do it fairly easily yourself, though.
Oh, what a detailed description, i'm going to look at it.
Thank you very much!
Norbert
> 3. You should probably create a special http ClientAuthMuxer that
> checks the TLS (a tls.ConnectionState) field of incoming http.Requests
> for an accepted certificate and send an appropriate HTTP error code if
> they're denied access.
Just one more question, though it's not Go-related:
Do you have an idea how to verify the client's certificate? The host
name of the client is usually unknown to the server, so he has no chance
to compare the name in the certificate with the client host name.. or am
i missing something?!
Norbert