Statistics
| Branch: | Tag: | Revision:

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

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 64cd4730 Antony Chazapis
from django.http import HttpResponseBadRequest
35 18ffbee1 Sofia Papagiannaki
from django.utils.translation import ugettext as _
36 18ffbee1 Sofia Papagiannaki
from django.contrib import messages
37 18ffbee1 Sofia Papagiannaki
from django.template import RequestContext
38 dda2e499 Sofia Papagiannaki
from django.views.decorators.http import require_http_methods
39 ef20ea07 Sofia Papagiannaki
from django.http import HttpResponseRedirect
40 ef20ea07 Sofia Papagiannaki
from django.core.urlresolvers import reverse
41 c0b26605 Sofia Papagiannaki
from django.core.exceptions import ImproperlyConfigured
42 d2633501 Kostas Papadimitriou
from django.shortcuts import get_object_or_404
43 d2633501 Kostas Papadimitriou
44 d2633501 Kostas Papadimitriou
from urlparse import urlunsplit, urlsplit
45 64cd4730 Antony Chazapis
46 aab4d540 Sofia Papagiannaki
from astakos.im.util import prepare_response, get_context
47 d2633501 Kostas Papadimitriou
from astakos.im.views import requires_anonymous, render_response, \
48 d2633501 Kostas Papadimitriou
        requires_auth_provider
49 ef20ea07 Sofia Papagiannaki
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL
50 ef20ea07 Sofia Papagiannaki
from astakos.im.models import AstakosUser, PendingThirdPartyUser
51 4e30244e Sofia Papagiannaki
from astakos.im.forms import LoginForm
52 4e30244e Sofia Papagiannaki
from astakos.im.activation_backends import get_backend, SimpleBackend
53 d2633501 Kostas Papadimitriou
from astakos.im import settings
54 64cd4730 Antony Chazapis
55 ae497612 Olga Brani
import astakos.im.messages as astakos_messages
56 5ce3ce4f Sofia Papagiannaki
57 ef20ea07 Sofia Papagiannaki
import logging
58 ef20ea07 Sofia Papagiannaki
59 ef20ea07 Sofia Papagiannaki
logger = logging.getLogger(__name__)
60 ef20ea07 Sofia Papagiannaki
61 64cd4730 Antony Chazapis
class Tokens:
62 64cd4730 Antony Chazapis
    # these are mapped by the Shibboleth SP software
63 5ce3ce4f Sofia Papagiannaki
    SHIB_EPPN = "HTTP_EPPN"  # eduPersonPrincipalName
64 64cd4730 Antony Chazapis
    SHIB_NAME = "HTTP_SHIB_INETORGPERSON_GIVENNAME"
65 64cd4730 Antony Chazapis
    SHIB_SURNAME = "HTTP_SHIB_PERSON_SURNAME"
66 64cd4730 Antony Chazapis
    SHIB_CN = "HTTP_SHIB_PERSON_COMMONNAME"
67 64cd4730 Antony Chazapis
    SHIB_DISPLAYNAME = "HTTP_SHIB_INETORGPERSON_DISPLAYNAME"
68 64cd4730 Antony Chazapis
    SHIB_EP_AFFILIATION = "HTTP_SHIB_EP_AFFILIATION"
69 64cd4730 Antony Chazapis
    SHIB_SESSION_ID = "HTTP_SHIB_SESSION_ID"
70 ca828a10 Sofia Papagiannaki
    SHIB_MAIL = "HTTP_SHIB_MAIL"
71 64cd4730 Antony Chazapis
72 d2633501 Kostas Papadimitriou
@requires_auth_provider('local', login=True)
73 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
74 ef20ea07 Sofia Papagiannaki
def login(
75 ef20ea07 Sofia Papagiannaki
    request,
76 d2633501 Kostas Papadimitriou
    template='im/third_party_check_local.html',
77 678b2236 Sofia Papagiannaki
    extra_context=None
78 678b2236 Sofia Papagiannaki
):
79 ef20ea07 Sofia Papagiannaki
    extra_context = extra_context or {}
80 ef20ea07 Sofia Papagiannaki
81 4e30244e Sofia Papagiannaki
    tokens = request.META
82 d2633501 Kostas Papadimitriou
83 6c8a3f7c Sofia Papagiannaki
    try:
84 6c8a3f7c Sofia Papagiannaki
        eppn = tokens.get(Tokens.SHIB_EPPN)
85 6c8a3f7c Sofia Papagiannaki
        if not eppn:
86 c0b26605 Sofia Papagiannaki
            raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_EPPN))
87 6c8a3f7c Sofia Papagiannaki
        if Tokens.SHIB_DISPLAYNAME in tokens:
88 6c8a3f7c Sofia Papagiannaki
            realname = tokens[Tokens.SHIB_DISPLAYNAME]
89 6c8a3f7c Sofia Papagiannaki
        elif Tokens.SHIB_CN in tokens:
90 6c8a3f7c Sofia Papagiannaki
            realname = tokens[Tokens.SHIB_CN]
91 6c8a3f7c Sofia Papagiannaki
        elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
92 6c8a3f7c Sofia Papagiannaki
            realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
93 6c8a3f7c Sofia Papagiannaki
        else:
94 c0b26605 Sofia Papagiannaki
            raise KeyError(_(astakos_messages.SHIBBOLETH_MISSING_NAME))
95 6c8a3f7c Sofia Papagiannaki
    except KeyError, e:
96 d2633501 Kostas Papadimitriou
        # invalid shibboleth headers, redirect to login, display message
97 2e90e3ec Kostas Papadimitriou
        messages.error(request, e.message)
98 d2633501 Kostas Papadimitriou
        return HttpResponseRedirect(reverse('login'))
99 d2633501 Kostas Papadimitriou
100 6c8a3f7c Sofia Papagiannaki
    affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
101 6c8a3f7c Sofia Papagiannaki
    email = tokens.get(Tokens.SHIB_MAIL, '')
102 d2633501 Kostas Papadimitriou
103 d2633501 Kostas Papadimitriou
    # an existing user accessed the view
104 d2633501 Kostas Papadimitriou
    if request.user.is_authenticated():
105 d2633501 Kostas Papadimitriou
        if request.user.has_auth_provider('shibboleth', identifier=eppn):
106 d2633501 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
107 d2633501 Kostas Papadimitriou
108 d2633501 Kostas Papadimitriou
        # automatically add eppn provider to user
109 d2633501 Kostas Papadimitriou
        user = request.user
110 f432088a Kostas Papadimitriou
        if not request.user.can_add_auth_provider('shibboleth',
111 f432088a Kostas Papadimitriou
                                                  identifier=eppn):
112 f432088a Kostas Papadimitriou
            messages.error(request, 'Account already exists.')
113 f432088a Kostas Papadimitriou
            return HttpResponseRedirect(reverse('edit_profile'))
114 f432088a Kostas Papadimitriou
115 f432088a Kostas Papadimitriou
        user.add_auth_provider('shibboleth', identifier=eppn)
116 f432088a Kostas Papadimitriou
        return HttpResponseRedirect(reverse('edit_profile'))
117 d2633501 Kostas Papadimitriou
118 64cd4730 Antony Chazapis
    try:
119 d2633501 Kostas Papadimitriou
        # astakos user exists ?
120 d2633501 Kostas Papadimitriou
        user = AstakosUser.objects.get_auth_provider_user(
121 d2633501 Kostas Papadimitriou
            'shibboleth',
122 d2633501 Kostas Papadimitriou
            identifier=eppn
123 ef20ea07 Sofia Papagiannaki
        )
124 18ffbee1 Sofia Papagiannaki
        if user.is_active:
125 d2633501 Kostas Papadimitriou
            # authenticate user
126 18ffbee1 Sofia Papagiannaki
            return prepare_response(request,
127 18ffbee1 Sofia Papagiannaki
                                    user,
128 18ffbee1 Sofia Papagiannaki
                                    request.GET.get('next'),
129 18ffbee1 Sofia Papagiannaki
                                    'renew' in request.GET)
130 1f3b4b39 Sofia Papagiannaki
        elif not user.activation_sent:
131 1f3b4b39 Sofia Papagiannaki
            message = _('Your request is pending activation')
132 2e90e3ec Kostas Papadimitriou
                        #TODO: use astakos_messages
133 d2633501 Kostas Papadimitriou
            if not settings.MODERATION_ENABLED:
134 d2633501 Kostas Papadimitriou
                url = user.get_resend_activation_url()
135 d2633501 Kostas Papadimitriou
                msg_extra = _('<a href="%s">Resend activation email?</a>') % url
136 d2633501 Kostas Papadimitriou
                message = message + u' ' + msg_extra
137 d2633501 Kostas Papadimitriou
138 1f3b4b39 Sofia Papagiannaki
            messages.error(request, message)
139 d2633501 Kostas Papadimitriou
            return HttpResponseRedirect(reverse('login'))
140 d2633501 Kostas Papadimitriou
141 18ffbee1 Sofia Papagiannaki
        else:
142 2e90e3ec Kostas Papadimitriou
                        #TODO: use astakos_messages
143 d2633501 Kostas Papadimitriou
            message = _(u'Account disabled. Please contact support')
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 2e90e3ec Kostas Papadimitriou
                #TODO: use astakos_messages
149 d2633501 Kostas Papadimitriou
        # eppn not stored in astakos models, create pending profile
150 d2633501 Kostas Papadimitriou
        user, created = PendingThirdPartyUser.objects.get_or_create(
151 d2633501 Kostas Papadimitriou
            third_party_identifier=eppn,
152 d2633501 Kostas Papadimitriou
            provider='shibboleth',
153 d2633501 Kostas Papadimitriou
        )
154 d2633501 Kostas Papadimitriou
        # update pending user
155 d2633501 Kostas Papadimitriou
        user.realname = realname
156 d2633501 Kostas Papadimitriou
        user.affiliation = affiliation
157 d2633501 Kostas Papadimitriou
        user.email = email
158 d2633501 Kostas Papadimitriou
        user.generate_token()
159 d2633501 Kostas Papadimitriou
        user.save()
160 d2633501 Kostas Papadimitriou
161 d2633501 Kostas Papadimitriou
        extra_context['provider'] = 'shibboleth'
162 d2633501 Kostas Papadimitriou
        extra_context['token'] = user.token
163 d2633501 Kostas Papadimitriou
164 ef20ea07 Sofia Papagiannaki
        return render_response(
165 ef20ea07 Sofia Papagiannaki
            template,
166 ef20ea07 Sofia Papagiannaki
            context_instance=get_context(request, extra_context)
167 ef20ea07 Sofia Papagiannaki
        )
168 ef20ea07 Sofia Papagiannaki
169 d2633501 Kostas Papadimitriou
170 d2633501 Kostas Papadimitriou
@requires_auth_provider('local', login=True, create=True)
171 ef20ea07 Sofia Papagiannaki
@require_http_methods(["GET"])
172 ef20ea07 Sofia Papagiannaki
@requires_anonymous
173 678b2236 Sofia Papagiannaki
def signup(
174 678b2236 Sofia Papagiannaki
    request,
175 d2633501 Kostas Papadimitriou
    token,
176 678b2236 Sofia Papagiannaki
    backend=None,
177 678b2236 Sofia Papagiannaki
    on_creation_template='im/third_party_registration.html',
178 d2633501 Kostas Papadimitriou
    extra_context=None):
179 d2633501 Kostas Papadimitriou
180 ef20ea07 Sofia Papagiannaki
    extra_context = extra_context or {}
181 d2633501 Kostas Papadimitriou
    if not token:
182 2e90e3ec Kostas Papadimitriou
                #TODO: use astakos_messages
183 6c8a3f7c Sofia Papagiannaki
        return HttpResponseBadRequest(_('Missing key parameter.'))
184 d2633501 Kostas Papadimitriou
185 d2633501 Kostas Papadimitriou
    pending = get_object_or_404(PendingThirdPartyUser, token=token)
186 d2633501 Kostas Papadimitriou
    d = pending.__dict__
187 d2633501 Kostas Papadimitriou
    d.pop('_state', None)
188 d2633501 Kostas Papadimitriou
    d.pop('id', None)
189 d2633501 Kostas Papadimitriou
    d.pop('token', None)
190 d2633501 Kostas Papadimitriou
    d.pop('created', None)
191 d2633501 Kostas Papadimitriou
    user = AstakosUser(**d)
192 d2633501 Kostas Papadimitriou
193 fffa19d2 Sofia Papagiannaki
    try:
194 fffa19d2 Sofia Papagiannaki
        backend = backend or get_backend(request)
195 fffa19d2 Sofia Papagiannaki
    except ImproperlyConfigured, e:
196 fffa19d2 Sofia Papagiannaki
        messages.error(request, e)
197 fffa19d2 Sofia Papagiannaki
    else:
198 fffa19d2 Sofia Papagiannaki
        extra_context['form'] = backend.get_signup_form(
199 fffa19d2 Sofia Papagiannaki
            provider='shibboleth',
200 fffa19d2 Sofia Papagiannaki
            instance=user
201 fffa19d2 Sofia Papagiannaki
        )
202 d2633501 Kostas Papadimitriou
203 d2633501 Kostas Papadimitriou
    extra_context['provider'] = 'shibboleth'
204 d2633501 Kostas Papadimitriou
    extra_context['third_party_token'] = token
205 ef20ea07 Sofia Papagiannaki
    return render_response(
206 ef20ea07 Sofia Papagiannaki
            on_creation_template,
207 ef20ea07 Sofia Papagiannaki
            context_instance=get_context(request, extra_context)
208 d2633501 Kostas Papadimitriou
    )