Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
OAuth2: avoid constant token refreshing if the expiration delay is < …
…2 minutes

Currently we refresh the token 2 minutes befores its theoretical expiration.
But if using default Keycloack configuration, the refresh delay is 60 seconds.
Which means we refresh the token for every network request. So for such short
delays, only refresh when the remaining validity time is below 10% of the
initial expiration delay.
  • Loading branch information
rouault committed Nov 16, 2020
1 parent b86cc93 commit a8af06f
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/auth/oauth2/qgsauthoauth2method.cpp
Expand Up @@ -28,6 +28,8 @@
#include "qgsmessagelog.h"
#include "qgssettings.h"

#include <algorithm>

#include <QDateTime>
#include <QInputDialog>
#include <QDesktopServices>
Expand Down Expand Up @@ -139,7 +141,10 @@ bool QgsAuthOAuth2Method::updateNetworkRequest( QNetworkRequest &request, const
if ( o2->expires() > 0 ) // QStringLiteral("").toInt() result for tokens with no expiration
{
int cursecs = static_cast<int>( QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000 );
expired = ( ( o2->expires() - cursecs ) < 120 ); // try refresh with expired or two minutes to go
const int lExpirationDelay = o2->expirationDelay();
// try refresh with expired or two minutes to go (or a fraction of the initial expiration delay if it is short)
const int refreshThreshold = lExpirationDelay > 0 ? std::min( 120, std::max( 2, lExpirationDelay / 10 ) ) : 120;
expired = ( ( o2->expires() - cursecs ) < refreshThreshold );
}

if ( expired )
Expand All @@ -160,6 +165,8 @@ bool QgsAuthOAuth2Method::updateNetworkRequest( QNetworkRequest &request, const
o2->refreshSynchronous();

// refresh result should set o2 to (un)linked
if ( o2->linked() )
o2->computeExpirationDelay();
}
}
}
Expand Down Expand Up @@ -226,6 +233,8 @@ bool QgsAuthOAuth2Method::updateNetworkRequest( QNetworkRequest &request, const
QgsMessageLog::logMessage( msg, AUTH_METHOD_KEY, Qgis::MessageLevel::Warning );
return false;
}

o2->computeExpirationDelay();
}

if ( o2->token().isEmpty() )
Expand Down
6 changes: 6 additions & 0 deletions src/auth/oauth2/qgso2.cpp
Expand Up @@ -431,3 +431,9 @@ void QgsO2::refreshSynchronous()
emit refreshFinished( blockingRequest.reply().error() );
}
}

void QgsO2::computeExpirationDelay()
{
const int lExpires = expires();
mExpirationDelay = lExpires > 0 ? lExpires - static_cast<int>( QDateTime::currentMSecsSinceEpoch() / 1000 ) : 0;
}
11 changes: 11 additions & 0 deletions src/auth/oauth2/qgso2.h
Expand Up @@ -61,6 +61,16 @@ class QgsO2: public O2
//! Refresh token in a synchronous way
void refreshSynchronous();

/**
* Compute expiration delay from current timestamp and expires()
* Should only be called just after a refresh / link event. */
void computeExpirationDelay();

/** Returns expiration delay.
* May be 0 if it is unknown
*/
int expirationDelay() const { return mExpirationDelay; }

public slots:

//! Clear all properties
Expand Down Expand Up @@ -104,6 +114,7 @@ class QgsO2: public O2
QString state_;
QgsAuthOAuth2Config *mOAuth2Config;
bool mIsLocalHost = false;
int mExpirationDelay = 0;

static QString O2_OAUTH2_STATE;
};
Expand Down

0 comments on commit a8af06f

Please sign in to comment.