Adds HA Authentication

This commit is contained in:
Franck Nijhof 2019-03-28 22:30:19 +01:00
parent 02b8296a99
commit 07fd06720e
No known key found for this signature in database
GPG key ID: D62583BA8AB11CA3
10 changed files with 279 additions and 39 deletions

View file

@ -60,17 +60,22 @@ RUN \
build-essential=12.4ubuntu1 \
colordiff=1.0.18-1 \
git=1:2.17.1-1ubuntu0.4 \
libnginx-mod-http-lua=1.14.0-0ubuntu1.2 \
locales=2.27-3ubuntu1 \
luarocks=2.4.2+dfsg-1 \
mosquitto-clients=1.4.15-2ubuntu0.18.04.2 \
net-tools=1.60+git20161116.90da8a0-1ubuntu1 \
nginx=1.14.0-0ubuntu1.2 \
nmap=7.60-1ubuntu5 \
openssh-client=1:7.6p1-4ubuntu0.3 \
openssl=1.1.0g-2ubuntu4.3 \
python3=3.6.7-1~18.04 \
python3-dev=3.6.7-1~18.04 \
python3=3.6.7-1~18.04 \
wget=1.19.4-1ubuntu2.1 \
zsh=5.4.2-3ubuntu3.1 \
\
&& luarocks install lua-resty-http 0.13-0 \
\
&& curl https://bootstrap.pypa.io/get-pip.py | python3 \
\
&& locale-gen en_US.UTF-8 \
@ -106,8 +111,9 @@ RUN \
&& pip3 install --no-cache-dir -r /tmp/requirements.txt \
\
&& apt-get purge -y --auto-remove \
python3-dev \
build-essential \
luarocks \
python3-dev \
\
&& find /usr/local/lib/python3.6/ -type d -name tests -depth -exec rm -rf {} \; \
&& find /usr/local/lib/python3.6/ -type d -name test -depth -exec rm -rf {} \; \

View file

@ -11,6 +11,7 @@
],
"boot": "auto",
"hassio_api": true,
"auth_api": true,
"hassio_role": "manager",
"homeassistant_api": true,
"host_network": false,
@ -26,7 +27,6 @@
"backup:rw"
],
"options": {
"password": "",
"ssl": true,
"certfile": "fullchain.pem",
"keyfile": "privkey.pem",
@ -35,7 +35,6 @@
},
"schema": {
"log_level": "match(^(trace|debug|info|notice|warning|error|fatal)$)?",
"password": "str",
"ssl": "bool",
"certfile": "str",
"keyfile": "str",

View file

@ -4,24 +4,3 @@
# This files check if all user configuration requirements are met
# ==============================================================================
bashio::config.require.ssl
if ! bashio::config.true 'leave_front_door_open'; then
if ! bashio::config.true 'i_like_to_be_pwned'; then
bashio::config.require.safe_password
else
bashio::config.require.password
fi
fi
if bashio::config.true 'leave_front_door_open' \
&& bashio::config.true 'ssl';
then
bashio::log.fatal
bashio::log.fatal "Due to a bug in code-server (which this add-on uses),"
bashio::log.fatal "it is impossible to disable authentication while"
bashio::log.fatal "using SSL."
bashio::log.fatal
bashio::log.fatal "Please enable authentication and set a password."
bashio::log.fatal
bashio::exit.nok
fi

View file

@ -0,0 +1,17 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: Visual Studio Code
# Configures NGINX for use with code-server
# ==============================================================================
declare certfile
declare keyfile
mkdir -p /var/log/nginx
if bashio::config.true 'ssl'; then
certfile=$(bashio::config 'certfile')
keyfile=$(bashio::config 'keyfile')
sed -i "s/%%certfile%%/${certfile}/g" /etc/nginx/nginx-ssl.conf
sed -i "s/%%keyfile%%/${keyfile}/g" /etc/nginx/nginx-ssl.conf
fi

View file

@ -0,0 +1,83 @@
local http = require "resty.http"
local auths = ngx.shared.auths
function authenticate()
--- Test Authentication header is set and with a value
local header = ngx.req.get_headers()['Authorization']
if header == nil or header:find(" ") == nil then
return false
end
local divider = header:find(' ')
if header:sub(0, divider-1) ~= 'Basic' then
return false
end
local auth = ngx.decode_base64(header:sub(divider+1))
if auth == nil or auth:find(':') == nil then
return false
end
divider = auth:find(':')
local username = auth:sub(0, divider-1)
local password = auth:sub(divider+1)
--- Check if authentication is cached
if auths:get(username) == password then
ngx.log(ngx.DEBUG, "Authenticated user against Home Assistant (cache).")
return true
end
--- HTTP request against Hassio API
local httpc = http.new()
local res, err = httpc:request_uri("http://hassio/auth", {
method = "POST",
body = ngx.encode_args({["username"]=username, ["password"]=password}),
headers = {
["Content-Type"] = "application/x-www-form-urlencoded",
["X-HASSIO-KEY"] = os.getenv("HASSIO_TOKEN"),
},
keepalive_timeout = 60,
keepalive_pool = 10
})
--- Error during API request
if err then
ngx.log(ngx.WARN, "Error during Hassio user authentication.", err)
return false
end
--- No result? Something went wrong...
if not res then
ngx.log(ngx.WARN, "Error during Hassio user authentication.")
return false
end
--- Valid response, the username/password is valid
if res.status == 200 then
ngx.log(ngx.INFO, "Authenticated user against Home Assistant.")
auths:set(username, password, 60)
return true
end
--- Whatever the response is, it is invalid
ngx.log(ngx.WARN, "Authentication against Home Assistant failed!")
return false
end
-- Only authenticate if its not disabled
if not os.getenv('DISABLE_HA_AUTHENTICATION') then
--- Try to authenticate against HA
local authenticated = authenticate()
--- If authentication failed, throw a basic auth
if not authenticated then
ngx.header.content_type = 'text/plain'
ngx.header.www_authenticate = 'Basic realm="Home Assistant"'
ngx.status = ngx.HTTP_UNAUTHORIZED
ngx.say('401 Access Denied')
ngx.exit(ngx.HTTP_UNAUTHORIZED)
end
end

View file

@ -0,0 +1,71 @@
worker_processes 1;
pid /var/run/nginx.pid;
error_log stderr;
env HASSIO_TOKEN;
env DISABLE_HA_AUTHENTICATION;
load_module "/usr/lib/nginx/modules/ndk_http_module.so";
load_module "/usr/lib/nginx/modules/ngx_http_lua_module.so";
events {
worker_connections 1024;
}
http {
access_log stdout;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
lua_shared_dict auths 16k;
resolver 127.0.0.11;
upstream code {
ip_hash;
server 127.0.0.1:8443;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name hassio.local;
listen 1337 default_server ssl;
root /dev/null;
ssl_certificate /ssl/%%certfile%%;
ssl_certificate_key /ssl/%%keyfile%%;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA;
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
location / {
access_by_lua_file /etc/nginx/ha-auth.lua;
proxy_redirect off;
proxy_pass http://code;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Authorization "";
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_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
}
}
}

View file

@ -0,0 +1,57 @@
worker_processes 1;
pid /var/run/nginx.pid;
error_log stderr;
env HASSIO_TOKEN;
env DISABLE_HA_AUTHENTICATION;
load_module "/usr/lib/nginx/modules/ndk_http_module.so";
load_module "/usr/lib/nginx/modules/ngx_http_lua_module.so";
events {
worker_connections 1024;
}
http {
access_log stdout;
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
lua_shared_dict auths 16k;
resolver 127.0.0.11;
upstream code {
ip_hash;
server 127.0.0.1:8443;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
server_name hassio.local;
listen 1337 default_server;
root /dev/null;
location / {
access_by_lua_file /etc/nginx/ha-auth.lua;
proxy_redirect off;
proxy_pass http://code;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Authorization "";
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_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
}

View file

@ -7,22 +7,13 @@ declare -a options
bashio::log.info 'Starting the code server...'
# Non-interactive
options+=(--port 1337)
options+=(--port 8443)
options+=(--data-dir "/data/vscode")
options+=(--host 127.0.0.1)
options+=(--allow-http)
if bashio::config.false 'ssl'; then
options+=(--allow-http)
else
options+=(--cert "/ssl/$(bashio::config 'certfile')")
options+=(--cert-key "/ssl/$(bashio::config 'keyfile')")
fi
if ! bashio::config.has_value 'password'; then
options+=(--no-auth)
else
options+=(--password "$(bashio::config 'password')")
fi
# Disable code authentication, we use HA authentication
options+=(--no-auth)
# Export env variables for the Home Assistant extension
export HASS_SERVER="http://hassio/homeassistant"

View file

@ -0,0 +1,9 @@
#!/usr/bin/execlineb -S0
# ==============================================================================
# Community Hass.io Add-ons: Visual Studio Code
# Take down the S6 supervision tree when Nginx fails
# ==============================================================================
if -n { s6-test $# -ne 0 }
if -n { s6-test ${1} -eq 256 }
s6-svscanctl -t /var/run/s6/services

View file

@ -0,0 +1,28 @@
#!/usr/bin/with-contenv bashio
# ==============================================================================
# Community Hass.io Add-ons: Visual Studio Code
# Runs the Nginx daemon
# ==============================================================================
declare -a options
# Wait for code-server to become available
s6-svwait -u -t 5000 /var/run/s6/services/code
timeout 15 \
bash -c \
'until echo > /dev/tcp/localhost/8443 ; do sleep 0.5; done' \
> /dev/null 2>&1
bashio::log.info "Starting NGinx..."
# Disable HA Authentication if front door is open
if bashio::config.true 'leave_front_door_open'; then
export DISABLE_HA_AUTHENTICATION=true
fi
options+=(-g "daemon off;")
if bashio::config.true 'ssl'; then
options+=(-c /etc/nginx/nginx-ssl.conf)
fi
exec nginx "${options[@]}"