Hi,
Based on the above solution, I have been working at creating a complete solution for both App and UI access through a reverse nginx proxy and trying to “limit” access by associating a password per sitemap, plus a master user having access to all sitemaps.
Here is the result:
nginx configuration file in reverse proxy setup giving access to basicui and App only, all other interfaces disabled:
server {
listen 80;
server_name myserver.dynu.net;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name myserver.dynu.net;
ssl_certificate /etc/letsencrypt/live/myserver.dynu.net/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/myserver.dynu.net/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
access_log /var/log/nginx/oh_ssl.access.log;
error_log /var/log/nginx/oh_ssl.error.log;
auth_basic "Sitemap";
auth_basic_user_file /etc/nginx/ohpass;
# Disable unwanted UIs
location ~ /(habpanel|classicui|paperui|doc|habmin) {
return 403;
}
# Redirect to expected UIs (need to do it in two steps to process auth_basic before the return 302
# authentified user is then used as the sitemap name
location = / {
try_files DUMMY @return302;
}
location @return302 {
return 302 /basicui/app?sitemap=$remote_user;
}
# User management at sitemap level -> strip openhab json file through filter script (see below)
location = /rest/sitemaps {
proxy_set_header X-Forwarded-Host $http_host;
proxy_pass http://127.0.0.1/cgi-bin/filter?user=$remote_user;
}
# Proxying the request to OpenHab
location / {
# Double test to limit access to the right UI and the right sitemap
if ($uri = "/basicui/app") {
set $test "${test}A";
}
if ($arg_sitemap != $remote_user) {
set $test "${test}B";
}
if ($remote_user = "master") {
set $test "";
}
if ($test = AB) {
return 403;
}
# Proxying the request
proxy_pass http://192.168.4.4:8083/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
#proxy_set_header Connection "";
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
# OpenHab authentication (base64 of user:password)
#proxy_set_header Authorization "Basic ZWxzYTpteWVsc2FwcHAK";
proxy_intercept_errors on;
}
}
The file /etc/nginx/ohpass contains the couple sitemaps/password, created through:
htpasswd -c /etc/nginx/ohpass master
htpasswd /etc/nginx/ohpass sitemap1
htpasswd /etc/nginx/ohpass sitemap2
...
sitemap1, sitemap2 are the filename of the different sitemaps (without the extension).
As the equivalent of mod_ext_filter is not available on nginx, the simplest solution I found was to call a script through the cgi-bin interface. Here is the corresponding filter script:
#!/bin/sh
eval $(echo "$QUERY_STRING"|awk -F'&' '{for(i=1;i<=NF;i++){print $i}}') # import the GET variables
read QUERY_STRING
eval $(echo "$QUERY_STRING"|awk -F'&' '{for(i=1;i<=NF;i++){print $i}}') # import the POST variables
if [ "$user" = "master" ]; then
exp="."
else
exp="[.[]|select(.name==\"$user\")]"
fi
echo Content-type: application/json
echo
curl --header "X-Forwarded-Host: $HTTP_X_FORWARDED_HOST" -s http://localhost:8083/rest/sitemaps | /usr/bin/jq -c "$exp"
The script is conceptually very similar to the one from Daniel, adding the exception of the master user having access to all sitemaps.
Once this is set-up, basicui is directly accessible through http://myserver.dynu.net (redirected automatically to SSL access and the full UI URL). User is prompted for a sitemap name and a password, and then get access to the UI. The same URL/sitemap name/password can be used in the App with the same limitations (ie either user is master and sees all, or user is sitemap name and limited to that given sitemap).
I have been testing that setup for some time and found it so far quite safe, with a clear separation by user and no unauthorized access to restricted sitemaps (I have for instance created a specific sitemap for my kids so that they can open the portal and switch on/off the alarm, but don’t want them to have access to the watering system or other critical automation at home).
I hope this will help anyone willing to set up access control to his/her OpenHab installation.