/* * Copyright (C) by Klaas Freitag * Copyright (c) by Markus Goetz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include "mirall/account.h" #include "mirall/mirallaccessmanager.h" #include "mirall/utility.h" #include "mirall/theme.h" #include "creds/credentialscommon.h" #include "creds/tokencredentials.h" namespace Mirall { namespace { int getauth(const char *prompt, char *buf, size_t len, int echo, int verify, void *userdata) { int re = 0; QMutex mutex; // ### safe? TokenCredentials* http_credentials = qobject_cast(AccountManager::instance()->account()->credentials()); if (!http_credentials) { qDebug() << "Not a HTTP creds instance!"; return -1; } QString qPrompt = QString::fromLatin1( prompt ).trimmed(); QString user = http_credentials->user(); QString pwd = http_credentials->password(); if( qPrompt == QLatin1String("Enter your username:") ) { // qDebug() << "OOO Username requested!"; QMutexLocker locker( &mutex ); qstrncpy( buf, user.toUtf8().constData(), len ); } else if( qPrompt == QLatin1String("Enter your password:") ) { QMutexLocker locker( &mutex ); // qDebug() << "OOO Password requested!"; qstrncpy( buf, pwd.toUtf8().constData(), len ); } else { re = handleNeonSSLProblems(prompt, buf, len, echo, verify, userdata); } return re; } const char userC[] = "user"; const char authenticationFailedC[] = "owncloud-authentication-failed"; } // ns class TokenCredentialsAccessManager : public MirallAccessManager { public: friend class TokenCredentials; TokenCredentialsAccessManager(const TokenCredentials *cred, QObject* parent = 0) : MirallAccessManager(parent), _cred(cred) {} protected: QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData) { if (_cred->user().isEmpty() || _cred->password().isEmpty() || _cred->_token.isEmpty()) { qWarning() << Q_FUNC_INFO << "Empty user/password/token provided!"; } QNetworkRequest req(request); QByteArray credHash = QByteArray(_cred->user().toUtf8()+":"+_cred->password().toUtf8()).toBase64(); req.setRawHeader(QByteArray("Authorization"), QByteArray("Basic ") + credHash); req.setRawHeader("Cookie", _cred->_token.toUtf8()); // analogous to neon in syncContextPreStart return MirallAccessManager::createRequest(op, req, outgoingData); } private: const TokenCredentials *_cred; }; TokenCredentials::TokenCredentials() : _user(), _password(), _ready(false) { } TokenCredentials::TokenCredentials(const QString& user, const QString& password, const QString &token) : _user(user), _password(password), _token(token), _ready(true) { } void TokenCredentials::syncContextPreInit (CSYNC* ctx) { csync_set_auth_callback (ctx, getauth); } void TokenCredentials::syncContextPreStart (CSYNC* ctx) { csync_set_module_property(ctx, "session_key", _token.toUtf8().data()); } bool TokenCredentials::changed(AbstractCredentials* credentials) const { TokenCredentials* other(dynamic_cast< TokenCredentials* >(credentials)); if (!other || (other->user() != this->user())) { return true; } return false; } QString TokenCredentials::authType() const { return QString::fromLatin1("token"); } QString TokenCredentials::user() const { return _user; } QString TokenCredentials::password() const { return _password; } QNetworkAccessManager* TokenCredentials::getQNAM() const { MirallAccessManager* qnam = new TokenCredentialsAccessManager(this); connect( qnam, SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)), this, SLOT(slotAuthentication(QNetworkReply*,QAuthenticator*))); return qnam; } bool TokenCredentials::ready() const { return _ready; } void TokenCredentials::fetch(Account *account) { if( !account ) { return; } Q_EMIT fetched(); } bool TokenCredentials::stillValid(QNetworkReply *reply) { return ((reply->error() != QNetworkReply::AuthenticationRequiredError) // returned if user/password or token are incorrect && (reply->error() != QNetworkReply::OperationCanceledError || !reply->property(authenticationFailedC).toBool())); } QString TokenCredentials::queryPassword(bool *ok) { return QString(); } void TokenCredentials::invalidateToken(Account *account) { qDebug() << Q_FUNC_INFO; _ready = false; account->clearCookieJar(); _token = QString(); _user = QString(); _password = QString(); } void TokenCredentials::persist(Account *account) { } void TokenCredentials::slotAuthentication(QNetworkReply* reply, QAuthenticator* authenticator) { Q_UNUSED(authenticator) // we cannot use QAuthenticator, because it sends username and passwords with latin1 // instead of utf8 encoding. Instead, we send it manually. Thus, if we reach this signal, // those credentials were invalid and we terminate. qDebug() << "Stop request: Authentication failed for " << reply->url().toString(); reply->setProperty(authenticationFailedC, true); reply->close(); } } // ns Mirall