~mardy/signon-ui/lp1171853

« back to all changes in this revision

Viewing changes to src/indicator-service.cpp

  • Committer: Alberto Mardegan
  • Date: 2012-11-13 09:46:57 UTC
  • mfrom: (66.3.4 reauthentication)
  • Revision ID: alberto.mardegan@canonical.com-20121113094657-d8goas34wnw9u034
New ReauthenticateAccount D-Bus API

This method will allow reauthenticating an account by replaying the
authentication session which caused the failure.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 
23
23
#include "debug.h"
24
24
#include "i18n.h"
 
25
#include "reauthenticator.h"
25
26
#include "webcredentials_adaptor.h"
26
27
 
 
28
#include <QDBusContext>
 
29
 
27
30
using namespace SignOnUi;
28
31
 
29
32
QDBusArgument &operator<<(QDBusArgument &argument, const QSet<uint> &set)
53
56
 
54
57
static IndicatorService *m_instance = 0;
55
58
 
56
 
class IndicatorServicePrivate: public QObject
 
59
class IndicatorServicePrivate: public QObject, QDBusContext
57
60
{
58
61
    Q_OBJECT
59
62
    Q_DECLARE_PUBLIC(IndicatorService)
72
75
    void ClearErrorStatus();
73
76
    void RemoveFailures(const QSet<uint> &accountIds);
74
77
    void ReportFailure(uint accountId, const QVariantMap &notification);
 
78
    bool ReauthenticateAccount(uint accountId,
 
79
                               const QVariantMap &extraParameters);
75
80
 
76
81
private:
77
82
    void setErrorStatus();
78
83
    void notifyPropertyChanged(const char *propertyName);
79
84
 
 
85
private Q_SLOTS:
 
86
    void onReauthenticatorFinished(bool success);
 
87
 
80
88
private:
81
89
    mutable IndicatorService *q_ptr;
82
90
    WebcredentialsAdaptor *m_adaptor;
83
91
    QSet<uint> m_failures;
 
92
    QMap<uint, QList<AuthData> > m_failureClientData;
 
93
    QMap<uint, Reauthenticator*> m_reauthenticators;
 
94
    QDBusMessage m_clientMessage;
84
95
    bool m_errorStatus;
85
96
};
86
97
 
112
123
void IndicatorServicePrivate::ReportFailure(uint accountId,
113
124
                                            const QVariantMap &notification)
114
125
{
115
 
    Q_UNUSED(notification);
116
 
 
117
126
    m_failures.insert(accountId);
 
127
 
 
128
    /* If the original client data is provided, we remember it: it can
 
129
     * be used to replay the authentication later.
 
130
     */
 
131
    if (notification.contains("ClientData")) {
 
132
        /* If the key is not found, the QMap's [] operator inserts an empty
 
133
         * element in the map and return a reference to it. So the following
 
134
         * line of code returns a valid QList even if the account never failed
 
135
         * before.
 
136
         */
 
137
        QList<AuthData> &failedAuthentications =
 
138
            m_failureClientData[accountId];
 
139
 
 
140
        AuthData authData;
 
141
        authData.sessionData = notification["ClientData"].toMap();
 
142
        authData.identity = quint32(notification["Identity"].toUInt());
 
143
        authData.method = notification["Method"].toString();
 
144
        authData.mechanism = notification["Mechanism"].toString();
 
145
        failedAuthentications.append(authData);
 
146
    }
 
147
 
118
148
    notifyPropertyChanged("Failures");
119
149
 
120
150
    setErrorStatus();
121
151
}
122
152
 
 
153
bool IndicatorServicePrivate::ReauthenticateAccount(uint accountId,
 
154
                                   const QVariantMap &extraParameters)
 
155
{
 
156
    if (!m_failureClientData.contains(accountId)) {
 
157
        /* Nothing we can do about this account */
 
158
        TRACE() << "No reauthentication data for account" << accountId;
 
159
        return false;
 
160
    }
 
161
 
 
162
    if (m_reauthenticators.contains(accountId)) {
 
163
        /* A reauthenticator for this account is already at work. This
 
164
         * shouldn't happen in a real world scenario. */
 
165
        qWarning() << "Reauthenticator already active on" << accountId;
 
166
        return false;
 
167
    }
 
168
 
 
169
    TRACE() << "Reauthenticating account" << accountId;
 
170
 
 
171
    /* If we need to reauthenticate, we are delivering the result
 
172
     * after iterating the event loop, so we must inform QtDBus that
 
173
     * it shouldn't use this method's return value as a result.
 
174
     */
 
175
    setDelayedReply(true);
 
176
    m_clientMessage = message();
 
177
    QList<AuthData> &failedAuthentications = m_failureClientData[accountId];
 
178
 
 
179
    Reauthenticator *reauthenticator =
 
180
        new Reauthenticator(failedAuthentications, extraParameters, this);
 
181
    m_reauthenticators[accountId] = reauthenticator;
 
182
 
 
183
    QObject::connect(reauthenticator, SIGNAL(finished(bool)),
 
184
                     this, SLOT(onReauthenticatorFinished(bool)),
 
185
                     Qt::QueuedConnection);
 
186
    reauthenticator->start();
 
187
 
 
188
    return true; // ignored, see setDelayedReply() above.
 
189
}
 
190
 
123
191
void IndicatorServicePrivate::setErrorStatus()
124
192
{
125
193
    /* Don't show more than one notification, until the error status is
145
213
    QDBusConnection::sessionBus().send(signal);
146
214
}
147
215
 
 
216
void IndicatorServicePrivate::onReauthenticatorFinished(bool success)
 
217
{
 
218
    Reauthenticator *reauthenticator =
 
219
        qobject_cast<Reauthenticator*>(sender());
 
220
 
 
221
    /* Find the account; searching a map by value is inefficient, but
 
222
     * in this case it's extremely likely that the map contains just
 
223
     * one element. :-) */
 
224
    uint accountId = 0;
 
225
    QMap<uint,Reauthenticator*>::const_iterator i;
 
226
    for (i = m_reauthenticators.constBegin();
 
227
         i != m_reauthenticators.constEnd();
 
228
         i++) {
 
229
        if (i.value() == reauthenticator) {
 
230
            accountId = i.key();
 
231
            break;
 
232
        }
 
233
    }
 
234
    Q_ASSERT (accountId != 0);
 
235
 
 
236
    QDBusMessage reply = m_clientMessage.createReply(success);
 
237
    QDBusConnection::sessionBus().send(reply);
 
238
 
 
239
    if (success) {
 
240
        m_failureClientData.remove(accountId);
 
241
        m_failures.remove(accountId);
 
242
        notifyPropertyChanged("Failures");
 
243
 
 
244
        if (m_failures.isEmpty()) {
 
245
            ClearErrorStatus();
 
246
        }
 
247
    }
 
248
 
 
249
    m_reauthenticators.remove(accountId);
 
250
    reauthenticator->deleteLater();
 
251
}
 
252
 
148
253
IndicatorService::IndicatorService(QObject *parent):
149
254
    QObject(parent),
150
255
    d_ptr(new IndicatorServicePrivate(this))