diff --git a/src/providers/wms/qgswmscapabilities.cpp b/src/providers/wms/qgswmscapabilities.cpp index fd2f2566532c..b136b6573440 100644 --- a/src/providers/wms/qgswmscapabilities.cpp +++ b/src/providers/wms/qgswmscapabilities.cpp @@ -42,8 +42,9 @@ bool QgsWmsSettings::parseUri( const QString &uriString ) uri.setEncodedUri( uriString ); // Setup authentication - mAuth.mUserName = uri.username(); - mAuth.mPassword = uri.password(); + QUrlQuery query{ uriString }; + mAuth.mUserName = query.queryItemValue( QStringLiteral( "username" ), QUrl::ComponentFormattingOption::FullyDecoded ); + mAuth.mPassword = query.queryItemValue( QStringLiteral( "password" ), QUrl::ComponentFormattingOption::FullyDecoded ); if ( !uri.authConfigId().isEmpty() ) { diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index 55bc9b111a92..5247d70320de 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -28,6 +28,7 @@ ADD_PYTHON_TEST(PyQgsAttributeForm test_qgsattributeform.py) ADD_PYTHON_TEST(PyQgsAttributeTableConfig test_qgsattributetableconfig.py) ADD_PYTHON_TEST(PyQgsAttributeTableModel test_qgsattributetablemodel.py) ADD_PYTHON_TEST(PyQgsAuthenticationSystem test_qgsauthsystem.py) +ADD_PYTHON_TEST(PyQgsAuthBasicMethod test_qgsauthbasicmethod.py) ADD_PYTHON_TEST(PyQgsBearingUtils test_qgsbearingutils.py) ADD_PYTHON_TEST(PyQgsBinaryWidget test_qgsbinarywidget.py) ADD_PYTHON_TEST(PyQgsBlendModes test_qgsblendmodes.py) diff --git a/tests/src/python/test_qgsauthbasicmethod.py b/tests/src/python/test_qgsauthbasicmethod.py new file mode 100644 index 000000000000..2e703b2bbca6 --- /dev/null +++ b/tests/src/python/test_qgsauthbasicmethod.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- +""" +Tests for Basic Auth + +From build dir, run: ctest -R PyQgsAuthBasicMethod -V + +.. note:: This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. +""" + +import os +import tempfile +import base64 + +from qgis.core import QgsApplication, QgsAuthManager, QgsAuthMethodConfig, QgsNetworkAccessManager +from qgis.PyQt.QtCore import QFileInfo, QUrl +from qgis.testing import start_app, unittest +from qgis.PyQt.QtNetwork import QNetworkRequest + +AUTHDBDIR = tempfile.mkdtemp() +os.environ['QGIS_AUTH_DB_DIR_PATH'] = AUTHDBDIR + + +__author__ = 'Alessandro Pasotti' +__date__ = '13/10/2020' +__copyright__ = 'Copyright 2020, The QGIS Project' + +qgis_app = start_app() + + +class TestAuthManager(unittest.TestCase): + + @classmethod + def setUpAuth(cls, username, password): + """Run before all tests and set up authentication""" + assert (cls.authm.setMasterPassword('masterpassword', True)) + # Client side + auth_config = QgsAuthMethodConfig("Basic") + auth_config.setConfig('username', username) + auth_config.setConfig('password', password) + auth_config.setName('test_basic_auth_config') + assert (cls.authm.storeAuthenticationConfig(auth_config)[0]) + assert auth_config.isValid() + return auth_config + + @classmethod + def setUpClass(cls): + """Run before all tests""" + cls.authm = QgsApplication.authManager() + assert not cls.authm.isDisabled(), cls.authm.disabledMessage() + + cls.mpass = 'pass' # master password + + db1 = QFileInfo(cls.authm.authenticationDatabasePath() + ).canonicalFilePath() + db2 = QFileInfo(AUTHDBDIR + '/qgis-auth.db').canonicalFilePath() + msg = 'Auth db temp path does not match db path of manager' + assert db1 == db2, msg + + @classmethod + def tearDownClass(cls): + """Run after all tests""" + pass + + def setUp(self): + """Run before each test.""" + pass + + def tearDown(self): + """Run after each test.""" + pass + + def _get_decoded_credentials(self, username, password): + """Extracts and decode credentials from request Authorization header""" + + ac = self.setUpAuth(username, password) + req = QNetworkRequest(QUrl('http://none')) + self.authm.updateNetworkRequest(req, ac.id()) + auth = bytes(req.rawHeader(b'Authorization'))[6:] + # Note that RFC7617 states clearly: User-ids containing colons cannot be encoded in user-pass strings + u, p = base64.decodestring(auth).split(b':') + return u.decode('utf8'), p.decode('utf8') + + def testHeaderEncoding(self): + """Test credentials encoding""" + + for creds in ( + ('username', 'password'), + ('username', r'pa%%word'), + ): + self.assertEqual(self._get_decoded_credentials(*creds), creds) + + +if __name__ == '__main__': + unittest.main()