2015-05-17 21:24:41 +00:00
|
|
|
# ⁻*- coding: utf-8 -*-
|
2015-05-27 20:10:06 +00:00
|
|
|
# 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 General Public License version 3 for
|
|
|
|
# more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License version 3
|
|
|
|
# along with this program; if not, write to the Free Software Foundation, Inc., 51
|
|
|
|
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
#
|
|
|
|
# (c) 2015 Valentin Samir
|
2015-05-27 19:56:39 +00:00
|
|
|
"""Some authentication classes for the CAS"""
|
2015-05-17 21:24:41 +00:00
|
|
|
from django.conf import settings
|
2015-12-12 16:26:19 +00:00
|
|
|
from django.contrib.auth import get_user_model
|
2016-06-17 17:28:49 +00:00
|
|
|
from django.utils import timezone
|
|
|
|
|
|
|
|
from datetime import timedelta
|
2015-05-17 21:24:41 +00:00
|
|
|
try:
|
|
|
|
import MySQLdb
|
|
|
|
import MySQLdb.cursors
|
|
|
|
import crypt
|
|
|
|
except ImportError:
|
|
|
|
MySQLdb = None
|
2015-05-27 19:56:39 +00:00
|
|
|
|
2016-06-17 17:28:49 +00:00
|
|
|
from .models import FederatedUser
|
|
|
|
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2015-12-12 16:26:19 +00:00
|
|
|
class AuthUser(object):
|
|
|
|
def __init__(self, username):
|
|
|
|
self.username = username
|
|
|
|
|
|
|
|
def test_password(self, password):
|
|
|
|
"""test `password` agains the user"""
|
|
|
|
raise NotImplemented()
|
|
|
|
|
|
|
|
def attributs(self):
|
|
|
|
"""return a dict of user attributes"""
|
|
|
|
raise NotImplemented()
|
|
|
|
|
|
|
|
|
|
|
|
class DummyAuthUser(AuthUser):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""A Dummy authentication class"""
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2015-05-17 21:24:41 +00:00
|
|
|
def __init__(self, username):
|
2015-12-12 16:26:19 +00:00
|
|
|
super(DummyAuthUser, self).__init__(username)
|
2015-05-17 21:24:41 +00:00
|
|
|
|
|
|
|
def test_password(self, password):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""test `password` agains the user"""
|
2015-05-17 21:24:41 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
def attributs(self):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""return a dict of user attributes"""
|
2015-05-17 21:24:41 +00:00
|
|
|
return {}
|
|
|
|
|
|
|
|
|
2015-12-12 16:26:19 +00:00
|
|
|
class TestAuthUser(AuthUser):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""A test authentication class with one user test having
|
|
|
|
alose test as password and some attributes"""
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2015-05-17 21:24:41 +00:00
|
|
|
def __init__(self, username):
|
2015-05-27 19:56:39 +00:00
|
|
|
super(TestAuthUser, self).__init__(username)
|
2015-05-17 21:24:41 +00:00
|
|
|
|
|
|
|
def test_password(self, password):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""test `password` agains the user"""
|
2015-05-17 21:24:41 +00:00
|
|
|
return self.username == "test" and password == "test"
|
|
|
|
|
|
|
|
def attributs(self):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""return a dict of user attributes"""
|
2015-06-12 16:10:52 +00:00
|
|
|
return {'nom': 'Nymous', 'prenom': 'Ano', 'email': 'anonymous@example.net'}
|
2015-05-17 21:24:41 +00:00
|
|
|
|
|
|
|
|
2015-12-12 16:26:19 +00:00
|
|
|
class MysqlAuthUser(AuthUser):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""A mysql auth class: authentication user agains a mysql database"""
|
2015-05-17 21:24:41 +00:00
|
|
|
user = None
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2015-05-17 21:24:41 +00:00
|
|
|
def __init__(self, username):
|
|
|
|
mysql_config = {
|
2015-05-27 19:56:39 +00:00
|
|
|
"user": settings.CAS_SQL_USERNAME,
|
|
|
|
"passwd": settings.CAS_SQL_PASSWORD,
|
|
|
|
"db": settings.CAS_SQL_DBNAME,
|
|
|
|
"host": settings.CAS_SQL_HOST,
|
2015-06-12 16:10:52 +00:00
|
|
|
"charset": settings.CAS_SQL_DBCHARSET,
|
|
|
|
"cursorclass": MySQLdb.cursors.DictCursor
|
2015-05-17 21:24:41 +00:00
|
|
|
}
|
|
|
|
if not MySQLdb:
|
|
|
|
raise RuntimeError("Please install MySQLdb before using the MysqlAuthUser backend")
|
|
|
|
conn = MySQLdb.connect(**mysql_config)
|
|
|
|
curs = conn.cursor()
|
|
|
|
if curs.execute(settings.CAS_SQL_USER_QUERY, (username,)) == 1:
|
|
|
|
self.user = curs.fetchone()
|
2015-12-19 16:14:02 +00:00
|
|
|
super(MysqlAuthUser, self).__init__(self.user['username'])
|
|
|
|
else:
|
|
|
|
super(MysqlAuthUser, self).__init__(username)
|
2015-05-17 21:24:41 +00:00
|
|
|
|
|
|
|
def test_password(self, password):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""test `password` agains the user"""
|
2015-05-17 21:24:41 +00:00
|
|
|
if not self.user:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
if settings.CAS_SQL_PASSWORD_CHECK == "plain":
|
|
|
|
return password == self.user["password"]
|
|
|
|
elif settings.CAS_SQL_PASSWORD_CHECK == "crypt":
|
|
|
|
if self.user["password"].startswith('$'):
|
|
|
|
salt = '$'.join(self.user["password"].split('$', 3)[:-1])
|
|
|
|
return crypt.crypt(password, salt) == self.user["password"]
|
|
|
|
else:
|
2015-05-27 20:18:01 +00:00
|
|
|
return crypt.crypt(
|
|
|
|
password,
|
|
|
|
self.user["password"][:2]
|
|
|
|
) == self.user["password"]
|
2015-05-17 21:24:41 +00:00
|
|
|
|
|
|
|
def attributs(self):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""return a dict of user attributes"""
|
2015-05-17 21:24:41 +00:00
|
|
|
if not self.user:
|
|
|
|
return {}
|
|
|
|
else:
|
|
|
|
return self.user
|
|
|
|
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2015-12-12 16:26:19 +00:00
|
|
|
class DjangoAuthUser(AuthUser):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""A django auth class: authenticate user agains django internal users"""
|
2015-05-17 21:24:41 +00:00
|
|
|
user = None
|
2015-06-12 16:10:52 +00:00
|
|
|
|
2015-05-17 21:24:41 +00:00
|
|
|
def __init__(self, username):
|
2015-12-12 16:26:19 +00:00
|
|
|
User = get_user_model()
|
2015-05-17 21:24:41 +00:00
|
|
|
try:
|
|
|
|
self.user = User.objects.get(username=username)
|
|
|
|
except User.DoesNotExist:
|
|
|
|
pass
|
|
|
|
super(DjangoAuthUser, self).__init__(username)
|
|
|
|
|
|
|
|
def test_password(self, password):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""test `password` agains the user"""
|
2015-05-17 21:24:41 +00:00
|
|
|
if not self.user:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return self.user.check_password(password)
|
|
|
|
|
|
|
|
def attributs(self):
|
2015-05-27 19:56:39 +00:00
|
|
|
"""return a dict of user attributes"""
|
2015-05-17 21:24:41 +00:00
|
|
|
if not self.user:
|
|
|
|
return {}
|
|
|
|
else:
|
|
|
|
attr = {}
|
|
|
|
for field in self.user._meta.fields:
|
2015-05-27 19:56:39 +00:00
|
|
|
attr[field.attname] = getattr(self.user, field.attname)
|
2015-05-17 21:24:41 +00:00
|
|
|
return attr
|
2016-06-17 17:28:49 +00:00
|
|
|
|
|
|
|
|
|
|
|
class CASFederateAuth(AuthUser):
|
|
|
|
user = None
|
|
|
|
|
|
|
|
def __init__(self, username):
|
|
|
|
component = username.split('@')
|
|
|
|
username = '@'.join(component[:-1])
|
|
|
|
provider = component[-1]
|
|
|
|
try:
|
|
|
|
self.user = FederatedUser.objects.get(username=username, provider=provider)
|
|
|
|
super(CASFederateAuth, self).__init__(
|
|
|
|
"%s@%s" % (self.user.username, self.user.provider)
|
|
|
|
)
|
|
|
|
except FederatedUser.DoesNotExist:
|
|
|
|
super(CASFederateAuth, self).__init__("%s@%s" % (username, provider))
|
|
|
|
|
|
|
|
def test_password(self, ticket):
|
|
|
|
"""test `password` agains the user"""
|
|
|
|
if not self.user or not self.user.ticket:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return (
|
|
|
|
ticket == self.user.ticket and
|
|
|
|
self.user.last_update >
|
|
|
|
(timezone.now() - timedelta(seconds=settings.CAS_TICKET_VALIDITY))
|
|
|
|
)
|
|
|
|
|
|
|
|
def attributs(self):
|
|
|
|
"""return a dict of user attributes"""
|
|
|
|
if not self.user:
|
|
|
|
return {}
|
|
|
|
else:
|
|
|
|
return self.user.attributs
|