KAuth

executejob.cpp
1 /*
2  SPDX-FileCopyrightText: 2009-2012 Dario Freddi <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "executejob.h"
8 
9 #include "BackendsManager.h"
10 #include "kauthdebug.h"
11 
12 #include <QCoreApplication>
13 #include <QEventLoop>
14 #include <QHash>
15 #include <QTimer>
16 
17 namespace KAuth
18 {
19 class ExecuteJobPrivate
20 {
21  Q_DECLARE_TR_FUNCTIONS(KAuth::ExecuteJob)
22 
23 public:
24  explicit ExecuteJobPrivate(ExecuteJob *parent)
25  : q(parent)
26  {
27  }
28 
29  ExecuteJob *q;
30  Action action;
31 
32  Action::ExecutionMode mode;
33  QVariantMap data;
34 
35  void doExecuteAction();
36  void doAuthorizeAction();
37  void actionPerformedSlot(const QString &action, const ActionReply &reply);
38  void progressStepSlot(const QString &action, int i);
39  void progressStepSlot(const QString &action, const QVariantMap &data);
40  void statusChangedSlot(const QString &action, KAuth::Action::AuthStatus status);
41 };
42 
43 static QHash<QString, ExecuteJob *> s_watchers;
44 
45 ExecuteJob::ExecuteJob(const Action &action, Action::ExecutionMode mode, QObject *parent)
46  : KJob(parent)
47  , d(new ExecuteJobPrivate(this))
48 {
49  d->action = action;
50  d->mode = mode;
51 
52  HelperProxy *helper = BackendsManager::helperProxy();
53 
54  connect(helper, &KAuth::HelperProxy::actionPerformed, this, [this](const QString &action, const ActionReply &reply) {
55  d->actionPerformedSlot(action, reply);
56  });
57  connect(helper, &KAuth::HelperProxy::progressStep, this, [this](const QString &action, int i) {
58  d->progressStepSlot(action, i);
59  });
60  connect(helper, &KAuth::HelperProxy::progressStepData, this, [this](const QString &action, const QVariantMap &data) {
61  d->progressStepSlot(action, data);
62  });
63 
64  connect(BackendsManager::authBackend(), &KAuth::AuthBackend::actionStatusChanged, this, [this](const QString &action, Action::AuthStatus status) {
65  d->statusChangedSlot(action, status);
66  });
67 }
68 
69 ExecuteJob::~ExecuteJob() = default;
70 
72 {
73  return d->action;
74 }
75 
76 QVariantMap ExecuteJob::data() const
77 {
78  return d->data;
79 }
80 
82 {
83  if (!d->action.isValid()) {
84  qCWarning(KAUTH) << "Tried to start an invalid action: " << d->action.name();
86  reply.setErrorDescription(tr("Tried to start an invalid action"));
87  d->actionPerformedSlot(d->action.name(), reply);
88  return;
89  }
90 
91  switch (d->mode) {
92  case Action::ExecuteMode:
93  QTimer::singleShot(0, this, [this]() {
94  d->doExecuteAction();
95  });
96  break;
97  case Action::AuthorizeOnlyMode:
98  QTimer::singleShot(0, this, [this]() {
99  d->doAuthorizeAction();
100  });
101  break;
102  default: {
104  reply.setErrorDescription(tr("Unknown execution mode chosen"));
105  d->actionPerformedSlot(d->action.name(), reply);
106  break;
107  }
108  }
109 }
110 
111 bool ExecuteJob::kill(KillVerbosity verbosity)
112 {
113  BackendsManager::helperProxy()->stopAction(d->action.name(), d->action.helperId());
114  KJob::kill(verbosity);
115  return true;
116 }
117 
118 void ExecuteJobPrivate::doExecuteAction()
119 {
120  // If this action authorizes from the client, let's do it now
121  if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) {
122  if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
123  BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget());
124  }
125 
126  Action::AuthStatus s = BackendsManager::authBackend()->authorizeAction(action.name());
127 
128  if (s == Action::AuthorizedStatus) {
129  if (action.hasHelper()) {
130  BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout());
131  } else {
132  // Done
133  actionPerformedSlot(action.name(), ActionReply::SuccessReply());
134  }
135  } else {
136  // Abort if authorization fails
137  switch (s) {
139  actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply());
140  break;
142  actionPerformedSlot(action.name(), ActionReply::InvalidActionReply());
143  break;
145  actionPerformedSlot(action.name(), ActionReply::UserCancelledReply());
146  break;
147  default: {
148  ActionReply r(ActionReply::BackendError);
149  r.setErrorDescription(tr("Unknown status for the authentication procedure"));
150  actionPerformedSlot(action.name(), r);
151  break;
152  }
153  }
154  }
155  } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) {
156  if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
157  BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget());
158  }
159  if (!action.hasHelper()) {
160  ActionReply r(ActionReply::InvalidActionReply());
161  r.setErrorDescription(tr("The current backend only allows helper authorization, but this action does not have a helper."));
162  actionPerformedSlot(action.name(), r);
163  return;
164  }
165  BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.detailsV2(), action.arguments(), action.timeout());
166  } else {
167  // There's something totally wrong here
168  ActionReply r(ActionReply::BackendError);
169  r.setErrorDescription(tr("The backend does not specify how to authorize"));
170  actionPerformedSlot(action.name(), r);
171  }
172 }
173 
174 void ExecuteJobPrivate::doAuthorizeAction()
175 {
176  // Check the status first
177  Action::AuthStatus s = action.status();
178  if (s == Action::AuthRequiredStatus) {
179  // Let's check what to do
180  if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) {
181  // In this case we can actually try an authorization
182  if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
183  BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget());
184  }
185 
186  s = BackendsManager::authBackend()->authorizeAction(action.name());
187  } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) {
188  // In this case, just throw out success, as the auth will take place later
190  } else {
191  // This should never, never happen
192  ActionReply r(ActionReply::BackendError);
193  r.setErrorDescription(tr("The backend does not specify how to authorize"));
194  actionPerformedSlot(action.name(), r);
195  }
196  }
197 
198  // Return based on the current status
199  if (s == Action::AuthorizedStatus) {
200  actionPerformedSlot(action.name(), ActionReply::SuccessReply());
201  } else {
202  actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply());
203  }
204 }
205 
206 void ExecuteJobPrivate::actionPerformedSlot(const QString &taction, const ActionReply &reply)
207 {
208  if (taction == action.name()) {
209  if (reply.failed()) {
210  q->setError(reply.errorCode());
211  q->setErrorText(reply.errorDescription());
212  } else {
213  data = reply.data();
214  }
215 
216  q->emitResult();
217  }
218 }
219 
220 void ExecuteJobPrivate::progressStepSlot(const QString &taction, int i)
221 {
222  if (taction == action.name()) {
223  q->setPercent(i);
224  }
225 }
226 
227 void ExecuteJobPrivate::progressStepSlot(const QString &taction, const QVariantMap &data)
228 {
229  if (taction == action.name()) {
230  Q_EMIT q->newData(data);
231  }
232 }
233 
234 void ExecuteJobPrivate::statusChangedSlot(const QString &taction, Action::AuthStatus status)
235 {
236  if (taction == action.name()) {
237  Q_EMIT q->statusChanged(status);
238  }
239 }
240 
241 } // namespace Auth
242 
243 #include "moc_executejob.cpp"
@ AuthorizedStatus
The authorization has been granted by the authorization backend.
Definition: action.h:86
QVariantMap data() const
Use this to get the data set in the action by HelperSupport::progressStep(QVariant) or returned at th...
Definition: executejob.cpp:76
Job for executing an Action.
Definition: executejob.h:39
AuthStatus
The three values set by authorization methods.
Definition: action.h:82
Class that encapsulates a reply coming from the helper after executing an action.
Definition: actionreply.h:334
bool kill(KillVerbosity verbosity=Quietly)
static const ActionReply UserCancelledReply()
errorCode() == UserCancelled
Definition: actionreply.cpp:72
~ExecuteJob() override
Virtual destructor.
void setErrorDescription(const QString &error)
Sets a human-readble description of the error.
@ BackendError
The underlying backend reported an error.
Definition: actionreply.h:372
Q_SCRIPTABLE CaptureState status()
bool kill(KillVerbosity verbosity=Quietly)
Attempts to halt the execution of the action associated with this job.
Definition: executejob.cpp:111
static const ActionReply AuthorizationDeniedReply()
errorCode() == AuthorizationDenied
Definition: actionreply.cpp:68
QVariantMap data() const
Returns the custom data coming from the helper.
static const ActionReply InvalidActionReply()
errorCode() == InvalidAction
Definition: actionreply.cpp:64
Definition: action.cpp:18
@ InvalidStatus
An invalid action cannot be authorized.
Definition: action.h:85
@ UserCancelledStatus
The user pressed Cancel the authentication dialog. Currently used only on the mac.
Definition: action.h:88
Capabilities capabilities()
static const ActionReply SuccessReply()
An empty successful reply. Same as using the default constructor.
Definition: actionreply.cpp:40
Class to access, authorize and execute actions.
Definition: action.h:75
@ DeniedStatus
The authorization has been denied by the authorization backend.
Definition: action.h:83
void start() override
Starts the job asynchronously.
Definition: executejob.cpp:81
@ InvalidActionError
You tried to execute an invalid action object.
Definition: actionreply.h:366
@ AuthRequiredStatus
The user could obtain the authorization after authentication.
Definition: action.h:87
QString tr(const char *sourceText, const char *disambiguation, int n)
Action action() const
Definition: executejob.cpp:71
ActionReply()
Default constructor. Sets type() to Success and errorCode() to zero.
Definition: actionreply.cpp:95
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Feb 5 2023 04:14:58 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.