iparapheur: resolv no basic_authentication on w3.org (#31274)

This commit is contained in:
Nicolas Roche 2019-03-08 12:08:19 +01:00
parent ac5172e542
commit 00211a4cc8
3 changed files with 140 additions and 7 deletions

View File

@ -85,6 +85,8 @@ class IParapheur(BaseResource, HTTPResource):
raise APIError('ServiceError: %s' % exc)
except TransportError as exc:
raise APIError('Transport Error: %s' % exc)
except TypeError as exc:
raise APIError('Type Error: %s' % exc)
return result
@endpoint(perm='can_access')
@ -142,12 +144,12 @@ class IParapheur(BaseResource, HTTPResource):
}
if email:
parameters['EmailEmetteur'] = email
rep = soap_client.service.CreerDossier(**parameters)
if not rep or not rep.MessageRetour:
resp = soap_client.service.CreerDossier(**parameters)
if not resp or not resp.MessageRetour:
raise FileError('unknown error, no response')
if rep.MessageRetour.codeRetour == 'KO':
raise FileError(rep.MessageRetour.message)
return {'data': {'RecordId': rep.DossierID, 'message': rep.MessageRetour.message}}
if resp.MessageRetour.codeRetour == 'KO':
raise FileError(resp.MessageRetour.message)
return {'data': {'RecordId': resp.DossierID, 'message': resp.MessageRetour.message}}
@endpoint(perm='can_access', name='get-file', pattern='(?P<file_id>[\w-]+)')
def get_file(self, request, file_id, appendix=None):

View File

@ -24,6 +24,7 @@ import warnings
from requests import Session as RequestSession, Response as RequestResponse
from requests.structures import CaseInsensitiveDict
from urllib3.exceptions import InsecureRequestWarning
from django.utils.six.moves.urllib import parse as urlparse
from django.conf import settings
from django.core.cache import cache
@ -288,14 +289,31 @@ class Request(RequestSession):
log_http_request(self.logger, request=request, response=response, exception=exception, error_log=error_log)
class SOAPTransport(Transport):
"""Wrapper around zeep.Transport
disable basic_authentication hosts unrelated to wsdl's endpoints
"""
def __init__(self, wsdl_url, **kwargs):
self.wsdl_host = urlparse.urlparse(wsdl_url).netloc
super(SOAPTransport, self).__init__(**kwargs)
def _load_remote_data(self, url):
if urlparse.urlparse(url).netloc != self.wsdl_host:
response = self.session.get(url, timeout=self.load_timeout, auth=None, cert=None)
response.raise_for_status()
return response.content
return super(SOAPTransport, self)._load_remote_data(url)
class SOAPClient(Client):
"""Wrapper around zeep.Client
resource muste have a wsdl_url and a requests attribute
"""
def __init__(self, resource, **kwargs):
transport = Transport(session=resource.requests, cache=InMemoryCache())
wsdl_url = kwargs.pop('wsdl_url', None) or resource.wsdl_url
transport = SOAPTransport(wsdl_url, session=resource.requests, cache=InMemoryCache())
super(SOAPClient, self).__init__(wsdl_url, transport=transport, **kwargs)

View File

@ -54,8 +54,9 @@ def iph_mocked_get(url, params=None, **kwargs):
if url == 'https://secure-iparapheur.demonstrations.adullact.org:443/ws-iparapheur?wsdl':
target_file = wsdl_file()
# simulate second GET call (nested <xsd:import> into wsdl fil)
# simulate second GET call (nested <xsd:import> into wsdl file)
elif url == 'http://www.w3.org/2005/05/xmlmime':
assert kwargs['auth'] is None # no basic_authenticton on wsdl' imports
target_file = xmlmime()
else:
@ -98,6 +99,7 @@ def test_create_file(mocked_post, mocked_get, app, conn):
typ = 'Courrier'
subtyp = 'maire'
visibility = 'SERVICE'
email = 'alice.boniadetos@arf.pt'
response = Response()
response.status_code = 200
@ -155,6 +157,32 @@ def test_create_file(mocked_post, mocked_get, app, conn):
assert 'zeep.exceptions.TransportError' in resp.json['err_class']
assert 'Server returned HTTP status 200 (<nada>)' in resp.json['err_desc']
# Unknown value for "visibility"
data = {'type': typ, 'subtype': subtyp, 'visibility': 'UNKNOWN_VISIBILITY',
'title': title, 'data': base64_data, 'content-type':'application/pdf'}
url = reverse('generic-endpoint', kwargs={'connector': 'iparapheur',
'endpoint': 'create-file', 'slug': conn.slug})
url += '?apikey=%s' % API_KEY
resp = app.post_json(url, params=data, status=500)
assert resp.json['err'] == 1
assert 'FileError' in resp.json['err_class']
# OK, providing email
data = {'type': typ, 'subtype': subtyp, 'visibility': visibility,
'title': title, 'data': base64_data, 'content-type':'application/pdf',
'email': email}
url = reverse('generic-endpoint', kwargs={'connector': 'iparapheur',
'endpoint': 'create-file', 'slug': conn.slug})
url += '?apikey=%s' % API_KEY
soap_response = """<nada>"""
response._content = soap_response
mocked_post.return_value = response
resp = app.post_json(url, params=data, status=500)
assert (BASE_URL,) == mocked_post.call_args[0]
assert resp.json['err'] == 1
assert 'zeep.exceptions.TransportError' in resp.json['err_class']
assert 'Server returned HTTP status 200 (<nada>)' in resp.json['err_desc']
@mock.patch('passerelle.utils.Request.get', side_effect=iph_mocked_get)
@mock.patch('passerelle.utils.Request.post')
def test_files(mocked_post, mocked_get, app, conn):
@ -175,6 +203,18 @@ def test_files(mocked_post, mocked_get, app, conn):
assert item['id']
assert item['timestamp']
# same call providing parameter
soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><RechercherDossiersResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"><LogDossier><timestamp>2015-10-29T15:42:08.732+01:00</timestamp><nom>test</nom><status>Lu</status><annotation></annotation><accessible>KO</accessible></LogDossier></RechercherDossiersResponse></S:Body></S:Envelope>"""
response._content = soap_response
mocked_post.return_value = response
url += '&status=Lu'
resp = app.get(url)
assert len(resp.json['data']) == 1
for item in resp.json['data']:
assert item['status']
assert item['id']
assert item['timestamp']
@mock.patch('passerelle.utils.Request.get', side_effect=iph_mocked_get)
@mock.patch('passerelle.utils.Request.post')
def test_get_file_status(mocked_post, mocked_get, app, conn):
@ -428,3 +468,76 @@ def test_call_wsdl_connectionerror(mocked_get, app, conn):
assert resp.json['err'] == 1
assert resp.json['data'] is None
assert 'mocked error' in resp.json['err_desc']
@mock.patch('passerelle.utils.Request.get')
@mock.patch('zeep.Transport._load_remote_data')
@mock.patch('passerelle.utils.Request.post')
def test_no_auth_on_wsdl_imports(mocked_post, mocked_load, mocked_get, app, conn):
"""
While getting wsdl:
- zeep.Transport._load_remote_data is call on basic_authentication (get wsdl file)
- passerelle.utils.Request.get is call on no basic_authenticaion (get xmlmime import's file)
Notice: this also test the 'echo' SOAP service
"""
response_xmlmime, response_post = Response(), Response()
response_xmlmime.status_code, response_post.status_code = 200, 200
response_xmlmime._content=file(xmlmime()).read()
response_post._content = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><echoResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime">[publik_test] m'a dit: &quot;ping&quot;!</echoResponse></S:Body></S:Envelope>
"""
mocked_load.return_value = file(wsdl_file()).read()
mocked_get.return_value = response_xmlmime
mocked_post.return_value = response_post
url = reverse('generic-endpoint', kwargs={'connector': 'iparapheur',
'endpoint': 'ping', 'slug': conn.slug})
resp = app.get(url, status=403)
url += '?apikey=%s' % API_KEY
resp = app.get(url)
assert resp.json['err'] == 0
assert resp.json['data'] == "[publik_test] m'a dit: \"ping\"!"
@mock.patch('passerelle.utils.Request.get', side_effect=iph_mocked_get)
@mock.patch('passerelle.utils.Request.post')
def test_types(mocked_post, mocked_get, app, conn):
"""test GetListeTypesRequest SOAP service"""
response = Response()
response.status_code = 200
# empty list of types as response
soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><GetListeTypesResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"/></S:Body></S:Envelope>"""
response._content = soap_response
mocked_post.return_value = response
url = reverse('generic-endpoint', kwargs={'slug': conn.slug, 'connector': 'iparapheur',
'endpoint': 'types'})
url += '?apikey=%s' % API_KEY
resp = app.get(url)
assert resp.json['err'] == 0
assert resp.json['data'] == []
@mock.patch('passerelle.utils.Request.get', side_effect=iph_mocked_get)
@mock.patch('passerelle.utils.Request.post')
def test_subtypes(mocked_post, mocked_get, app, conn):
"""test GetListeSousTypes SOAP service"""
response = Response()
response.status_code = 200
# error: no parameter provided
url = reverse('generic-endpoint', kwargs={'slug': conn.slug, 'connector': 'iparapheur',
'endpoint': 'subtypes'})
resp = app.get(url, status=403)
url += '?apikey=%s' % API_KEY
resp = app.get(url)
assert resp.json['err'] == 1
assert resp.json['err_desc'] == "Type Error: TypeTechnique() takes exactly 1 argument (0 given). Simple types expect only a single value argument"
# providing a type as parameter
soap_response = """<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><GetListeTypesResponse xmlns="http://www.adullact.org/spring-ws/iparapheur/1.0" xmlns:xmime="http://www.w3.org/2005/05/xmlmime"/></S:Body></S:Envelope>"""
response._content = soap_response # empty list of subtypes as response
mocked_post.return_value = response
url += '&type=my_unknown_type'
resp = app.get(url)
assert resp.json['err'] == 0
assert resp.json['data'] == []