Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7 kB)

1 aba1e498 Antony Chazapis
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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 64cd4730 Antony Chazapis
# 
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.db.models import Q
40 ef20ea07 Sofia Papagiannaki
from django.core.exceptions import ValidationError
41 ef20ea07 Sofia Papagiannaki
from django.http import HttpResponseRedirect
42 ef20ea07 Sofia Papagiannaki
from django.core.urlresolvers import reverse
43 ef20ea07 Sofia Papagiannaki
from urlparse import urlunsplit, urlsplit
44 ef20ea07 Sofia Papagiannaki
from django.utils.http import urlencode
45 64cd4730 Antony Chazapis
46 6151009c Sofia Papagiannaki
from astakos.im.util import prepare_response, get_context, get_invitation
47 8f5a3a06 Sofia Papagiannaki
from astakos.im.views import requires_anonymous, render_response
48 ef20ea07 Sofia Papagiannaki
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL
49 ef20ea07 Sofia Papagiannaki
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 64cd4730 Antony Chazapis
54 ef20ea07 Sofia Papagiannaki
import logging
55 ef20ea07 Sofia Papagiannaki
56 ef20ea07 Sofia Papagiannaki
logger = logging.getLogger(__name__)
57 ef20ea07 Sofia Papagiannaki
58 64cd4730 Antony Chazapis
class Tokens:
59 64cd4730 Antony Chazapis
    # these are mapped by the Shibboleth SP software
60 64cd4730 Antony Chazapis
    SHIB_EPPN = "HTTP_EPPN" # eduPersonPrincipalName
61 64cd4730 Antony Chazapis
    SHIB_NAME = "HTTP_SHIB_INETORGPERSON_GIVENNAME"
62 64cd4730 Antony Chazapis
    SHIB_SURNAME = "HTTP_SHIB_PERSON_SURNAME"
63 64cd4730 Antony Chazapis
    SHIB_CN = "HTTP_SHIB_PERSON_COMMONNAME"
64 64cd4730 Antony Chazapis
    SHIB_DISPLAYNAME = "HTTP_SHIB_INETORGPERSON_DISPLAYNAME"
65 64cd4730 Antony Chazapis
    SHIB_EP_AFFILIATION = "HTTP_SHIB_EP_AFFILIATION"
66 64cd4730 Antony Chazapis
    SHIB_SESSION_ID = "HTTP_SHIB_SESSION_ID"
67 ca828a10 Sofia Papagiannaki
    SHIB_MAIL = "HTTP_SHIB_MAIL"
68 64cd4730 Antony Chazapis
69 dda2e499 Sofia Papagiannaki
@require_http_methods(["GET", "POST"])
70 63ecdd20 Sofia Papagiannaki
@requires_anonymous
71 ef20ea07 Sofia Papagiannaki
def login(
72 ef20ea07 Sofia Papagiannaki
    request,
73 ef20ea07 Sofia Papagiannaki
    on_login_template='im/login.html',
74 ef20ea07 Sofia Papagiannaki
    on_signup_template='im/third_party_check_local.html',
75 678b2236 Sofia Papagiannaki
    extra_context=None
76 678b2236 Sofia Papagiannaki
):
77 ef20ea07 Sofia Papagiannaki
    extra_context = extra_context or {}
78 ef20ea07 Sofia Papagiannaki
79 4e30244e Sofia Papagiannaki
    tokens = request.META
80 4e30244e Sofia Papagiannaki
    
81 4e30244e Sofia Papagiannaki
    try:
82 4e30244e Sofia Papagiannaki
        eppn = tokens[Tokens.SHIB_EPPN]
83 4d1749fd Sofia Papagiannaki
        if not eppn:
84 4d1749fd Sofia Papagiannaki
            raise KeyError
85 4e30244e Sofia Papagiannaki
    except KeyError:
86 4e30244e Sofia Papagiannaki
        return HttpResponseBadRequest("Missing unique token in request")
87 4e30244e Sofia Papagiannaki
    
88 4e30244e Sofia Papagiannaki
    if Tokens.SHIB_DISPLAYNAME in tokens:
89 4e30244e Sofia Papagiannaki
        realname = tokens[Tokens.SHIB_DISPLAYNAME]
90 4e30244e Sofia Papagiannaki
    elif Tokens.SHIB_CN in tokens:
91 4e30244e Sofia Papagiannaki
        realname = tokens[Tokens.SHIB_CN]
92 4e30244e Sofia Papagiannaki
    elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
93 4e30244e Sofia Papagiannaki
        realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
94 4e30244e Sofia Papagiannaki
    else:
95 4e30244e Sofia Papagiannaki
        return HttpResponseBadRequest("Missing user name in request")
96 4e30244e Sofia Papagiannaki
    
97 4e30244e Sofia Papagiannaki
    affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
98 ef20ea07 Sofia Papagiannaki
    email = tokens.get(Tokens.SHIB_MAIL, '')
99 ef20ea07 Sofia Papagiannaki
        
100 64cd4730 Antony Chazapis
    try:
101 ef20ea07 Sofia Papagiannaki
        user = AstakosUser.objects.get(
102 ef20ea07 Sofia Papagiannaki
            provider='shibboleth',
103 ef20ea07 Sofia Papagiannaki
            third_party_identifier=eppn
104 ef20ea07 Sofia Papagiannaki
        )
105 18ffbee1 Sofia Papagiannaki
        if user.is_active:
106 18ffbee1 Sofia Papagiannaki
            return prepare_response(request,
107 18ffbee1 Sofia Papagiannaki
                                    user,
108 18ffbee1 Sofia Papagiannaki
                                    request.GET.get('next'),
109 18ffbee1 Sofia Papagiannaki
                                    'renew' in request.GET)
110 18ffbee1 Sofia Papagiannaki
        else:
111 18ffbee1 Sofia Papagiannaki
            message = _('Inactive account')
112 18ffbee1 Sofia Papagiannaki
            messages.add_message(request, messages.ERROR, message)
113 18ffbee1 Sofia Papagiannaki
            return render_response(on_login_template,
114 672d445a Sofia Papagiannaki
                                   login_form = LoginForm(request=request),
115 18ffbee1 Sofia Papagiannaki
                                   context_instance=RequestContext(request))
116 8f5a3a06 Sofia Papagiannaki
    except AstakosUser.DoesNotExist, e:
117 ef20ea07 Sofia Papagiannaki
        # First time
118 ef20ea07 Sofia Papagiannaki
        try:
119 ef20ea07 Sofia Papagiannaki
            user, created = PendingThirdPartyUser.objects.get_or_create(
120 ef20ea07 Sofia Papagiannaki
                third_party_identifier=eppn,
121 ef20ea07 Sofia Papagiannaki
                provider='shibboleth',
122 ef20ea07 Sofia Papagiannaki
                defaults=dict(
123 ef20ea07 Sofia Papagiannaki
                    realname=realname,
124 ef20ea07 Sofia Papagiannaki
                    affiliation=affiliation,
125 ef20ea07 Sofia Papagiannaki
                    email=email
126 ef20ea07 Sofia Papagiannaki
                )
127 ef20ea07 Sofia Papagiannaki
            )
128 ef20ea07 Sofia Papagiannaki
            user.save()
129 ef20ea07 Sofia Papagiannaki
        except BaseException, e:
130 ef20ea07 Sofia Papagiannaki
            logger.exception(e)
131 ef20ea07 Sofia Papagiannaki
            template = on_login_template
132 ef20ea07 Sofia Papagiannaki
            extra_context['login_form'] = LoginForm(request=request)
133 ef20ea07 Sofia Papagiannaki
            messages.error(request, _('Something went wrong.'))
134 ef20ea07 Sofia Papagiannaki
        else:
135 ef20ea07 Sofia Papagiannaki
            if not ENABLE_LOCAL_ACCOUNT_MIGRATION:
136 ef20ea07 Sofia Papagiannaki
                url = reverse(
137 ef20ea07 Sofia Papagiannaki
                    'astakos.im.target.shibboleth.signup'
138 ef20ea07 Sofia Papagiannaki
                )
139 ef20ea07 Sofia Papagiannaki
                parts = list(urlsplit(url))
140 ef20ea07 Sofia Papagiannaki
                parts[3] = urlencode({'key': user.username})
141 ef20ea07 Sofia Papagiannaki
                url = urlunsplit(parts)
142 ef20ea07 Sofia Papagiannaki
                return HttpResponseRedirect(url)
143 ef20ea07 Sofia Papagiannaki
            else:
144 ef20ea07 Sofia Papagiannaki
                template = on_signup_template
145 ef20ea07 Sofia Papagiannaki
                extra_context['key'] = user.username
146 ef20ea07 Sofia Papagiannaki
        
147 ef20ea07 Sofia Papagiannaki
        extra_context['provider']='shibboleth'
148 ef20ea07 Sofia Papagiannaki
        return render_response(
149 ef20ea07 Sofia Papagiannaki
            template,
150 ef20ea07 Sofia Papagiannaki
            context_instance=get_context(request, extra_context)
151 ef20ea07 Sofia Papagiannaki
        )
152 ef20ea07 Sofia Papagiannaki
153 ef20ea07 Sofia Papagiannaki
@require_http_methods(["GET"])
154 ef20ea07 Sofia Papagiannaki
@requires_anonymous
155 678b2236 Sofia Papagiannaki
def signup(
156 678b2236 Sofia Papagiannaki
    request,
157 678b2236 Sofia Papagiannaki
    backend=None,
158 678b2236 Sofia Papagiannaki
    on_creation_template='im/third_party_registration.html',
159 678b2236 Sofia Papagiannaki
    extra_context=None
160 ef20ea07 Sofia Papagiannaki
):
161 ef20ea07 Sofia Papagiannaki
    extra_context = extra_context or {}
162 ef20ea07 Sofia Papagiannaki
    username = request.GET.get('key')
163 ef20ea07 Sofia Papagiannaki
    if not username:
164 ef20ea07 Sofia Papagiannaki
        return HttpResponseBadRequest(_('Missing key parameter.'))
165 ef20ea07 Sofia Papagiannaki
    try:
166 ef20ea07 Sofia Papagiannaki
        pending = PendingThirdPartyUser.objects.get(username=username)
167 ef20ea07 Sofia Papagiannaki
    except BaseException, e:
168 ef20ea07 Sofia Papagiannaki
        logger.exception(e)
169 ef20ea07 Sofia Papagiannaki
        return HttpResponseBadRequest(_('Invalid key.'))
170 ef20ea07 Sofia Papagiannaki
    else:
171 ef20ea07 Sofia Papagiannaki
        d = pending.__dict__
172 ef20ea07 Sofia Papagiannaki
        d.pop('_state', None)
173 ef20ea07 Sofia Papagiannaki
        d.pop('id', None)
174 ef20ea07 Sofia Papagiannaki
        user = AstakosUser(**d)
175 4e30244e Sofia Papagiannaki
        try:
176 ef20ea07 Sofia Papagiannaki
            backend = backend or get_backend(request)
177 ef20ea07 Sofia Papagiannaki
        except ImproperlyConfigured, e:
178 ef20ea07 Sofia Papagiannaki
            messages.error(request, e)
179 ef20ea07 Sofia Papagiannaki
        else:
180 ef20ea07 Sofia Papagiannaki
            extra_context['form'] = backend.get_signup_form(
181 ef20ea07 Sofia Papagiannaki
                provider='shibboleth',
182 ef20ea07 Sofia Papagiannaki
                instance=user
183 ef20ea07 Sofia Papagiannaki
            )
184 ef20ea07 Sofia Papagiannaki
    extra_context['provider']='shibboleth'
185 ef20ea07 Sofia Papagiannaki
    return render_response(
186 ef20ea07 Sofia Papagiannaki
            on_creation_template,
187 ef20ea07 Sofia Papagiannaki
            context_instance=get_context(request, extra_context)
188 ef20ea07 Sofia Papagiannaki
    )