Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / views / target / shibboleth.py @ 412048af

History | View | Annotate | Download (7.6 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 5ce3ce4f Sofia Papagiannaki
#
3 64cd4730 Antony Chazapis
# Redistribution and use in source and binary forms, with or
4 64cd4730 Antony Chazapis
# without modification, are permitted provided that the following
5 64cd4730 Antony Chazapis
# conditions are met:
6 5ce3ce4f Sofia Papagiannaki
#
7 64cd4730 Antony Chazapis
#   1. Redistributions of source code must retain the above
8 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
9 64cd4730 Antony Chazapis
#      disclaimer.
10 5ce3ce4f Sofia Papagiannaki
#
11 64cd4730 Antony Chazapis
#   2. Redistributions in binary form must reproduce the above
12 64cd4730 Antony Chazapis
#      copyright notice, this list of conditions and the following
13 64cd4730 Antony Chazapis
#      disclaimer in the documentation and/or other materials
14 64cd4730 Antony Chazapis
#      provided with the distribution.
15 5ce3ce4f Sofia Papagiannaki
#
16 64cd4730 Antony Chazapis
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 64cd4730 Antony Chazapis
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 64cd4730 Antony Chazapis
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 64cd4730 Antony Chazapis
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 64cd4730 Antony Chazapis
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 64cd4730 Antony Chazapis
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 64cd4730 Antony Chazapis
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 64cd4730 Antony Chazapis
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 64cd4730 Antony Chazapis
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 64cd4730 Antony Chazapis
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 64cd4730 Antony Chazapis
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 64cd4730 Antony Chazapis
# POSSIBILITY OF SUCH DAMAGE.
28 5ce3ce4f Sofia Papagiannaki
#
29 64cd4730 Antony Chazapis
# The views and conclusions contained in the software and
30 64cd4730 Antony Chazapis
# documentation are those of the authors and should not be
31 64cd4730 Antony Chazapis
# interpreted as representing official policies, either expressed
32 64cd4730 Antony Chazapis
# or implied, of GRNET S.A.
33 64cd4730 Antony Chazapis
34 9d20fe23 Kostas Papadimitriou
from django.conf import settings as global_settings
35 18ffbee1 Sofia Papagiannaki
from django.utils.translation import ugettext as _
36 18ffbee1 Sofia Papagiannaki
from django.contrib import messages
37 dda2e499 Sofia Papagiannaki
from django.views.decorators.http import require_http_methods
38 ef20ea07 Sofia Papagiannaki
from django.http import HttpResponseRedirect
39 64cd4730 Antony Chazapis
40 3e0a032d Sofia Papagiannaki
from astakos.im.util import login_url
41 6a80a0ae Kostas Papadimitriou
from astakos.im.models import AstakosUser, AstakosUserAuthProvider, \
42 6a80a0ae Kostas Papadimitriou
    PendingThirdPartyUser
43 d2633501 Kostas Papadimitriou
from astakos.im import settings
44 3e0a032d Sofia Papagiannaki
from astakos.im.views.target import get_pending_key, \
45 3e0a032d Sofia Papagiannaki
    handle_third_party_signup, handle_third_party_login, \
46 3e0a032d Sofia Papagiannaki
    init_third_party_session
47 3e0a032d Sofia Papagiannaki
from astakos.im.views.decorators import cookie_fix, requires_auth_provider
48 64cd4730 Antony Chazapis
49 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
50 ef20ea07 Sofia Papagiannaki
import logging
51 ef20ea07 Sofia Papagiannaki
52 ef20ea07 Sofia Papagiannaki
logger = logging.getLogger(__name__)
53 ef20ea07 Sofia Papagiannaki
54 dd5f8f4d Kostas Papadimitriou
55 6a80a0ae Kostas Papadimitriou
def migrate_eppn_to_remote_id(eppn, remote_id):
56 6a80a0ae Kostas Papadimitriou
    """
57 6a80a0ae Kostas Papadimitriou
    Retrieve active and pending accounts that are associated with shibboleth
58 6a80a0ae Kostas Papadimitriou
    using EPPN as the third party unique identifier update them by storing
59 6a80a0ae Kostas Papadimitriou
    REMOTE_USER value instead.
60 6a80a0ae Kostas Papadimitriou
    """
61 6a80a0ae Kostas Papadimitriou
    if eppn == remote_id:
62 6a80a0ae Kostas Papadimitriou
        return
63 6a80a0ae Kostas Papadimitriou
64 6a80a0ae Kostas Papadimitriou
    try:
65 6a80a0ae Kostas Papadimitriou
        provider = AstakosUserAuthProvider.objects.get(module='shibboleth',
66 6a80a0ae Kostas Papadimitriou
                                                       identifier=eppn)
67 6a80a0ae Kostas Papadimitriou
        msg = "Migrating user %r eppn (%s -> %s)"
68 6a80a0ae Kostas Papadimitriou
        logger.info(msg, provider.user.log_display, eppn, remote_id)
69 6a80a0ae Kostas Papadimitriou
        provider.identifier = remote_id
70 6a80a0ae Kostas Papadimitriou
        provider.save()
71 6a80a0ae Kostas Papadimitriou
    except AstakosUserAuthProvider.DoesNotExist:
72 6a80a0ae Kostas Papadimitriou
        pass
73 6a80a0ae Kostas Papadimitriou
74 6a80a0ae Kostas Papadimitriou
    pending_users = \
75 5bc77346 Giorgos Korfiatis
        PendingThirdPartyUser.objects.filter(third_party_identifier=eppn,
76 5bc77346 Giorgos Korfiatis
                                             provider='shibboleth')
77 6a80a0ae Kostas Papadimitriou
78 6a80a0ae Kostas Papadimitriou
    for pending in pending_users:
79 6a80a0ae Kostas Papadimitriou
        msg = "Migrating pending user %s eppn (%s -> %s)"
80 6a80a0ae Kostas Papadimitriou
        logger.info(msg, pending.email, eppn, remote_id)
81 6a80a0ae Kostas Papadimitriou
        pending.third_party_identifier = remote_id
82 6a80a0ae Kostas Papadimitriou
        pending.save()
83 6a80a0ae Kostas Papadimitriou
84 6a80a0ae Kostas Papadimitriou
    return remote_id
85 6a80a0ae Kostas Papadimitriou
86 6a80a0ae Kostas Papadimitriou
87 64cd4730 Antony Chazapis
class Tokens:
88 64cd4730 Antony Chazapis
    # these are mapped by the Shibboleth SP software
89 5ce3ce4f Sofia Papagiannaki
    SHIB_EPPN = "HTTP_EPPN"  # eduPersonPrincipalName
90 64cd4730 Antony Chazapis
    SHIB_NAME = "HTTP_SHIB_INETORGPERSON_GIVENNAME"
91 64cd4730 Antony Chazapis
    SHIB_SURNAME = "HTTP_SHIB_PERSON_SURNAME"
92 64cd4730 Antony Chazapis
    SHIB_CN = "HTTP_SHIB_PERSON_COMMONNAME"
93 64cd4730 Antony Chazapis
    SHIB_DISPLAYNAME = "HTTP_SHIB_INETORGPERSON_DISPLAYNAME"
94 64cd4730 Antony Chazapis
    SHIB_EP_AFFILIATION = "HTTP_SHIB_EP_AFFILIATION"
95 64cd4730 Antony Chazapis
    SHIB_SESSION_ID = "HTTP_SHIB_SESSION_ID"
96 ca828a10 Sofia Papagiannaki
    SHIB_MAIL = "HTTP_SHIB_MAIL"
97 830747d2 Kostas Papadimitriou
    SHIB_REMOTE_USER = "HTTP_REMOTE_USER"
98 64cd4730 Antony Chazapis
99 dd5f8f4d Kostas Papadimitriou
100 9d20fe23 Kostas Papadimitriou
@requires_auth_provider('shibboleth')
101 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
102 222305b7 Sofia Papagiannaki
@cookie_fix
103 8fb8d0cf Giorgos Korfiatis
def login(request,
104 8fb8d0cf Giorgos Korfiatis
          template='im/third_party_check_local.html',
105 8fb8d0cf Giorgos Korfiatis
          extra_context=None):
106 73fbaec4 Sofia Papagiannaki
107 0e79735c Kostas Papadimitriou
    init_third_party_session(request)
108 ef20ea07 Sofia Papagiannaki
    extra_context = extra_context or {}
109 ef20ea07 Sofia Papagiannaki
110 4e30244e Sofia Papagiannaki
    tokens = request.META
111 dd5f8f4d Kostas Papadimitriou
    third_party_key = get_pending_key(request)
112 d2633501 Kostas Papadimitriou
113 a53ee093 Kostas Papadimitriou
    shibboleth_headers = {}
114 a53ee093 Kostas Papadimitriou
    for token in dir(Tokens):
115 a53ee093 Kostas Papadimitriou
        if token == token.upper():
116 feebcc02 Kostas Papadimitriou
            shibboleth_headers[token] = request.META.get(getattr(Tokens,
117 feebcc02 Kostas Papadimitriou
                                                                 token),
118 feebcc02 Kostas Papadimitriou
                                                         'NOT_SET')
119 ed355f9a Kostas Papadimitriou
            # also include arbitrary shibboleth headers
120 ed355f9a Kostas Papadimitriou
            for key in request.META.keys():
121 ed355f9a Kostas Papadimitriou
                if key.startswith('HTTP_SHIB_'):
122 ed355f9a Kostas Papadimitriou
                    shibboleth_headers[key.replace('HTTP_', '')] = \
123 ed355f9a Kostas Papadimitriou
                        request.META.get(key)
124 f3463a00 Kostas Papadimitriou
125 a53ee093 Kostas Papadimitriou
    # log shibboleth headers
126 a53ee093 Kostas Papadimitriou
    # TODO: info -> debug
127 a53ee093 Kostas Papadimitriou
    logger.info("shibboleth request: %r" % shibboleth_headers)
128 a53ee093 Kostas Papadimitriou
129 564a2292 Kostas Papadimitriou
    try:
130 6a80a0ae Kostas Papadimitriou
        eppn = tokens.get(Tokens.SHIB_EPPN, None)
131 6a80a0ae Kostas Papadimitriou
        user_id = tokens.get(Tokens.SHIB_REMOTE_USER)
132 c1f65a1e Kostas Papadimitriou
        fullname, first_name, last_name, email = None, None, None, None
133 9d20fe23 Kostas Papadimitriou
        if global_settings.DEBUG and not eppn:
134 6a80a0ae Kostas Papadimitriou
            user_id = getattr(global_settings, 'SHIBBOLETH_TEST_REMOTE_USER',
135 6a80a0ae Kostas Papadimitriou
                              None)
136 9d20fe23 Kostas Papadimitriou
            eppn = getattr(global_settings, 'SHIBBOLETH_TEST_EPPN', None)
137 c1f65a1e Kostas Papadimitriou
            fullname = getattr(global_settings, 'SHIBBOLETH_TEST_FULLNAME',
138 9d20fe23 Kostas Papadimitriou
                               None)
139 9d20fe23 Kostas Papadimitriou
140 6a80a0ae Kostas Papadimitriou
        if not user_id:
141 6a80a0ae Kostas Papadimitriou
            raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_USER_ID) % {
142 8c8e318d Kostas Papadimitriou
                'domain': settings.BASE_HOST,
143 31bc3a62 Kostas Papadimitriou
                'contact_email': settings.CONTACT_EMAIL
144 564a2292 Kostas Papadimitriou
            })
145 564a2292 Kostas Papadimitriou
        if Tokens.SHIB_DISPLAYNAME in tokens:
146 c1f65a1e Kostas Papadimitriou
            fullname = tokens[Tokens.SHIB_DISPLAYNAME]
147 564a2292 Kostas Papadimitriou
        elif Tokens.SHIB_CN in tokens:
148 c1f65a1e Kostas Papadimitriou
            fullname = tokens[Tokens.SHIB_CN]
149 c1f65a1e Kostas Papadimitriou
        if Tokens.SHIB_NAME in tokens:
150 c1f65a1e Kostas Papadimitriou
            first_name = tokens[Tokens.SHIB_NAME]
151 c1f65a1e Kostas Papadimitriou
        if Tokens.SHIB_SURNAME in tokens:
152 c1f65a1e Kostas Papadimitriou
            last_name = tokens[Tokens.SHIB_SURNAME]
153 c1f65a1e Kostas Papadimitriou
154 c1f65a1e Kostas Papadimitriou
        if fullname:
155 c1f65a1e Kostas Papadimitriou
            splitted = fullname.split(' ', 1)
156 c1f65a1e Kostas Papadimitriou
            if len(splitted) == 2:
157 c1f65a1e Kostas Papadimitriou
                first_name, last_name = splitted
158 c1f65a1e Kostas Papadimitriou
        fullname = '%s %s' % (first_name, last_name)
159 c1f65a1e Kostas Papadimitriou
160 c1f65a1e Kostas Papadimitriou
        if not any([first_name, last_name]) and \
161 11d5fd8b Kostas Papadimitriou
                    settings.SHIBBOLETH_REQUIRE_NAME_INFO:
162 c1f65a1e Kostas Papadimitriou
            raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_NAME))
163 564a2292 Kostas Papadimitriou
164 564a2292 Kostas Papadimitriou
    except KeyError, e:
165 564a2292 Kostas Papadimitriou
        # invalid shibboleth headers, redirect to login, display message
166 412048af Kostas Papadimitriou
        logger.exception(e)
167 564a2292 Kostas Papadimitriou
        messages.error(request, e.message)
168 564a2292 Kostas Papadimitriou
        return HttpResponseRedirect(login_url(request))
169 564a2292 Kostas Papadimitriou
170 6a80a0ae Kostas Papadimitriou
    if settings.SHIBBOLETH_MIGRATE_EPPN:
171 6a80a0ae Kostas Papadimitriou
        migrate_eppn_to_remote_id(eppn, user_id)
172 6a80a0ae Kostas Papadimitriou
173 564a2292 Kostas Papadimitriou
    affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, 'Shibboleth')
174 564a2292 Kostas Papadimitriou
    email = tokens.get(Tokens.SHIB_MAIL, '')
175 6a80a0ae Kostas Papadimitriou
    provider_info = {'eppn': eppn, 'email': email, 'name': fullname,
176 6a80a0ae Kostas Papadimitriou
                     'headers': shibboleth_headers, 'user_id': user_id}
177 d2633501 Kostas Papadimitriou
178 64cd4730 Antony Chazapis
    try:
179 c8d89a3c Kostas Papadimitriou
        return handle_third_party_login(request, 'shibboleth',
180 6a80a0ae Kostas Papadimitriou
                                        user_id, provider_info,
181 c8d89a3c Kostas Papadimitriou
                                        affiliation, third_party_key)
182 8f5a3a06 Sofia Papagiannaki
    except AstakosUser.DoesNotExist, e:
183 c8d89a3c Kostas Papadimitriou
        third_party_key = get_pending_key(request)
184 c1f65a1e Kostas Papadimitriou
        user_info = {'affiliation': affiliation,
185 c1f65a1e Kostas Papadimitriou
                     'first_name': first_name,
186 c1f65a1e Kostas Papadimitriou
                     'last_name': last_name,
187 c1f65a1e Kostas Papadimitriou
                     'email': email}
188 6a80a0ae Kostas Papadimitriou
        return handle_third_party_signup(request, user_id, 'shibboleth',
189 dd5f8f4d Kostas Papadimitriou
                                         third_party_key,
190 dd5f8f4d Kostas Papadimitriou
                                         provider_info,
191 dd5f8f4d Kostas Papadimitriou
                                         user_info,
192 dd5f8f4d Kostas Papadimitriou
                                         template,
193 dd5f8f4d Kostas Papadimitriou
                                         extra_context)