mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-13 13:03:01 +00:00
Merge pull request #1828 from rkdarst/authenthicator_blacklist
Authenthicator blacklist
This commit is contained in:
@@ -88,6 +88,20 @@ class Authenticator(LoggingConfigurable):
|
|||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).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')
|
@observe('whitelist')
|
||||||
def _check_whitelist(self, change):
|
def _check_whitelist(self, change):
|
||||||
short_names = [name for name in change['new'] if len(name) <= 1]
|
short_names = [name for name in change['new'] if len(name) <= 1]
|
||||||
@@ -205,6 +219,21 @@ class Authenticator(LoggingConfigurable):
|
|||||||
return True
|
return True
|
||||||
return username in self.whitelist
|
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):
|
async def get_authenticated_user(self, handler, data):
|
||||||
"""Authenticate the user who is attempting to log in
|
"""Authenticate the user who is attempting to log in
|
||||||
|
|
||||||
@@ -244,7 +273,14 @@ class Authenticator(LoggingConfigurable):
|
|||||||
self.log.warning("Disallowing invalid username %r.", username)
|
self.log.warning("Disallowing invalid username %r.", username)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
blacklist_pass = await maybe_future(self.check_blacklist(username))
|
||||||
whitelist_pass = await maybe_future(self.check_whitelist(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:
|
if whitelist_pass:
|
||||||
return authenticated
|
return authenticated
|
||||||
else:
|
else:
|
||||||
|
@@ -103,6 +103,65 @@ def test_pam_auth_group_whitelist():
|
|||||||
assert authorized is None
|
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
|
@pytest.mark.gen_test
|
||||||
def test_pam_auth_no_such_group():
|
def test_pam_auth_no_such_group():
|
||||||
authenticator = MockPAMAuthenticator(group_whitelist={'nosuchcrazygroup'})
|
authenticator = MockPAMAuthenticator(group_whitelist={'nosuchcrazygroup'})
|
||||||
|
Reference in New Issue
Block a user