Add named referencies implementation
[accounts-sso:vitalyrepins-signon.git] / src / signond / signonidentity.cpp
1 /*
2  * This file is part of signon
3  *
4  * Copyright (C) 2009-2010 Nokia Corporation.
5  *
6  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
7  * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * version 2.1 as published by the Free Software Foundation.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  */
23
24 #include <iostream>
25
26 #include "signond-common.h"
27 #include "signonidentity.h"
28 #include "signonui_interface.h"
29
30 #include "accesscontrolmanager.h"
31 #include "signonidentityadaptor.h"
32
33
34 #define SIGNON_RETURN_IF_CAM_UNAVAILABLE(_ret_arg_) do {                          \
35         if (!(CredentialsAccessManager::instance()->credentialsSystemOpened())) { \
36             QDBusMessage errReply = message().createErrorReply(                   \
37                     internalServerErrName,                                        \
38                     internalServerErrStr + QLatin1String("Could not access Signon Database.")); \
39             SIGNOND_BUS.send(errReply); \
40             return _ret_arg_;           \
41         }                               \
42     } while(0)
43
44 namespace SignonDaemonNS {
45
46     const QString internalServerErrName = SIGNOND_INTERNAL_SERVER_ERR_NAME;
47     const QString internalServerErrStr = SIGNOND_INTERNAL_SERVER_ERR_STR;
48
49     SignonIdentity::SignonIdentity(quint32 id, int timeout,
50                                    SignonDaemon *parent)
51             : SignonDisposable(timeout, parent),
52               m_pInfo(NULL),
53               m_pSignonDaemon(parent),
54               m_registered(false)
55     {
56         m_id = id;
57
58         /*
59          * creation of unique name for the given identity
60          * */
61         static quint32 incr = 0;
62         QString objectName = SIGNOND_DAEMON_OBJECTPATH + QLatin1String("/Identity_")
63                              + QString::number(incr++, 16);
64         setObjectName(objectName);
65
66         m_signonui = new SignonUiAdaptor(
67                                         SIGNON_UI_SERVICE,
68                                         SIGNON_UI_DAEMON_OBJECTPATH,
69                                         SIGNOND_BUS,
70                                         this);
71     }
72
73     SignonIdentity::~SignonIdentity()
74     {
75         if (m_registered)
76         {
77             emit unregistered();
78             QDBusConnection connection = SIGNOND_BUS;
79             connection.unregisterObject(objectName());
80         }
81
82         if (credentialsStored())
83             m_pSignonDaemon->m_storedIdentities.remove(m_id);
84         else
85             m_pSignonDaemon->m_unstoredIdentities.remove(objectName());
86
87         delete m_signonui;
88     }
89
90     bool SignonIdentity::init()
91     {
92         QDBusConnection connection = SIGNOND_BUS;
93
94         if (!connection.isConnected()) {
95             QDBusError err = connection.lastError();
96             TRACE() << "Connection cannot be established:" << err.errorString(err.type()) ;
97             return false;
98         }
99
100         QDBusConnection::RegisterOptions registerOptions = QDBusConnection::ExportAllContents;
101
102 #ifndef SIGNON_DISABLE_ACCESS_CONTROL
103         (void)new SignonIdentityAdaptor(this);
104         registerOptions = QDBusConnection::ExportAdaptors;
105 #endif
106
107         if (!connection.registerObject(objectName(), this, registerOptions)) {
108             TRACE() << "Object cannot be registered: " << objectName();
109             return false;
110         }
111
112         return (m_registered = true);
113     }
114
115     SignonIdentity *SignonIdentity::createIdentity(quint32 id, SignonDaemon *parent)
116     {
117         SignonIdentity *identity =
118             new SignonIdentity(id, parent->identityTimeout(), parent);
119
120         if (!identity->init()) {
121             TRACE() << "The created identity is invalid and will be deleted.\n";
122             delete identity;
123             return NULL;
124         }
125
126         return identity;
127     }
128
129     void SignonIdentity::destroy()
130     {
131         if (m_registered)
132         {
133             emit unregistered();
134             QDBusConnection connection = SIGNOND_BUS;
135             connection.unregisterObject(objectName());
136             m_registered = false;
137         }
138
139         deleteLater();
140     }
141
142     SignonIdentityInfo SignonIdentity::queryInfo(bool &ok, bool queryPassword)
143     {
144         ok = true;
145
146         if (m_pInfo) {
147             return *m_pInfo;
148         } else {
149             CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
150             m_pInfo = new SignonIdentityInfo(db->credentials(m_id, queryPassword));
151
152             if (db->error().type() != QSqlError::NoError) {
153                 ok = false;
154                 delete m_pInfo;
155                 m_pInfo = NULL;
156                 return SignonIdentityInfo();
157             }
158         }
159         return *m_pInfo;
160     }
161
162     bool SignonIdentity::addReference(const QString &reference)
163     {
164         RequestCounter::instance()->addIdentityRequest();
165         TRACE() << "addReference: " << reference;
166         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
167         if (db == NULL) {
168             BLAME() << "NULL database handler object.";
169             return SIGNOND_NEW_IDENTITY;
170         }
171         QString aegisIdToken = AccessControlManager::idTokenOfPeer(static_cast<QDBusContext>(*this));
172         keepInUse();
173         return db->addReference(m_id, aegisIdToken, reference);
174     }
175
176     bool SignonIdentity::removeReference(const QString &reference)
177     {
178         RequestCounter::instance()->addIdentityRequest();
179         TRACE() << "removeReference: " << reference;
180         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
181         if (db == NULL) {
182             BLAME() << "NULL database handler object.";
183             return SIGNOND_NEW_IDENTITY;
184         }
185         QString aegisIdToken = AccessControlManager::idTokenOfPeer(static_cast<QDBusContext>(*this));
186         keepInUse();
187         return db->removeReference(m_id, aegisIdToken, reference);
188     }
189
190     quint32 SignonIdentity::requestCredentialsUpdate(const QString &displayMessage)
191     {
192         RequestCounter::instance()->addIdentityRequest();
193         Q_UNUSED(displayMessage);
194
195         SIGNON_RETURN_IF_CAM_UNAVAILABLE(0);
196
197         QDBusMessage errReply = message().createErrorReply(
198                                                 SIGNOND_UNKNOWN_ERR_NAME,
199                                                 QLatin1String("Not implemented."));
200         SIGNOND_BUS.send(errReply);
201         keepInUse();
202         return 0;
203     }
204
205     QList<QVariant> SignonIdentity::queryInfo()
206     {
207         RequestCounter::instance()->addIdentityRequest();
208         TRACE() << "QUERYING INFO";
209
210         SIGNON_RETURN_IF_CAM_UNAVAILABLE(QList<QVariant>());
211
212         bool ok;
213         SignonIdentityInfo info = queryInfo(ok, false);
214
215         TRACE() << info.serialize();
216         if (!ok) {
217             TRACE();
218             QDBusMessage errReply = message().createErrorReply(
219                                         SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_NAME,
220                                         QString(SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_STR
221                                                 + QLatin1String("Database querying error occurred.")));
222             SIGNOND_BUS.send(errReply);
223             return QList<QVariant>();
224         }
225
226         if (info.m_id == 0) {
227             TRACE();
228             QDBusMessage errReply = message().createErrorReply(SIGNOND_IDENTITY_NOT_FOUND_ERR_NAME,
229                                                                SIGNOND_IDENTITY_NOT_FOUND_ERR_STR);
230             SIGNOND_BUS.send(errReply);
231             return QList<QVariant>();
232         }
233
234         TRACE() << "INFO as variant list:" << info.toVariantList();
235         keepInUse();
236         return info.toVariantList();
237     }
238
239     bool SignonIdentity::verifyUser(const QString &displayMessage)
240     {
241         RequestCounter::instance()->addIdentityRequest();
242         Q_UNUSED(displayMessage)
243
244         SIGNON_RETURN_IF_CAM_UNAVAILABLE(false);
245
246         QDBusMessage errReply = message().createErrorReply(SIGNOND_UNKNOWN_ERR_NAME,
247                                                            QLatin1String("Not implemented."));
248         SIGNOND_BUS.send(errReply);
249         keepInUse();
250         return false;
251     }
252
253     bool SignonIdentity::verifySecret(const QString &secret)
254     {
255         RequestCounter::instance()->addIdentityRequest();
256
257         SIGNON_RETURN_IF_CAM_UNAVAILABLE(false);
258
259         bool ok;
260         queryInfo(ok);
261         if (!ok) {
262             TRACE();
263             QDBusMessage errReply = message().createErrorReply(
264                                         SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_NAME,
265                                         QString(SIGNOND_CREDENTIALS_NOT_AVAILABLE_ERR_STR
266                                                 + QLatin1String("Database querying error occurred.")));
267             SIGNOND_BUS.send(errReply);
268             return false;
269         }
270
271         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
272         bool ret = db->checkPassword(m_pInfo->m_id, m_pInfo->m_userName, secret);
273
274         keepInUse();
275         return ret;
276     }
277
278     void SignonIdentity::remove()
279     {
280         RequestCounter::instance()->addIdentityRequest();
281
282         SIGNON_RETURN_IF_CAM_UNAVAILABLE();
283
284         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
285         if (!db->removeCredentials(m_id)) {
286             TRACE() << "Error occurred while inserting/updating credemtials.";
287             QDBusMessage errReply = message().createErrorReply(
288                                                         SIGNOND_REMOVE_FAILED_ERR_NAME,
289                                                         QString(SIGNOND_REMOVE_FAILED_ERR_STR
290                                                                 + QLatin1String("Database error occurred.")));
291             SIGNOND_BUS.send(errReply);
292         }
293         emit infoUpdated((int)SignOn::IdentityRemoved);
294         keepInUse();
295     }
296
297     bool SignonIdentity::signOut()
298     {
299         RequestCounter::instance()->addIdentityRequest();
300         TRACE() << "Signout request. Identity ID: " << id();
301         /*
302            - If the identity is stored (thus registered here)
303            signal 'sign out' to all identities subsribed to this object,
304            otherwise the only identity subscribed to this is the newly
305            created client side identity, which called this method.
306            - This is just a safety check, as the client identity - if it is a new one -
307            should not inform server side to sign out.
308         */
309         if (id() != SIGNOND_NEW_IDENTITY) {
310             //clear stored sessiondata
311             CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
312             if (!db->removeData(m_id)) {
313                 TRACE() << "clear data failed";
314             }
315
316             emit infoUpdated((int)SignOn::IdentitySignedOut);
317         }
318         keepInUse();
319         return true;
320     }
321
322     quint32 SignonIdentity::storeCredentials(const quint32 id,
323                                              const QString &userName,
324                                              const QString &secret,
325                                              const bool storeSecret,
326                                              const QMap<QString, QVariant> &methods,
327                                              const QString &caption,
328                                              const QStringList &realms,
329                                              const QStringList &accessControlList,
330                                              const int type)
331     {
332         RequestCounter::instance()->addIdentityRequest();
333
334         SIGNON_RETURN_IF_CAM_UNAVAILABLE(SIGNOND_NEW_IDENTITY);
335
336         QString aegisIdToken = AccessControlManager::idTokenOfPeer(static_cast<QDBusContext>(*this));
337
338         QStringList accessControlListLocal = accessControlList;
339         if (!aegisIdToken.isNull())
340             accessControlListLocal.prepend(aegisIdToken);
341
342         SignonIdentityInfo info(id, userName, secret, methods, caption,
343                                 realms, accessControlListLocal, type);
344
345         TRACE() << info.serialize();
346         storeCredentials(info, storeSecret);
347         if (m_id == SIGNOND_NEW_IDENTITY) {
348             QDBusMessage errReply = message().createErrorReply(SIGNOND_STORE_FAILED_ERR_NAME,
349                                                                SIGNOND_STORE_FAILED_ERR_STR);
350             SIGNOND_BUS.send(errReply);
351         }
352
353         keepInUse();
354         return m_id;
355     }
356
357     quint32 SignonIdentity::storeCredentials(const SignonIdentityInfo &info, bool storeSecret)
358     {
359         CredentialsDB *db = CredentialsAccessManager::instance()->credentialsDB();
360         if (db == NULL) {
361             BLAME() << "NULL database handler object.";
362             return SIGNOND_NEW_IDENTITY;
363         }
364
365         bool newIdentity = (info.m_id == SIGNOND_NEW_IDENTITY);
366
367         if (newIdentity)
368             m_id = db->insertCredentials(info, storeSecret);
369         else
370             db->updateCredentials(info, storeSecret);
371
372         if (db->errorOccurred()) {
373             if (newIdentity)
374                 m_id = SIGNOND_NEW_IDENTITY;
375
376             TRACE() << "Error occurred while inserting/updating credentials.";
377         } else {
378             if (m_pInfo) {
379                 delete m_pInfo;
380                 m_pInfo = NULL;
381             }
382             m_pSignonDaemon->identityStored(this);
383             TRACE() << "FRESH, JUST STORED CREDENTIALS ID:" << m_id;
384             emit infoUpdated((int)SignOn::IdentityDataUpdated);
385         }
386         return m_id;
387     }
388
389 } //namespace SignonDaemonNS