add pre/post-spawn hooks for Authenticators

allows setup/cleanup to be performed by the authenticator

use this to open PAM sessions at spawn
and close them at stop,
rather than open at login and never close.
This commit is contained in:
Min RK
2015-10-14 16:07:12 +02:00
parent bd3c878c67
commit 6f2aefb990
2 changed files with 41 additions and 7 deletions

View File

@@ -58,6 +58,18 @@ class Authenticator(LoggingConfigurable):
and return None on failed authentication.
"""
def pre_spawn_start(self, user, spawner):
"""Hook called before spawning a user's server.
Can be used to do auth-related startup, e.g. opening PAM sessions.
"""
def post_spawn_stop(self, user, spawner):
"""Hook called after stopping a user container.
Can be used to do auth-related cleanup, e.g. closing PAM sessions.
"""
def check_whitelist(self, user):
"""
Return True if the whitelist is empty or user is in the whitelist.
@@ -210,9 +222,22 @@ class PAMAuthenticator(LocalAuthenticator):
return
try:
pamela.authenticate(username, data['password'], service=self.service)
pamela.open_session(username, service=self.service)
except pamela.PAMError as e:
self.log.warn("PAM Authentication failed: %s", e)
else:
return username
def pre_spawn_start(self, user, spawner):
"""Open PAM session for user"""
try:
pamela.open_session(user.name, service=self.service)
except pamela.PAMError as e:
self.log.warn("Failed to open PAM session for %s: %s", user.name, e)
def post_spawn_stop(self, user, spawner):
"""Close PAM session for user"""
try:
pamela.close_session(user.name, service=self.service)
except pamela.PAMError as e:
self.log.warn("Failed to close PAM session for %s: %s", user.name, e)

View File

@@ -363,6 +363,9 @@ class User(Base):
spawner.clear_state()
spawner.api_token = api_token
# trigger pre-spawn hook on authenticator
if (authenticator):
yield gen.maybe_future(authenticator.pre_spawn_start(self, spawner))
self.spawn_pending = True
# wait for spawner.start to return
try:
@@ -429,21 +432,27 @@ class User(Base):
and cleanup after it.
"""
self.spawn_pending = False
if self.spawner is None:
spawner = self.spawner
if spawner is None:
return
self.spawner.stop_polling()
spawner.stop_polling()
self.stop_pending = True
try:
status = yield self.spawner.poll()
status = yield spawner.poll()
if status is None:
yield self.spawner.stop()
self.spawner.clear_state()
self.state = self.spawner.get_state()
spawner.clear_state()
self.state = spawner.get_state()
self.server = None
inspect(self).session.commit()
finally:
self.stop_pending = False
# trigger post-spawner hook on authenticator
auth = spawner.authenticator
if auth:
yield gen.maybe_future(
auth.post_spawn_stop(self, spawner)
)
class APIToken(Base):
"""An API token"""