3

I am trying to automate a couple of things when a QGIS plugin is activated:

  1. If Layer A is not in the TOC, add it. This requests username and password to access a PostGIS table using the inbuilt credentials dialog.
  2. If Layer A now exists in the TOC, access the same PostGIS table to run a query using the same user credentials.

Apparently as I'm not storing the password, I can't access it to use in connecting to the database (using psycopg). Is there any way around this? I want to avoid having the user type credentials twice, and also I want to avoid storing the credentials permanently. I have tried to reimplement the QgsCredentialDialog class but that adds so much complexity (e.g. when a connection error is thrown).

What other ways can I add a layer using a non-stored username and password, and access the credentials later to query the same database? The easiest option I can think of is to access the inbuilt credentials dialog request, but I'm not sure how to do that.

EDIT

My implementation of this was to create a function which I call at the point my layer has been added. It then sets my plugin class attributes username and password correctly which I can use in my db query.

def get_credentials(self, lyr):
    connInfo = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()).connectionInfo()
    success, username, password = QgsCredentials.instance().get(connInfo, None, None)
    if success:
        # QgsCredentials.instance().put(connInfo, username, password)
        self.username = username
        self.password = password
underdark
  • 84,148
  • 21
  • 231
  • 413
James N
  • 531
  • 3
  • 15

3 Answers3

5

QGIS caches the connection credentials inside QgsCredentials based on the connection info. So for a layer lyr do:

connInfo = QgsDataSourceURI( lyr.dataProvider().dataSourceUri() ).connectionInfo()
(success, user, passwd ) = QgsCredentials.instance().get( connInfo, None, None )
# Put the credentials back (for yourself and the provider), as QGIS removes it when you "get" it
if success:
    QgsCredentials.instance().put( connInfo, user, passwd )
Matthias Kuhn
  • 27,780
  • 3
  • 88
  • 129
  • 1
    I think your last line should be: QgsCredentials.instance().put( connInfo, user, passwd ) – Cao Minh Tu Nov 28 '13 at 09:36
  • Thanks, that has worked. Haven't implemented it yet but I just tried the code and can get the cached username and password. – James N Nov 28 '13 at 16:49
2

Instead of dealing inside QGIS with the credentials, you could keep them outside. You can use the file .pgpass for this

on linux you would create a file .pgpass in your home folder with the content:

Structure:

[database.hostname]:[port]:[database]:[username]:[password]

Example:

localhost:5432:*:user:pass
Matthias Kuhn
  • 27,780
  • 3
  • 88
  • 129
  • Thanks Matthias but I don't want to store the credentials anywhere, but I do want them persistent and accessible within a QGIS session. Unless I've missed something, this stores the credentials. – James N Nov 27 '13 at 10:17
  • That's true of course, it just helps not to save credentials inside the project file (and unintentionally passing it on). I will leave the answer for reference. – Matthias Kuhn Nov 27 '13 at 18:46
1

Database, connection parameters and user credential are stored in registry. It's possible to get them with QSettings class:

def getConnections(self):
    s = QSettings() 
    s.beginGroup("PostgreSQL/connections")
    currentConnections = s.childGroups()
    s.endGroup()
    return currentConnections

def setConnection(self,conn):
    s = QSettings()
    s.beginGroup("PostgreSQL/connections/"+conn)
    currentKeys = s.childKeys()
    print "keys: ", currentKeys
    PSQLDatabase=s.value("database", "" )
    PSQLHost=s.value("host", "" )
    PSQLUsername=s.value("username", "" )
    PSQLPassword=s.value("password", "" )
    PSQLPort=s.value("port", "" )
    PSQLService=s.value("service", "" )
    s.endGroup()
    self.db = QSqlDatabase.addDatabase("QPSQL")
    self.db.setHostName(PSQLHost)
    self.db.setDatabaseName(PSQLDatabase)
    self.db.setUserName(PSQLUsername)
    self.db.setPassword(PSQLPassword)
    ok = self.db.open()
    if not ok:
        error = "Database Error: %s" % db.lastError().text()
    else:
        error=""

getConnections returns a list of currently avalaible postgresql connections

setConnection(connection Qstring) opens the specified postgresql connection