Merge pull request #1828 from rkdarst/authenthicator_blacklist

Authenthicator blacklist
This commit is contained in:
Min RK
2018-04-26 17:59:44 +02:00
committed by GitHub
2 changed files with 95 additions and 0 deletions

View File

@@ -88,6 +88,20 @@ class Authenticator(LoggingConfigurable):
"""
).tag(config=True)
blacklist = Set(
help="""
Blacklist of usernames that are not allowed to log in.
Use this with supported authenticators to restrict which users can not log in. This is an
additional blacklist that further restricts users, beyond whatever restrictions the
authenticator has in place.
If empty, does not perform any additional restriction.
.. versionadded: 0.9
"""
).tag(config=True)
@observe('whitelist')
def _check_whitelist(self, change):
short_names = [name for name in change['new'] if len(name) <= 1]
@@ -205,6 +219,21 @@ class Authenticator(LoggingConfigurable):
return True
return username in self.whitelist
def check_blacklist(self, username):
"""Check if a username is blocked to authenticate based on blacklist configuration
Return True if username is allowed, False otherwise.
No blacklist means any username is allowed.
Names are normalized *before* being checked against the blacklist.
.. versionadded: 0.9
"""
if not self.blacklist:
# No blacklist means any name is allowed
return True
return username not in self.blacklist
async def get_authenticated_user(self, handler, data):
"""Authenticate the user who is attempting to log in
@@ -244,7 +273,14 @@ class Authenticator(LoggingConfigurable):
self.log.warning("Disallowing invalid username %r.", username)
return
blacklist_pass = await maybe_future(self.check_blacklist(username))
whitelist_pass = await maybe_future(self.check_whitelist(username))
if blacklist_pass:
pass
else:
self.log.warning("User %r in blacklist. Stop authentication", username)
return
if whitelist_pass:
return authenticated
else:

View File

@@ -103,6 +103,65 @@ def test_pam_auth_group_whitelist():
assert authorized is None
@pytest.mark.gen_test
def test_pam_auth_blacklist():
# Null case compared to next case
authenticator = MockPAMAuthenticator()
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'wash',
'password': 'wash',
})
assert authorized['name'] == 'wash'
# Blacklist basics
authenticator = MockPAMAuthenticator(blacklist={'wash'})
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'wash',
'password': 'wash',
})
assert authorized is None
# User in both white and blacklists: default deny. Make error someday?
authenticator = MockPAMAuthenticator(blacklist={'wash'}, whitelist={'wash', 'kaylee'})
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'wash',
'password': 'wash',
})
assert authorized is None
# User not in blacklist can log in
authenticator = MockPAMAuthenticator(blacklist={'wash'}, whitelist={'wash', 'kaylee'})
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'kaylee',
'password': 'kaylee',
})
assert authorized['name'] == 'kaylee'
# User in whitelist, blacklist irrelevent
authenticator = MockPAMAuthenticator(blacklist={'mal'}, whitelist={'wash', 'kaylee'})
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'wash',
'password': 'wash',
})
assert authorized['name'] == 'wash'
# User in neither list
authenticator = MockPAMAuthenticator(blacklist={'mal'}, whitelist={'wash', 'kaylee'})
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'simon',
'password': 'simon',
})
assert authorized is None
# blacklist == {}
authenticator = MockPAMAuthenticator(blacklist=set(), whitelist={'wash', 'kaylee'})
authorized = yield authenticator.get_authenticated_user(None, {
'username': 'kaylee',
'password': 'kaylee',
})
assert authorized['name'] == 'kaylee'
@pytest.mark.gen_test
def test_pam_auth_no_such_group():
authenticator = MockPAMAuthenticator(group_whitelist={'nosuchcrazygroup'})