Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / target / shibboleth.py @ e1dc6dec

History | View | Annotate | Download (7 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 c630fee6 Kostas Papadimitriou
import json
35 c630fee6 Kostas Papadimitriou
36 64cd4730 Antony Chazapis
from django.http import HttpResponseBadRequest
37 18ffbee1 Sofia Papagiannaki
from django.utils.translation import ugettext as _
38 18ffbee1 Sofia Papagiannaki
from django.contrib import messages
39 18ffbee1 Sofia Papagiannaki
from django.template import RequestContext
40 dda2e499 Sofia Papagiannaki
from django.views.decorators.http import require_http_methods
41 ef20ea07 Sofia Papagiannaki
from django.http import HttpResponseRedirect
42 ef20ea07 Sofia Papagiannaki
from django.core.urlresolvers import reverse
43 c0b26605 Sofia Papagiannaki
from django.core.exceptions import ImproperlyConfigured
44 d2633501 Kostas Papadimitriou
from django.shortcuts import get_object_or_404
45 d2633501 Kostas Papadimitriou
46 d2633501 Kostas Papadimitriou
from urlparse import urlunsplit, urlsplit
47 64cd4730 Antony Chazapis
48 aab4d540 Sofia Papagiannaki
from astakos.im.util import prepare_response, get_context
49 d2633501 Kostas Papadimitriou
from astakos.im.views import requires_anonymous, render_response, \
50 d2633501 Kostas Papadimitriou
        requires_auth_provider
51 ef20ea07 Sofia Papagiannaki
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL
52 ef20ea07 Sofia Papagiannaki
from astakos.im.models import AstakosUser, PendingThirdPartyUser
53 4e30244e Sofia Papagiannaki
from astakos.im.forms import LoginForm
54 4e30244e Sofia Papagiannaki
from astakos.im.activation_backends import get_backend, SimpleBackend
55 c630fee6 Kostas Papadimitriou
from astakos.im import auth_providers
56 d2633501 Kostas Papadimitriou
from astakos.im import settings
57 64cd4730 Antony Chazapis
58 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
59 5ce3ce4f Sofia Papagiannaki
60 ef20ea07 Sofia Papagiannaki
import logging
61 ef20ea07 Sofia Papagiannaki
62 ef20ea07 Sofia Papagiannaki
logger = logging.getLogger(__name__)
63 ef20ea07 Sofia Papagiannaki
64 64cd4730 Antony Chazapis
class Tokens:
65 64cd4730 Antony Chazapis
    # these are mapped by the Shibboleth SP software
66 5ce3ce4f Sofia Papagiannaki
    SHIB_EPPN = "HTTP_EPPN"  # eduPersonPrincipalName
67 64cd4730 Antony Chazapis
    SHIB_NAME = "HTTP_SHIB_INETORGPERSON_GIVENNAME"
68 64cd4730 Antony Chazapis
    SHIB_SURNAME = "HTTP_SHIB_PERSON_SURNAME"
69 64cd4730 Antony Chazapis
    SHIB_CN = "HTTP_SHIB_PERSON_COMMONNAME"
70 64cd4730 Antony Chazapis
    SHIB_DISPLAYNAME = "HTTP_SHIB_INETORGPERSON_DISPLAYNAME"
71 64cd4730 Antony Chazapis
    SHIB_EP_AFFILIATION = "HTTP_SHIB_EP_AFFILIATION"
72 64cd4730 Antony Chazapis
    SHIB_SESSION_ID = "HTTP_SHIB_SESSION_ID"
73 ca828a10 Sofia Papagiannaki
    SHIB_MAIL = "HTTP_SHIB_MAIL"
74 64cd4730 Antony Chazapis
75 c630fee6 Kostas Papadimitriou
@requires_auth_provider('shibboleth', login=True)
76 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
77 ef20ea07 Sofia Papagiannaki
def login(
78 ef20ea07 Sofia Papagiannaki
    request,
79 d2633501 Kostas Papadimitriou
    template='im/third_party_check_local.html',
80 678b2236 Sofia Papagiannaki
    extra_context=None
81 678b2236 Sofia Papagiannaki
):
82 ef20ea07 Sofia Papagiannaki
    extra_context = extra_context or {}
83 ef20ea07 Sofia Papagiannaki
84 4e30244e Sofia Papagiannaki
    tokens = request.META
85 d2633501 Kostas Papadimitriou
86 6c8a3f7c Sofia Papagiannaki
    try:
87 6c8a3f7c Sofia Papagiannaki
        eppn = tokens.get(Tokens.SHIB_EPPN)
88 e1dc6dec Olga Brani
        eppn = "1234"
89 e1dc6dec Olga Brani
        tokens[Tokens.SHIB_DISPLAYNAME] = 'Olga Brani'
90 6c8a3f7c Sofia Papagiannaki
        if not eppn:
91 c0b26605 Sofia Papagiannaki
            raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_EPPN))
92 6c8a3f7c Sofia Papagiannaki
        if Tokens.SHIB_DISPLAYNAME in tokens:
93 6c8a3f7c Sofia Papagiannaki
            realname = tokens[Tokens.SHIB_DISPLAYNAME]
94 6c8a3f7c Sofia Papagiannaki
        elif Tokens.SHIB_CN in tokens:
95 6c8a3f7c Sofia Papagiannaki
            realname = tokens[Tokens.SHIB_CN]
96 6c8a3f7c Sofia Papagiannaki
        elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
97 6c8a3f7c Sofia Papagiannaki
            realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
98 6c8a3f7c Sofia Papagiannaki
        else:
99 1d59653f Kostas Papadimitriou
            print settings.SHIBBOLETH_REQUIRE_NAME_INFO, "LALALALAL"
100 1d59653f Kostas Papadimitriou
            if settings.SHIBBOLETH_REQUIRE_NAME_INFO:
101 1d59653f Kostas Papadimitriou
                raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_NAME))
102 1d59653f Kostas Papadimitriou
            else:
103 1d59653f Kostas Papadimitriou
                realname = ''
104 6c8a3f7c Sofia Papagiannaki
    except KeyError, e:
105 d2633501 Kostas Papadimitriou
        # invalid shibboleth headers, redirect to login, display message
106 2e90e3ec Kostas Papadimitriou
        messages.error(request, e.message)
107 d2633501 Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login'))
108 d2633501 Kostas Papadimitriou
109 6c8a3f7c Sofia Papagiannaki
    affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
110 6c8a3f7c Sofia Papagiannaki
    email = tokens.get(Tokens.SHIB_MAIL, '')
111 c630fee6 Kostas Papadimitriou
    provider_info = {'eppn': eppn, 'email': email}
112 d2633501 Kostas Papadimitriou
113 d2633501 Kostas Papadimitriou
    # an existing user accessed the view
114 d2633501 Kostas Papadimitriou
    if request.user.is_authenticated():
115 d2633501 Kostas Papadimitriou
        if request.user.has_auth_provider('shibboleth', identifier=eppn):
116 d2633501 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
117 d2633501 Kostas Papadimitriou
118 d2633501 Kostas Papadimitriou
        # automatically add eppn provider to user
119 d2633501 Kostas Papadimitriou
        user = request.user
120 f432088a Kostas Papadimitriou
        if not request.user.can_add_auth_provider('shibboleth',
121 f054a8b3 Kostas Papadimitriou
                                                  identifier=eppn):
122 f432088a Kostas Papadimitriou
            messages.error(request, 'Account already exists.')
123 f432088a Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
124 f432088a Kostas Papadimitriou
125 c630fee6 Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier=eppn,
126 c630fee6 Kostas Papadimitriou
                               affiliation=affiliation)
127 c630fee6 Kostas Papadimitriou
        messages.success(request, 'Account assigned.')
128 f432088a Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
129 d2633501 Kostas Papadimitriou
130 64cd4730 Antony Chazapis
    try:
131 d2633501 Kostas Papadimitriou
        # astakos user exists ?
132 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get_auth_provider_user(
133 d2633501 Kostas Papadimitriou
            'shibboleth',
134 d2633501 Kostas Papadimitriou
            identifier=eppn
135 ef20ea07 Sofia Papagiannaki
        )
136 18ffbee1 Sofia Papagiannaki
        if user.is_active:
137 d2633501 Kostas Papadimitriou
            # authenticate user
138 18ffbee1 Sofia Papagiannaki
            return prepare_response(request,
139 18ffbee1 Sofia Papagiannaki
                                    user,
140 18ffbee1 Sofia Papagiannaki
                                    request.GET.get('next'),
141 18ffbee1 Sofia Papagiannaki
                                    'renew' in request.GET)
142 18ffbee1 Sofia Papagiannaki
        else:
143 c4b1a172 Kostas Papadimitriou
            message = user.get_inactive_message()
144 1f3b4b39 Sofia Papagiannaki
            messages.error(request, message)
145 d2633501 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('login'))
146 d2633501 Kostas Papadimitriou
147 8f5a3a06 Sofia Papagiannaki
    except AstakosUser.DoesNotExist, e:
148 c630fee6 Kostas Papadimitriou
        provider = auth_providers.get_provider('shibboleth')
149 c630fee6 Kostas Papadimitriou
        if not provider.is_available_for_create():
150 c4b1a172 Kostas Papadimitriou
            messages.error(request,
151 c4b1a172 Kostas Papadimitriou
                           _(astakos_messages.AUTH_PROVIDER_NOT_ACTIVE) % provider.get_title_display)
152 c4b1a172 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('login'))
153 c630fee6 Kostas Papadimitriou
154 d2633501 Kostas Papadimitriou
        # eppn not stored in astakos models, create pending profile
155 d2633501 Kostas Papadimitriou
        user, created = PendingThirdPartyUser.objects.get_or_create(
156 d2633501 Kostas Papadimitriou
            third_party_identifier=eppn,
157 3b258643 Kostas Papadimitriou
            provider='shibboleth'
158 d2633501 Kostas Papadimitriou
        )
159 d2633501 Kostas Papadimitriou
        # update pending user
160 d2633501 Kostas Papadimitriou
        user.realname = realname
161 d2633501 Kostas Papadimitriou
        user.affiliation = affiliation
162 d2633501 Kostas Papadimitriou
        user.email = email
163 3b258643 Kostas Papadimitriou
        user.info = json.dumps(provider_info)
164 d2633501 Kostas Papadimitriou
        user.generate_token()
165 d2633501 Kostas Papadimitriou
        user.save()
166 d2633501 Kostas Papadimitriou
167 d2633501 Kostas Papadimitriou
        extra_context['provider'] = 'shibboleth'
168 ab7e3a9e Kostas Papadimitriou
        extra_context['provider_title'] = 'Academic credentials'
169 d2633501 Kostas Papadimitriou
        extra_context['token'] = user.token
170 c630fee6 Kostas Papadimitriou
        extra_context['signup_url'] = reverse('signup') + \
171 c630fee6 Kostas Papadimitriou
                                        "?third_party_token=%s" % user.token
172 d2633501 Kostas Papadimitriou
173 ef20ea07 Sofia Papagiannaki
        return render_response(
174 ef20ea07 Sofia Papagiannaki
            template,
175 ef20ea07 Sofia Papagiannaki
            context_instance=get_context(request, extra_context)
176 ef20ea07 Sofia Papagiannaki
        )