OAuth: Fix refresh of token after expiration

Before commit d3b00532b1,
fetchFromKeychain was called everytime we detect that the creds are
invalid (in AccountState::slotInvalidCredentials)
But since that commit, AccountState was calling askFromUser directly,
breaking the refresh of the token.

So I made sure AccountState::slotInvalidCredentials still calls
refreshAccessToken.

Another change that was made was too be sure to clear the cookies
in HttpCredentials::invalidateToken even when we are only clearing the
access_token. That's because the session with a cookie may stay valid
longer than the access_token
This commit is contained in:
Olivier Goffart 2017-07-18 14:53:41 +02:00 committed by Olivier Goffart
parent a831164d65
commit c043840cb1
3 changed files with 25 additions and 12 deletions

View file

@ -16,6 +16,7 @@
#include "accountmanager.h"
#include "account.h"
#include "creds/abstractcredentials.h"
#include "creds/httpcredentials.h"
#include "logger.h"
#include "configfile.h"
@ -305,12 +306,17 @@ void AccountState::slotInvalidCredentials()
qCInfo(lcAccountState) << "Invalid credentials for" << _account->url().toString()
<< "asking user";
if (account()->credentials()->ready())
account()->credentials()->invalidateToken();
account()->credentials()->askFromUser();
setState(AskingCredentials);
_waitingForNewCredentials = true;
setState(AskingCredentials);
if (account()->credentials()->ready()) {
account()->credentials()->invalidateToken();
if (auto creds = qobject_cast<HttpCredentials *>(account()->credentials())) {
if (creds->refreshAccessToken())
return;
}
}
account()->credentials()->askFromUser();
}
void AccountState::slotCredentialsFetched(AbstractCredentials *)

View file

@ -292,8 +292,11 @@ void HttpCredentials::slotReadJobDone(QKeychain::Job *incomingJob)
}
}
void HttpCredentials::refreshAccessToken()
bool HttpCredentials::refreshAccessToken()
{
if (_refreshToken.isEmpty())
return false;
QUrl requestToken(_account->url().toString()
+ QLatin1String("/index.php/apps/oauth2/api/v1/token?grant_type=refresh_token&refresh_token=")
+ _refreshToken);
@ -324,6 +327,7 @@ void HttpCredentials::refreshAccessToken()
}
emit fetched();
});
return true;
}
@ -344,6 +348,9 @@ void HttpCredentials::invalidateToken()
return;
}
// clear the session cookie.
_account->clearCookieJar();
if (!_refreshToken.isEmpty()) {
// Only invalidate the access_token (_password) but keep the _refreshToken in the keychain
// (when coming from forgetSensitiveData, the _refreshToken is cleared)
@ -364,9 +371,6 @@ void HttpCredentials::invalidateToken()
job2->setKey(kck);
job2->start();
// clear the session cookie.
_account->clearCookieJar();
// let QNAM forget about the password
// This needs to be done later in the event loop because we might be called (directly or
// indirectly) from QNetworkAccessManagerPrivate::authenticationRequired, which itself

View file

@ -46,8 +46,8 @@ namespace OCC {
1) First, AccountState will attempt to load the certificate from the keychain
----> fetchFromKeychain ------------------------> shortcut to refreshAccessToken if the cached
| } information is still valid
----> fetchFromKeychain
| }
v }
slotReadClientCertPEMJobDone } There are first 3 QtKeychain jobs to fetch
| } the TLS client keys, if any, and the password
@ -92,7 +92,10 @@ public:
QString fetchUser();
virtual bool sslIsTrusted() { return false; }
void refreshAccessToken();
/* If we still have a valid refresh token, try to refresh it assynchronously and emit fetched()
* otherwise return false
*/
bool refreshAccessToken();
// To fetch the user name as early as possible
void setAccount(Account *account) Q_DECL_OVERRIDE;