Python Zeep.Client SOAP Request con Header custom-adicional

willy_chaos

Hola a todos, estoy peleándome con el cliente SOAP desde Python y me encuentro con que no consigo generar correctamente el XML que se envía.

Os pongo un ejemplo de código que se debería generar (el correcto extraído del SOAP UI, obviamente cambiando los datos de credenciales)

Peticion SOAP UI

Codigo en Python (Django) que genera la peticion SOAP

Codigo Python

XML Generado por Python

<soap-env:Envelope xmlns:soap-env="http://www.w3.org/2003/05/soap-envelope">
	<soap-env:Header>
		<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
			<wsse:UsernameToken>
				<wsse:Username>developer_user</wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">miPasswordEnTextoPlano</wsse:Password>
			</wsse:UsernameToken>
		</wsse:Security>
	</soap-env:Header>
	<soap-env:Body>
		<ns0:consultarCodiProjecteMDMInput xmlns:ns0="https://services.dev.midominio.edu/soa/servei/MDMCodisProjectes/v01_00">
			<ns0:idMDM>100045976</ns0:idMDM>
		</ns0:consultarCodiProjecteMDMInput>
	</soap-env:Body>
</soap-env:Envelope>

Estoy mirandome el PDF https://buildmedia.readthedocs.org/media/pdf/python-zeep/master/python-zeep.pdf donde en la pagina 18 indica lo siguiente

from zeep import xsd
header = xsd.Element(
 '{http://test.python-zeep.org}auth',xsd.ComplexType([
  xsd.Element(
  '{http://test.python-zeep.org}username',
  xsd.String()),
  ])
)
header_value = header(username='mvantellingen')
client.service.Method(_soapheaders=[header_value])

pero no termino de ver exactamente como he de poner los datos para que se traduzca al XML que debería ser, ayer intente hacer una prueba pero nanai.

  • Añadir en el header el formato correcto del UsernameToken y la cabecera headerMDMPeticio con todo el contenido dentro.
  • Añadir en el body el usosDada con todo su contenido.

Si le hago una petición a saco, metiendo todo el XML en una String y poniendo los valores que me interesan, funciona. Pero claro la idea es usar zeep para generar las peticiones.

willy_chaos

nadie??? joer no me creo que ningun developer de MV no se haya tenido que pelear con SOAP

B

nunca he usado python para hacer peticiones soap.

tampoco nunca he creado cabeceras personalizadas.

por cierto, felicidades al campeón que ha echo ese wsdl. Como que no tiene mucho sentido esas cabeceras? usuariConnectat si es el mismo que Username, sobra totalmente, y sino ese nombre es muy malo. El rolUsuariConnectat lo mismo, qué sentido tiene que tú especifiques el rol? Me puedo poner admin así como así? Los roles deberían de estar mapeados en el servidor, invisibles para el cliente.

Jo programo en català, programo sense vergonya.


ésto no funciona

id_service = '100045976'
soapDataUserPass = {'Username':'developer_user','Password':'miPasswordEnTextoPlano'}
print(soapClient.service.consultarCodiProjecteMDM(id_service,soapDataUsosDada))

porque le tienes que pasar la estructura correctamente digo yo, tal como lo indica en el ejemplo + el body

1 respuesta
willy_chaos

#3 respecto a lo de catalán... enfin...

no soy quien ha hecho el wsdl pero aun asi, que mas da? si el campo se llama usuariConnectat o se llama usuarioConectado

respecto a las cabeceras custom, pues he intentado cosillas tal como indica el pdf , pero nade de nada :/ y son obligatorias de enviar.

En otros lenguajes si envío la petición en RAW, funciona, pero claro tengo que gestionar yo el parsing de XML para saber si ha habido error o no, y quiero evitarme todo eso...

Simplemente me falta esto, pero bueno seguiré peleandome con ello a ver si lo saco . no creo que sea el primero al que le pasa...

1 respuesta
B

es cuestión de saber cómo construir los headers y hacer bien la llamada

mirate la respuesta de éste: https://stackoverflow.com/questions/42963114/python-zeep-soap-complex-header

#4willy_chaos:

no soy quien ha hecho el wsdl pero aun asi, que mas da? si el campo se llama usuariConnectat o se llama usuarioConectado

estaba puntualizando el mal diseño del wsdl, o a ti no te sorprende que hayan dos campos que sirvan para lo mismo?? y con un nombre mejor no me refiero que este en castellano, sino que describa bien su verdadera función. Pero vamos, que tampoco te toca a ti cambiarlo, pero sí deberías de criticarlo y hacerlo saber a tus superiores

1 respuesta
willy_chaos

#5 Ese link que has pasado de Stackoverflow es lo que estuve probando y la verdad o no he sabido hacerlo (ya ves tu, es seguir los pasos...) , pero no me ha funcionado :/, aun así, este martes volveré a intentarlo.

#5oldFox-64:

que hayan dos campos que sirvan para lo mismo??

Realmente no sirven para lo mismo.

El usuario y password es quien tiene definidos realmente los permisos para llamar (crear, actualizar, eliminar, listar) al Service.

El usuariConnectat es mas bien porque esto va a ser integrado en una Intranet, y lo que se quiere, es saber quien ha realizado la petición desde la intranet, y el rol que tenia seleccionado dentro de la intranet (como digo, es a modo meramente informativo) puesto quien tiene permisos para hacer llamadas a ciertos ¿endpoint? es el username.

Solo que yo al copiar aqui la peticion XML o el codigo Python, he puesto en ambos campos el mismo usuario (para ahorrar tiempo)

willy_chaos

Bueno voy haciendo avances, aunque algo dummies pero me van sirviendo. Así que lo voy poniendo aquí para si alguien se encuentra en la misma situación. Para crear las cabeceras he hecho uso del siguiente código

header = xsd.Element(
  'headerMDMPeticio',xsd.ComplexType([
		xsd.Element('idSistemaOrigen',xsd.String()),
		xsd.Element(
			'headerMidominio',xsd.ComplexType([
				xsd.Element('usuariConnectat',xsd.String()),
				xsd.Element('rolUsuariConnectat',xsd.String())
			])
		)
	])
)
#Bindeamos los datos a la cabecera
header_value = header(idSistemaOrigen='1',headerMidominio={'usuariConnectat':'usuarioIntranet','rolUsuariConnectat':'rolIntranet'})

Con esto ya se genera bien la cabecera, pero no se generaban en el UsernameToken los campos Nonce, y Created, así que antes de realizar la creacion del Client hice lo siguiente:

usernameToken = UsernameToken('usuarioOSB','miPasswordEnTextoPlano')
usernameToken.use_digest=True
soapClient = Client(url_wsdl,wsse=usernameToken)

Finalmente para realizar la llamada hago uso

response = soapClient.service.consultarCodiProjecteMDM( _soapheaders=[header_value],idMDM=id_service )

Ahora unicamente se me queja de que los headers que he añadido han de ser "Qualified" vease, han de contener el v01:headerMDMPeticio con lo cual me estoy peleando.

Usuarios habituales