Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (7.7 kB)

1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
# 
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
# 
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
# 
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
# 
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
# 
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from django.http import HttpResponseBadRequest
35
from django.utils.translation import ugettext as _
36
from django.contrib import messages
37
from django.template import RequestContext
38
from django.views.decorators.http import require_http_methods
39
from django.db.models import Q
40
from django.core.exceptions import ValidationError
41
from django.http import HttpResponseRedirect
42
from django.core.urlresolvers import reverse
43
from urlparse import urlunsplit, urlsplit
44
from django.utils.http import urlencode
45

    
46
from astakos.im.util import prepare_response, get_context, get_invitation
47
from astakos.im.views import requires_anonymous, render_response
48
from astakos.im.settings import ENABLE_LOCAL_ACCOUNT_MIGRATION, BASEURL
49

    
50
from astakos.im.models import AstakosUser, PendingThirdPartyUser
51
from astakos.im.forms import LoginForm
52
from astakos.im.activation_backends import get_backend, SimpleBackend
53

    
54
import logging
55

    
56
logger = logging.getLogger(__name__)
57

    
58
class Tokens:
59
    # these are mapped by the Shibboleth SP software
60
    SHIB_EPPN = "HTTP_EPPN" # eduPersonPrincipalName
61
    SHIB_NAME = "HTTP_SHIB_INETORGPERSON_GIVENNAME"
62
    SHIB_SURNAME = "HTTP_SHIB_PERSON_SURNAME"
63
    SHIB_CN = "HTTP_SHIB_PERSON_COMMONNAME"
64
    SHIB_DISPLAYNAME = "HTTP_SHIB_INETORGPERSON_DISPLAYNAME"
65
    SHIB_EP_AFFILIATION = "HTTP_SHIB_EP_AFFILIATION"
66
    SHIB_SESSION_ID = "HTTP_SHIB_SESSION_ID"
67
    SHIB_MAIL = "HTTP_SHIB_MAIL"
68

    
69
@require_http_methods(["GET", "POST"])
70
@requires_anonymous
71
def login(
72
    request,
73
    login_template='im/login.html',
74
    signup_template='im/third_party_check_local.html',
75
    extra_context=None
76
):
77
    extra_context = extra_context or {}
78

    
79
    tokens = request.META
80
    
81
#     try:
82
#         eppn = tokens.get(Tokens.SHIB_EPPN)
83
#         if not eppn:
84
#             raise KeyError(_('Missing unique token in request'))
85
#         if Tokens.SHIB_DISPLAYNAME in tokens:
86
#             realname = tokens[Tokens.SHIB_DISPLAYNAME]
87
#         elif Tokens.SHIB_CN in tokens:
88
#             realname = tokens[Tokens.SHIB_CN]
89
#         elif Tokens.SHIB_NAME in tokens and Tokens.SHIB_SURNAME in tokens:
90
#             realname = tokens[Tokens.SHIB_NAME] + ' ' + tokens[Tokens.SHIB_SURNAME]
91
#         else:
92
#             raise KeyError(_('Missing user name in request'))
93
#     except KeyError, e:
94
#         extra_context['login_form'] = LoginForm(request=request)
95
#         messages.error(request, e)
96
#         return render_response(
97
#             login_template,
98
#             context_instance=get_context(request, extra_context)
99
#         )
100
#     
101
#     affiliation = tokens.get(Tokens.SHIB_EP_AFFILIATION, '')
102
#     email = tokens.get(Tokens.SHIB_MAIL, '')
103
    
104
    eppn, realname, affiliation, email = 'shibboleth1', 'shib Boleth', '', '' 
105
    
106
    try:
107
        user = AstakosUser.objects.get(
108
            provider='shibboleth',
109
            third_party_identifier=eppn
110
        )
111
        if user.is_active:
112
            return prepare_response(request,
113
                                    user,
114
                                    request.GET.get('next'),
115
                                    'renew' in request.GET)
116
        elif not user.activation_sent:
117
            message = _('Your request is pending activation')
118
            messages.error(request, message)
119
        else:
120
            urls = {}
121
            urls['send_activation'] = reverse(
122
                'send_activation',
123
                kwargs={'user_id':user.id}
124
            )
125
            urls['signup'] = reverse(
126
                'shibboleth_signup',
127
                args= [user.username]
128
            )   
129
            message = _(
130
                'You have not followed the activation link. \
131
                <a href="%(send_activation)s">Resend activation email?</a> or \
132
                <a href="%(signup)s">Provide new email?</a>' % urls
133
            )
134
            messages.error(request, message)
135
        return render_response(login_template,
136
                               login_form = LoginForm(request=request),
137
                               context_instance=RequestContext(request))
138
    except AstakosUser.DoesNotExist, e:
139
        # First time
140
        try:
141
            user, created = PendingThirdPartyUser.objects.get_or_create(
142
                third_party_identifier=eppn,
143
                provider='shibboleth',
144
                defaults=dict(
145
                    realname=realname,
146
                    affiliation=affiliation,
147
                    email=email
148
                )
149
            )
150
            user.save()
151
        except BaseException, e:
152
            logger.exception(e)
153
            template = login_template
154
            extra_context['login_form'] = LoginForm(request=request)
155
            messages.error(request, _('Something went wrong.'))
156
        else:
157
            if not ENABLE_LOCAL_ACCOUNT_MIGRATION:
158
                url = reverse(
159
                    'shibboleth_signup',
160
                    args= [user.username]
161
                )
162
                return HttpResponseRedirect(url)
163
            else:
164
                template = signup_template
165
                extra_context['username'] = user.username
166
        
167
        extra_context['provider']='shibboleth'
168
        return render_response(
169
            template,
170
            context_instance=get_context(request, extra_context)
171
        )
172

    
173
@require_http_methods(["GET"])
174
@requires_anonymous
175
def signup(
176
    request,
177
    username,
178
    backend=None,
179
    on_creation_template='im/third_party_registration.html',
180
    extra_context=None
181
):
182
    extra_context = extra_context or {}
183
    try:
184
        pending = PendingThirdPartyUser.objects.get(username=username)
185
    except BaseException, e:
186
        try:
187
            user = AstakosUser.objects.get(username=username)
188
        except BaseException, e:
189
            logger.exception(e)
190
            return HttpResponseBadRequest(_('Invalid key.'))
191
    else:
192
        d = pending.__dict__
193
        d.pop('_state', None)
194
        d.pop('id', None)
195
        user = AstakosUser(**d)
196
    try:
197
        backend = backend or get_backend(request)
198
    except ImproperlyConfigured, e:
199
        messages.error(request, e)
200
    else:
201
        extra_context['form'] = backend.get_signup_form(
202
            provider='shibboleth',
203
            instance=user
204
        )
205
    extra_context['provider']='shibboleth'
206
    return render_response(
207
            on_creation_template,
208
            context_instance=get_context(request, extra_context)
209
    )