200 lines
8.2 KiB
Plaintext
200 lines
8.2 KiB
Plaintext
import os
|
|
import sys
|
|
import re
|
|
|
|
try:
|
|
import lasso
|
|
except ImportError:
|
|
print >> sys.stderr, 'Missing Lasso module, IdWsf 2.0 support disabled'
|
|
else:
|
|
if not lasso.WSF_SUPPORT:
|
|
print >> sys.stderr, 'Found Lasso module, but IdWsf 2.0 support not enabled'
|
|
|
|
from quixote import get_publisher, get_session, get_request, get_response, redirect
|
|
from quixote.directory import Directory
|
|
|
|
from qommon.liberty import SOAPException, soap_call
|
|
from qommon import template
|
|
from qommon.misc import http_get_page
|
|
|
|
import misc
|
|
from form_prefill import FormPrefill
|
|
from field_prefill import FieldPrefill
|
|
|
|
def cleanup_html_value(value):
|
|
# Ensure the field value can be properly integrated in HTML code
|
|
value = value.replace('"', "'")
|
|
# Conversion to iso-8859-1
|
|
try:
|
|
value = unicode(value, 'utf-8').encode('iso-8859-1')
|
|
except UnicodeEncodeError:
|
|
return None
|
|
|
|
class IdWsf2(Directory):
|
|
_q_exports = []
|
|
|
|
def _q_lookup(self, component):
|
|
if not hasattr(get_session(), 'prefill_form'):
|
|
get_session().prefill_form = component
|
|
get_session().after_url = get_request().get_url()
|
|
if get_request().get_query():
|
|
get_session().after_url += '?' + get_request().get_query()
|
|
return redirect('../saml/login')
|
|
else:
|
|
prefill_form = FormPrefill.get(get_session().prefill_form)
|
|
del get_session().prefill_form
|
|
if prefill_form:
|
|
try:
|
|
response, status, page, auth_header = http_get_page(prefill_form.url)
|
|
except:
|
|
return template.error_page(_('Failed connecting to the original site.'))
|
|
try:
|
|
fields = self.do_prefill_form(prefill_form)
|
|
if not fields:
|
|
raise lasso.Error
|
|
for key, value in get_request().get_fields().iteritems():
|
|
value = cleanup_html_value(value)
|
|
if value:
|
|
fields[key] = value
|
|
except lasso.Error:
|
|
return page + '<script type="text/javascript">alert("%s")</script>' % \
|
|
_('Failed getting attributes from the attribute provider.')
|
|
except:
|
|
return page + '<script type="text/javascript">alert("%s")</script>' % \
|
|
_('Failed getting attributes for an unknown reason.')
|
|
|
|
return self.send_prefilled_form(prefill_form, page, fields)
|
|
|
|
def do_prefill_form(self, prefill_form):
|
|
server = misc.get_lasso_server(protocol = 'saml2')
|
|
disco = lasso.IdWsf2Discovery(server)
|
|
if not get_session().lasso_session_dumps or not get_session().lasso_session_dumps[server.providerId]:
|
|
return None
|
|
disco.setSessionFromDump(get_session().lasso_session_dumps[server.providerId])
|
|
|
|
disco.initQuery()
|
|
disco.addRequestedServiceType(prefill_form.profile)
|
|
disco.buildRequestMsg()
|
|
|
|
try:
|
|
soap_answer = soap_call(disco.msgUrl, disco.msgBody)
|
|
except SOAPException:
|
|
return None
|
|
disco.processQueryResponseMsg(soap_answer)
|
|
|
|
service = disco.getService()
|
|
lasso.registerIdWsf2DstService(prefill_form.prefix, prefill_form.profile)
|
|
|
|
service.initQuery()
|
|
|
|
fields = FieldPrefill.select(lambda x: x.form_id == prefill_form.id)
|
|
for field in fields:
|
|
if field.xpath and field.name:
|
|
service.addQueryItem(field.xpath, field.name)
|
|
|
|
service.buildRequestMsg()
|
|
|
|
try:
|
|
soap_answer = soap_call(service.msgUrl, service.msgBody)
|
|
except SOAPException:
|
|
return None
|
|
service.processQueryResponseMsg(soap_answer)
|
|
|
|
fields_dict = {}
|
|
for field in fields:
|
|
if not field.xpath or not field.name:
|
|
continue
|
|
if field.number > 0:
|
|
number = field.number -1
|
|
try:
|
|
if field.raw_xml:
|
|
value = service.getAttributeNodes(field.name)[number]
|
|
else:
|
|
value = service.getAttributeStrings(field.name)[number]
|
|
except (IndexError, TypeError):
|
|
value = ''
|
|
# Log
|
|
if value:
|
|
# Regexp transformation
|
|
if field.regexp_match:
|
|
value = re.sub(field.regexp_match, field.regexp_replacing, value)
|
|
value = cleanup_html_value(value)
|
|
# Conversion of select field options
|
|
if field.select_options:
|
|
try:
|
|
value = field.select_options[value]
|
|
except (IndexError, KeyError):
|
|
pass
|
|
if not value:
|
|
continue
|
|
fields_dict[field.name] = value
|
|
|
|
return fields_dict
|
|
|
|
def send_prefilled_form(self, prefill_form, page, fields):
|
|
for field_name, new_value in fields.iteritems():
|
|
# Input
|
|
regex = re.compile('(.*)(<input[^>]*? id="%s".*?>)(.*)' % field_name,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match = regex.match(page)
|
|
if not match:
|
|
regex = re.compile('(.*)(<input[^>]*? name="%s".*?>)(.*)' % field_name,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match = regex.match(page)
|
|
if match:
|
|
before, input_field, after = match.groups()
|
|
if 'value="' in input_field.lower():
|
|
regex_sub = re.compile('value=".*?"', re.DOTALL | re.IGNORECASE)
|
|
input_field = regex_sub.sub('value="%s"' % new_value, input_field)
|
|
else:
|
|
input_field = input_field.replace('<input', '<input value="%s"' % new_value)
|
|
page = ''.join([before, input_field, after])
|
|
continue
|
|
|
|
# Textarea
|
|
regex = re.compile('(.*<textarea[^>]*? id="%s".*?>)[^<]*(</textarea>.*)' % field_name,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match = regex.match(page)
|
|
if not match:
|
|
regex = re.compile('(.*<textarea[^>]*? name="%s".*?>)[^<]*(</textarea>.*)' % field_name,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match = regex.match(page)
|
|
if match:
|
|
before, after = match.groups()
|
|
page = ''.join([before, new_value, after])
|
|
continue
|
|
|
|
# Select
|
|
regex = re.compile('(.*<select[^>]*? id="%s".*?>)(.*?)(</select>.*)' % field_name,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match = regex.match(page)
|
|
if not match:
|
|
regex = re.compile('(.*<select[^>]*? name="%s".*?>)(.*?)(</select>.*)' % field_name,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match = regex.match(page)
|
|
if match:
|
|
before, options, after = match.groups()
|
|
# If the option to select is found, first unselect the previoulsy selected one
|
|
regex2 = re.compile('(.*<option[^>]*? value="%s".*?)(>[^<]*</option>.*)' % new_value,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match2 = regex2.match(options)
|
|
if match2:
|
|
before2, after2 = match2.groups()
|
|
regex3 = re.compile('(.*<option[^>]*?)( selected(="selected")?)(.*?>[^<]*</option>.*)',
|
|
re.DOTALL | re.IGNORECASE)
|
|
match3 = regex3.match(options)
|
|
if match3:
|
|
before3, selected, selected_value, after3 = match3.groups()
|
|
options = ''.join([before3, after3])
|
|
regex2 = re.compile('(.*<option[^>]*? value="%s".*?)(>[^<]*</option>.*)' % new_value,
|
|
re.DOTALL | re.IGNORECASE)
|
|
match2 = regex2.match(options)
|
|
if match2:
|
|
before2, after2 = match2.groups()
|
|
options = ''.join([before2, ' selected="selected"', after2])
|
|
|
|
page = ''.join([before, options, after])
|
|
|
|
return page
|
|
|