remove iq auth
Remove old iq auth that is replaced by sasl
This commit is contained in:
parent
9d95cbd606
commit
3060e7db20
2 changed files with 155 additions and 103 deletions
|
|
@ -402,22 +402,20 @@ class XMPPAsyncClient:
|
|||
if self.TLSUpgraded == False:
|
||||
# With STARTTLS #https://xmpp.org/rfcs/rfc3920.html
|
||||
self.send(
|
||||
'<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
'<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
)
|
||||
|
||||
else:
|
||||
# Already using TLS send authentication support for iq-auth (fallback) and SASL
|
||||
# Already using TLS send authentication support for SASL
|
||||
self.send(
|
||||
'<stream:features><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
'<stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
)
|
||||
|
||||
else:
|
||||
self.send("</stream>")
|
||||
|
||||
else:
|
||||
if "jabber:iq:auth" in xml.tag: # Handle iq-auth
|
||||
self._handle_iq_auth(xml)
|
||||
elif (
|
||||
if (
|
||||
"urn:ietf:params:xml:ns:xmpp-sasl" in xml.tag
|
||||
): # Handle SASL Auth
|
||||
self._handle_sasl_auth(xml)
|
||||
|
|
@ -486,98 +484,6 @@ class XMPPAsyncClient:
|
|||
except Exception as e:
|
||||
xmppserverlog.exception("{}".format(e))
|
||||
|
||||
def _handle_iq_auth(self, data):
|
||||
try:
|
||||
xml = ET.fromstring(data.decode("utf-8"))
|
||||
ctl = xml[0][0]
|
||||
xmppserverlog.info("IQ AUTH XML: {}".format(xml))
|
||||
# Received username and auth tag, send username/password requirement
|
||||
if (
|
||||
xml.get("type") == "get"
|
||||
and "auth}username" in ctl.tag
|
||||
and self.type == self.UNKNOWN
|
||||
):
|
||||
self.send(
|
||||
'<iq type="result" id="{}"><query xmlns="jabber:iq:auth"><username/><password/></query></iq>'.format(
|
||||
xml.get("id")
|
||||
)
|
||||
)
|
||||
|
||||
# Received username, password, resource - Handle auth here and return pass or fail
|
||||
if (
|
||||
xml.get("type") == "set"
|
||||
and "auth}username" in ctl.tag
|
||||
and self.type == self.UNKNOWN
|
||||
):
|
||||
xmlauth = xml[0].getchildren()
|
||||
# uid = ""
|
||||
password = ""
|
||||
authcode = ""
|
||||
resource = ""
|
||||
for aitem in xmlauth:
|
||||
if "username" in aitem.tag:
|
||||
self.uid = aitem.text
|
||||
|
||||
elif "password" in aitem.tag:
|
||||
password = aitem.text.split("/")[2]
|
||||
authcode = password
|
||||
|
||||
elif "resource" in aitem.tag:
|
||||
self.clientresource = aitem.text
|
||||
resource = self.clientresource
|
||||
|
||||
if self.devclass: # if there is a devclass it is a bot
|
||||
bumper.bot_add("", self.uid, "", resource, "eco-legacy")
|
||||
xmppserverlog.debug("bot authenticated {}".format(self.uid))
|
||||
|
||||
# Client authenticated, move to next state
|
||||
self._set_state("INIT")
|
||||
|
||||
# Successful auth
|
||||
self.send('<iq type="result" id="{}"/>'.format(xml.get("id")))
|
||||
|
||||
else:
|
||||
auth = False
|
||||
if bumper.check_authcode(self.uid, authcode):
|
||||
auth = True
|
||||
elif bumper.use_auth == False:
|
||||
auth = True
|
||||
|
||||
if auth:
|
||||
bumper.client_add(self.uid, "bumper", self.clientresource)
|
||||
xmppserverlog.debug("client authenticated {}".format(self.uid))
|
||||
|
||||
# Client authenticated, move to next state
|
||||
self._set_state("INIT")
|
||||
|
||||
# Successful auth
|
||||
self.send('<iq type="result" id="{}"/>'.format(xml.get("id")))
|
||||
|
||||
else:
|
||||
# Failed auth
|
||||
self.send(
|
||||
'<iq type="error" id="{}"><error code="401" type="auth"><not-authorized xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>'.format(
|
||||
xml.get("id")
|
||||
)
|
||||
)
|
||||
|
||||
except ET.ParseError as e:
|
||||
if "no element found" in e.msg:
|
||||
xmppserverlog.debug(
|
||||
"xml parse error - {} - {}".format(data.decode("utf-8"), e)
|
||||
)
|
||||
elif "not well-formed (invalid token)" in e.msg:
|
||||
xmppserverlog.debug(
|
||||
"xml parse error - {} - {}".format(data.decode("utf-8"), e)
|
||||
)
|
||||
else:
|
||||
xmppserverlog.debug(
|
||||
"xml parse error - {} - {}".format(data.decode("utf-8"), e)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
xmppserverlog.exception("{}".format(e))
|
||||
|
||||
def _handle_sasl_auth(self, xml):
|
||||
try:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ async def test_client_connect_no_starttls(*args, **kwargs):
|
|||
# Server tells client available features
|
||||
assert (
|
||||
mock_send.mock_calls[1].args[0]
|
||||
== '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
== '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
)
|
||||
|
||||
# Reset mock calls
|
||||
|
|
@ -60,6 +60,38 @@ async def test_client_connect_no_starttls(*args, **kwargs):
|
|||
assert xmppclient.state == xmppclient.INIT # Client moved to INIT state
|
||||
|
||||
|
||||
async def test_client_end_stream(*args, **kwargs):
|
||||
test_transport = asyncio.Transport()
|
||||
test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info())
|
||||
test_transport.write = mock.Mock(return_value=return_send_data)
|
||||
xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport)
|
||||
xmppclient.state = xmppclient.CONNECT # Set client state to CONNECT
|
||||
mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data)
|
||||
|
||||
# Send end stream from "client"
|
||||
test_data = "</stream:stream>".encode("utf-8")
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
# Expect 2 calls to send
|
||||
assert mock_send.call_count == 1
|
||||
# Server opens stream
|
||||
assert mock_send.mock_calls[0].args[0] == "</stream:stream>"
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send abnormal stream from "client"
|
||||
test_data = "<badstr />".encode("utf-8")
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send blank from "client"
|
||||
test_data = "".encode("utf-8")
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
|
||||
async def test_client_connect_starttls_called(*args, **kwargs):
|
||||
test_transport = asyncio.Transport()
|
||||
test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info())
|
||||
|
|
@ -84,7 +116,7 @@ async def test_client_connect_starttls_called(*args, **kwargs):
|
|||
# Server tells client available features
|
||||
assert (
|
||||
mock_send.mock_calls[1].args[0]
|
||||
== '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
== '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
)
|
||||
|
||||
# Reset mock calls
|
||||
|
|
@ -117,7 +149,7 @@ async def test_client_connect_starttls_called(*args, **kwargs):
|
|||
# Server tells client available features (without STARTTLS)
|
||||
assert (
|
||||
mock_send.mock_calls[1].args[0]
|
||||
== '<stream:features><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
== '<stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
)
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
|
@ -135,6 +167,80 @@ async def test_client_connect_starttls_called(*args, **kwargs):
|
|||
assert xmppclient.state == xmppclient.INIT # Client moved to INIT state
|
||||
|
||||
|
||||
async def test_client_init(*args, **kwargs):
|
||||
test_transport = asyncio.Transport()
|
||||
test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info())
|
||||
test_transport.write = mock.Mock(return_value=return_send_data)
|
||||
xmppclient = bumper.xmppserver.XMPPAsyncClient(test_transport)
|
||||
xmppclient.state = xmppclient.INIT # Set client state to INIT
|
||||
xmppclient.uid = "fuid_tmpuser"
|
||||
xmppclient.resource = "IOSF53D07BA"
|
||||
xmppclient.bumper_jid = "fuid_tmpuser@ecouser.net/IOSF53D07BA"
|
||||
xmppclient.type = xmppclient.CONTROLLER
|
||||
mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data)
|
||||
|
||||
# Send connect stream from "client"
|
||||
test_data = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' to='ecouser.net'>".encode(
|
||||
"utf-8"
|
||||
)
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
# Expect 2 calls to send
|
||||
assert mock_send.call_count == 2
|
||||
# Server opens stream
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" version="1.0" id="1" from="ecouser.net">'
|
||||
)
|
||||
# Server tells client binds
|
||||
assert (
|
||||
mock_send.mock_calls[1].args[0]
|
||||
== '<stream:features><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>'
|
||||
)
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send bind from "client"
|
||||
test_data = '<iq type="set" id="5E9872D5-547E-49AF-AE51-9EFAA282F952"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>IOSF53D07BA</resource></bind></iq>'.encode(
|
||||
"utf-8"
|
||||
)
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<iq type="result" id="5E9872D5-547E-49AF-AE51-9EFAA282F952"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>fuid_tmpuser@ecouser.net/IOSF53D07BA</jid></bind></iq>'
|
||||
) # client successfully binded
|
||||
assert xmppclient.state == xmppclient.BIND # client moved to BIND state
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send set session from client
|
||||
test_data = '<iq type="set" id="FA1041E7-AA27-43DD-BAA3-64DE2DE56AA3"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>'.encode(
|
||||
"utf-8"
|
||||
)
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
assert xmppclient.state == xmppclient.READY # client moved to READY state
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<iq type="result" id="FA1041E7-AA27-43DD-BAA3-64DE2DE56AA3" />'
|
||||
) # client ready
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Send presense from client
|
||||
test_data = '<presence type="available"/>'.encode("utf-8")
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<presence to="fuid_tmpuser@ecouser.net/IOSF53D07BA"> dummy </presence>'
|
||||
) # client presence - dummy response
|
||||
|
||||
|
||||
async def test_bot_connect(*args, **kwargs):
|
||||
test_transport = asyncio.Transport()
|
||||
test_transport.get_extra_info = mock.Mock(return_value=mock_transport_extra_info())
|
||||
|
|
@ -159,7 +265,7 @@ async def test_bot_connect(*args, **kwargs):
|
|||
# Server tells client available features
|
||||
assert (
|
||||
mock_send.mock_calls[1].args[0]
|
||||
== '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><auth xmlns="http://jabber.org/features/iq-auth"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
== '<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism></mechanisms></stream:features>'
|
||||
)
|
||||
|
||||
# Reset mock calls
|
||||
|
|
@ -187,6 +293,7 @@ async def test_bot_init(*args, **kwargs):
|
|||
xmppclient.state = xmppclient.INIT # Set client state to INIT
|
||||
xmppclient.uid = "E0000000000000001234"
|
||||
xmppclient.devclass = "159"
|
||||
xmppclient.type = xmppclient.BOT
|
||||
mock_send = xmppclient.send = mock.Mock(side_effect=return_send_data)
|
||||
|
||||
# Send connect stream from "bot"
|
||||
|
|
@ -302,12 +409,22 @@ async def test_ping_client_to_client(*args, **kwargs):
|
|||
)
|
||||
xmppclient._parse_data(test_data)
|
||||
|
||||
assert (
|
||||
mock_send2.mock_calls[0].args[0]
|
||||
== '<iq from="E0000000000000001234@159.ecorobot.net/atom" id="104934615" to="fuid_tmpuser@ecouser.net/IOSF53D07BA" type="get"><ping xmlns="urn:xmpp:ping" /></iq>'
|
||||
) # ping response
|
||||
|
||||
# Ping response from bot to user
|
||||
test_data = "<iq type='result' to='E0000000000000001234@159.ecorobot.net/atom' id='104934615'/>".encode(
|
||||
"utf-8"
|
||||
)
|
||||
xmppclient2._parse_data(test_data)
|
||||
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<iq from="fuid_tmpuser@ecouser.net/IOSF53D07BA" id="104934615" to="E0000000000000001234@159.ecorobot.net/atom" type="result" />'
|
||||
) # ping response
|
||||
|
||||
|
||||
async def test_client_send_iq(*args, **kwargs):
|
||||
test_transport = asyncio.Transport()
|
||||
|
|
@ -341,7 +458,7 @@ async def test_client_send_iq(*args, **kwargs):
|
|||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<iq type="error" id="EE0XQ-2"><error type="cancel" code="501"><feature-not-implemented xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>'
|
||||
) # ping response
|
||||
) # feature not implemented response
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
|
@ -373,3 +490,32 @@ async def test_client_send_iq(*args, **kwargs):
|
|||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Bot result
|
||||
test_data = "<iq type='result' from='E0000000000000001234@159.ecorobot.net/atom' to='ecouser.net' id='s2c1'/>".encode(
|
||||
"utf-8"
|
||||
)
|
||||
xmppclient2._parse_data(test_data)
|
||||
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<iq from="E0000000000000001234@159.ecorobot.net/atom" id="s2c1" to="ecouser.net" type="result" />'
|
||||
) # result sent to ecouser.net
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
# Bot iq set
|
||||
test_data = "<iq to='fuid_tmpuser@ecouser.net/IOSF53D07BA' type='set' id='2700'><query xmlns='com:ctl'><ctl td='BatteryInfo'><battery power='100'/></ctl></query></iq>".encode(
|
||||
"utf-8"
|
||||
)
|
||||
xmppclient2._parse_data(test_data)
|
||||
|
||||
assert (
|
||||
mock_send.mock_calls[0].args[0]
|
||||
== '<iq from="E0000000000000001234@159.ecorobot.net/atom" id="2700" to="fuid_tmpuser@ecouser.net/IOSF53D07BA" type="set"><query xmlns="com:ctl"><ctl td="BatteryInfo"><battery power="100" /></ctl></query></iq>'
|
||||
) # result sent to ecouser.net
|
||||
|
||||
# Reset mock calls
|
||||
mock_send.reset_mock()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue