Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.

Allow passing hashed HTTP auth credentials #107

Merged
merged 1 commit into from
Jan 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ Settings in this part is immutable, you have to redeploy HAProxy service to make
|EXTRA_SSL_CERTS| |list of extra certificate names separated by comma, eg. `CERT1, CERT2, CERT3`. You also need to specify each certificate as separate env variables like so: `CERT1="<cert-body1>"`, `CERT2="<cert-body2>"`, `CERT3="<cert-body3>"`|
|HEALTH_CHECK|check|set health check on each backend route, possible value: "check inter 2000 rise 2 fall 3". See:[HAProxy:check](https://cbonte.github.io/haproxy-dconv/configuration-1.5.html#5.2-check)|
|HTTP_BASIC_AUTH| |a comma-separated list of credentials(`<user>:<pass>`) for HTTP basic auth, which applies to all the backend routes. To escape comma, use `\,`. *Attention:* DO NOT rely on this for authentication in production|
|HTTP_BASIC_AUTH_SECURE| |a comma-separated list of credentials(`<user>:<encrypted-pass>`) for HTTP basic auth, which applies to all the backend routes. To escape comma, use `\,`. See:[HAProxy:user](https://cbonte.github.io/haproxy-dconv/1.5/configuration.html#3.4-user) *Attention:* DO NOT rely on this for authentication in production|
|MAXCONN|4096|sets the maximum per-process number of concurrent connections.|
|MODE|http|mode of load balancing for HAProxy. Possible values include: `http`, `tcp`, `health`|
|MONITOR_PORT| |the port number where monitor_uri should be added to. Use together with `MONTIOR_URI`. Possible value: `80`|
Expand Down
1 change: 1 addition & 0 deletions haproxy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def parse_extra_frontend_settings(envvars):
HAPROXY_SERVICE_URI = os.getenv("DOCKERCLOUD_SERVICE_API_URI")
HEALTH_CHECK = os.getenv("HEALTH_CHECK", "check inter 2000 rise 2 fall 3")
HTTP_BASIC_AUTH = os.getenv("HTTP_BASIC_AUTH")
HTTP_BASIC_AUTH_SECURE = os.getenv("HTTP_BASIC_AUTH_SECURE")
MAXCONN = os.getenv("MAXCONN", "4096")
MODE = os.getenv("MODE", "http")
MONITOR_PORT = os.getenv("MONITOR_PORT")
Expand Down
22 changes: 14 additions & 8 deletions haproxy/haproxycfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def update(self):
cfg_dict.update(self._config_global_section())
cfg_dict.update(self._config_defaults_section())
cfg_dict.update(self._config_stats_section())
cfg_dict.update(self._config_userlist_section(HTTP_BASIC_AUTH))
cfg_dict.update(self._config_userlist_section(HTTP_BASIC_AUTH, HTTP_BASIC_AUTH_SECURE))
cfg_dict.update(self._config_tcp_sections())
cfg_dict.update(self._config_frontend_sections())
cfg_dict.update(self._config_backend_sections())
Expand Down Expand Up @@ -238,21 +238,27 @@ def _config_defaults_section():
return cfg

@staticmethod
def _config_userlist_section(basic_auth):
cfg = OrderedDict()
if basic_auth:
auth_list = re.split(r'(?<!\\),', basic_auth)
def _parse_userlist(auth_section, type):
userlist = []
if auth_section:
auth_list = re.split(r'(?<!\\),', auth_section)
userlist = []
for auth in auth_list:
if auth.strip():
terms = auth.strip().split(":", 1)
if len(terms) == 2:
username = terms[0].replace("\,", ",")
password = terms[1].replace("\,", ",")
userlist.append("user %s insecure-password %s" % (username, password))
userlist.append("user %s %s %s" % (username, type, password))
return userlist

if userlist:
cfg["userlist haproxy_userlist"] = userlist
@staticmethod
def _config_userlist_section(self, basic_auth, basic_auth_secure):
cfg = OrderedDict()
userlist = self._parse_userlist(basic_auth, "insecure-password") + \
self._parse_userlist(basic_auth_secure, "password")
if userlist:
cfg["userlist haproxy_userlist"] = userlist
return cfg

def _config_tcp_sections(self):
Expand Down
13 changes: 9 additions & 4 deletions tests/unit/test_haproxycfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,23 @@ def test_config_ssl_certs(self, mock_init, mock_save):

class HaproxyConfigUserListTestCase(unittest.TestCase):
def test_config_userlist_section(self):
self.assertEqual({}, Haproxy._config_userlist_section(""))
self.assertEqual({}, Haproxy._config_userlist_section(Haproxy, "", ""))
self.assertEqual({'userlist haproxy_userlist': ['user user password hash']},
Haproxy._config_userlist_section(Haproxy, "", "user:hash"))
self.assertEqual({'userlist haproxy_userlist': ['user user insecure-password pass']},
Haproxy._config_userlist_section("user:pass"))
Haproxy._config_userlist_section(Haproxy, "user:pass", ""))
self.assertEqual(OrderedDict([('userlist haproxy_userlist', ['user user1 insecure-password pass1',
'user user2 password hash2'])]),
Haproxy._config_userlist_section(Haproxy, "user1:pass1", "user2:hash2"))
self.assertEqual(OrderedDict([('userlist haproxy_userlist', ['user user1 insecure-password pass1',
'user user2 insecure-password pass2',
'user user3 insecure-password pass3'])]),
Haproxy._config_userlist_section("user1:pass1, user2:pass2 ,user3:pass3"))
Haproxy._config_userlist_section(Haproxy, "user1:pass1, user2:pass2 ,user3:pass3", ""))

self.assertEqual(OrderedDict([('userlist haproxy_userlist', ['user us,er1 insecure-password pass,1',
'user user2 insecure-password ',
'user insecure-password pass3'])]),
Haproxy._config_userlist_section("us\,er1:pass\,1, user2:, :pass3"))
Haproxy._config_userlist_section(Haproxy, "us\,er1:pass\,1, user2:, :pass3", ""))

@mock.patch.object(Specs, 'get_routes')
@mock.patch.object(Specs, 'get_service_aliases')
Expand Down