VC: Fix error on clone page for legacy-ID events
[cds-indico.git] / indico / modules / auth / __init__.py
blob67a33adbe965d382d946e8b15d5c21bf66580f84
1 # This file is part of Indico.
2 # Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
4 # Indico is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3 of the
7 # License, or (at your option) any later version.
9 # Indico is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with Indico; if not, see <http://www.gnu.org/licenses/>.
17 from __future__ import unicode_literals
19 from flask import session, redirect, request
20 from flask_multipass import MultipassException
22 from indico.core import signals
23 from indico.core.auth import multipass
24 from indico.core.db import db
25 from indico.core.logger import Logger
26 from indico.modules.auth.models.identities import Identity
27 from indico.modules.auth.util import save_identity_info
28 from indico.modules.users import User
29 from indico.util.i18n import _
30 from indico.web.flask.util import url_for
31 from indico.web.menu import MenuItem
32 from MaKaC.common.timezoneUtils import SessionTZ
35 logger = Logger.get('auth')
38 @multipass.identity_handler
39 def process_identity(identity_info):
40 logger.info('Received identity info: {}'.format(identity_info))
41 identity = Identity.query.filter_by(provider=identity_info.provider.name,
42 identifier=identity_info.identifier).first()
43 if identity is None:
44 logger.info('Identity does not exist in the database yet')
45 user = None
46 emails = {email.lower() for email in identity_info.data.getlist('email') if email}
47 if emails:
48 identity_info.data.setlist('email', emails)
49 users = User.query.filter(~User.is_deleted, User.all_emails.contains(db.func.any(list(emails)))).all()
50 if len(users) == 1:
51 user = users[0]
52 elif len(users) > 1:
53 # TODO: handle this case somehow.. let the user select which user to log in to?
54 raise NotImplementedError('Multiple emails matching multiple users')
55 save_identity_info(identity_info, user if user and not user.is_pending else None)
56 if not user or user.is_pending:
57 if user and user.is_pending:
58 logger.info('Found pending user with matching email: {}'.format(user))
59 else:
60 logger.info('Email search did not find an existing user')
61 return redirect(url_for('auth.register', provider=identity_info.provider.name))
62 else:
63 logger.info('Found user with matching email: {}'.format(user))
64 return redirect(url_for('auth.link_account', provider=identity_info.provider.name))
65 elif identity.user.is_deleted:
66 raise MultipassException(_('Your Indico profile has been deleted.'))
67 else:
68 user = identity.user
69 if user.is_pending:
70 # This should never happen!
71 raise ValueError('Got identity for pending user')
72 logger.info('Found existing identity {} for user {}'.format(identity, user))
73 # Update the identity with the latest information
74 if identity.multipass_data != identity_info.multipass_data:
75 logger.info('Updated multipass data'.format(identity, user))
76 identity.multipass_data = identity_info.multipass_data
77 if identity.data != identity_info.data:
78 logger.info('Updated data'.format(identity, user))
79 identity.data = identity_info.data
80 if user.is_blocked:
81 raise MultipassException(_('Your Indico profile has been blocked.'))
82 login_user(user, identity)
85 def login_user(user, identity=None):
86 """Sets the session user and performs on-login logic
88 When specifying `identity`, the provider/identitifer information
89 is saved in the session so the identity management page can prevent
90 the user from removing the identity he used to login.
92 :param user: The :class:`~indico.modules.users.User` to log in to.
93 :param identity: The :class:`Identity` instance used to log in.
94 """
95 avatar = user.as_avatar
96 session.timezone = SessionTZ(avatar).getSessionTZ()
97 session.user = user
98 session.lang = user.settings.get('lang')
99 if identity:
100 identity.register_login(request.remote_addr)
101 session['login_identity'] = identity.id
102 else:
103 session.pop('login_identity', None)
104 user.synchronize_data()
107 @signals.users.profile_sidemenu.connect
108 def _extend_profile_menu(user, **kwargs):
109 return MenuItem(_('Accounts'), 'auth.accounts')