Skip to content
Permalink
Browse files

Merge pull request #39347 from elpaso/bugfix-gh39243-wms-auth-basic-d…

…ecode

Fix WMS auth basic password encoding
  • Loading branch information
elpaso committed Oct 14, 2020
2 parents 02d7afa + c8f90c1 commit 2659c411a6ea6fb8a7cb4298f829ab115da1be19
@@ -638,7 +638,7 @@ void QgsDataSourceUri::setEncodedUri( const QByteArray &uri )
url.setQuery( QString::fromLatin1( uri ) );
const QUrlQuery query( url );

const auto constQueryItems = query.queryItems();
const auto constQueryItems = query.queryItems( QUrl::ComponentFormattingOption::FullyDecoded );
for ( const QPair<QString, QString> &item : constQueryItems )
{
if ( item.first == QLatin1String( "username" ) )
@@ -290,6 +290,15 @@ void TestQgsDataSourceUri::checkAuthParams()
QVERIFY( uri.param( QStringLiteral( "authcfg" ) ).isEmpty() );
QVERIFY( uri.authConfigId().isEmpty() );

// issue GH #39243
QgsDataSourceUri uri4;
uri4.setEncodedUri( QStringLiteral( "dpiMode=7&url=http://localhost:8000/ows/?MAP%3D/home/bug.qgs&username=username&password=pa%25%25word" ) );

QCOMPARE( uri4.param( QStringLiteral( "username" ) ), QStringLiteral( "username" ) );
QCOMPARE( uri4.username(), QStringLiteral( "username" ) );
QCOMPARE( uri4.param( QStringLiteral( "password" ) ), QStringLiteral( "pa%%word" ) );
QCOMPARE( uri4.password(), QStringLiteral( "pa%%word" ) );

}


@@ -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)
@@ -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()

0 comments on commit 2659c41

Please sign in to comment.
You can’t perform that action at this time.