mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Get rid of gnupg, just store a hash of the id:token to reauthenticate later using session info
This commit is contained in:
parent
3822496622
commit
7482f052f6
5 changed files with 60 additions and 60 deletions
|
@ -52,7 +52,6 @@ Requirements
|
|||
|
||||
* Python 2.7
|
||||
* python-bottle (>= 0.10)
|
||||
* python-gnupg (>= 0.3)
|
||||
* python-ldap (>= 2.4)
|
||||
* PyYAML
|
||||
|
||||
|
|
1
debian/control
vendored
1
debian/control
vendored
|
@ -13,7 +13,6 @@ Depends: ${misc:Depends}, ${python:Depends},
|
|||
python-ldap,
|
||||
python-yaml,
|
||||
python-bottle (>= 0.12),
|
||||
python-gnupg,
|
||||
python-gevent-websocket,
|
||||
python-argcomplete,
|
||||
python-toml,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
sphinx
|
||||
gnupg
|
||||
mock
|
||||
pyyaml
|
||||
toml
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"instance_already_running": "An instance is already running",
|
||||
"invalid_argument": "Invalid argument '{argument}': {error}",
|
||||
"invalid_password": "Invalid password",
|
||||
"invalid_token": "Invalid token - please authenticate",
|
||||
"invalid_usage": "Invalid usage, pass --help to see help",
|
||||
"ldap_attribute_already_exists": "Attribute '{attribute}' already exists with value '{value}'",
|
||||
"ldap_operation_error": "An error occurred during LDAP operation",
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import gnupg
|
||||
import logging
|
||||
import hashlib
|
||||
|
||||
from moulinette.cache import open_cachefile, get_cachedir
|
||||
from moulinette.core import MoulinetteError
|
||||
|
@ -88,24 +88,11 @@ class BaseAuthenticator(object):
|
|||
"""
|
||||
if self.is_authenticated:
|
||||
return self
|
||||
store_session = True if password and token else False
|
||||
|
||||
if token:
|
||||
try:
|
||||
# Extract id and actual token
|
||||
s_id, s_token = token
|
||||
except TypeError as e:
|
||||
logger.error("unable to extract token parts from '%s' because '%s'", token, e)
|
||||
if password is None:
|
||||
raise MoulinetteError('error_see_log')
|
||||
|
||||
logger.info("session will not be stored")
|
||||
store_session = False
|
||||
else:
|
||||
if password is None:
|
||||
# Retrieve session
|
||||
password = self._retrieve_session(s_id, s_token)
|
||||
|
||||
#
|
||||
# Authenticate using the password
|
||||
#
|
||||
if password:
|
||||
try:
|
||||
# Attempt to authenticate
|
||||
self.authenticate(password)
|
||||
|
@ -116,10 +103,11 @@ class BaseAuthenticator(object):
|
|||
self.name, self.vendor, e)
|
||||
raise MoulinetteError('unable_authenticate')
|
||||
|
||||
# Store session
|
||||
if store_session:
|
||||
# Store session for later using the provided (new) token if any
|
||||
if token:
|
||||
try:
|
||||
self._store_session(s_id, s_token, password)
|
||||
s_id, s_token = token
|
||||
self._store_session(s_id, s_token)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
@ -127,6 +115,27 @@ class BaseAuthenticator(object):
|
|||
else:
|
||||
logger.debug("session has been stored")
|
||||
|
||||
#
|
||||
# Authenticate using the token provided
|
||||
#
|
||||
elif token:
|
||||
try:
|
||||
s_id, s_token = token
|
||||
# Attempt to authenticate
|
||||
self._authenticate_session(s_id, s_token)
|
||||
except MoulinetteError:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception("authentication (name: '%s', vendor: '%s') fails because '%s'",
|
||||
self.name, self.vendor, e)
|
||||
raise MoulinetteError('unable_authenticate')
|
||||
|
||||
#
|
||||
# No credentials given, can't authenticate
|
||||
#
|
||||
else:
|
||||
raise MoulinetteError('unable_authenticate')
|
||||
|
||||
return self
|
||||
|
||||
# Private methods
|
||||
|
@ -136,36 +145,31 @@ class BaseAuthenticator(object):
|
|||
return open_cachefile('%s.asc' % session_id, mode,
|
||||
subdir='session/%s' % self.name)
|
||||
|
||||
def _store_session(self, session_id, session_token, password):
|
||||
"""Store a session and its associated password"""
|
||||
gpg = gnupg.GPG()
|
||||
gpg.encoding = 'utf-8'
|
||||
|
||||
# Encrypt the password using the session token
|
||||
s = str(gpg.encrypt(password, None, symmetric=True, passphrase=session_token))
|
||||
assert len(s), "For some reason GPG can't perform encryption, maybe check /root/.gnupg/gpg.conf or re-run with gpg = gnupg.GPG(verbose=True) ?"
|
||||
def _store_session(self, session_id, session_token):
|
||||
"""Store a session to be able to use it later to reauthenticate"""
|
||||
|
||||
# We store a hash of the session_id and the session_token (the token is assumed to be secret)
|
||||
to_hash = "{id}:{token}".format(id=session_id, token=session_token)
|
||||
hash_ = hashlib.sha256sum(to_hash).hexdigest()
|
||||
with self._open_sessionfile(session_id, 'w') as f:
|
||||
f.write(s)
|
||||
f.write(hash_)
|
||||
|
||||
def _retrieve_session(self, session_id, session_token):
|
||||
def _authenticate_session(self, session_id, session_token):
|
||||
"""Retrieve a session and return its associated password"""
|
||||
try:
|
||||
with self._open_sessionfile(session_id, 'r') as f:
|
||||
enc_pwd = f.read()
|
||||
stored_hash = f.read()
|
||||
except IOError as e:
|
||||
logger.debug("unable to retrieve session", exc_info=1)
|
||||
raise MoulinetteError('unable_retrieve_session', exception=e)
|
||||
else:
|
||||
gpg = gnupg.GPG()
|
||||
gpg.encoding = 'utf-8'
|
||||
to_hash = "{id}:{token}".format(id=session_id, token=session_token)
|
||||
hash_ = hashlib.sha256sum(to_hash).hexdigest()
|
||||
|
||||
decrypted = gpg.decrypt(enc_pwd, passphrase=session_token)
|
||||
if decrypted.ok is not True:
|
||||
error_message = "unable to decrypt password for the session: %s" % decrypted.status
|
||||
logger.error(error_message)
|
||||
raise MoulinetteError('unable_retrieve_session', exception=error_message)
|
||||
return decrypted.data
|
||||
if hash_ != stored_hash:
|
||||
raise MoulinetteError('invalid_token')
|
||||
else:
|
||||
return
|
||||
|
||||
def _clean_session(self, session_id):
|
||||
"""Clean a session cache
|
||||
|
@ -181,5 +185,3 @@ class BaseAuthenticator(object):
|
|||
os.remove(os.path.join(sessiondir, self.name, '%s.asc' % session_id))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue