Non-ASCII characters in Nextcloud account password

REPRODUCIBILITY: 100%
OS VERSION: 5.0.0.77
HARDWARE: Motrola Edge 30 Neo (unrelated)
UI LANGUAGE: English
REGRESSION: Probably not

DESCRIPTION:

If you have non-ascii, in my case polish characters in password, nextcloud will report as incorrect password when setting up nextcloud account, even though same password works literally everywhere else, via website, via webdav (via api client), via desktop client, just not in sfos.

PRECONDITIONS:

Have nextcloud account with non-ascii (or polish) characters in password.

STEPS TO REPRODUCE:

  1. Try to make account
  2. ???
  3. profit

EXPECTED RESULT:

I’d expect account creation to be successful which happened after i changed password to one without polish characters.

ACTUAL RESULT:

It throws incorrect password.

MODIFICATIONS:

nu-uh

ADDITIONAL INFORMATION:

{"reqId":"moGWdCsAxV7ata6qWRuP","level":0,"time":"June 07, 2026 16:51:07","remoteAddr":"192.168.69.19","user":"--","app":"caldav","method":"PROPFIND","url":"/remote.php/caldav/calendars/Mister_Magister/","scriptName":"/remote.php","message":"Username or password was incorrect","userAgent":"Mozilla/5.0","version":"32.0.11.1","exception":{"Exception":"Sabre\\DAV\\Exception\\NotAuthenticated","Message":"Username or password was incorrect","Code":0,"Trace":[{"file":"/var/nextcloud/3rdparty/sabre/event/lib/WildcardEmitterTrait.php","line":89,"function":"beforeMethod","class":"Sabre\\DAV\\Auth\\Plugin","type":"->"},{"file":"/var/nextcloud/3rdparty/sabre/dav/lib/DAV/Server.php","line":456,"function":"emit","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/nextcloud/3rdparty/sabre/dav/lib/DAV/Server.php","line":253,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/nextcloud/3rdparty/sabre/dav/lib/DAV/Server.php","line":321,"function":"start","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/nextcloud/apps/dav/appinfo/v1/caldav.php","line":128,"function":"exec","class":"Sabre\\DAV\\Server","type":"->"},{"file":"/var/nextcloud/remote.php","line":151,"args":["/var/nextcloud/apps/dav/appinfo/v1/caldav.php"],"function":"require_once"}],"File":"/var/nextcloud/3rdparty/sabre/dav/lib/DAV/Auth/Plugin.php","Line":152,"message":"Username or password was incorrect","exception":{},"CustomMessage":"Username or password was incorrect"}}

Can you use app passwords instead? I have a Nextcloud instance and haven’t had password issues with it. Not a fix really, but should let you add the account.

What app passwords?

Well do you have non-ascii character in the password?

I can add account if i remove polish character from the password

2 Likes

Since it is reported for some CalDAV address, let’s assume this an issue with the code from buteo-sync-plugin-caldav. Can you try:

  • install buteo-sync-plugin-caldav-tools package (devel-su pkcon install buteo-sync-plugin-caldav-tools).
  • try to list your calendars with QT_LOGGING_RULES="*.debug=true" dav-client -u your.login@provider.org -P "xxxxxxx" -S caldav -D provider.org --list-calendars "".

dav-client can also work with a direct server URL and root, without relying on discovering features : dav-client -u your.login@provider.org -P "xxxxxxxxx" -s https://dav.provider.org -R path/to/dav/service --list-calendars ""

Change provider.org with the DNS name of your provider (like mailbox.org for instance), or https://dav.provider.org with the full server name hosting the DAV service. Use a -R option if the DAV service is not available at the root of your server.

But i’m not talking about just caldav, i’m talking about nextcloud account

I got it, but as I mentioned the additional informations you reported contains "method":"PROPFIND","url":"/remote.php/caldav/calendars/Mister_Magister/". I would like to rule out (or incriminate) the code in buteo-sync-plugin-caldav, from which such kind of PROPFIND request may originate. The Nextcloud plugin is using some code from that repo also, not only from sailfish-account-nextcloud one.

If the above commands work, then, the code from that repo is clean in term of non ascii characters. If not, I need to fix it. I cannot test, because my provider doesn’t allow non ascii characters, otherwise I would have done it myself.

In any case, working or not, the code from sailfish-account-nextcloud is also emitting this kind of PROPFIND requests. So it will have to be checked also (but this one I don’t know it much, so I cannot comment).

2 Likes

AFAICS the NC account setup qml pages do not use anything special.
All is done using stock components.

I guess the problem may be here:

buteo-plugins/buteo-common/networkrequestgenerator.cpp

102     } else if (!m_username.isEmpty() && !m_password.isEmpty()) {
103         QUrl authenticatedUrl = url;
104         authenticatedUrl.setUserName(m_username);
105         authenticatedUrl.setPassword(m_password);
106         request.setUrl(authenticatedUrl);

QUrl::setPassword should be able to url-encode correctly, but maybe that fails?

Above that section there’s:

96         QByteArray credentials((m_username + ':' + m_password).toUtf8());
97         request.setRawHeader("Authorization", QByteArray("Basic ") + credentials.toBase64());

does that produce a correct Authorization token?

EDIT: Seems to work ok:

#include <QString>
#include <QUrl>
#include <QDebug>

int main(int argc, char* argv[]) {

const QString username = "Mister_Magister";
const QString password = "ćłńóś ../żąę:%\\x';drop table accounts;commit;";

QUrl authenticatedUrl("https://foo.com/login");
authenticatedUrl.setUserName(username);
authenticatedUrl.setPassword(password);
qDebug() << "URL" << authenticatedUrl.toString();
qDebug() << "Valid:" << authenticatedUrl.isValid();
}
 $ ./a.out
test.cpp:13 main URL "https://Mister_Magister:ćłńóś ..%2Fżąę:%25%5Cx';drop table accounts;commit;@foo.com/login"
test.cpp:14 main Valid: true

…though the space may be a problem.

2 Likes

Thanks @nephros for pointing these out. I’m testing this also in the DAV client from buteo-sync-plugin-caldav on a Nextcloud instance (that I don’t control), and I notice this issue:

  • QUrl::setPassword(“ASCII pass”), works,
  • QUrl::setPassword(“non ASCII pass”), fails,
  • Basic authentication headers always succeeds.

The encoded URL produced with the credentials in the URL is correct and not double percent encoded. This can be tested with curl, using the same encoded form. But somehow, the server is not able to properly decode it.

Forcing the basic authentication headers always works.

But looking at the code you pointed out, @nephros, it seems that the basic auth route is used only if “/ocs/” is within the path, which is not often the case, as far as I know.

I would suspect a misconfiguration from the server, but I don’t have access to it. Forcing basic authentication may be the solution. curl is doing such thing anyway, as soon as a credential is given in the url, it is transformed into a basic authentication header.

1 Like

I’d expect basic auth to be used anyway per nextcloud’s documentation but what do i know

Indeed, when the credentials are passed in the URL (percent encoded) with non-ASCII characters, the server is replying with a 401 status, and a www-authentication : basic header. So asking for a authentication header in the request (with ascii characters only in the URL, the server is not emitting the challenge).

Qt is handling these cases, with a signal on the QNetworkAccessManager, asking for authentication informations:

connect(manager, &QNetworkAccessManager::authenticationRequired,
               this, &Request::onAuthRequired);

void Request::onAuthRequired(QNetworkReply *reply, QAuthenticator *authenticator)
{
    // Provide username and password to the authenticator object.
}

So far so good. But it still doesn’t work, because it is implemented with a response constructed with (see Qt code source):

response = user.toLatin1() + ':' + password.toLatin1();

While the server is expecting UTF-8 !

I thought it was because of the ancient 5.6 Qt version in Sailfish OS, but no. The latest code in Qt 6 is also responding with username and password encoded in latin 1…

The workaround is to do something like this when giving the password to the authenticator:

authenticator->setPassword(QString::fromLatin1(mSettings->password().toUtf8()));

I find this quite unexpected. Is nobody using the signal + QAuthenticator mechanism and always provide the authenticator header instead ?

4 Likes

For reference, here is the PR for buteo-sync-plugin-caldav: [buteo-sync-plugin-caldav] Send basic auth on request. by dcaliste · Pull Request #38 · sailfishos/buteo-sync-plugin-caldav · GitHub

2 Likes