mirror of
https://github.com/progval/irctest.git
synced 2025-04-04 22:39:50 +00:00
Compare commits
6 Commits
dacb4eb517
...
e50cac1a39
Author | SHA1 | Date | |
---|---|---|---|
e50cac1a39 | |||
aaa2e26b6e | |||
052198c61b | |||
9f33633cc7 | |||
465f6637ed | |||
6243908ecc |
@ -1,3 +1,4 @@
|
|||||||
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@ -51,6 +52,8 @@ class BaseHybridController(BaseServerController, DirectoryBasedController):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
ssl_config = ""
|
ssl_config = ""
|
||||||
|
binary_path = shutil.which(self.binary_name)
|
||||||
|
assert binary_path, f"Could not find '{binary_path}' executable"
|
||||||
with self.open_file("server.conf") as fd:
|
with self.open_file("server.conf") as fd:
|
||||||
fd.write(
|
fd.write(
|
||||||
(self.template_config).format(
|
(self.template_config).format(
|
||||||
@ -60,6 +63,7 @@ class BaseHybridController(BaseServerController, DirectoryBasedController):
|
|||||||
services_port=services_port,
|
services_port=services_port,
|
||||||
password_field=password_field,
|
password_field=password_field,
|
||||||
ssl_config=ssl_config,
|
ssl_config=ssl_config,
|
||||||
|
install_prefix=Path(binary_path).parent.parent,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
assert self.directory
|
assert self.directory
|
||||||
|
@ -3,6 +3,9 @@ from typing import Set, Type
|
|||||||
from .base_hybrid import BaseHybridController
|
from .base_hybrid import BaseHybridController
|
||||||
|
|
||||||
TEMPLATE_CONFIG = """
|
TEMPLATE_CONFIG = """
|
||||||
|
module_base_path = "{install_prefix}/lib/ircd-hybrid/modules";
|
||||||
|
.include "./reference.modules.conf"
|
||||||
|
|
||||||
serverinfo {{
|
serverinfo {{
|
||||||
name = "My.Little.Server";
|
name = "My.Little.Server";
|
||||||
sid = "42X";
|
sid = "42X";
|
||||||
|
@ -101,7 +101,7 @@ TEMPLATE_V4_CONFIG = """
|
|||||||
|
|
||||||
# HELP/HELPOP
|
# HELP/HELPOP
|
||||||
<module name="help">
|
<module name="help">
|
||||||
<include file="examples/help.conf.example">
|
<include file="examples/help.example.conf">
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@ -408,6 +408,7 @@ class SableController(BaseServerController, DirectoryBasedController):
|
|||||||
],
|
],
|
||||||
cwd=self.directory,
|
cwd=self.directory,
|
||||||
preexec_fn=os.setsid,
|
preexec_fn=os.setsid,
|
||||||
|
env={"RUST_BACKTRACE": "1", **os.environ},
|
||||||
)
|
)
|
||||||
self.pgroup_id = os.getpgid(self.proc.pid)
|
self.pgroup_id = os.getpgid(self.proc.pid)
|
||||||
|
|
||||||
@ -485,6 +486,7 @@ class SableServicesController(BaseServicesController):
|
|||||||
],
|
],
|
||||||
cwd=self.server_controller.directory,
|
cwd=self.server_controller.directory,
|
||||||
preexec_fn=os.setsid,
|
preexec_fn=os.setsid,
|
||||||
|
env={"RUST_BACKTRACE": "1", **os.environ},
|
||||||
)
|
)
|
||||||
self.pgroup_id = os.getpgid(self.proc.pid)
|
self.pgroup_id = os.getpgid(self.proc.pid)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import base64
|
import base64
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from irctest import cases, runner, scram
|
from irctest import cases, runner, scram
|
||||||
from irctest.numerics import ERR_SASLFAIL, RPL_LOGGEDIN, RPL_SASLMECHS
|
from irctest.numerics import ERR_SASLFAIL, RPL_LOGGEDIN, RPL_SASLMECHS
|
||||||
@ -11,8 +12,34 @@ class RegistrationTestCase(cases.BaseServerTestCase):
|
|||||||
self.controller.registerUser(self, "testuser", "mypassword")
|
self.controller.registerUser(self, "testuser", "mypassword")
|
||||||
|
|
||||||
|
|
||||||
@cases.mark_services
|
class _BaseSasl(cases.BaseServerTestCase):
|
||||||
class SaslTestCase(cases.BaseServerTestCase):
|
sasl_ir: bool
|
||||||
|
capabilities: List[str]
|
||||||
|
|
||||||
|
def _doInitialExchange(self, client, mechanism: str, chunk: str):
|
||||||
|
"""Does the initial C->S, S->C, C->S exchange.
|
||||||
|
|
||||||
|
With ``sasl_ir=False``, this is done with the usual three messages exchange
|
||||||
|
(``AUTHENTICATE <mechanism>``, ``AUTHENTICATE +``, ``AUTHENTICATE <chunk>``)
|
||||||
|
with ``sasl_ir=True``, this is done in a single C->S message
|
||||||
|
(``AUTHENTICATE <mechanism> <chunk>``)
|
||||||
|
|
||||||
|
See the [sasl-ir spec](https://github.com/ircv3/ircv3-specifications/pull/520)
|
||||||
|
"""
|
||||||
|
if self.sasl_ir:
|
||||||
|
self.sendLine(client, f"AUTHENTICATE {mechanism} {chunk}")
|
||||||
|
else:
|
||||||
|
self.sendLine(client, f"AUTHENTICATE {mechanism}")
|
||||||
|
m = self.getRegistrationMessage(1)
|
||||||
|
self.assertMessageMatch(
|
||||||
|
m,
|
||||||
|
command="AUTHENTICATE",
|
||||||
|
params=["+"],
|
||||||
|
fail_msg=f"Sent “AUTHENTICATE {mechanism}”, server should have "
|
||||||
|
f"replied with “AUTHENTICATE +”, but instead sent: {{msg}}",
|
||||||
|
)
|
||||||
|
self.sendLine(client, f"AUTHENTICATE {chunk}")
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
@cases.mark_specifications("IRCv3")
|
||||||
@cases.skipUnlessHasMechanism("PLAIN")
|
@cases.skipUnlessHasMechanism("PLAIN")
|
||||||
def testPlain(self):
|
def testPlain(self):
|
||||||
@ -34,17 +61,8 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
capabilities["sasl"],
|
capabilities["sasl"],
|
||||||
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
self.sendLine(1, "AUTHENTICATE PLAIN")
|
self._doInitialExchange(1, "PLAIN", "amlsbGVzAGppbGxlcwBzZXNhbWU=")
|
||||||
m = self.getRegistrationMessage(1)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, server should have "
|
|
||||||
"replied with “AUTHENTICATE +”, but instead sent: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(1, "AUTHENTICATE amlsbGVzAGppbGxlcwBzZXNhbWU=")
|
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
m,
|
m,
|
||||||
@ -88,17 +106,8 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
).decode()
|
).decode()
|
||||||
self.controller.registerUser(self, "foo", password)
|
self.controller.registerUser(self, "foo", password)
|
||||||
self.addClient()
|
self.addClient()
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
self.sendLine(1, "AUTHENTICATE PLAIN")
|
self._doInitialExchange(1, "PLAIN", authstring)
|
||||||
m = self.getRegistrationMessage(1)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, server should have "
|
|
||||||
"replied with “AUTHENTICATE +”, but instead sent: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(1, "AUTHENTICATE " + authstring)
|
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
m,
|
m,
|
||||||
@ -148,17 +157,8 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
capabilities["sasl"],
|
capabilities["sasl"],
|
||||||
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
self.sendLine(1, "AUTHENTICATE PLAIN")
|
self._doInitialExchange(1, "PLAIN", "AGppbGxlcwBzZXNhbWU=")
|
||||||
m = self.getRegistrationMessage(1)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, server should have "
|
|
||||||
"replied with “AUTHENTICATE +”, but instead sent: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(1, "AUTHENTICATE AGppbGxlcwBzZXNhbWU=")
|
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
self.assertMessageMatch(
|
self.assertMessageMatch(
|
||||||
m,
|
m,
|
||||||
@ -184,8 +184,11 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
capabilities,
|
capabilities,
|
||||||
fail_msg="Does not have SASL as the controller claims.",
|
fail_msg="Does not have SASL as the controller claims.",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
self.sendLine(1, "AUTHENTICATE FOO")
|
if self.sasl_ir:
|
||||||
|
self.sendLine(1, "AUTHENTICATE FOO AGppbGxlcwBzZXNhbWU=")
|
||||||
|
else:
|
||||||
|
self.sendLine(1, "AUTHENTICATE FOO")
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
while m.command == RPL_SASLMECHS:
|
while m.command == RPL_SASLMECHS:
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
@ -235,17 +238,8 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
capabilities["sasl"],
|
capabilities["sasl"],
|
||||||
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
self.sendLine(1, "AUTHENTICATE PLAIN")
|
self._doInitialExchange(1, "PLAIN", authstring[0:400])
|
||||||
m = self.getRegistrationMessage(1)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, expected "
|
|
||||||
"“AUTHENTICATE +” as a response, but got: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(1, "AUTHENTICATE {}".format(authstring[0:400]))
|
|
||||||
self.sendLine(1, "AUTHENTICATE {}".format(authstring[400:]))
|
self.sendLine(1, "AUTHENTICATE {}".format(authstring[400:]))
|
||||||
|
|
||||||
self.confirmSuccessfulAuth()
|
self.confirmSuccessfulAuth()
|
||||||
@ -305,17 +299,8 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
capabilities["sasl"],
|
capabilities["sasl"],
|
||||||
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
fail_msg="Does not have PLAIN mechanism as the controller " "claims",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
self.sendLine(1, "AUTHENTICATE PLAIN")
|
self._doInitialExchange(1, "PLAIN", authstring)
|
||||||
m = self.getRegistrationMessage(1)
|
|
||||||
self.assertMessageMatch(
|
|
||||||
m,
|
|
||||||
command="AUTHENTICATE",
|
|
||||||
params=["+"],
|
|
||||||
fail_msg="Sent “AUTHENTICATE PLAIN”, expected "
|
|
||||||
"“AUTHENTICATE +” as a response, but got: {msg}",
|
|
||||||
)
|
|
||||||
self.sendLine(1, "AUTHENTICATE {}".format(authstring))
|
|
||||||
self.sendLine(1, "AUTHENTICATE +")
|
self.sendLine(1, "AUTHENTICATE +")
|
||||||
|
|
||||||
self.confirmSuccessfulAuth()
|
self.confirmSuccessfulAuth()
|
||||||
@ -324,6 +309,12 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
# I don't know how to do it, because it would make the registration
|
# I don't know how to do it, because it would make the registration
|
||||||
# message's length too big for it to be valid.
|
# message's length too big for it to be valid.
|
||||||
|
|
||||||
|
|
||||||
|
@cases.mark_services
|
||||||
|
class SaslTestCase(_BaseSasl):
|
||||||
|
sasl_ir = False
|
||||||
|
capabilities = ["sasl"]
|
||||||
|
|
||||||
@cases.mark_specifications("IRCv3")
|
@cases.mark_specifications("IRCv3")
|
||||||
@cases.skipUnlessHasMechanism("SCRAM-SHA-256")
|
@cases.skipUnlessHasMechanism("SCRAM-SHA-256")
|
||||||
def testScramSha256Success(self):
|
def testScramSha256Success(self):
|
||||||
@ -344,7 +335,7 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
fail_msg="Does not have SCRAM-SHA-256 mechanism as the "
|
fail_msg="Does not have SCRAM-SHA-256 mechanism as the "
|
||||||
"controller claims",
|
"controller claims",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
|
|
||||||
self.sendLine(1, "AUTHENTICATE SCRAM-SHA-256")
|
self.sendLine(1, "AUTHENTICATE SCRAM-SHA-256")
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
@ -400,7 +391,7 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
fail_msg="Does not have SCRAM-SHA-256 mechanism as the "
|
fail_msg="Does not have SCRAM-SHA-256 mechanism as the "
|
||||||
"controller claims",
|
"controller claims",
|
||||||
)
|
)
|
||||||
self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=False)
|
self.requestCapabilities(1, self.capabilities, skip_if_cap_nak=False)
|
||||||
|
|
||||||
self.sendLine(1, "AUTHENTICATE SCRAM-SHA-256")
|
self.sendLine(1, "AUTHENTICATE SCRAM-SHA-256")
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
@ -430,3 +421,36 @@ class SaslTestCase(cases.BaseServerTestCase):
|
|||||||
)
|
)
|
||||||
m = self.getRegistrationMessage(1)
|
m = self.getRegistrationMessage(1)
|
||||||
self.assertMessageMatch(m, command=ERR_SASLFAIL)
|
self.assertMessageMatch(m, command=ERR_SASLFAIL)
|
||||||
|
|
||||||
|
|
||||||
|
@cases.mark_services
|
||||||
|
class SaslIrTestCase(_BaseSasl):
|
||||||
|
"""Tests SASL with clients requesting the
|
||||||
|
[sasl-ir](https://github.com/ircv3/ircv3-specifications/pull/520) cap and using it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sasl_ir = True
|
||||||
|
capabilities = ["sasl", "draft/sasl-ir"]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.connectClient(
|
||||||
|
"capgetter", capabilities=["draft/sasl-ir"], skip_if_cap_nak=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@cases.mark_services
|
||||||
|
class ImplicitSaslIrTestCase(_BaseSasl):
|
||||||
|
"""Tests SASL with clients using the
|
||||||
|
[sasl-ir](https://github.com/ircv3/ircv3-specifications/pull/520) CAP without
|
||||||
|
requesting it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
sasl_ir = True
|
||||||
|
capabilities = ["sasl"]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.connectClient(
|
||||||
|
"capgetter", capabilities=["draft/sasl-ir"], skip_if_cap_nak=True
|
||||||
|
)
|
||||||
|
Reference in New Issue
Block a user