3a9ab5abd19c1cbe508b852b2c49c078463a300c
[cas.git] / provider / cas_provider / views.py
1 from django.http import HttpResponse, HttpResponseForbidden, HttpResponseRedirect
2 from django.shortcuts import render_to_response
3 from django.template import RequestContext
4 from django.contrib.auth.models import User
5 from django.contrib.auth import authenticate
6 from django.contrib.auth import login as auth_login, logout as auth_logout
7 from django.utils.encoding import smart_str
8 from django.utils.translation import ugettext_lazy as _
9
10 from cas_provider.forms import LoginForm
11 from cas_provider.models import ServiceTicket, LoginTicket, auth_success_response
12 from cas_provider.utils import create_service_ticket
13
14 import urlparse, urllib
15
16 try:
17     from urlparse import parse_qs as url_parse_qs
18 except ImportError:
19     from cgi import parse_qs as url_parse_qs
20
21 import logging
22 logger = logging.getLogger("cas.provider")
23
24 __all__ = ['login', 'validate', 'service_validate', 'logout']
25
26 def _add_query_param(url, param, value):
27     parsed = urlparse.urlparse(url)
28     query = url_parse_qs(smart_str(parsed.query))
29     query[param] = [unicode(value, 'utf-8')]
30     query = [ ((k, v) if len(v) != 1 else (k, v[0])) for k, v in query.iteritems() ]
31     parsed = urlparse.ParseResult(parsed.scheme, parsed.netloc,
32                                   parsed.path, parsed.params,
33                                   urllib.urlencode(query), parsed.fragment)
34     return parsed.geturl()
35
36
37 def login(request, template_name='cas/login.html', success_redirect='/accounts/'):
38     service = request.GET.get('service', None)
39
40     if request.user.is_authenticated():
41         if service is not None:
42             ticket = create_service_ticket(request.user, service)
43             target = _add_query_param(service, 'ticket', ticket.ticket)
44             logger.info("Redirecting to %s", target)
45             return HttpResponseRedirect(target)
46         else:
47             logger.info("Redirecting to default: %s", success_redirect)
48             return HttpResponseRedirect(success_redirect)
49
50     errors = []
51     if request.method == 'POST':
52         username = request.POST.get('username', None)
53         password = request.POST.get('password', None)
54         service = request.POST.get('service', None)
55         lt = request.POST.get('lt', None)
56
57         logger.debug("User %s logging in", username)
58
59         try:
60             login_ticket = LoginTicket.objects.get(ticket=lt)
61         except:
62             errors.append(_(u'Login ticket expired. Please try again.'))
63         else:
64             login_ticket.delete()
65             user = authenticate(username=username, password=password)
66             if user is not None:
67                 if user.is_active:
68                     auth_login(request, user)
69                     if service is not None:
70                         ticket = create_service_ticket(user, service)
71                         target = _add_query_param(service, 'ticket', ticket.ticket)
72                         return HttpResponseRedirect(target)
73                     else:
74                         return HttpResponseRedirect(success_redirect)
75                 else:
76                     errors.append(_(u'This account is disabled.'))
77             else:
78                     errors.append(_(u'Incorrect username and/or password.'))
79
80     form = LoginForm(service)
81     return render_to_response(template_name, {'form': form, 'errors': errors}, context_instance=RequestContext(request))
82
83 def validate(request):
84     service = request.GET.get('service', None)
85     ticket_string = request.GET.get('ticket', None)
86     if service is not None and ticket_string is not None:
87         try:
88             ticket = ServiceTicket.objects.get(ticket=ticket_string)
89             username = ticket.user.username
90             ticket.delete()
91             return HttpResponse("yes\n%s\n" % username)
92         except:
93             pass
94     return HttpResponse("no\n\n")
95
96 def service_validate(request):
97     service = request.GET.get('service', None)
98     ticket_string = request.GET.get('ticket', None)
99     if service is None or ticket_string is None:
100         return HttpResponse(r'''<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
101             <cas:authenticationFailure code="INVALID_REQUEST">
102                 Not all required parameters were sent.
103             </cas:authenticationFailure>
104         </cas:serviceResponse>''', mimetype='application/xml')
105
106     try:
107         ticket = ServiceTicket.objects.get(ticket=ticket_string)
108         ticket.delete()
109         return HttpResponse(auth_success_response(ticket.user), mimetype='text/xml')
110     except ServiceTicket.DoesNotExist:
111         return HttpResponse(r'''<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
112             <cas:authenticationFailure code="INVALID_TICKET">
113                 The provided ticket is invalid.
114             </cas:authenticationFailure>
115         </cas:serviceResponse>''', mimetype='application/xml')
116
117 def logout(request, template_name='cas/logout.html'):
118     url = request.GET.get('url', None)
119     auth_logout(request)
120     return render_to_response(template_name, {'url': url}, context_instance=RequestContext(request))