return;
}
+ // If we never fetched credentials, do that now - otherwise connection attempts
+ // make little sense, we might be missing client certs.
+ if (!account()->credentials()->wasFetched()) {
+ _waitingForNewCredentials = true;
+ account()->credentials()->fetchFromKeychain();
+ return;
+ }
+
// IF the account is connected the connection check can be skipped
// if the last successful etag check job is not so long ago.
ConfigFile cfg;
// much more likely, so keep trying to connect.
setState(NetworkError);
break;
- case ConnectionValidator::CredentialsMissingOrWrong:
+ case ConnectionValidator::CredentialsWrong:
+ case ConnectionValidator::CredentialsNotReady:
slotInvalidCredentials();
break;
- case ConnectionValidator::UserCanceledCredentials:
+ case ConnectionValidator::SslError:
setState(SignedOut);
break;
case ConnectionValidator::ServiceUnavailable:
if (isSignedOut() || _waitingForNewCredentials)
return;
+ qCInfo(lcAccountState) << "Invalid credentials for" << _account->url().toString()
+ << "asking user";
+
if (account()->credentials()->ready())
account()->credentials()->invalidateToken();
- account()->credentials()->fetchFromKeychain();
+ account()->credentials()->askFromUser();
setState(ConfigurationError);
_waitingForNewCredentials = true;
}
-void AccountState::slotCredentialsFetched(AbstractCredentials *credentials)
+void AccountState::slotCredentialsFetched(AbstractCredentials *)
{
- if (!credentials->ready()) {
- // No exiting credentials found in the keychain
- credentials->askFromUser();
- return;
- }
-
+ // Make a connection attempt, no matter whether the credentials are
+ // ready or not - we want to check whether we can get an SSL connection
+ // going before bothering the user for a password.
+ qCInfo(lcAccountState) << "Fetched credentials for" << _account->url().toString()
+ << "attempting to connect";
_waitingForNewCredentials = false;
-
- if (_connectionValidator) {
- // When new credentials become available we always want to restart the
- // connection validation, even if it's currently running.
- _connectionValidator->deleteLater();
- _connectionValidator = 0;
- }
-
checkConnectivity();
}
void AccountState::slotCredentialsAsked(AbstractCredentials *credentials)
{
+ qCInfo(lcAccountState) << "Credentials asked for" << _account->url().toString()
+ << "are they ready?" << credentials->ready();
+
_waitingForNewCredentials = false;
if (!credentials->ready()) {
void ShibbolethCredentials::fetchFromKeychain()
{
+ _wasFetched = true;
+
if (_user.isEmpty()) {
_user = _account->credentialSetting(QLatin1String(userC)).toString();
}
case Connected:
return QLatin1String("Connected");
case NotConfigured:
- return QLatin1String("NotConfigured");
+ return QLatin1String("Not configured");
case ServerVersionMismatch:
return QLatin1String("Server Version Mismatch");
- case CredentialsMissingOrWrong:
+ case CredentialsNotReady:
+ return QLatin1String("Credentials not ready");
+ case CredentialsWrong:
return QLatin1String("Credentials Wrong");
+ case SslError:
+ return QLatin1String("SSL Error");
case StatusNotFound:
return QLatin1String("Status not found");
- case UserCanceledCredentials:
- return QLatin1String("User canceled credentials");
case ServiceUnavailable:
return QLatin1String("Service unavailable");
case MaintenanceMode:
}
// now check the authentication
- if (_account->credentials()->ready())
- QTimer::singleShot(0, this, SLOT(checkAuthentication()));
- else
- reportResult(CredentialsMissingOrWrong);
+ QTimer::singleShot( 0, this, SLOT( checkAuthentication() ));
}
// status.php could not be loaded (network or server issue!).
{
auto job = qobject_cast<CheckServerJob *>(sender());
qCWarning(lcConnectionValidator) << reply->error() << job->errorString() << reply->peek(1024);
- if (!_account->credentials()->ready()) {
- // This could be needed for SSL client certificates
- // We need to load them from keychain and try
- reportResult(CredentialsMissingOrWrong);
- } else if (!_account->credentials()->stillValid(reply)) {
+ if (reply->error() == QNetworkReply::SslHandshakeFailedError) {
+ reportResult(SslError);
+ return;
+ }
+
+ if (!_account->credentials()->stillValid(reply)) {
+ // Note: Why would this happen on a status.php request?
_errors.append(tr("Authentication error: Either username or password are wrong."));
} else {
//_errors.append(tr("Unable to connect to %1").arg(_account->url().toString()));
{
AbstractCredentials *creds = _account->credentials();
- if (!creds->ready()) { // The user canceled
- reportResult(UserCanceledCredentials);
+ if (!creds->ready()) {
+ reportResult(CredentialsNotReady);
+ return;
}
// simply GET the webdav root, will fail if credentials are wrong.
auto job = qobject_cast<PropfindJob *>(sender());
Status stat = Timeout;
- if (reply->error() == QNetworkReply::AuthenticationRequiredError || !_account->credentials()->stillValid(reply)) {
+ if (reply->error() == QNetworkReply::SslHandshakeFailedError) {
+ _errors << job->errorStringParsingBody();
+ stat = SslError;
+
+ } else if (reply->error() == QNetworkReply::AuthenticationRequiredError
+ || !_account->credentials()->stillValid(reply)) {
qCWarning(lcConnectionValidator) << "******** Password is wrong!" << reply->error() << job->errorString();
_errors << tr("The provided credentials are not correct");
- stat = CredentialsMissingOrWrong;
+ stat = CredentialsWrong;
} else if (reply->error() != QNetworkReply::NoError) {
_errors << job->errorStringParsingBody();
Connected,
NotConfigured,
ServerVersionMismatch, // The server version is too old
- CredentialsMissingOrWrong, // Credentials aren't ready or AuthenticationRequiredError
+ CredentialsNotReady, // Credentials aren't ready
+ CredentialsWrong, // AuthenticationRequiredError
+ SslError, // SSL handshake error, certificate rejected by user?
StatusNotFound, // Error retrieving status.php
- UserCanceledCredentials, // checkAuthentication when credentials aren't ready
ServiceUnavailable, // 503 on authed request
MaintenanceMode, // maintenance enabled in status.php
Timeout // actually also used for other errors on the authed request
AbstractCredentials::AbstractCredentials()
: _account(0)
+ , _wasFetched(false)
{
}
virtual QString authType() const = 0;
virtual QString user() const = 0;
virtual QNetworkAccessManager *getQNAM() const = 0;
+
+ /** Whether there are credentials that can be used for a connection attempt. */
virtual bool ready() const = 0;
+
+ /** Whether fetchFromKeychain() was called before. */
+ bool wasFetched() const { return _wasFetched; }
+
+ /** Trigger (async) fetching of credential information
+ *
+ * Should set _wasFetched = true, and later emit fetched() when done.
+ */
virtual void fetchFromKeychain() = 0;
+
+ /** Ask credentials from the user (typically async)
+ *
+ * Should emit asked() when done.
+ */
virtual void askFromUser() = 0;
+
virtual bool stillValid(QNetworkReply *reply) = 0;
virtual void persist() = 0;
*
* Note that sensitive data (like the password used to acquire the
* session cookie) may be retained. See forgetSensitiveData().
+ *
+ * ready() must return false afterwards.
*/
virtual void invalidateToken() = 0;
static QString keychainKey(const QString &url, const QString &user);
Q_SIGNALS:
+ /** Emitted when fetchFromKeychain() is done.
+ *
+ * Note that ready() can be true or false, depending on whether there was useful
+ * data in the keychain.
+ */
void fetched();
+
+ /** Emitted when askFromUser() is done.
+ *
+ * Note that ready() can be true or false, depending on whether the user provided
+ * data or not.
+ */
void asked();
protected:
Account *_account;
+ bool _wasFetched;
};
} // namespace OCC
void DummyCredentials::fetchFromKeychain()
{
+ _wasFetched = true;
Q_EMIT(fetched());
}
void HttpCredentials::fetchFromKeychain()
{
+ _wasFetched = true;
+
// User must be fetched from config file
fetchUser();
void TokenCredentials::fetchFromKeychain()
{
+ _wasFetched = true;
Q_EMIT fetched();
}