0002-mdph13-pass-client-ip-to-backend-31445.patch
passerelle/contrib/mdph13/models.py | ||
---|---|---|
84 | 84 |
response.raise_for_status() |
85 | 85 |
return content |
86 | 86 | |
87 |
def call_situation_dossier(self, file_number, secret, dob, email=None): |
|
87 |
def call_situation_dossier(self, file_number, secret, dob, email=None, ip=None):
|
|
88 | 88 |
url = self.situation_dossier_url(file_number) |
89 | 89 |
email = email or 'appel-sans-utilisateur@cd13.fr' |
90 |
content = self.url_get( |
|
91 |
url, |
|
92 |
headers={ |
|
93 |
'X-CD13-Secret': base64.b64encode(secret.encode('utf-8')).decode('ascii'), |
|
94 |
'X-CD13-Email': email, |
|
95 |
'X-CD13-DateNaissBenef': dob.isoformat(), |
|
96 |
}) |
|
90 |
headers = { |
|
91 |
'X-CD13-Secret': base64.b64encode(secret.encode('utf-8')).decode('ascii'), |
|
92 |
'X-CD13-Email': email, |
|
93 |
'X-CD13-DateNaissBenef': dob.isoformat(), |
|
94 |
} |
|
95 |
if ip: |
|
96 |
headers['X-CD13-IP'] = ip |
|
97 |
content = self.url_get(url, headers=headers) |
|
97 | 98 | |
98 | 99 |
data = content.get('data') |
99 | 100 |
if not isinstance(data, dict): |
... | ... | |
199 | 200 |
'description': _('Publik known email'), |
200 | 201 |
'example_value': 'john.doe@example.com', |
201 | 202 |
}, |
203 |
'ip': { |
|
204 |
'description': _('Publik client IP'), |
|
205 |
'example_value': '88.67.23.45', |
|
206 |
}, |
|
202 | 207 |
}) |
203 |
def link(self, request, NameID, numero_dossier, secret, date_de_naissance, email): |
|
208 |
def link(self, request, NameID, numero_dossier, secret, date_de_naissance, email, ip=None):
|
|
204 | 209 |
file_number = numero_dossier.strip() |
205 | 210 |
try: |
206 | 211 |
int(file_number) |
... | ... | |
220 | 225 |
file_number=file_number, |
221 | 226 |
secret=secret, |
222 | 227 |
dob=dob, |
223 |
email=email) |
|
228 |
email=email, |
|
229 |
ip=ip) |
|
224 | 230 |
return {'link_id': link.pk, 'created': created, 'updated': updated} |
225 | 231 | |
226 | 232 |
@endpoint(name='unlink', |
... | ... | |
266 | 272 |
'link_id': { |
267 | 273 |
'description': _('Link identifier'), |
268 | 274 |
'example_value': '1', |
269 |
} |
|
275 |
}, |
|
276 |
'ip': { |
|
277 |
'description': _('Publik client IP'), |
|
278 |
'example_value': '88.67.23.45', |
|
279 |
}, |
|
270 | 280 |
}) |
271 |
def dossiers(self, request, NameID, email, link_id=None): |
|
281 |
def dossiers(self, request, NameID, email, link_id=None, ip=None):
|
|
272 | 282 |
email = email.strip() |
273 | 283 |
if not self.EMAIL_RE.match(email): |
274 | 284 |
raise APIError('email is not valid', http_status=400) |
... | ... | |
291 | 301 |
'err': 0, |
292 | 302 |
} |
293 | 303 |
try: |
294 |
file_data['dossier'] = link.get_file(email=email) |
|
304 |
file_data['dossier'] = link.get_file(email=email, ip=ip)
|
|
295 | 305 |
except Exception as e: |
296 | 306 |
if link_id: |
297 | 307 |
raise |
... | ... | |
328 | 338 |
max_length=128, |
329 | 339 |
blank=True) |
330 | 340 | |
331 |
def get_file(self, email=None): |
|
341 |
def get_file(self, email=None, ip=None):
|
|
332 | 342 |
# email is necessary for audit purpose |
333 | 343 |
mdph_file = self.resource.call_situation_dossier( |
334 | 344 |
file_number=self.file_number, |
335 | 345 |
secret=self.secret, |
336 | 346 |
dob=self.dob, |
337 |
email=email) |
|
347 |
email=email, |
|
348 |
ip=ip) |
|
338 | 349 |
display_name = self._make_display_name(mdph_file) |
339 | 350 |
if self.display_name != display_name: |
340 | 351 |
self.display_name = display_name |
... | ... | |
342 | 353 |
return mdph_file |
343 | 354 | |
344 | 355 |
@classmethod |
345 |
def create_or_update(self, resource, NameID, file_number, secret, dob, email=None): |
|
356 |
def create_or_update(self, resource, NameID, file_number, secret, dob, email=None, ip=None):
|
|
346 | 357 |
# email is necessary for audit purpose |
347 | 358 |
mdph_file = resource.call_situation_dossier( |
348 | 359 |
file_number=file_number, |
349 | 360 |
secret=secret, |
350 | 361 |
dob=dob, |
351 |
email=email) |
|
362 |
email=email, |
|
363 |
ip=ip) |
|
352 | 364 |
display_name = self._make_display_name(mdph_file) |
353 | 365 | |
354 | 366 |
link, created = Link.objects.get_or_create( |
tests/test_mdph13.py | ||
---|---|---|
37 | 37 |
DOB_ISOFORMAT = '1993-05-04' |
38 | 38 |
EMAIL = 'john.doe@example.com' |
39 | 39 |
SECRET = 'secret' |
40 |
IP = '88.34.56.56' |
|
40 | 41 | |
41 | 42 |
VALID_RESPONSE = json.dumps({ |
42 | 43 |
'err': 0, |
... | ... | |
246 | 247 |
assert headers['X-CD13-Secret'] == base64.b64encode(SECRET.encode('utf-8')).decode('ascii') |
247 | 248 |
assert headers['X-CD13-DateNaissBenef'] == '1993-05-04' |
248 | 249 |
assert headers['X-CD13-Email'] == 'appel-sans-utilisateur@cd13.fr' |
250 |
assert 'X-CD13-IP' not in headers |
|
249 | 251 | |
250 | 252 | |
251 |
def test_call_situation_dossier_with_email(mdph13, mock_http): |
|
253 |
def test_call_situation_dossier_with_email_and_ip(mdph13, mock_http):
|
|
252 | 254 |
mock_http.add_response(VALID_RESPONSE) |
253 |
mdph13.call_situation_dossier(1234, SECRET, DOB, email=EMAIL) |
|
255 |
mdph13.call_situation_dossier(1234, SECRET, DOB, email=EMAIL, ip=IP)
|
|
254 | 256 |
request = mock_http.last_request |
255 | 257 |
headers = request.headers |
256 | 258 |
url = request.url |
... | ... | |
258 | 260 |
assert headers['X-CD13-Secret'] == base64.b64encode(SECRET.encode('utf-8')).decode('ascii') |
259 | 261 |
assert headers['X-CD13-DateNaissBenef'] == DOB_ISOFORMAT |
260 | 262 |
assert headers['X-CD13-Email'] == EMAIL |
263 |
assert headers['X-CD13-IP'] == IP |
|
261 | 264 | |
262 | 265 | |
263 | 266 |
def test_check_status_no_link(mdph13): |
... | ... | |
347 | 350 |
assert not Link.objects.count() |
348 | 351 |
response = mdph13.link(request=None, NameID=NAME_ID, |
349 | 352 |
numero_dossier=FILE_NUMBER, secret=SECRET, |
350 |
date_de_naissance=DOB_ISOFORMAT, email=EMAIL) |
|
353 |
date_de_naissance=DOB_ISOFORMAT, email=EMAIL, ip=IP)
|
|
351 | 354 |
link = Link.objects.get() |
352 | 355 |
assert response == { |
353 | 356 |
'link_id': link.pk, |
... | ... | |
423 | 426 |
secret=SECRET, |
424 | 427 |
dob=DOB) |
425 | 428 |
mock_http.add_response(VALID_RESPONSE) |
426 |
response = mdph13.dossiers(None, NAME_ID, EMAIL) |
|
429 |
response = mdph13.dossiers(None, NAME_ID, EMAIL, ip=IP)
|
|
427 | 430 |
assert response['data'] |
428 | 431 |
assert response['data'][0]['id'] == str(link.pk) |
429 | 432 |
assert response['data'][0]['numero_dossier'] == FILE_NUMBER |
... | ... | |
446 | 449 |
secret=SECRET, |
447 | 450 |
dob=DOB) |
448 | 451 |
mock_http.add_response(VALID_RESPONSE) |
449 |
response = mdph13.dossiers(None, NAME_ID, EMAIL, link_id=str(link.pk)) |
|
452 |
response = mdph13.dossiers(None, NAME_ID, EMAIL, link_id=str(link.pk), ip=IP)
|
|
450 | 453 |
assert response['data'] |
451 | 454 |
assert response['data']['id'] == str(link.pk) |
452 | 455 |
assert response['data']['numero_dossier'] == FILE_NUMBER |
... | ... | |
486 | 489 |
assert link2.display_name |
487 | 490 |
mock_http.add_response(VALID_RESPONSE) |
488 | 491 |
mock_http.add_response({'status_code': 500, 'content': ''}) |
489 |
response = mdph13.dossiers(None, NAME_ID, EMAIL) |
|
492 |
response = mdph13.dossiers(None, NAME_ID, EMAIL, ip=IP)
|
|
490 | 493 |
assert response['data'] |
491 | 494 |
assert response['data'][0]['id'] == str(link1.pk) |
492 | 495 |
assert response['data'][0]['err'] == 0 |
... | ... | |
513 | 516 | |
514 | 517 | |
515 | 518 |
def test_dossier_http_error(app, mdph13, mock_http, caplog): |
516 |
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s' |
|
517 |
url = url % (NAME_ID, FILE_NUMBER, DOB, SECRET, EMAIL) |
|
519 |
url = '/mdph13/test1/link/?NameID=%s&numero_dossier=%s&date_de_naissance=%s&secret=%s&email=%s&ip=%s'
|
|
520 |
url = url % (NAME_ID, FILE_NUMBER, DOB, SECRET, EMAIL, IP)
|
|
518 | 521 |
mock_http.add_response({'status_code': 401, 'content': 'wtf', 'reason': 'Authentication required'}) |
519 | 522 |
response = app.post(url, status=500) |
520 | 523 |
assert response.json['err_class'] == 'requests.exceptions.HTTPError' |
521 |
- |