Skip to content
Snippets Groups Projects
Commit 071d5307 authored by Ben Adida's avatar Ben Adida
Browse files

merged v3.0 maintenance changes

parents 10e736b4 705802da
No related branches found
No related tags found
No related merge requests found
......@@ -9,12 +9,13 @@ from django.http import *
from django.core.mail import send_mail
from django.conf import settings
import sys, os, cgi, urllib, urllib2, re
import sys, os, cgi, urllib, urllib2, re, uuid, datetime
from xml.etree import ElementTree
CAS_EMAIL_DOMAIN = "princeton.edu"
CAS_URL= 'https://fed.princeton.edu/cas/'
CAS_LOGOUT_URL = 'https://fed.princeton.edu/cas/logout?service=%s'
CAS_SAML_VALIDATE_URL = 'https://fed.princeton.edu/cas/samlValidate?TARGET=%s'
# eligibility checking
if hasattr(settings, 'CAS_USERNAME'):
......@@ -34,7 +35,7 @@ def _get_service_url():
from django.conf import settings
from django.core.urlresolvers import reverse
return settings.URL_HOST + reverse(after)
return settings.SECURE_URL_HOST + reverse(after)
def get_auth_url(request, redirect_url):
request.session['cas_redirect_url'] = redirect_url
......@@ -52,6 +53,47 @@ def get_user_category(user_id):
parsed_result = ElementTree.fromstring(result)
return parsed_result.text
def get_saml_info(ticket):
"""
Using SAML, get all of the information needed
"""
import logging
saml_request = """<?xml version='1.0' encoding='UTF-8'?>
<soap-env:Envelope
xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'>
<soap-env:Header />
<soap-env:Body>
<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"
MajorVersion="1" MinorVersion="1"
RequestID="%s"
IssueInstant="%sZ">
<samlp:AssertionArtifact>%s</samlp:AssertionArtifact>
</samlp:Request>
</soap-env:Body>
</soap-env:Envelope>
""" % (uuid.uuid1(), datetime.datetime.utcnow().isoformat(), ticket)
url = CAS_SAML_VALIDATE_URL % urllib.quote(_get_service_url())
# by virtue of having a body, this is a POST
req = urllib2.Request(url, saml_request)
raw_response = urllib2.urlopen(req).read()
logging.info("RESP:\n%s\n\n" % raw_response)
response = ElementTree.fromstring(raw_response)
# ugly path down the tree of attributes
attributes = response.findall('{http://schemas.xmlsoap.org/soap/envelope/}Body/{urn:oasis:names:tc:SAML:1.0:protocol}Response/{urn:oasis:names:tc:SAML:1.0:assertion}Assertion/{urn:oasis:names:tc:SAML:1.0:assertion}AttributeStatement/{urn:oasis:names:tc:SAML:1.0:assertion}Attribute')
values = {}
for attribute in attributes:
values[str(attribute.attrib['AttributeName'])] = attribute.findtext('{urn:oasis:names:tc:SAML:1.0:assertion}AttributeValue')
# parse response for netid, display name, and employee type (category)
return {'user_id': values.get('mail',None), 'name': values.get('displayName', None), 'category': values.get('employeeType',None)}
def get_user_info(user_id):
url = 'http://dsml.princeton.edu/'
......@@ -101,34 +143,49 @@ def get_user_info(user_id):
else:
return None
def get_user_info_after_auth(request):
ticket = request.GET.get('ticket', None)
# if no ticket, this is a logout
if not ticket:
return None
def get_user_info_special(ticket):
# fetch the information from the CAS server
val_url = CAS_URL + "validate" + \
'?service=' + urllib.quote(_get_service_url()) + \
'&ticket=' + urllib.quote(ticket)
r = urllib.urlopen(val_url).readlines() # returns 2 lines
r = urllib.urlopen(val_url).readlines() # returns 2 lines
# success
if len(r) == 2 and re.match("yes", r[0]) != None:
netid = r[1].strip()
category = get_user_category(netid)
user_info = get_user_info(netid)
#try:
# user_info = get_user_info(netid)
#except:
# user_info = None
# for now, no need to wait for this request to finish
user_info = None
if user_info:
info = {'name': user_info['name'], 'category': category}
else:
info = {'name': netid, 'category': category}
return {'type': 'cas', 'user_id': netid, 'name': info['name'], 'info': info, 'token': None}
return {'user_id': netid, 'name': info['name'], 'info': info, 'token': None}
else:
return None
def get_user_info_after_auth(request):
ticket = request.GET.get('ticket', None)
# if no ticket, this is a logout
if not ticket:
return None
#user_info = get_saml_info(ticket)
user_info = get_user_info_special(ticket)
user_info['type'] = 'cas'
return user_info
def do_logout(user):
"""
......
......@@ -33,8 +33,8 @@ class EmailVotersForm(forms.Form):
class TallyNotificationEmailForm(forms.Form):
subject = forms.CharField(max_length=80)
body = forms.CharField(max_length=2000, widget=forms.Textarea)
send_to = forms.ChoiceField(label="Send To", choices= [('all', 'all voters'), ('voted', 'only voters who cast a ballot')])
body = forms.CharField(max_length=2000, widget=forms.Textarea, required=False)
send_to = forms.ChoiceField(label="Send To", choices= [('all', 'all voters'), ('voted', 'only voters who cast a ballot'), ('none', 'no one -- are you sure about this?')])
class VoterPasswordForm(forms.Form):
voter_id = forms.CharField(max_length=50)
......
......@@ -27,7 +27,9 @@
{% for t in trustees %}
<h3> Trustee #{{forloop.counter}}: {{t.name}}
{% if admin_p %}
{% if not t.secret_key %}
{% if t.secret_key %}
{% if not election.frozen_at %}[<a onclick="return confirm('Are you sure you want to remove Helios as a trustee?');" href="{% url helios.views.delete_trustee election.uuid %}?uuid={{t.uuid}}">x</a>]{% endif %}
{% else %}
({{t.email}})
{% if not election.frozen_at %}[<a onclick="return confirm('Are you sure you want to remove this Trustee?');" href="{% url helios.views.delete_trustee election.uuid %}?uuid={{t.uuid}}">x</a>]{% endif %}
[<a onclick="return confirm('Are you sure you want to send this trustee his/her admin URL?');" href="{% url helios.views.trustee_send_url election.uuid t.uuid %}">send login</a>]
......
......@@ -353,7 +353,7 @@ def new_trustee_helios(request, election):
election.generate_trustee(ELGAMAL_PARAMS)
return HttpResponseRedirect(reverse(list_trustees_view, args=[election.uuid]))
@election_admin()
@election_admin(frozen=False)
def delete_trustee(request, election):
trustee = Trustee.get_by_election_and_uuid(election, request.GET['uuid'])
trustee.delete()
......@@ -538,7 +538,7 @@ def one_election_cast_confirm(request, election):
# status update this vote
if voter and user and user.can_update_status():
status_update_label = voter.user.update_status_template() % "your smart ballot tracker"
status_update_message = "I voted in %s, my smart tracker is %s.. -- %s" % (election.name, cast_vote.vote_hash[:10], get_election_url(election))
status_update_message = "I voted in %s - my smart tracker is %s.. #heliosvoting" % (get_election_url(election),cast_vote.vote_hash[:10])
else:
status_update_label = None
status_update_message = None
......@@ -929,21 +929,24 @@ def combine_decryptions(request, election):
'election' : election
}
# exclude those who have not voted
if email_form.cleaned_data['send_to'] == 'voted':
voter_constraints_exclude = {'vote_hash' : None}
else:
voter_constraints_exclude = {}
# if the user opted for notifying no one, then we skip this step
if email_form.cleaned_data['send_to'] != 'none':
# exclude those who have not voted
if email_form.cleaned_data['send_to'] == 'voted':
voter_constraints_exclude = {'vote_hash' : None}
else:
voter_constraints_exclude = {}
# full-length email
tasks.voters_email.delay(election_id = election.id,
subject_template = 'email/result_subject.txt',
body_template = 'email/result_body.txt',
extra_vars = extra_vars,
voter_constraints_exclude = voter_constraints_exclude)
# full-length email
tasks.voters_email.delay(election_id = election.id,
subject_template = 'email/result_subject.txt',
body_template = 'email/result_body.txt',
extra_vars = extra_vars,
voter_constraints_exclude = voter_constraints_exclude)
# rapid short-message notification
# this inherently only applies to those who have voted (for the most part)
# and this is not configurable, this is ALWAYS sent
tasks.voters_notify.delay(election_id = election.id,
notification_template = 'notification/result.txt',
extra_vars = extra_vars)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment