# -*- coding: utf-8 -*-
#
# django_pam/auth/backends.py
#
"""
Django PAM backend.
"""
__docformat__ = "restructuredtext en"
import logging
import pam as pam_base
from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.backends import ModelBackend
User = get_user_model()
log = logging.getLogger('django_pam.auth.backends')
[docs]
class PAMBackend(ModelBackend):
"""
An implementation of a PAM backend authentication module.
"""
_pam = pam_base.pam()
[docs]
def authenticate(self, request, username=None, password=None,
**extra_fields):
"""
Authenticate using PAM then get the account if it exists else create
a new account.
.. note::
The keyword arguments 'service', 'encoding', and 'resetcreds'
can also be passed and will be pulled off the 'extra_fields'
kwargs.
:param username: The users username. This is a manditory field.
:type username: str
:param password: The users password. This is a manditory field.
:type password: str
:param extra_fields: Additonal keyword options of any editable field
in the user model or arguments in the PAM
`authenticate` method.
:type extra_fields: dict
:rtype: The Django user object or `None` if it fails.
"""
UserModel = get_user_model()
user = None
service = extra_fields.pop('service', 'login')
encoding = extra_fields.pop('encoding', 'utf-8')
resetcreds = extra_fields.pop('resetcreds', True)
log.debug("request: %s, username: %s, service: %s, encoding: %s, "
"resetcreds: %s, extra_fields: %s", request, username,
service, encoding, resetcreds, extra_fields)
if self._pam.authenticate(username, password, service=service,
encoding=encoding, resetcreds=resetcreds):
try: # pragma: no cover
user = UserModel._default_manager.get_by_natural_key(
username=username)
except UserModel.DoesNotExist: # pragma: no cover
# delete "request" if exists in extra_fields
extra_fields.pop("request", None)
user = UserModel._default_manager.create_user(
username, **extra_fields)
else:
msg = ("Either the credentials are invalid or the user does not "
"have shadow permissions.")
log.error(msg)
return user
[docs]
def get_user(self, user_data):
"""
Get the user by either the ``username``, ``email``, or the ``pk``.
:param user_data: The username, email or pk.
:type user: str or int
:rtype: A Django user object.
"""
UserModel = get_user_model()
obj = None
if user_data is not None and (isinstance(user_data, int)
or user_data.isdigit()):
query = models.Q(pk=user_data)
elif isinstance(user_data, str):
query = models.Q(username=user_data) | models.Q(email=user_data)
else:
msg = _("The user argument type should be either an integer "
"(valid pk) or a string (username or email), found "
"type {}.").format(type(user_data))
log.error(msg)
raise TypeError(msg)
try:
obj = UserModel._default_manager.get(query)
except UserModel.DoesNotExist:
pass
log.debug("user_data: %s, obj: %s", user_data, obj)
return obj