Projet

Général

Profil

0002-mdph13-pass-client-ip-to-backend-31445.patch

Benjamin Dauvergne, 15 mars 2019 11:17

Télécharger (8,83 ko)

Voir les différences:

Subject: [PATCH 2/2] mdph13: pass client ip to backend (#31445)

 passerelle/contrib/mdph13/models.py | 46 ++++++++++++++++++-----------
 tests/test_mdph13.py                | 19 +++++++-----
 2 files changed, 40 insertions(+), 25 deletions(-)
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
-