1
|
import os
|
2
|
import sys
|
3
|
import re
|
4
|
|
5
|
try:
|
6
|
import lasso
|
7
|
except ImportError:
|
8
|
print >> sys.stderr, 'Missing Lasso module, IdWsf 2.0 support disabled'
|
9
|
else:
|
10
|
if not lasso.WSF_SUPPORT:
|
11
|
print >> sys.stderr, 'Found Lasso module, but IdWsf 2.0 support not enabled'
|
12
|
|
13
|
from quixote import get_publisher, get_session, get_request, get_response, redirect
|
14
|
from quixote.directory import Directory
|
15
|
|
16
|
from qommon.liberty import SOAPException, soap_call
|
17
|
from qommon import template
|
18
|
from qommon.misc import http_get_page
|
19
|
|
20
|
import misc
|
21
|
from form_prefill import FormPrefill
|
22
|
from field_prefill import FieldPrefill
|
23
|
|
24
|
def cleanup_html_value(value):
|
25
|
# Ensure the field value can be properly integrated in HTML code
|
26
|
value = value.replace('"', "'")
|
27
|
# Conversion to iso-8859-1
|
28
|
try:
|
29
|
value = unicode(value, 'utf-8').encode('iso-8859-1')
|
30
|
except UnicodeEncodeError:
|
31
|
return None
|
32
|
|
33
|
class IdWsf2(Directory):
|
34
|
_q_exports = []
|
35
|
|
36
|
def _q_lookup(self, component):
|
37
|
if not hasattr(get_session(), 'prefill_form'):
|
38
|
get_session().prefill_form = component
|
39
|
get_session().after_url = get_request().get_url()
|
40
|
if get_request().get_query():
|
41
|
get_session().after_url += '?' + get_request().get_query()
|
42
|
return redirect('../saml/login')
|
43
|
else:
|
44
|
prefill_form = FormPrefill.get(get_session().prefill_form)
|
45
|
del get_session().prefill_form
|
46
|
if prefill_form:
|
47
|
try:
|
48
|
response, status, page, auth_header = http_get_page(prefill_form.url)
|
49
|
except:
|
50
|
return template.error_page(_('Failed connecting to the original site.'))
|
51
|
try:
|
52
|
fields = self.do_prefill_form(prefill_form)
|
53
|
if not fields:
|
54
|
raise lasso.Error
|
55
|
for key, value in get_request().get_fields().iteritems():
|
56
|
value = cleanup_html_value(value)
|
57
|
if value:
|
58
|
fields[key] = value
|
59
|
except lasso.Error:
|
60
|
return page + '<script type="text/javascript">alert("%s")</script>' % \
|
61
|
_('Failed getting attributes from the attribute provider.')
|
62
|
except:
|
63
|
return page + '<script type="text/javascript">alert("%s")</script>' % \
|
64
|
_('Failed getting attributes for an unknown reason.')
|
65
|
|
66
|
return self.send_prefilled_form(prefill_form, page, fields)
|
67
|
|
68
|
def do_prefill_form(self, prefill_form):
|
69
|
server = misc.get_lasso_server(protocol = 'saml2')
|
70
|
disco = lasso.IdWsf2Discovery(server)
|
71
|
if not get_session().lasso_session_dumps or not get_session().lasso_session_dumps[server.providerId]:
|
72
|
return None
|
73
|
disco.setSessionFromDump(get_session().lasso_session_dumps[server.providerId])
|
74
|
|
75
|
disco.initQuery()
|
76
|
disco.addRequestedServiceType(prefill_form.profile)
|
77
|
disco.buildRequestMsg()
|
78
|
|
79
|
try:
|
80
|
soap_answer = soap_call(disco.msgUrl, disco.msgBody)
|
81
|
except SOAPException:
|
82
|
return None
|
83
|
disco.processQueryResponseMsg(soap_answer)
|
84
|
|
85
|
service = disco.getService()
|
86
|
lasso.registerIdWsf2DstService(prefill_form.prefix, prefill_form.profile)
|
87
|
|
88
|
service.initQuery()
|
89
|
|
90
|
fields = FieldPrefill.select(lambda x: x.form_id == prefill_form.id)
|
91
|
for field in fields:
|
92
|
if field.xpath and field.name:
|
93
|
service.addQueryItem(field.xpath, field.name)
|
94
|
|
95
|
service.buildRequestMsg()
|
96
|
|
97
|
try:
|
98
|
soap_answer = soap_call(service.msgUrl, service.msgBody)
|
99
|
except SOAPException:
|
100
|
return None
|
101
|
service.processQueryResponseMsg(soap_answer)
|
102
|
|
103
|
fields_dict = {}
|
104
|
for field in fields:
|
105
|
if not field.xpath or not field.name:
|
106
|
continue
|
107
|
if field.number > 0:
|
108
|
number = field.number -1
|
109
|
try:
|
110
|
if field.raw_xml:
|
111
|
value = service.getAttributeNodes(field.name)[number]
|
112
|
else:
|
113
|
value = service.getAttributeStrings(field.name)[number]
|
114
|
except (IndexError, TypeError):
|
115
|
value = ''
|
116
|
# Log
|
117
|
if value:
|
118
|
# Regexp transformation
|
119
|
if field.regexp_match:
|
120
|
value = re.sub(field.regexp_match, field.regexp_replacing, value)
|
121
|
value = cleanup_html_value(value)
|
122
|
# Conversion of select field options
|
123
|
if field.select_options:
|
124
|
try:
|
125
|
value = field.select_options[value]
|
126
|
except (IndexError, KeyError):
|
127
|
pass
|
128
|
if not value:
|
129
|
continue
|
130
|
fields_dict[field.name] = value
|
131
|
|
132
|
return fields_dict
|
133
|
|
134
|
def send_prefilled_form(self, prefill_form, page, fields):
|
135
|
for field_name, new_value in fields.iteritems():
|
136
|
# Input
|
137
|
regex = re.compile('(.*)(<input[^>]*? id="%s".*?>)(.*)' % field_name,
|
138
|
re.DOTALL | re.IGNORECASE)
|
139
|
match = regex.match(page)
|
140
|
if not match:
|
141
|
regex = re.compile('(.*)(<input[^>]*? name="%s".*?>)(.*)' % field_name,
|
142
|
re.DOTALL | re.IGNORECASE)
|
143
|
match = regex.match(page)
|
144
|
if match:
|
145
|
before, input_field, after = match.groups()
|
146
|
if 'value="' in input_field.lower():
|
147
|
regex_sub = re.compile('value=".*?"', re.DOTALL | re.IGNORECASE)
|
148
|
input_field = regex_sub.sub('value="%s"' % new_value, input_field)
|
149
|
else:
|
150
|
input_field = input_field.replace('<input', '<input value="%s"' % new_value)
|
151
|
page = ''.join([before, input_field, after])
|
152
|
continue
|
153
|
|
154
|
# Textarea
|
155
|
regex = re.compile('(.*<textarea[^>]*? id="%s".*?>)[^<]*(</textarea>.*)' % field_name,
|
156
|
re.DOTALL | re.IGNORECASE)
|
157
|
match = regex.match(page)
|
158
|
if not match:
|
159
|
regex = re.compile('(.*<textarea[^>]*? name="%s".*?>)[^<]*(</textarea>.*)' % field_name,
|
160
|
re.DOTALL | re.IGNORECASE)
|
161
|
match = regex.match(page)
|
162
|
if match:
|
163
|
before, after = match.groups()
|
164
|
page = ''.join([before, new_value, after])
|
165
|
continue
|
166
|
|
167
|
# Select
|
168
|
regex = re.compile('(.*<select[^>]*? id="%s".*?>)(.*?)(</select>.*)' % field_name,
|
169
|
re.DOTALL | re.IGNORECASE)
|
170
|
match = regex.match(page)
|
171
|
if not match:
|
172
|
regex = re.compile('(.*<select[^>]*? name="%s".*?>)(.*?)(</select>.*)' % field_name,
|
173
|
re.DOTALL | re.IGNORECASE)
|
174
|
match = regex.match(page)
|
175
|
if match:
|
176
|
before, options, after = match.groups()
|
177
|
# If the option to select is found, first unselect the previoulsy selected one
|
178
|
regex2 = re.compile('(.*<option[^>]*? value="%s".*?)(>[^<]*</option>.*)' % new_value,
|
179
|
re.DOTALL | re.IGNORECASE)
|
180
|
match2 = regex2.match(options)
|
181
|
if match2:
|
182
|
before2, after2 = match2.groups()
|
183
|
regex3 = re.compile('(.*<option[^>]*?)( selected(="selected")?)(.*?>[^<]*</option>.*)',
|
184
|
re.DOTALL | re.IGNORECASE)
|
185
|
match3 = regex3.match(options)
|
186
|
if match3:
|
187
|
before3, selected, selected_value, after3 = match3.groups()
|
188
|
options = ''.join([before3, after3])
|
189
|
regex2 = re.compile('(.*<option[^>]*? value="%s".*?)(>[^<]*</option>.*)' % new_value,
|
190
|
re.DOTALL | re.IGNORECASE)
|
191
|
match2 = regex2.match(options)
|
192
|
if match2:
|
193
|
before2, after2 = match2.groups()
|
194
|
options = ''.join([before2, ' selected="selected"', after2])
|
195
|
|
196
|
page = ''.join([before, options, after])
|
197
|
|
198
|
return page
|
199
|
|