Extended SCRAM-SHA Support

Since this version, SCRAM authentication mechanisms were extended to support additional hashing algorithms. So far only SHA-1 was available for hashing and now SHA-224, SHA-256, SHA-384 and SHA-512 are also supported. This includes the authentication mechanisms and the password format that is stored. Please note that enabling and using this functionality might require adjusting the server setup.

SASL mechanisms

The possible list of allowed SALS mechanisms was changed. We've added new and more secure methods that can be used during stream negotiation.

Please note that if you were using the following in the configurations file

{sasl_mechanisms, [cyrsasl_scram]}

using cyrsasl_scram as sasl_mechanism is now incorrect. You can achieve the same result of allowing the usage of SHA-1 with SCRAM authentication mechanism with:

{sasl_mechanisms, [cyrsasl_scram_sha1]}

You can also specify a list of all supported SCRAM-SHA mechanisms with:

{sasl_mechanisms, [cyrsasl_scram_sha1, cyrsasl_scram_sha224, cyrsasl_scram_sha256, cyrsasl_scram_sha384, cyrsasl_scram_sha512, cyrsasl_scram_sha1_plus, cyrsasl_scram_sha224_plus, cyrsasl_scram_sha256_plus, cyrsasl_scram_sha384_plus, cyrsasl_scram_sha512_plus]}

Before setting up this configuration, please make sure that the client application is capable of authenticating with a selected set of authentication mechanisms. For more details please refer to the authentication section.

SCRAM password format

To complement the extensions of the authentication mechanisms, the SCRAM password format was also updated. Please note that SCRAM is now the default password format. While it is still possible to configure the password storage in plaintext format, we highly discourage doing so for security reasons. Changing the default of this option can lead to unexpected behaviours, so if after the upgrade you encounter issues with authenticating the users, please check the conifg file. If you are missing any of the following configuration lines:

{password_format, scram} or {password_format, plain}

it means that you were using the default plaintext format.

Since the default of the password format has changed, your MongooseIM server thinks that the plaintext passwords are stored as SCRAM hashes. This can lead to users failing to authenticate.

If you are still using the plaintext password format, please consider migrating your password storage to store scram hashes instead. Using the plaintext password format is still possible to support legacy installations and to ease the debuging while developing new features. Should you want to continue using the plaintext password format please add the following in the auth_opts:

{password_format, plain}

Legacy plaintext and SCRAM formats are still supported. Nonetheless, please note that if you were using SCRAM as a password format, this meant that SHA-1 was used as the hashing algorithm. This allowed authenticating with PLAINTEXT and SCRAM-SHA-1.

In the new setup the user will still authenticate with those mechanisms given the possible slight syntax change explained above.

However, mixing of the old password format with the new authentication mechanisms can lead to conflicting situations where:

  1. A user wants to authenticate with e.g. SCRAM-SHA-256.
  2. His old password format is only storing SHA-1 password hash.
  3. The authentication fails as it is not possible to derive SHA-256 hash from SHA-1.

If you want to use the new password format with a full set of supported SHA hashes, a password change is required to calculate all the new SHA hashes. Otherwise, please make sure that you provide the right sasl_mechanism configuration, where the mechanism you authenticate with is compatible with the password format you store.

For more details related to the new password format, please refer to authentication and SCRAM serialization sections.

Message retraction

If you are using MAM with RDBMS, please update your database schema with the following queries. This change is necessary as the support for XEP-0424: Message Retraction requires a new column for the origin_id attribute of MAM messages, which allows MAM to identify the messages to retract. Indexes for this column are required for efficient queries. Only the messages stored after this change can be retracted.

MySQL

ALTER TABLE mam_message ADD COLUMN origin_id varchar(250) CHARACTER SET binary;
CREATE INDEX i_mam_message_username_jid_origin_id USING BTREE ON mam_message (user_id, remote_bare_jid, origin_id);

ALTER TABLE mam_muc_message ADD COLUMN origin_id varchar(250) CHARACTER SET binary;
CREATE INDEX i_mam_muc_message_room_id_sender_id_origin_id USING BTREE ON mam_muc_message (room_id, sender_id, origin_id);

PostgreSQL

ALTER TABLE mam_message ADD COLUMN origin_id varchar;
CREATE INDEX i_mam_message_username_jid_origin_id ON mam_message USING BTREE (user_id, remote_bare_jid, origin_id);

ALTER TABLE mam_muc_message ADD COLUMN origin_id varchar;
CREATE INDEX i_mam_muc_message_room_id_sender_id_origin_id ON mam_muc_message USING BTREE (room_id, sender_id, origin_id);

MSSQL

Note: i_mam_message_username_jid_id was missing from the schema, this is now fixed. It is not required by message retraction, but this change is recommended.

ALTER TABLE mam_message ADD origin_id nvarchar(250) NULL;
CREATE INDEX i_mam_message_username_jid_id ON mam_message (user_id, remote_bare_jid, id);
CREATE INDEX i_mam_message_username_jid_origin_id ON mam_message (user_id, remote_bare_jid, origin_id);

ALTER TABLE mam_muc_message ADD origin_id nvarchar(250) NULL;
CREATE INDEX i_mam_muc_message_room_id_sender_id_origin_id ON mam_muc_message (room_id, sender_id, origin_id);

RDBMS backend for Multi-User Chats (MUC)

If you're planning to use the new RDBMS backend for MUC, note that the following tables need to be added to the schema:

MySQL

CREATE TABLE muc_rooms(
    id SERIAL,
    muc_host VARCHAR(250)   NOT NULL,
    room_name VARCHAR(250)       NOT NULL,
    options JSON            NOT NULL,
    PRIMARY KEY (muc_host, room_name)
);

CREATE TABLE muc_room_aff(
    room_id BIGINT          NOT NULL REFERENCES muc_rooms(id),
    luser VARCHAR(250)      NOT NULL,
    lserver VARCHAR(250)    NOT NULL,
    resource VARCHAR(250)   NOT NULL,
    aff SMALLINT            NOT NULL
);

CREATE INDEX i_muc_room_aff_id ON muc_room_aff (room_id);

CREATE TABLE muc_registered(
    muc_host VARCHAR(250)   NOT NULL,
    luser VARCHAR(250)      NOT NULL,
    lserver VARCHAR(250)    NOT NULL,
    nick VARCHAR(250)       NOT NULL,
    PRIMARY KEY (muc_host, luser, lserver)
);

PostgreSQL

CREATE TABLE muc_rooms(
    id BIGSERIAL            NOT NULL UNIQUE,
    muc_host VARCHAR(250)   NOT NULL,
    room_name VARCHAR(250)       NOT NULL,
    options JSON            NOT NULL,
    PRIMARY KEY (muc_host, room_name)
);

CREATE TABLE muc_room_aff(
    room_id BIGINT          NOT NULL REFERENCES muc_rooms(id),
    luser VARCHAR(250)      NOT NULL,
    lserver VARCHAR(250)    NOT NULL,
    resource VARCHAR(250)   NOT NULL,
    aff SMALLINT            NOT NULL
);

CREATE INDEX i_muc_room_aff_id ON muc_room_aff (room_id);

CREATE TABLE muc_registered(
    muc_host VARCHAR(250)   NOT NULL,
    luser VARCHAR(250)      NOT NULL,
    lserver VARCHAR(250)    NOT NULL,
    nick VARCHAR(250)       NOT NULL,
    PRIMARY KEY (muc_host, luser, lserver)
);

MSSQL

CREATE TABLE muc_rooms(
    id BIGINT IDENTITY(1,1) NOT NULL UNIQUE,
    muc_host VARCHAR(250)   NOT NULL,
    room_name VARCHAR(250)       NOT NULL,
    options VARCHAR(MAX)    NOT NULL,
    PRIMARY KEY (muc_host, room_name)
);

CREATE TABLE muc_room_aff(
    room_id BIGINT          NOT NULL REFERENCES muc_rooms(id),
    luser VARCHAR(250)      NOT NULL,
    lserver VARCHAR(250)    NOT NULL,
    resource VARCHAR(250)   NOT NULL,
    aff SMALLINT            NOT NULL
);

CREATE INDEX i_muc_room_aff_id ON muc_room_aff (room_id);

CREATE TABLE muc_registered(
    muc_host VARCHAR(250)   NOT NULL,
    luser VARCHAR(250)      NOT NULL,
    lserver VARCHAR(250)    NOT NULL,
    nick VARCHAR(250)       NOT NULL,
    PRIMARY KEY (muc_host, luser, lserver)
);