# Petale - Simple App as Key/Value Storage Interface # Copyright (C) 2017 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging import requests from django.utils.six.moves.urllib import parse as urlparse from django.conf import settings from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ from rest_framework.authentication import BasicAuthentication from rest_framework.exceptions import AuthenticationFailed class PetalAuthentication(BasicAuthentication): def authentic_proxy(self, userid, password): '''Check userid and password with configured Authentic IdP, and verify it is an OIDC client. ''' logger = logging.getLogger(__name__) authentic_url = getattr(settings, 'PETALE_AUTHENTIC_URL', None) if not authentic_url: logger.warning(u'authentic check-password not configured') return False, '' authentic_auth = getattr(settings, 'PETALE_AUTHENTIC_AUTH', None) if not authentic_auth: logger.warning(u'authentic check-password not configured') return False, '' url = urlparse.urljoin(authentic_url, 'api/check-password/') try: response = requests.post(url, json={ 'username': userid, 'password': password}, auth=authentic_auth, verify=False) response.raise_for_status() except requests.RequestException as e: logger.warning(u'authentic check-password API failed: %s', e) return False, 'authentic is down' try: response = response.json() except ValueError as e: logger.warning(u'authentic check-password API failed: %s, %r', e, response.content) return False, 'authentic is down' if response.get('result') == 0: logger.warning(u'authentic check-password API failed') return False, response.get('errors', [''])[0] return True, None def authenticate_credentials(self, userid, password, request=None): username = userid[:30] try: user, auth = super(PetalAuthentication, self).authenticate_credentials(username, password) except AuthenticationFailed: success, error = self.authentic_proxy(userid, password) if not success: raise AuthenticationFailed(error or _('Invalid username/password.')) # pylint: disable=unused-variable user, created = User.objects.get_or_create(username=username) user.set_password(password) auth = None # needed to request authentic user.credentials = (userid, password) return user, auth