{"id":1654,"date":"2017-09-06T13:31:17","date_gmt":"2017-09-06T11:31:17","guid":{"rendered":"https:\/\/blog.zitnik.si\/?p=1654"},"modified":"2017-09-06T13:35:36","modified_gmt":"2017-09-06T11:35:36","slug":"apache-and-forwarding-a-client-certificate-id-to-websocket","status":"publish","type":"post","link":"https:\/\/blog.zitnik.si\/?p=1654","title":{"rendered":"Apache and forwarding a client certificate Id to WebSocket"},"content":{"rendered":"<p>Recently I came across a problem of forwarding a certificate Id to backend service for the authentication purposes. I also do not want to handle SSL at services. <\/p>\n<p>Let&#8217;s say I have a server setup as follows: There is an Angular website on port 4200 and REST\/Websocket services on port 3000. REST services are accessible over endpoint <code>\/kumuluz<\/code> and Websocket connections via \/v1\/devices. As a common facade to access these services I set up Apache as a reverse proxy as in an example configuration below.<\/p>\n<p>To extract a field from a client certificate (e.g. CN in my case) and forward request to a backend REST server with an additional header field is not a problem. I just extract property <code>%{SSL_CLIENT_S_DN_CN}s<\/code> and set a header field <code>clientId<\/code>.<\/p>\n<p>The problem comes, when you would like to do the same for the Websocket connections &#8211; you cannot set header for these type of connections. But you can do a workaround (the point of this post): Tell clients to connect to the endpoint <code>\/v1\/devices\/CLIENT_ID<\/code> and then check if the parameter matches the client id of underlying client certificate. Now you forced the client to use the correct ids in URL, which you can use for authentication as Apache forwards only requests where SSLRequire successes.<\/p>\n<pre><code language=\"apacheconf\">\r\n<VirtualHost *:80>\r\n   ServerName portal.zitnik.si\r\n   Redirect permanent \/ https:\/\/portal.zitnik.si\/\r\n<\/VirtualHost>\r\n\r\n<VirtualHost *:443>\r\n        ServerAdmin slavko@zitnik.si\r\n        ServerName portal.zitnik.si\r\n        ServerAlias portal.zitnik.si\r\n\r\n        DocumentRoot \/var\/www\r\n\r\n        ProxyPreserveHost On\r\n        ProxyRequests Off\r\n\r\n        ProxyPass \/images !\r\n        \r\n        ProxyPass \/v1\/devices ws:\/\/localhost:3000\/v1\/devices\r\n        ProxyPassReverse \/v1\/devices ws:\/\/localhost:3000\/v1\/devices\r\n\r\n        ProxyPass \/kumuluz http:\/\/localhost:3000\r\n        ProxyPassReverse \/kumuluz http:\/\/localhost:3000\r\n\r\n        ProxyPass \/ http:\/\/localhost:4200\/\r\n        ProxyPassReverse \/ http:\/\/localhost:4200\/\r\n\r\n        RedirectMatch ^\/$ https:\/\/portal.zitnik.si\r\n\r\n        SSLEngine on\r\n        SSLCertificateFile \/home\/slavkoz\/certs\/portal.zitnik.si.crt\r\n        SSLCertificateKeyFile \/home\/slavkoz\/certs\/portal.zitnik.si.key\r\n\r\n        SSLCACertificateFile \/home\/slavkoz\/certs\/CA.pem\r\n        SSLVerifyClient none\r\n        RequestHeader set clientId \"\"\r\n\r\n        <Location \/kumuluz\/software>\r\n                SSLVerifyClient require\r\n                SSLVerifyDepth 1\r\n\r\n                RequestHeader set clientId \"%{SSL_CLIENT_S_DN_CN}s\"\r\n        <\/Location>\r\n\r\n        <Location \/v1\/devices>\r\n                SSLVerifyClient require\r\n                SSLVerifyDepth 1\r\n\r\n                SetEnvIf Request_URI \"\/v1\/devices\/(.*)$\" CLIENT_ID=$1\r\n                SSLRequire       %{SSL_CLIENT_S_DN_CN}  eq %{ENV:CLIENT_ID}\r\n        <\/Location>\r\n<\/VirtualHost>\r\n<\/code><\/pre>\n<div style=\"margin-top: 0px; margin-bottom: 0px;\" class=\"sharethis-inline-share-buttons\" ><\/div>","protected":false},"excerpt":{"rendered":"<p>Recently I came across a problem of forwarding a certificate Id to backend service for the authentication purposes. I also do not want to handle SSL at services. Let&#8217;s say I have a server setup as follows: There is an Angular website on port 4200 and REST\/Websocket services on port&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/blog.zitnik.si\/?p=1654\">Continue reading<span class=\"screen-reader-text\">Apache and forwarding a client certificate Id to WebSocket<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":1661,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-1654","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-computer-engineering","entry"],"_links":{"self":[{"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/posts\/1654","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1654"}],"version-history":[{"count":7,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/posts\/1654\/revisions"}],"predecessor-version":[{"id":1664,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/posts\/1654\/revisions\/1664"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=\/wp\/v2\/media\/1661"}],"wp:attachment":[{"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1654"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1654"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.zitnik.si\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1654"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}