wsse:Nonce and wsu:Created keys not included when Password type is PasswordText
First of all, thank you for you super useful soap module. Nice piece of work!
I'm using version 3.3.1.
My soap server requires my request to include a wsse:Nonce and wsu:Updated key even when the Password type is PasswordText.
Although the username and password are in clear text, the Nonce and created keys are part of WSE Security specification and are meant to allow the server to detect and prevent replay attacks, even when the Password is in clear text. The hashed nonce should be unique per request which the server can store and check for before running another request thus ensuring that a request is not replayed with exactly the same values.
(https://weblog.west-wind.com/posts/2012/nov/24/wcf-wssecurity-and-wse-nonce-authentication)
Could this option be added? As an optional argument when instantiating the Client object (e.g.: use_nonce=True/False).
Thank you! Dieter
Hello, how are you, were you able to solve this problem, I've been having this same problem for weeks and the zeep module works very well but it has very little documentation, or the existing one is often not very clear, to say for this type of inconvenience, I would appreciate it if you managed to solve it the inconvenience tell us how you did it.
I solved the problem this way, I'm not a programmer, I just adapted the class so that it would return the xml in the format you need. this worked for me.
from zeep.wsse import utils import base64 import hashlib import os from zeep import ns
#Esta clase es original de zeep pero la modifique para que me devolviera el xml #con el formato que espera el servicio, username password tex y nonce. class UsernameToken:
username_token_profile_ns = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0" # noqa soap_message_secutity_ns = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0" # noqa
def init( self, username, password=None, password_digest=None, use_digest=False, nonce=None, created=None, timestamp_token=None, zulu_timestamp=None, hash_password=None, ): """ Some SOAP services want zulu timestamps with Z in timestamps and in password digests they may want password to be hashed before adding it to nonce and created. """ self.username = username self.password = password self.password_digest = password_digest self.nonce = nonce self.created = created self.use_digest = use_digest self.timestamp_token = timestamp_token self.zulu_timestamp = zulu_timestamp self.hash_password = hash_password
def apply(self, envelope, headers): security = utils.get_security_header(envelope) # The token placeholder might already exists since it is specified in # the WSDL. token = security.find("{%s}UsernameToken" % ns.WSSE) if token is None: token = utils.WSSE.UsernameToken() security.append(token)
if self.timestamp_token is not None:
security.append(self.timestamp_token)
# Create the sub elements of the UsernameToken element
elements = [utils.WSSE.Username(self.username)]
if self.password is not None or self.password_digest is not None:
if self.use_digest:
pass
else:
elements.extend(self._create_password_digest())
token.extend(elements)
return envelope, headers
def verify(self, envelope): pass
def _create_password_digest(self):
if self.nonce:
nonce = self.nonce.encode("utf-8")
else:
nonce = os.urandom(16)
timestamp = utils.get_timestamp(self.created, self.zulu_timestamp)
if isinstance(self.password, str):
password = self.password.encode("utf-8")
else:
password = self.password
# digest = Base64 ( SHA-1 ( nonce + created + password ) )
if not self.password_digest and self.hash_password:
digest = base64.b64encode(
hashlib.sha1(
nonce + timestamp.encode("utf-8") + hashlib.sha1(password).digest()
).digest()
).decode("ascii")
elif not self.password_digest:
digest = base64.b64encode(
hashlib.sha1(nonce + timestamp.encode("utf-8") + password).digest()
).decode("ascii")
else:
digest = self.password_digest
return [
utils.WSSE.Password(
self.password, Type="%s#PasswordText" % self.username_token_profile_ns
),
utils.WSSE.Nonce(
base64.b64encode(nonce).decode("utf-8"),
EncodingType="%s#Base64Binary" % self.soap_message_secutity_ns,
),
utils.WSU.Created(timestamp),
]