diff --git a/README.md b/README.md index ec7a506..727a58a 100644 --- a/README.md +++ b/README.md @@ -107,21 +107,10 @@ To launch the servers you can use the provided Docker Compose file. Just [install Docker](https://www.docker.com/get-started/) and run: ``` -docker-compose up -d +docker compose up -d ``` -**Note:** ejabberd takes around *ten minutes* to start. - -### Vagrant (Deprecated) - -To launch the servers you can use the provided Vagrant box. -Just [install Vagrant](https://www.vagrantup.com/downloads) and run: - -``` -vagrant up -``` - -After some minutes you'll have the runnig server instances inside of a virtual machine. +**Note:** ejabberd takes up to *twenty minutes* to start. ### RUN diff --git a/Vagrantfile b/Vagrantfile deleted file mode 100644 index c4acc12..0000000 --- a/Vagrantfile +++ /dev/null @@ -1,147 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -Vagrant.require_version ">= 1.6.0" - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - # All Vagrant configuration is done here. The most common configuration - # options are documented and commented below. For a complete reference, - # please see the online documentation at vagrantup.com. - - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = "ubuntu/xenial64" - - # Disable automatic box update checking. If you disable this, then - # boxes will only be checked for updates when the user runs - # `vagrant box outdated`. This is not recommended. - # config.vm.box_check_update = false - - # Create a forwarded port mapping which allows access to a specific port - # within the machine from a port on the host machine. In the example below, - # accessing "localhost:8080" will access port 80 on the guest machine. - # config.vm.network "forwarded_port", guest: 80, host: 8080 - config.vm.network "forwarded_port", guest: 15222, host: 15222 - config.vm.network "forwarded_port", guest: 11110, host: 11110 - - # Message after `vagrant up` - config.vm.post_up_message = < /dev/null" - - # Install ejabberd for integration tests by bash script - config.vm.provision "shell" do |s| - s.path = "tests/provisioner/install_ejabberd.sh" - s.args = ["testuser", "testpass"] - end - - # Install dovecot for integration tests by bash script - config.vm.provision "shell" do |s| - s.path = "tests/provisioner/install_dovecot.sh" - s.args = ["vmail", "pass"] - end - - # Enable provisioning with CFEngine. CFEngine Community packages are - # automatically installed. For example, configure the host as a - # policy server and optionally a policy file to run: - # - # config.vm.provision "cfengine" do |cf| - # cf.am_policy_hub = true - # # cf.run_file = "motd.cf" - # end - # - # You can also configure and bootstrap a client to an existing - # policy server: - # - # config.vm.provision "cfengine" do |cf| - # cf.policy_server_address = "10.0.2.15" - # end - - # Enable provisioning with Puppet stand alone. Puppet manifests - # are contained in a directory path relative to this Vagrantfile. - # You will need to create the manifests directory and a manifest in - # the file default.pp in the manifests_path directory. - # - # config.vm.provision "puppet" do |puppet| - # puppet.manifests_path = "manifests" - # puppet.manifest_file = "default.pp" - # end - - # Enable provisioning with chef solo, specifying a cookbooks path, roles - # path, and data_bags path (all relative to this Vagrantfile), and adding - # some recipes and/or roles. - # - # config.vm.provision "chef_solo" do |chef| - # chef.cookbooks_path = "../my-recipes/cookbooks" - # chef.roles_path = "../my-recipes/roles" - # chef.data_bags_path = "../my-recipes/data_bags" - # chef.add_recipe "mysql" - # chef.add_role "web" - # - # # You may also specify custom JSON attributes: - # chef.json = { mysql_password: "foo" } - # end - - # Enable provisioning with chef server, specifying the chef server URL, - # and the path to the validation key (relative to this Vagrantfile). - # - # The Opscode Platform uses HTTPS. Substitute your organization for - # ORGNAME in the URL and validation key. - # - # If you have your own Chef Server, use the appropriate URL, which may be - # HTTP instead of HTTPS depending on your configuration. Also change the - # validation key to validation.pem. - # - # config.vm.provision "chef_client" do |chef| - # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" - # chef.validation_key_path = "ORGNAME-validator.pem" - # end - # - # If you're using the Opscode platform, your validator client is - # ORGNAME-validator, replacing ORGNAME with your organization name. - # - # If you have your own Chef Server, the default validation client name is - # chef-validator, unless you changed the configuration. - # - # chef.validation_client_name = "ORGNAME-validator" -end diff --git a/behat.yml b/behat.yml index b513678..351c69a 100644 --- a/behat.yml +++ b/behat.yml @@ -3,14 +3,14 @@ default: authentication_features: paths: [ "%paths.base%/tests/features/" ] contexts: - - Fabiang\Sasl\Behat\XmppContext: + - Fabiang\Sasl\Behat\XMPPContext: - localhost - 15222 - - ubuntu-xenial + - localhost - testuser - testpass - "%paths.base%/tests/log/features/" - - Fabiang\Sasl\Behat\Pop3Context: + - Fabiang\Sasl\Behat\POP3Context: - localhost - 11110 - vmail diff --git a/docker-compose.yml b/docker-compose.yml index 21f07d9..fe3c79c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,28 +1,14 @@ version: '3' services: xmpp: - image: rroemhild/ejabberd:18.12 - hostname: ubuntu-xenial + image: ejabberd/ecs:${EJABBERD_VERSION:-23.10} volumes: - - "./tests/config/ejabberd/ejabberd.yml.tpl:/opt/ejabberd/conf/ejabberd.yml.tpl" - - "./tests/config/ejabberd/ejabberd.db:/opt/ejabberd/database/ejabberd.db" - environment: - - XMPP_DOMAIN=ubuntu-xenial - - "EJABBERD_USERS=testuser@ubuntu-xenial:testpass admin@ubuntu-xenial" - - EJABBERD_ADMINS=admin@ubuntu-xenial - - TZ=Europe/Berlin - - EJABBERD_STARTTLS=false - - EJABBERD_S2S_SSL=false - - EJABBERD_SKIP_MAKE_SSLCERT=true - - EJABBERD_LOGLEVEL=5 - - EJABBERD_DEBUG_MODE=true - - EJABBERD_AUTH_METHOD=sql - - EJABBERD_AUTH_PASSWORD_FORMAT=plain - - EJABBERD_CONFIGURE_ODBC=true - - EJABBERD_ODBC_TYPE=sqlite - - EJABBERD_ODBC_DATABASE=/opt/ejabberd/database/ejabberd.db + - "./tests/config/ejabberd/ejabberd.yml:/home/ejabberd/conf/ejabberd.yml" + - "./tests/config/ejabberd/ejabberd.db:/home/ejabberd/database/ejabberd.db" ports: - "15222:5222" + environment: + - CTL_ON_CREATE=register testuser localhost testpass mail: image: dovecot/dovecot:2.3.18 diff --git a/src/Authentication/SCRAM.php b/src/Authentication/SCRAM.php index 9283d2d..7499aa3 100644 --- a/src/Authentication/SCRAM.php +++ b/src/Authentication/SCRAM.php @@ -76,7 +76,7 @@ public function __construct(Options $options, $hash) // Though I could be strict, I will actually also accept the naming used in the PHP core hash framework. // For instance "sha1" is accepted, while the registered hash name should be "SHA-1". - $normalizedHash = str_replace('-', '', strtolower($hash)); + $normalizedHash = strtolower(preg_replace('#^sha-(\d+)#i', 'sha\1', $hash)); $hashAlgos = hash_algos(); if (!in_array($normalizedHash, $hashAlgos)) { diff --git a/tests/config/ejabberd/ejabberd.yml b/tests/config/ejabberd/ejabberd.yml new file mode 100644 index 0000000..d55e939 --- /dev/null +++ b/tests/config/ejabberd/ejabberd.yml @@ -0,0 +1,240 @@ +### +### ejabberd configuration file +### +### The parameters used in this configuration file are explained at +### +### https://docs.ejabberd.im/admin/configuration +### +### The configuration file is written in YAML. +### ******************************************************* +### ******* !!! WARNING !!! ******* +### ******* YAML IS INDENTATION SENSITIVE ******* +### ******* MAKE SURE YOU INDENT SECTIONS CORRECTLY ******* +### ******************************************************* +### Refer to http://en.wikipedia.org/wiki/YAML for the brief description. +### + +hosts: + - localhost + +loglevel: debug + +## If you already have certificates, list them here +# certfiles: +# - /etc/letsencrypt/live/domain.tld/fullchain.pem +# - /etc/letsencrypt/live/domain.tld/privkey.pem + +listen: + - + port: 5222 + ip: "::" + module: ejabberd_c2s + max_stanza_size: 262144 + shaper: c2s_shaper + access: c2s + starttls_required: false +# - +# port: 5223 +# ip: "::" +# module: ejabberd_c2s +# max_stanza_size: 262144 +# shaper: c2s_shaper +# access: c2s +# tls: true +# - +# port: 5269 +# ip: "::" +# module: ejabberd_s2s_in +# max_stanza_size: 524288 +# shaper: s2s_shaper +# - +# port: 5443 +# ip: "::" +# module: ejabberd_http +# tls: true +# request_handlers: +# /admin: ejabberd_web_admin +# /api: mod_http_api +# /bosh: mod_bosh +# /captcha: ejabberd_captcha +# /upload: mod_http_upload +# /ws: ejabberd_http_ws +# - +# port: 5280 +# ip: "::" +# module: ejabberd_http +# request_handlers: +# /admin: ejabberd_web_admin +# /.well-known/acme-challenge: ejabberd_acme + - + port: 3478 + ip: "::" + transport: udp + module: ejabberd_stun + use_turn: true + ## The server's public IPv4 address: + # turn_ipv4_address: "203.0.113.3" + ## The server's public IPv6 address: + # turn_ipv6_address: "2001:db8::3" + - + port: 1883 + ip: "::" + module: mod_mqtt + backlog: 1000 + +s2s_use_starttls: optional + +acl: + local: + user_regexp: "" + loopback: + ip: + - 127.0.0.0/8 + - ::1/128 + +access_rules: + local: + allow: local + c2s: + deny: blocked + allow: all + announce: + allow: admin + configure: + allow: admin + muc_create: + allow: local + pubsub_createnode: + allow: local + trusted_network: + allow: loopback + +api_permissions: + "console commands": + from: + - ejabberd_ctl + who: all + what: "*" + "admin access": + who: + access: + allow: + - acl: loopback + - acl: admin + oauth: + scope: "ejabberd:admin" + access: + allow: + - acl: loopback + - acl: admin + what: + - "*" + - "!stop" + - "!start" + "public commands": + who: + ip: 127.0.0.1/8 + what: + - status + - connected_users_number + +shaper: + normal: + rate: 3000 + burst_size: 20000 + fast: 100000 + +shaper_rules: + max_user_sessions: 10 + max_user_offline_messages: + 5000: admin + 100: all + c2s_shaper: + none: admin + normal: all + s2s_shaper: fast + +modules: + mod_adhoc: {} + mod_admin_extra: {} + mod_announce: + access: announce + mod_avatar: {} + mod_blocking: {} + mod_bosh: {} + mod_caps: {} + mod_carboncopy: {} + mod_client_state: {} + mod_configure: {} + mod_disco: {} + mod_fail2ban: {} + mod_http_api: {} + mod_http_upload: + put_url: https://@HOST@:5443/upload + custom_headers: + "Access-Control-Allow-Origin": "https://@HOST@" + "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS" + "Access-Control-Allow-Headers": "Content-Type" + mod_last: {} + mod_mam: + ## Mnesia is limited to 2GB, better to use an SQL backend + ## For small servers SQLite is a good fit and is very easy + ## to configure. Uncomment this when you have SQL configured: + ## db_type: sql + assume_mam_usage: true + default: always + mod_mqtt: {} + mod_muc: + access: + - allow + access_admin: + - allow: admin + access_create: muc_create + access_persistent: muc_create + access_mam: + - allow + default_room_options: + mam: true + mod_muc_admin: {} + mod_offline: + access_max_user_messages: max_user_offline_messages + mod_ping: {} + mod_privacy: {} + mod_private: {} + mod_proxy65: + access: local + max_connections: 5 + mod_pubsub: + access_createnode: pubsub_createnode + plugins: + - flat + - pep + force_node_config: + ## Avoid buggy clients to make their bookmarks public + storage:bookmarks: + access_model: whitelist + mod_push: {} + mod_push_keepalive: {} + mod_register: + ## Only accept registration requests from the "trusted" + ## network (see access_rules section above). + ## Think twice before enabling registration from any + ## address. See the Jabber SPAM Manifesto for details: + ## https://github.com/ge0rg/jabber-spam-fighting-manifesto + ip_access: trusted_network + mod_roster: + versioning: true + mod_s2s_dialback: {} + mod_shared_roster: {} + mod_stream_mgmt: + resend_on_timeout: if_offline + mod_stun_disco: {} + mod_vcard: {} + mod_vcard_xupdate: {} + mod_version: + show_os: false + +### Local Variables: +### mode: yaml +### End: +### vim: set filetype=yaml tabstop=8 diff --git a/tests/config/ejabberd/ejabberd.yml.tpl b/tests/config/ejabberd/ejabberd.yml.tpl deleted file mode 100644 index bf88f72..0000000 --- a/tests/config/ejabberd/ejabberd.yml.tpl +++ /dev/null @@ -1,579 +0,0 @@ -### UPDATED VERSION OF CONFIGURATION FILE -### FULL DIFF IS HERE https://editor.mergely.com/7eL4SHnR/ -### - - - - -### -### ejabberd configuration file -### -### - -### The parameters used in this configuration file are explained in more detail -### in the ejabberd Installation and Operation Guide. -### Please consult the Guide in case of doubts, it is included with -### your copy of ejabberd, and is also available online at -### http://www.process-one.net/en/ejabberd/docs/ - -### ======= -### LOGGING - -loglevel: {{ env['EJABBERD_LOGLEVEL'] or 4 }} -log_rotate_size: 10485760 -log_rotate_count: 0 - -## watchdog_admins: -## - "bob@example.com" - -### ================ -### SERVED HOSTNAMES - -hosts: -{%- for xmpp_domain in env['XMPP_DOMAIN'].split() %} - - "{{ xmpp_domain }}" -{%- endfor %} - -## -## route_subdomains: Delegate subdomains to other XMPP servers. -## For example, if this ejabberd serves example.org and you want -## to allow communication with an XMPP server called im.example.org. -## -## route_subdomains: s2s - -### =============== -### LISTENING PORTS - -listen: - - - port: 5222 - module: ejabberd_c2s - {%- if env['EJABBERD_STARTTLS'] == "true" %} - starttls_required: true - {%- endif %} - protocol_options: - - "no_sslv2" - - "no_sslv3" - {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1', "false") == "false" %} - - "no_tlsv1" - {%- endif %} - {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1_1', "true") == "false" %} - - "no_tlsv1_1" - {%- endif %} - - "cipher_server_preference" - max_stanza_size: 65536 - shaper: c2s_shaper - access: c2s - tls_compression: false - ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" - {%- if env.get('EJABBERD_DHPARAM', false) == "true" %} - dhfile: "/opt/ejabberd/ssl/dh.dhpem" - {%- endif %} - - - port: 5223 - module: ejabberd_c2s - {%- if env['EJABBERD_STARTTLS'] == "true" %} - tls: true - {%- endif %} - protocol_options: - - "no_sslv2" - - "no_sslv3" - {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1', "false") == "false" %} - - "no_tlsv1" - {%- endif %} - {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1_1', "false") == "false" %} - - "no_tlsv1_1" - {%- endif %} - - "cipher_server_preference" - max_stanza_size: 65536 - shaper: c2s_shaper - access: c2s - tls_compression: false - ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" - {%- if env.get('EJABBERD_DHPARAM', false) == "true" %} - dhfile: "/opt/ejabberd/ssl/dh.dhpem" - {%- endif %} - - - port: 5269 - module: ejabberd_s2s_in - {%- if env['EJABBERD_S2S_SSL'] == "true" %} - - - port: 5270 - module: ejabberd_s2s_in - tls: true - {% endif %} - - - port: 4560 - module: ejabberd_xmlrpc - #api_permissions: - # configure: - # all: [] - - - - - port: 5280 - module: ejabberd_http - request_handlers: - "/websocket": ejabberd_http_ws - ## "/pub/archive": mod_http_fileserver - web_admin: true - http_bind: true - ## register: true - {%- if env.get('EJABBERD_CAPTCHA', false) == "true" %} - captcha: true - {% endif %} - {%- if env['EJABBERD_HTTPS'] == "true" %} - tls: true - tls_compression: false - ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" - {%- if env.get('EJABBERD_DHPARAM', "false") == "true" %} - dhfile: "/opt/ejabberd/ssl/dh.dhpem" - {%- endif %} - {% endif %} - - -{%- if env.get('EJABBERD_STUN', "false") == "true" %} - port: 3478 - module: ejabberd_stun - auth_realm: "{{ env['XMPP_DOMAIN'] }}" - {%- if env.get('EJABBERD_TURN_IP') %} - use_turn: true - ## The server's public IPv4 address: - turn_ipv4_address: {{ env.get('EJABBERD_TURN_IP') }} - {%- endif %} - - - port: 3478 - transport: udp - module: ejabberd_stun - auth_realm: "{{ env['XMPP_DOMAIN'] }}" - {%- if env.get('EJABBERD_TURN_IP') %} - use_turn: true - ## The server's public IPv4 address: - turn_ipv4_address: {{ env.get('EJABBERD_TURN_IP') }} - {%- endif %} - - - port: 5349 - transport: tcp - module: ejabberd_stun - tls: true - auth_realm: "{{ env['XMPP_DOMAIN'] }}" - {%- if env.get('EJABBERD_TURN_IP') %} - use_turn: true - ## The server's public IPv4 address: - turn_ipv4_address: {{ env.get('EJABBERD_TURN_IP') }} - {%- endif %} - - -{%- endif %} - port: 5443 - module: ejabberd_http - request_handlers: - "": mod_http_upload - {%- if env['EJABBERD_HTTPS'] == "true" %} - tls: true - tls_compression: false - ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" - {%- if env.get('EJABBERD_DHPARAM', false) == "true" %} - dhfile: "/opt/ejabberd/ssl/dh.dhpem" - {%- endif %} - {% endif %} - - -### CERTIFICATES -### ================ -certfiles: - - "/opt/ejabberd/ssl/*.pem" - -### SERVER TO SERVER -### ================ - -{%- if env['EJABBERD_S2S_SSL'] == "true" %} -s2s_use_starttls: required -s2s_protocol_options: - - "no_sslv2" - - "no_sslv3" - {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1', "false") == "false" %} - - "no_tlsv1" - {%- endif %} - {%- if env.get('EJABBERD_PROTOCOL_OPTIONS_TLSV1_1', "true") == "false" %} - - "no_tlsv1_1" - {%- endif %} - - "cipher_server_preference" -s2s_ciphers: "{{ env.get('EJABBERD_CIPHERS', 'HIGH:!aNULL:!3DES') }}" -{%- if env.get('EJABBERD_DHPARAM', false) == "true" %} -s2s_dhfile: "/opt/ejabberd/ssl/dh.dhpem" -{%- endif %} -{% endif %} - -### ============== -### AUTHENTICATION - -auth_method: -{%- for auth_method in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} - - {{ auth_method }} -{%- endfor %} - -auth_password_format: {{ env.get('EJABBERD_AUTH_PASSWORD_FORMAT', 'scram') }} - -{%- if 'anonymous' in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} -anonymous_protocol: both -allow_multiple_connections: true -{%- endif %} - - -## LDAP authentication - -{%- if 'ldap' in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} - -ldap_servers: -{%- for ldap_server in env.get('EJABBERD_LDAP_SERVERS', 'internal').split() %} - - "{{ ldap_server }}" -{%- endfor %} - -ldap_encrypt: {{ env.get('EJABBERD_LDAP_ENCRYPT', 'none') }} -ldap_tls_verify: {{ env.get('EJABBERD_LDAP_TLS_VERIFY', 'false') }} - -{%- if env['EJABBERD_LDAP_TLS_CACERTFILE'] %} -ldap_tls_cacertfile: "{{ env['EJABBERD_LDAP_TLS_CACERTFILE'] }}" -{%- endif %} - -ldap_tls_depth: {{ env.get('EJABBERD_LDAP_TLS_DEPTH', 1) }} - -{%- if env['EJABBERD_LDAP_PORT'] %} -ldap_port: {{ env['EJABBERD_LDAP_PORT'] }} -{%- endif %} - -{%- if env['EJABBERD_LDAP_ROOTDN'] %} -ldap_rootdn: "{{ env['EJABBERD_LDAP_ROOTDN'] }}" -{%- endif %} - -{%- if env['EJABBERD_LDAP_PASSWORD'] %} -ldap_password: "{{ env['EJABBERD_LDAP_PASSWORD'] }}" -{%- endif %} - -ldap_deref_aliases: {{ env.get('EJABBERD_LDAP_DEREF_ALIASES', 'never') }} -ldap_base: "{{ env['EJABBERD_LDAP_BASE'] }}" - -{%- if env['EJABBERD_LDAP_UIDS'] %} -ldap_uids: -{%- for ldap_uid in env['EJABBERD_LDAP_UIDS'].split() %} - "{{ ldap_uid.split(':')[0] }}": "{{ ldap_uid.split(':')[1] }}" -{%- endfor %} -{%- endif %} - -{%- if env['EJABBERD_LDAP_FILTER'] %} -ldap_filter: "{{ env['EJABBERD_LDAP_FILTER'] }}" -{%- endif %} - -{%- if env['EJABBERD_LDAP_DN_FILTER'] %} -ldap_dn_filter: -{%- for dn_filter in env['EJABBERD_LDAP_DN_FILTER'].split() %} - "{{ dn_filter.split(':')[0] }}": ["{{ dn_filter.split(':')[1] }}"] -{%- endfor %} -{%- endif %} - -{%- endif %} - -{%- if 'external' in env.get('EJABBERD_AUTH_METHOD', 'internal').split() %} - {%- if env['EJABBERD_EXTAUTH_PROGRAM'] %} -extauth_program: "{{ env['EJABBERD_EXTAUTH_PROGRAM'] }}" - {%- endif %} - {%- if env['EJABBERD_EXTAUTH_INSTANCES'] %} -extauth_instances: {{ env['EJABBERD_EXTAUTH_INSTANCES'] }} - {%- endif %} - {%- if 'internal' in env.get('EJABBERD_AUTH_METHOD').split() %} -extauth_cache: false - {%- elif env['EJABBERD_EXTAUTH_CACHE'] %} -extauth_cache: {{ env['EJABBERD_EXTAUTH_CACHE'] }} - {%- endif %} -{% endif %} - -### =============== -### TRAFFIC SHAPERS - -shaper: - normal: - rate: 10000 - burst_size: 30000 - fast: 100000 - -### ==================== -### ACCESS CONTROL LISTS - -acl: - admin: - user: - {%- if env['EJABBERD_ADMINS'] %} - {%- for admin in env['EJABBERD_ADMINS'].split() %} - - "{{ admin.split('@')[0] }}": "{{ admin.split('@')[1] }}" - {%- endfor %} - {%- else %} - - "admin": "{{ env['XMPP_DOMAIN'].split()[0] }}" - {%- endif %} - local: - user_regexp: "" - -### ============ -### ACCESS RULES - -access_rules: - ## This rule allows access only for local users: - local: - allow: local - ## Only non-blocked users can use c2s connections: - c2s: - deny: blocked - allow: all - ## Only admins can send announcement messages: - announce: - allow: admin - ## Only admins can use the configuration interface: - configure: - allow: admin - ## Admins of this server are also admins of the MUC service: - muc_admin: - allow: admin - ## Only accounts of the local ejabberd server, or only admins can create rooms, depending on environment variable: - muc_create: - {%- if env['EJABBERD_MUC_CREATE_ADMIN_ONLY'] == "true" %} - allow: admin - {% else %} - allow: local - {% endif %} - ## All users are allowed to use the MUC service: - muc: - allow: all - ## Only accounts on the local ejabberd server can create Pubsub nodes: - pubsub_createnode: - allow: local - ## In-band registration allows registration of any possible username. - register: - {%- if env['EJABBERD_REGISTER_ADMIN_ONLY'] == "true" %} - deny: all - allow: admin - {% else %} - deny: all - {% endif %} - ## Only allow to register from localhost - trusted_network: - allow: loopback - -### ============ -### SHAPER RULES - -shaper_rules: - ## Maximum number of simultaneous sessions allowed for a single user: - max_user_sessions: 10 - ## Maximum number of offline messages that users can have: - max_user_offline_messages: - 5000 : admin - 100 : all - ## For C2S connections, all users except admins use the "normal" shaper - c2s_shaper: - none: admin - normal: all - ## All S2S connections use the "fast" shaper - s2s_shaper: fast - soft_upload_quota: - - {{ env.get('EJABBERD_SOFT_UPLOAD_QUOTA', 400) }} : all # MiB - hard_upload_quota: - - {{ env.get('EJABBERD_HARD_UPLOAD_QUOTA', 500) }} : all # MiB - -language: "en" - -### ======= -### MODULES - -modules: - mod_adhoc: {} - {% if env.get('EJABBERD_MOD_ADMIN_EXTRA', "true") == "true" %} - mod_admin_extra: {} - {% endif %} - mod_announce: # recommends mod_adhoc - access: announce - mod_blocking: {} # requires mod_privacy - mod_bosh: {} - mod_caps: {} - mod_carboncopy: {} - mod_client_state: - queue_chat_states: true - queue_presence: false - mod_configure: {} # requires mod_adhoc - mod_disco: {} - ## mod_echo: {} - ## mod_http_fileserver: - ## docroot: "/var/www" - ## accesslog: "/var/log/ejabberd/access.log" - mod_http_upload: - docroot: "/opt/ejabberd/upload" - {%- if env['EJABBERD_HTTPS'] == "true" %} - put_url: "https://@HOST@:5443" - {%- else %} - put_url: "http://@HOST@:5443" - {% endif %} - mod_http_upload_quota: - max_days: {{ env.get('EJABBERD_UPLOAD_QUOTA_MAX_DAYS', 10) }} - mod_last: {} - mod_mam: - default: always - use_cache: true - compress_xml: true - mod_muc: - host: "conference.@HOST@" - access: muc - access_create: muc_create - access_persistent: muc_create - access_admin: muc_admin - history_size: 500 - default_room_options: - persistent: true - mam : true - {%- if env['EJABBERD_MOD_MUC_ADMIN'] == "true" %} - mod_muc_admin: {} - {% endif %} - ## mod_muc_log: {} - ## mod_multicast: {} - mod_offline: - access_max_user_messages: max_user_offline_messages - mod_ping: {} - ## mod_pres_counter: - ## count: 5 - ## interval: 60 - mod_privacy: {} - mod_private: {} - mod_proxy65: - host: "proxy.@HOST@" - name: "File Transfer Proxy" - port: 5277 - mod_pubsub: - access_createnode: pubsub_createnode - force_node_config: - "eu.siacs.conversations.axolotl.*": - access_model: open - ## reduces resource comsumption, but XEP incompliant - # ignore_pep_from_offline: true - ## XEP compliant, but increases resource comsumption - ignore_pep_from_offline: false - last_item_cache: true - plugins: - - "flat" - - "pep" # pep requires mod_caps - mod_push: {} - mod_push_keepalive: {} - mod_register: - {%- if env.get('EJABBERD_CAPTCHA', false) == "true" %} - ## - ## Protect In-Band account registrations with CAPTCHA. - ## - captcha_protected: true - {% endif %} - - ## - ## Set the minimum informational entropy for passwords. - ## - ## password_strength: 32 - - ## - ## After successful registration, the user receives - ## a message with this subject and body. - ## - welcome_message: - subject: "Welcome!" - body: |- - Hi. - Welcome to this XMPP server. - - ## - ## Only clients in the server machine can register accounts - ## - {%- if env.get('EJABBERD_REGISTER_TRUSTED_NETWORK_ONLY', "true") == "true" %} - ip_access: trusted_network - {% endif %} - - access: register - mod_roster: - versioning: true - mod_s2s_dialback: {} - mod_shared_roster: {} - mod_stats: {} - mod_stream_mgmt: - resend_on_timeout: if_offline -{%- if env.get('EJABBERD_STUN', "false") == "true" %} - mod_stun_disco: - secret: "{{ env.get('EJABBERD_STUN_DISCO_SECRET', 'it-is-secret') }}" - services: - - - host: {{ env.get('EJABBERD_TURN_IP') }} # Your coturn's public address. - port: 3478 - type: stun - transport: udp - restricted: false - - - host: {{ env.get('EJABBERD_TURN_IP') }} # Your coturn's public address. - port: 3478 - type: turn - transport: udp - restricted: true - - - host: stun.@HOST@ # Your coturn's public address. - port: 5349 - type: stuns - transport: tcp - restricted: false - - - host: turn.@HOST@ # Your coturn's public address. - port: 5349 - type: turns - transport: tcp - restricted: true -{%- endif %} - mod_time: {} - #mod_avatar: {} - mod_vcard: {} - {%- if env.get('EJABBERD_MOD_VERSION', "true") == "true" %} - mod_version: - show_os: false - {%- endif %} - -### ============ -### HOST CONFIG - -{%- if env['EJABBERD_CONFIGURE_ODBC'] == "true" %} -### ==================== -### ODBC DATABASE CONFIG -sql_type: {{ env['EJABBERD_ODBC_TYPE'] }} -sql_server: "{{ env['EJABBERD_ODBC_SERVER'] }}" -sql_database: "{{ env['EJABBERD_ODBC_DATABASE'] }}" -sql_username: "{{ env['EJABBERD_ODBC_USERNAME'] }}" -sql_password: "{{ env['EJABBERD_ODBC_PASSWORD'] }}" -# sql_keepalive_interval: "{{ env.get('EJABBERD_ODBC_KEEPALIVE_INTERVAL', 60) }}" - -default_db: sql -{% endif %} - -{%- if env['EJABBERD_DEFAULT_DB'] is defined %} -default_db: {{ env['EJABBERD_DEFAULT_DB'] }} -{% endif %} - -### ===================== -### SESSION MANAGEMENT DB -sm_db_type: {{ env['EJABBERD_SESSION_DB'] or "mnesia" }} - -{%- if env['EJABBERD_CONFIGURE_REDIS'] == "true" %} -### ==================== -### REDIS DATABASE CONFIG -redis_server: {{ env['EJABBERD_REDIS_SERVER'] or "localhost" }} -redis_port: {{ env['EJABBERD_REDIS_PORT'] or 6379 }} -{%- if env['EJABBERD_REDIS_PASSWORD'] is defined %} -redis_password: {{ env['EJABBERD_REDIS_PASSWORD'] }} -{% endif %} -redis_db: {{ env['EJABBERD_REDIS_DB'] or 0}} -redis_reconnect_timeout: {{ env['EJABBERD_REDIS_RECONNECT_TIMEOUT'] or 1 }} -redis_connect_timeout: {{ env['EJABBERD_REDIS_CONNECT_TIMEOUT'] or 1 }} -{% endif %} - -{%- if env.get('EJABBERD_CAPTCHA', false) == "true" %} -### ======= -### CAPTCHA -## -## Full path to a script that generates the image. -captcha_cmd: "{{ env.get('EJABBERD_CAPTCHA_CMD', '/usr/local/lib/ejabberd-' ~ env['EJABBERD_BRANCH'] ~ '/priv/bin/captcha.sh') }}" -{% endif %} diff --git a/tests/features/bootstrap/AbstractContext.php b/tests/features/bootstrap/AbstractContext.php index 017f9f5..d4cfcf1 100644 --- a/tests/features/bootstrap/AbstractContext.php +++ b/tests/features/bootstrap/AbstractContext.php @@ -47,7 +47,6 @@ */ abstract class AbstractContext { - protected $stream; protected $logdir; protected $logfile; diff --git a/tests/features/bootstrap/AbstractXMPPContext.php b/tests/features/bootstrap/AbstractXMPPContext.php new file mode 100644 index 0000000..48f7c27 --- /dev/null +++ b/tests/features/bootstrap/AbstractXMPPContext.php @@ -0,0 +1,96 @@ + + */ + +namespace Fabiang\Sasl\Behat; + +use Behat\Behat\Context\Context; +use Behat\Behat\Context\SnippetAcceptingContext; +use Fabiang\Sasl\Sasl; + +/** + * Description of AbstractXMPPContext + * + * @author fabian.grutschus + */ +abstract class AbstractXMPPContext extends AbstractContext implements Context, SnippetAcceptingContext +{ + protected $hostname; + protected $port; + protected $domain; + protected $username; + protected $password; + + /** + * @var \Fabiang\Sasl\Authentication\AuthenticationInterface + */ + protected $authenticationObject; + + /** + * @var Sasl + */ + protected $authenticationFactory; + + /** + * Initializes context. + * + * Every scenario gets its own context instance. + * You can also pass arbitrary arguments to the + * context constructor through behat.yml. + * + * @param string $hostname Hostname for connection + * @param integer $port + * @param string $domain + * @param string $username Domain name of server (important for connecting) + * @param string $password + * @param string $logdir + */ + public function __construct($hostname, $port, $domain, $username, $password, $logdir) + { + $this->hostname = $hostname; + $this->port = (int) $port; + $this->domain = $domain; + $this->username = $username; + $this->password = $password; + + if (!is_dir($logdir)) { + mkdir($logdir, 0777, true); + } + + $this->authenticationFactory = new Sasl; + $this->logdir = $logdir; + } +} diff --git a/tests/features/bootstrap/Pop3Context.php b/tests/features/bootstrap/POP3Context.php similarity index 98% rename from tests/features/bootstrap/Pop3Context.php rename to tests/features/bootstrap/POP3Context.php index 0d99c30..f1641c1 100644 --- a/tests/features/bootstrap/Pop3Context.php +++ b/tests/features/bootstrap/POP3Context.php @@ -48,7 +48,7 @@ * * @author Fabian Grutschus */ -class Pop3Context extends AbstractContext implements Context, SnippetAcceptingContext +class POP3Context extends AbstractContext implements Context, SnippetAcceptingContext { protected $hostname; diff --git a/tests/features/bootstrap/XmppContext.php b/tests/features/bootstrap/XMPPContext.php similarity index 80% rename from tests/features/bootstrap/XmppContext.php rename to tests/features/bootstrap/XMPPContext.php index 5bc8781..4e2aec3 100644 --- a/tests/features/bootstrap/XmppContext.php +++ b/tests/features/bootstrap/XMPPContext.php @@ -37,10 +37,7 @@ namespace Fabiang\Sasl\Behat; -use Behat\Behat\Context\Context; -use Behat\Behat\Context\SnippetAcceptingContext; use PHPUnit\Framework\Assert; -use Fabiang\Sasl\Sasl; use Fabiang\Sasl\Options; /** @@ -48,53 +45,54 @@ * * @author Fabian Grutschus */ -class XmppContext extends AbstractContext implements Context, SnippetAcceptingContext +class XMPPContext extends AbstractXMPPContext { - - protected $hostname; - protected $port; - protected $domain; - protected $username; - protected $password; - /** - * @var \Fabiang\Sasl\Authentication\AuthenticationInterface + * @When authenticate with method SCRAM-SHA-1 */ - protected $authenticationObject; + public function authenticateWithMethodScramSha1() + { + $this->authenticationObject = $this->authenticationFactory->factory( + 'scram-sha-1', + new Options($this->username, $this->password) + ); + + $authData = base64_encode($this->authenticationObject->createResponse()); + $this->write( + "$authData" + ); + } /** - * @var Sasl + * @When authenticate with method SCRAM-SHA-256 */ - protected $authenticationFactory; + public function authenticateWithMethodScramSha256() + { + $this->authenticationObject = $this->authenticationFactory->factory( + 'scram-sha-256', + new Options($this->username, $this->password) + ); + + $authData = base64_encode($this->authenticationObject->createResponse()); + $this->write( + "$authData" + ); + } /** - * Initializes context. - * - * Every scenario gets its own context instance. - * You can also pass arbitrary arguments to the - * context constructor through behat.yml. - * - * @param string $hostname Hostname for connection - * @param integer $port - * @param string $domain - * @param string $username Domain name of server (important for connecting) - * @param string $password - * @param string $logdir + * @When authenticate with method SCRAM-SHA-512 */ - public function __construct($hostname, $port, $domain, $username, $password, $logdir) + public function authenticateWithMethodScramSha512() { - $this->hostname = $hostname; - $this->port = (int) $port; - $this->domain = $domain; - $this->username = $username; - $this->password = $password; - - if (!is_dir($logdir)) { - mkdir($logdir, 0777, true); - } + $this->authenticationObject = $this->authenticationFactory->factory( + 'scram-sha-512', + new Options($this->username, $this->password) + ); - $this->authenticationFactory = new Sasl; - $this->logdir = $logdir; + $authData = base64_encode($this->authenticationObject->createResponse()); + $this->write( + "$authData" + ); } /** @@ -144,25 +142,9 @@ public function authenticateWithMethodDigestMd5() } /** - * @When authenticate with method SCRAM-SHA-1 - */ - public function authenticateWithMethodScramSha1() - { - $this->authenticationObject = $this->authenticationFactory->factory( - 'scram-sha-1', - new Options($this->username, $this->password) - ); - - $authData = base64_encode($this->authenticationObject->createResponse()); - $this->write( - "$authData" - ); - } - - /** - * @When responde to challenge received for DIGEST-MD5 + * @When response to challenge received for DIGEST-MD5 */ - public function respondeToChallengeReceivedForDigestMd5() + public function responseToChallengeReceivedForDigestMd5() { $data = $this->readStreamUntil(array('', '')); Assert::assertMatchesRegularExpression( @@ -188,9 +170,9 @@ public function respondeToChallengeReceivedForDigestMd5() } /** - * @When responde to rspauth challenge + * @When response to rspauth challenge */ - public function respondeToRspauthChallenge() + public function responseToRspauthChallenge() { $data = $this->readStreamUntil(array('', '')); @@ -202,9 +184,9 @@ public function respondeToRspauthChallenge() } /** - * @When responde to challenge for SCRAM-SHA-1 + * @When response to challenge for SCRAM-SHA-:hash */ - public function respondeToChallengeForScramSha1() + public function responseToChallengeForScramSha($hash) { $data = $this->readStreamUntil(array('', '')); Assert::assertMatchesRegularExpression( diff --git a/tests/features/xmpp.feature b/tests/features/xmpp.feature index 85f12de..8a91964 100644 --- a/tests/features/xmpp.feature +++ b/tests/features/xmpp.feature @@ -14,13 +14,27 @@ Feature: Authentication with a xmpp server Scenario: Authenticate with xmpp server through digest-md5 authentication Given xmpp server supports authentication method "DIGEST-MD5" When authenticate with method DIGEST-MD5 - And responde to challenge received for DIGEST-MD5 - And responde to rspauth challenge + And response to challenge received for DIGEST-MD5 + And response to rspauth challenge Then should be authenticated at xmpp server @scramsha1 Scenario: Authenticate with xmpp server through scram-sha-1 authentication Given xmpp server supports authentication method "SCRAM-SHA-1" When authenticate with method SCRAM-SHA-1 - And responde to challenge for SCRAM-SHA-1 + And response to challenge for SCRAM-SHA-1 + Then should be authenticated at xmpp server with verification + + @scramsha256 + Scenario: Authenticate with xmpp server through scram-sha-256 authentication + Given xmpp server supports authentication method "SCRAM-SHA-256" + When authenticate with method SCRAM-SHA-256 + And response to challenge for SCRAM-SHA-256 + Then should be authenticated at xmpp server with verification + + @scramsha512 + Scenario: Authenticate with xmpp server through scram-sha-512 authentication + Given xmpp server supports authentication method "SCRAM-SHA-512" + When authenticate with method SCRAM-SHA-512 + And response to challenge for SCRAM-SHA-512 Then should be authenticated at xmpp server with verification diff --git a/tests/provisioner/install_dovecot.sh b/tests/provisioner/install_dovecot.sh deleted file mode 100755 index 62b0580..0000000 --- a/tests/provisioner/install_dovecot.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash - -## -# Sasl library. -# -# Copyright (c) 2002-2003 Richard Heyes, -# 2014-2023 Fabian Grutschus -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# o Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# o Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution.| -# o The names of the authors may not be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# @author Fabian Grutschus -# - -dovecot_username=$1 -dovecot_password=$2 - -# Install dovecot when control binary doesn't exists -if [ -z `which dovecot` ]; then - echo -n "Install dovecot... " - apt-get install -y dovecot-pop3d > /dev/null - echo "done" -fi - -dovecot_configured="/etc/dovecot/configured" -dovecot_restart=0 - -if [ ! -f "$dovecot_configured" ]; then - echo -n "Configure dovecot... " - - dovecot_master_config="/etc/dovecot/conf.d/10-master.conf" - if [ ! -f "$dovecot_master_config.orig" ]; then - cp "$dovecot_master_config" "$dovecot_master_config.orig" - fi - - dovecot_auth_config="/etc/dovecot/conf.d/10-auth.conf" - if [ ! -f "$dovecot_auth_config.orig" ]; then - cp "$dovecot_auth_config" "$dovecot_auth_config.orig" - fi - - dovecot_mail_config="/etc/dovecot/conf.d/10-mail.conf" - if [ ! -f "$dovecot_mail_config.orig" ]; then - cp "$dovecot_mail_config" "$dovecot_mail_config.orig" - fi - - dovecot_logging_config="/etc/dovecot/conf.d/10-logging.conf" - if [ ! -f "$dovecot_logging_config.orig" ]; then - cp "$dovecot_logging_config" "$dovecot_logging_config.orig" - fi - - dovecot_passwdfile_config="/etc/dovecot/conf.d/auth-passwdfile.conf.ext" - if [ ! -f "$dovecot_passwdfile_config.orig" ]; then - cp "$dovecot_passwdfile_config" "$dovecot_passwdfile_config.orig" - fi - - port_config=$(grep '#port = 110' $dovecot_master_config) - if [ -n "$port_config" ]; then - sed -i 's/#port = 110/port = 11110/' "$dovecot_master_config" - dovecot_restart=1 - fi - - config_auth=$(grep 'auth_mechanisms = plain' "$dovecot_auth_config") - if [ -n "$config_auth" ]; then - sed -i 's/auth_mechanisms = plain/auth_mechanisms = plain cram-md5/' "$dovecot_auth_config" - dovecot_restart=1 - fi - - config_auth=$(grep '#!include auth-passwdfile.conf.ext' "$dovecot_auth_config") - if [ -n "$config_auth" ]; then - sed -i 's/#!include auth-passwdfile.conf.ext/!include auth-passwdfile.conf.ext/' "$dovecot_auth_config" - dovecot_restart=1 - fi - - config_mail=$(grep '#mail_location =' "$dovecot_mail_config") - if [ -n "$config_mail" ]; then - sed -i 's/#mail_location =/mail_location = maildir:~\/Maildir/' "$dovecot_mail_config" - dovecot_restart=1 - fi - - config_logging=$(grep '#log_path = syslog' "$dovecot_logging_config") - if [ -n "$config_logging" ]; then - sed -i 's/#log_path = syslog/log_path = \/var\/log\/dovecot.log/' "$dovecot_logging_config" - dovecot_restart=1 - fi - - config_passwd=$(grep 'scheme=CRYPT' "$dovecot_passwdfile_config") - if [ -n "$config_passwd" ]; then - sed -i 's/scheme=CRYPT/scheme=cram-md5/' "$dovecot_passwdfile_config" - dovecot_restart=1 - fi - - dovecot_passwdfile='/etc/dovecot/users' - if [ ! -f "$dovecot_passwdfile" ]; then - echo -n "$dovecot_username:" > $dovecot_passwdfile - echo -ne "$dovecot_password\n$dovecot_password" | doveadm pw | sed 's/{CRAM-MD5}//' >> $dovecot_passwdfile - fi - - touch $dovecot_configured - echo "done" -fi - -id "$dovecot_username" > /dev/null 2>&1 -if [ $? -eq 1 ]; then - echo -n "Adding user '$dovecot_username' with password '$dovecot_password'... " - useradd --password "$dovecot_password" --user-group --groups mail "$dovecot_username" > /dev/null - mkdir -p "/home/$dovecot_username/Maildir" - mkdir -p "/home/$dovecot_username/mail" - chown "$dovecot_username:$dovecot_username" "/home/$dovecot_username/Maildir" - chown "$dovecot_username:$dovecot_username" "/home/$dovecot_username/mail" - echo "done" -fi - -if [ $dovecot_restart -eq 1 ]; then - echo "Trigger restart of dovecot" - service dovecot restart > /dev/null -fi diff --git a/tests/provisioner/install_ejabberd.sh b/tests/provisioner/install_ejabberd.sh deleted file mode 100755 index a20a000..0000000 --- a/tests/provisioner/install_ejabberd.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/usr/bin/env bash - -## -# Sasl library. -# -# Copyright (c) 2002-2003 Richard Heyes, -# 2014-2023 Fabian Grutschus -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# -# o Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# o Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution.| -# o The names of the authors may not be used to endorse or promote -# products derived from this software without specific prior written -# permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# @author Fabian Grutschus -# - -jabber_username=$1 -jabber_password=$2 - -# Install ejabberd when control binary doesn't exists -if [ -z `which ejabberdctl` ]; then - echo -n "Install ejabberd... " - apt-get update > /dev/null - apt-get install -y ejabberd > /dev/null - dpkg --configure ejabberd > /dev/null 2>&1 - echo "done" -fi - -ejabberd_config="/etc/ejabberd/ejabberd.yml" -ejabberd_configured="/etc/ejabberd/configured" -ejabberd_restart=0 - -if [ ! -f "$ejabberd_configured" ]; then - echo -n "Configure ejabberd... " - - service ejabberd stop > /dev/null - - cp "$ejabberd_config" "$ejabberd_config.orig" - - port_config=$(grep ' port: 5222' $ejabberd_config) - if [ -n "$port_config" ]; then - sed -i 's/ port: 5222/ port: 15222/' "$ejabberd_config" - ejabberd_restart=1 - fi - - host_config=$(grep ' - "localhost"' $ejabberd_config) - if [ -n "$host_config" ]; then - sed -i "s/ - \"localhost\"/ - \"$HOSTNAME\"/" "$ejabberd_config" - ejabberd_restart=1 - fi - - digestMD5=$(grep 'disable_sasl_mechanisms: "digest-md5"' $ejabberd_config) - if [ -n "$digestMD5" ]; then - sed -i "s/disable_sasl_mechanisms: \"digest-md5\"/disable_sasl_mechanisms: \"\"/" "$ejabberd_config" - ejabberd_restart=1 - fi - - authPlain=$(grep 'auth_password_format: scram' "$ejabberd_config") - if [ -n "$authPlain" ]; then - sed -i "s/auth_password_format: scram/auth_password_format: plain/" "$ejabberd_config" - ejabberd_restart=1 - fi - - iptables -A INPUT -p tcp -m tcp --dport 22 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 5222 -j ACCEPT - iptables -A INPUT -p udp -m udp --dport 5222 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 15222 -j ACCEPT - iptables -A INPUT -p udp -m udp --dport 15222 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 5223 -j ACCEPT - iptables -A INPUT -p udp -m udp --dport 5223 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 5269 -j ACCEPT - iptables -A INPUT -p udp -m udp --dport 5269 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 5280 -j ACCEPT - iptables -A INPUT -p udp -m udp --dport 5280 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 4369 -j ACCEPT - iptables -A INPUT -p udp -m udp --dport 4369 -j ACCEPT - iptables -A INPUT -p tcp -m tcp --dport 53873 -j ACCEPT - - touch $ejabberd_configured - echo "done" -fi - -if [ $ejabberd_restart -eq 1 ]; then - echo "Trigger restart of ejabberd" - service ejabberd restart > /dev/null -fi - -# Adding users must be done after restarting the server, since hostname must be present -user_exists=$(ejabberdctl registered-users $HOSTNAME | grep "$jabber_username" ) -if [ -z "$user_exists" ]; then - echo -n "Register user '$jabber_username' with password '$jabber_password' at ejabberd... " - - # restart and wait before adding users, otherwise adding fails - service ejabberd restart > /dev/null - sleep 5 - - ejabberdctl register "$jabber_username" "$HOSTNAME" "$jabber_password" > /dev/null - echo "done" -fi diff --git a/tests/src/Authentication/SCRAMTest.php b/tests/src/Authentication/SCRAMTest.php index ec47ac4..6fa56de 100644 --- a/tests/src/Authentication/SCRAMTest.php +++ b/tests/src/Authentication/SCRAMTest.php @@ -68,15 +68,92 @@ protected function setUp(): void } /** + * @param string $input + * @param string $expected + * @dataProvider provideOldHashAlgos * @covers ::__construct * @covers ::getHashAlgo * @uses Fabiang\Sasl\Options * @uses Fabiang\Sasl\Authentication\AbstractAuthentication::__construct */ - public function testConstructor() + public function testConstructor($input, $expected) { - $object = new SCRAM(new Options('test'), 'sha-1'); - $this->assertSame('sha1', $object->getHashAlgo()); + $object = new SCRAM(new Options('test'), $input); + $this->assertSame($expected, $object->getHashAlgo()); + } + + /** + * @return array + */ + public static function provideOldHashAlgos() + { + return array( + array( + 'input' => 'sha1', + 'expected' => 'sha1', + ), + array( + 'input' => 'sha-1', + 'expected' => 'sha1', + ), + array( + 'input' => 'SHA-1', + 'expected' => 'sha1', + ), + array( + 'input' => 'sha256', + 'expected' => 'sha256', + ), + array( + 'input' => 'sha-256', + 'expected' => 'sha256', + ), + array( + 'input' => 'sha512', + 'expected' => 'sha512', + ), + array( + 'input' => 'sha-512', + 'expected' => 'sha512', + ), + ); + } + + /** + * @requires PHP 7.1 + * @param string $input + * @param string $expected + * @dataProvider provideNewHashAlgos + * @covers ::__construct + * @covers ::getHashAlgo + * @uses Fabiang\Sasl\Options + * @uses Fabiang\Sasl\Authentication\AbstractAuthentication::__construct + */ + public function testConstructorNewAlogs($input, $expected) + { + $object = new SCRAM(new Options('test'), $input); + $this->assertSame($expected, $object->getHashAlgo()); + } + + /** + * @return array + */ + public static function provideNewHashAlgos() + { + return array( + array( + 'input' => 'sha3-256', + 'expected' => 'sha3-256', + ), + array( + 'input' => 'sha3-512', + 'expected' => 'sha3-512', + ), + array( + 'input' => 'sha-3-512', + 'expected' => 'sha3-512', + ), + ); } /**