16 |
16 |
|
17 |
17 |
import logging
|
18 |
18 |
|
19 |
|
from mellon.adapters import DefaultAdapter
|
|
19 |
from mellon.adapters import DefaultAdapter, UserCreationError
|
20 |
20 |
from mellon.utils import get_setting
|
21 |
21 |
|
22 |
22 |
from authentic2 import utils
|
23 |
23 |
|
|
24 |
logger = logging.getLogger('authentic2.auth_saml')
|
|
25 |
|
24 |
26 |
|
25 |
27 |
class AuthenticAdapter(DefaultAdapter):
|
26 |
28 |
def create_user(self, user_class):
|
27 |
29 |
return user_class.objects.create()
|
28 |
30 |
|
29 |
31 |
def finish_create_user(self, idp, saml_attributes, user):
|
|
32 |
self.provision_a2_attributes(user, idp, saml_attributes, do_raise=True)
|
|
33 |
|
|
34 |
def provision(self, user, idp, saml_attributes):
|
|
35 |
super(AuthenticAdapter, self).provision(user, idp, saml_attributes)
|
|
36 |
self.provision_a2_attributes(user, idp, saml_attributes)
|
|
37 |
|
|
38 |
def provision_a2_attributes(self, user, idp, saml_attributes, do_raise=False):
|
30 |
39 |
'''Copy incoming SAML attributes to user attributes, A2_ATTRIBUTE_MAPPING must be a list of
|
31 |
|
dictinnaries like:
|
|
40 |
dictionaries like:
|
32 |
41 |
|
33 |
42 |
{
|
34 |
43 |
'attribute': 'email',
|
... | ... | |
40 |
49 |
If an attribute is not mandatory any error is just logged, if the attribute is
|
41 |
50 |
mandatory, login will fail.
|
42 |
51 |
'''
|
43 |
|
log = logging.getLogger(__name__)
|
44 |
52 |
|
45 |
53 |
attribute_mapping = get_setting(idp, 'A2_ATTRIBUTE_MAPPING', [])
|
|
54 |
user_modified = False
|
46 |
55 |
for mapping in attribute_mapping:
|
47 |
56 |
attribute = mapping['attribute']
|
48 |
57 |
saml_attribute = mapping['saml_attribute']
|
49 |
58 |
mandatory = mapping.get('mandatory', False)
|
50 |
|
if not saml_attributes.get(saml_attribute):
|
|
59 |
logger.debug('auth_saml: trying mapping attribute from %r to %r', saml_attribute, attribute,
|
|
60 |
extra={'user': user})
|
|
61 |
if saml_attribute not in saml_attributes:
|
51 |
62 |
if mandatory:
|
52 |
|
log.error('mandatory saml attribute %r is missing', saml_attribute,
|
53 |
|
extra={'attributes': repr(saml_attributes)})
|
54 |
|
raise ValueError('missing attribute')
|
|
63 |
logger.error('auth_saml: mandatory saml attribute %r is missing', saml_attribute,
|
|
64 |
extra={'attributes': repr(saml_attributes), 'user': user})
|
|
65 |
if do_raise:
|
|
66 |
raise UserCreationError('missing saml_attribute %r' % saml_attribute)
|
55 |
67 |
else:
|
56 |
|
continue
|
|
68 |
logger.debug('auth_saml: saml_attribute %r not found', saml_attribute, extra={'user': user})
|
|
69 |
continue
|
57 |
70 |
try:
|
58 |
71 |
value = saml_attributes[saml_attribute]
|
59 |
|
self.set_user_attribute(user, attribute, value)
|
|
72 |
if self.set_user_attribute(user, attribute, value):
|
|
73 |
user_modified = True
|
60 |
74 |
except Exception as e:
|
61 |
|
log.error(u'failed to set attribute %r from saml attribute %r with value %r: %s',
|
62 |
|
attribute, saml_attribute, value, e,
|
63 |
|
extra={'attributes': repr(saml_attributes)})
|
64 |
|
if mandatory:
|
65 |
|
raise
|
|
75 |
logger.error(u'failed to set attribute %r from saml attribute %r with value %r: %s',
|
|
76 |
attribute, saml_attribute, value, e,
|
|
77 |
extra={'attributes': repr(saml_attributes), 'user': user})
|
|
78 |
if mandatory and do_raise:
|
|
79 |
raise UserCreationError('could not set attribute %s' % attribute, e)
|
|
80 |
if user_modified:
|
|
81 |
user.save()
|
66 |
82 |
|
67 |
83 |
def set_user_attribute(self, user, attribute, value):
|
68 |
84 |
if isinstance(value, list):
|
... | ... | |
70 |
86 |
raise ValueError('too much values')
|
71 |
87 |
value = value[0]
|
72 |
88 |
if attribute in ('first_name', 'last_name', 'email', 'username'):
|
73 |
|
setattr(user, attribute, value)
|
|
89 |
if getattr(user, attribute) != value:
|
|
90 |
logger.info('auth_saml: attribute %r set to %r', attribute, value, extra={'user': user})
|
|
91 |
setattr(user, attribute, value)
|
|
92 |
return True
|
74 |
93 |
else:
|
75 |
|
setattr(user.attributes, attribute, value)
|
|
94 |
if getattr(user.attributes, attribute) != value:
|
|
95 |
logger.info('auth_saml: attribute %r set to %r', attribute, value, extra={'user': user})
|
|
96 |
setattr(user.attributes, attribute, value)
|
|
97 |
return True
|
|
98 |
return False
|
76 |
99 |
|
77 |
100 |
def auth_login(self, request, user):
|
78 |
101 |
utils.login(request, user, 'saml')
|