-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[auth][api] QgsAuthConfigurationStorage classes and tests #57992
Conversation
* Abstract class that defines the interface for all authentication configuration storage implementations. | ||
* \since QGIS 3.40 | ||
*/ | ||
class CORE_EXPORT QgsAuthConfigurationStorage: public QObject SIP_ABSTRACT |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class CORE_EXPORT QgsAuthConfigurationStorage: public QObject SIP_ABSTRACT | |
class CORE_EXPORT QgsAbstractAuthConfigurationStorage: public QObject SIP_ABSTRACT |
I'd argue that "storage" in this class name is needlessly restrictive. Perhaps QgsAbstractAuthBackend is a better choice?
|
||
bool QgsAuthConfigurationStorageDb::authDbOpen() const | ||
{ | ||
QMutexLocker locker( &mMutex ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are all these implementations 1:1 copies of the current code? Or are there modifications I should look over specifically?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are mostly 1:1 copies but I did not just cut & paste. I'd say that you can defer the review of the CRUD methods after finish writing the tests, I will probably intercept most issues while testing.
54117f8
to
40ddba2
Compare
50b2786
to
d93a8c2
Compare
04b6f9b
to
da447d3
Compare
} | ||
|
||
QSqlQuery query( authDatabaseConnection() ); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
More of a design question than a code question -- but I'm curious how this method will work in a multi-user setup? Eg a number of plugins I've come across (and some I maintain) use this method to securely store API tokens after a user authenticates with a service. So I'm wondering what would happen if there's a central auth db setup (say on postgres), and then a plugin attempts to store something inherently user-specific like a API token? Either the db will be locked down and prevent this, or they'll clobber their work colleagues' token. Both situations are bad, and would ultimately break the plugin. 😱 (Or is the intention here that a centrally managed auth db is siloed into completely separate user "buckets" via db-level handling? )
Unless this situation is gracefully handled I can see this being a blocker for real-world use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make a step back: the original goal was to provide a way to store credentials in a real client-server DB to remove the filesystem sqlite DB which is causing a lot of issues with QGIS server deployments in the cloud.
For the desktop there is an enterprise use case which I think is interesting (and I spotted in the wild when working with big government orgs in the past): centrally managed shared credentials for company's services.
With the new API you can have read/only storages and you can have multiple storages, so you can imagine using a read/write local storage for user overrides.
Also, you can subclass QgsAuthConfigurationStorage (if not SIP_ABSTRACT) or QgsAuthConfigurationStorageDb and create your own accessors to the DB with filters for the user.
I thought about adding a 'user' field or something similar to the tables but I thought it was too much specific and it wouldn't ever cover all use cases.
Coming back to your use case (if I get this right): if a plugin uses the auth system for its own secure storage it would probably be capable of managing its own keys naming convention to avoid clashes with other users.
ea9842d
to
a9961a1
Compare
ed7845a
to
77b4b83
Compare
@nyalldawson I have applied the recommended changes: if the default storage is not local (SQLITE) it is added read-only. I have also added some more tests for these cases and made sure the GUI behaves correctly with a read-only storage. Managing multiple storages from the GUI is out of scope for now but the API supports multiple as well as custom storages. |
@3nids do you have any idea what's happening with sipify? It is driving me mad, first the map yaml files and now it is not even running locally, it gives multiple errors like
|
@elpaso Nyall has moved sipify from Perl to Python, there might some remaining issues. Regarding the map files, no need to update them from the PR. |
@elpaso what about the explicit exceptions we discussed when If I recall correctly we agreed that these would raise an exception with the error QgsNotSupportedException: "This method is not supported by your authentication configuration. Please contact your local QGIS administrator for support." |
Yes, I did not forget it but decided it wasn't appropriate: all the methods return False in case of storage failure and the last error is set to indicate the reason, I have also expanded the support for read-only storages (that because are fully supported do not need throw any exception in case of writing failure). Also, the DB storages based non-filesystem based DBs are added read-only by default. |
77b4b83
to
6bbfb40
Compare
I'm disappointed by that. I think we have an opportunity here to make the PyQGIS API more friendly to developers, and instead we're opting for an opaque, unfriendly API. Returning false isn't very helpful at all -- it's going to cost someone hours in debugging time to realise what's happening there, and then they'll be forced to dig into the QGIS source to work out why it's returning false in the first place. Vs adding the exception, which is a minor change here, and which INSTANTLY gives the PyQGIS developer helpful feedback about what's gone wrong and how they can handle this...
In that case IMO all DB storages should raise an explicit "QgsAuthenticationException" whenever a write method is called. |
@nyalldawson These are two different situations: image that the storage is a local sqlite with RW (and delete) capabilities but a delete operation fails because the item to be deleted could not be found in the storage: do you want that to raise and exception or just return false? If you opt for return void and always raise I think we would need different exceptions for the different cases: unsupported operation vs. other errors. |
7241a0e
to
fdb2874
Compare
Implementation of QEP Authentication System: allow Database storage for authentication DB qgis/QGIS-Enhancement-Proposals#248
Abstract authentication credentials storage
Implementation of qgis/QGIS-Enhancement-Proposals#248
Donors
This work was financed with funds from:
Goal
Provide an abstract API to manage authentication configurations storage.
The new API supports any database supported by
QSqlDatabase
(https://doc.qt.io/qt-5/qsqldatabase.html) includingSQLite
.Additional features:
QgsAuthConfigurationStorageRegistry
that holds the (ordered) list of authentication storages available to the system