mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Accept login from approved ips without password (#3427)
This commit is contained in:
parent
2c43d6718b
commit
11c07440fe
@ -74,7 +74,8 @@ def setup(hass, yaml_config):
|
|||||||
api_password=None,
|
api_password=None,
|
||||||
ssl_certificate=None,
|
ssl_certificate=None,
|
||||||
ssl_key=None,
|
ssl_key=None,
|
||||||
cors_origins=[]
|
cors_origins=[],
|
||||||
|
approved_ips=[]
|
||||||
)
|
)
|
||||||
|
|
||||||
server.register_view(DescriptionXmlView(hass, config))
|
server.register_view(DescriptionXmlView(hass, config))
|
||||||
|
@ -28,6 +28,7 @@ DOMAIN = 'http'
|
|||||||
REQUIREMENTS = ('cherrypy==8.1.0', 'static3==0.7.0', 'Werkzeug==0.11.11')
|
REQUIREMENTS = ('cherrypy==8.1.0', 'static3==0.7.0', 'Werkzeug==0.11.11')
|
||||||
|
|
||||||
CONF_API_PASSWORD = 'api_password'
|
CONF_API_PASSWORD = 'api_password'
|
||||||
|
CONF_APPROVED_IPS = 'approved_ips'
|
||||||
CONF_SERVER_HOST = 'server_host'
|
CONF_SERVER_HOST = 'server_host'
|
||||||
CONF_SERVER_PORT = 'server_port'
|
CONF_SERVER_PORT = 'server_port'
|
||||||
CONF_DEVELOPMENT = 'development'
|
CONF_DEVELOPMENT = 'development'
|
||||||
@ -71,7 +72,8 @@ CONFIG_SCHEMA = vol.Schema({
|
|||||||
vol.Optional(CONF_DEVELOPMENT): cv.string,
|
vol.Optional(CONF_DEVELOPMENT): cv.string,
|
||||||
vol.Optional(CONF_SSL_CERTIFICATE): cv.isfile,
|
vol.Optional(CONF_SSL_CERTIFICATE): cv.isfile,
|
||||||
vol.Optional(CONF_SSL_KEY): cv.isfile,
|
vol.Optional(CONF_SSL_KEY): cv.isfile,
|
||||||
vol.Optional(CONF_CORS_ORIGINS): cv.ensure_list
|
vol.Optional(CONF_CORS_ORIGINS): vol.All(cv.ensure_list, [cv.string]),
|
||||||
|
vol.Optional(CONF_APPROVED_IPS): vol.All(cv.ensure_list, [cv.string])
|
||||||
}),
|
}),
|
||||||
}, extra=vol.ALLOW_EXTRA)
|
}, extra=vol.ALLOW_EXTRA)
|
||||||
|
|
||||||
@ -108,6 +110,7 @@ def setup(hass, config):
|
|||||||
ssl_certificate = conf.get(CONF_SSL_CERTIFICATE)
|
ssl_certificate = conf.get(CONF_SSL_CERTIFICATE)
|
||||||
ssl_key = conf.get(CONF_SSL_KEY)
|
ssl_key = conf.get(CONF_SSL_KEY)
|
||||||
cors_origins = conf.get(CONF_CORS_ORIGINS, [])
|
cors_origins = conf.get(CONF_CORS_ORIGINS, [])
|
||||||
|
approved_ips = conf.get(CONF_APPROVED_IPS, [])
|
||||||
|
|
||||||
server = HomeAssistantWSGI(
|
server = HomeAssistantWSGI(
|
||||||
hass,
|
hass,
|
||||||
@ -117,7 +120,8 @@ def setup(hass, config):
|
|||||||
api_password=api_password,
|
api_password=api_password,
|
||||||
ssl_certificate=ssl_certificate,
|
ssl_certificate=ssl_certificate,
|
||||||
ssl_key=ssl_key,
|
ssl_key=ssl_key,
|
||||||
cors_origins=cors_origins
|
cors_origins=cors_origins,
|
||||||
|
approved_ips=approved_ips
|
||||||
)
|
)
|
||||||
|
|
||||||
def start_wsgi_server(event):
|
def start_wsgi_server(event):
|
||||||
@ -249,7 +253,8 @@ class HomeAssistantWSGI(object):
|
|||||||
# pylint: disable=too-many-arguments
|
# pylint: disable=too-many-arguments
|
||||||
|
|
||||||
def __init__(self, hass, development, api_password, ssl_certificate,
|
def __init__(self, hass, development, api_password, ssl_certificate,
|
||||||
ssl_key, server_host, server_port, cors_origins):
|
ssl_key, server_host, server_port, cors_origins,
|
||||||
|
approved_ips):
|
||||||
"""Initilalize the WSGI Home Assistant server."""
|
"""Initilalize the WSGI Home Assistant server."""
|
||||||
from werkzeug.wrappers import Response
|
from werkzeug.wrappers import Response
|
||||||
|
|
||||||
@ -268,6 +273,7 @@ class HomeAssistantWSGI(object):
|
|||||||
self.server_host = server_host
|
self.server_host = server_host
|
||||||
self.server_port = server_port
|
self.server_port = server_port
|
||||||
self.cors_origins = cors_origins
|
self.cors_origins = cors_origins
|
||||||
|
self.approved_ips = approved_ips
|
||||||
self.event_forwarder = None
|
self.event_forwarder = None
|
||||||
self.server = None
|
self.server = None
|
||||||
|
|
||||||
@ -468,6 +474,9 @@ class HomeAssistantView(object):
|
|||||||
if self.hass.wsgi.api_password is None:
|
if self.hass.wsgi.api_password is None:
|
||||||
authenticated = True
|
authenticated = True
|
||||||
|
|
||||||
|
elif request.remote_addr in self.hass.wsgi.approved_ips:
|
||||||
|
authenticated = True
|
||||||
|
|
||||||
elif hmac.compare_digest(request.headers.get(HTTP_HEADER_HA_AUTH, ''),
|
elif hmac.compare_digest(request.headers.get(HTTP_HEADER_HA_AUTH, ''),
|
||||||
self.hass.wsgi.api_password):
|
self.hass.wsgi.api_password):
|
||||||
# A valid auth header has been set
|
# A valid auth header has been set
|
||||||
|
@ -72,6 +72,15 @@ class TestHttp:
|
|||||||
|
|
||||||
assert req.status_code == 401
|
assert req.status_code == 401
|
||||||
|
|
||||||
|
def test_access_denied_with_ip_no_in_approved_ips(self, caplog):
|
||||||
|
"""Test access deniend with ip not in approved ip."""
|
||||||
|
hass.wsgi.approved_ips = ['134.4.56.1']
|
||||||
|
|
||||||
|
req = requests.get(_url(const.URL_API),
|
||||||
|
params={'api_password': ''})
|
||||||
|
|
||||||
|
assert req.status_code == 401
|
||||||
|
|
||||||
def test_access_with_password_in_header(self, caplog):
|
def test_access_with_password_in_header(self, caplog):
|
||||||
"""Test access with password in URL."""
|
"""Test access with password in URL."""
|
||||||
# Hide logging from requests package that we use to test logging
|
# Hide logging from requests package that we use to test logging
|
||||||
@ -112,6 +121,15 @@ class TestHttp:
|
|||||||
# assert const.URL_API in logs
|
# assert const.URL_API in logs
|
||||||
assert API_PASSWORD not in logs
|
assert API_PASSWORD not in logs
|
||||||
|
|
||||||
|
def test_access_with_ip_in_approved_ips(self, caplog):
|
||||||
|
"""Test access with approved ip."""
|
||||||
|
hass.wsgi.approved_ips = ['127.0.0.1', '134.4.56.1']
|
||||||
|
|
||||||
|
req = requests.get(_url(const.URL_API),
|
||||||
|
params={'api_password': ''})
|
||||||
|
|
||||||
|
assert req.status_code == 200
|
||||||
|
|
||||||
def test_cors_allowed_with_password_in_url(self):
|
def test_cors_allowed_with_password_in_url(self):
|
||||||
"""Test cross origin resource sharing with password in url."""
|
"""Test cross origin resource sharing with password in url."""
|
||||||
req = requests.get(_url(const.URL_API),
|
req = requests.get(_url(const.URL_API),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user