Skip to content

Commit

Permalink
[devicelock] Add API for services to directly request permission for …
Browse files Browse the repository at this point in the history
…actions. Contributes to JB#40880

This allows a service to directly ask prompt the user to confirm it
should perform an action on behalf of an application. Or for a user
session service to act as an agent for another authentication service
such as polkit.
  • Loading branch information
adenexter committed Mar 29, 2018
1 parent 82172d2 commit 573c5c9
Show file tree
Hide file tree
Showing 22 changed files with 356 additions and 60 deletions.
3 changes: 3 additions & 0 deletions dbus/org.nemomobile.devicelock.AuthenticationInput.xml
Expand Up @@ -17,6 +17,9 @@
<method name="RequestSecurityCode">
<arg name="client" type="o" direction="in"/>
</method>
<method name="Authorize">
<arg name="client" type="o" direction="in"/>
</method>
<method name="Cancel">
<arg name="client" type="o" direction="in"/>
</method>
Expand Down
5 changes: 5 additions & 0 deletions dbus/org.nemomobile.devicelock.Authenticator.xml
Expand Up @@ -8,6 +8,11 @@
<arg name="challenge_code" type="v" direction="in"/>
<arg name="methods" type="u" direction="in"/>
</method>
<method name="RequestPermission">
<arg name="client" type="o" direction="in"/>
<arg name="message" type="s" direction="in"/>
<arg name="methods" type="u" direction="in"/>
</method>
<method name="Cancel">
<arg name="client" type="o" direction="in"/>
</method>
Expand Down
2 changes: 2 additions & 0 deletions dbus/org.nemomobile.devicelock.Authorization.xml
Expand Up @@ -4,6 +4,8 @@
<interface name="org.nemomobile.devicelock.Authorization">
<method name="RequestChallenge">
<arg name="client" type="o" direction="in"/>
<arg name="requested_methods" type="u" direction="in"/>
<arg name="authenticating_pid" type="u" direction="in"/>
<arg name="challenge_code" type="v" direction="out"/>
<arg name="allowed_methods" type="u" direction="out"/>
</method>
Expand Down
3 changes: 3 additions & 0 deletions dbus/org.nemomobile.devicelock.client.Authenticator.xml
Expand Up @@ -5,6 +5,9 @@
<method name="Authenticated">
<arg name="authentication_token" type="v" direction="in"/>
</method>
<method name="PermissionGranted">
<arg name="method" type="u" direction="in"/>
</method>
<method name="Aborted"/>
</interface>
</node>
2 changes: 0 additions & 2 deletions rpm/nemo-qml-plugin-devicelock.spec
Expand Up @@ -16,7 +16,6 @@ BuildRequires: pkgconfig(libsystemd-daemon)
BuildRequires: pkgconfig(mce)
BuildRequires: pkgconfig(nemodbus)
Obsoletes: nemo-qml-plugin-devicelock-default < 0.2.0
Requires: nemo-devicelock-daemon

%description
%{summary}.
Expand All @@ -43,7 +42,6 @@ Requires: pkgconfig(nemodbus)
Summary: Development libraries for device lock daemons
Group: Development/Libraries
Requires: %{name}-devel = %{version}-%{release}
Requires: nemo-devicelock-daemon-cli = %{version}-%{release}
Requires: pkgconfig(keepalive)
Requires: pkgconfig(libsystemd-daemon)
Requires: pkgconfig(mce)
Expand Down
9 changes: 9 additions & 0 deletions src/nemo-devicelock/authenticationinput.cpp
Expand Up @@ -434,6 +434,15 @@ void AuthenticationInput::requestSecurityCode()
call(QStringLiteral("RequestSecurityCode"), m_localPath);
}

/*!
Informs the security dialog that an action was authorized without authenticating.
*/

void AuthenticationInput::authorize()
{
call(QStringLiteral("Authorize"), m_localPath);
}

/*!
Sends a request to cancel authentication to the security daemon.
*/
Expand Down
6 changes: 4 additions & 2 deletions src/nemo-devicelock/authenticationinput.h
Expand Up @@ -66,7 +66,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
Q_OBJECT
Q_PROPERTY(Authenticator::Methods utilizedMethods READ utilizedMethods NOTIFY utilizedMethodsChanged)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
Q_PROPERTY(bool authenticatingProcess READ authenticatingPid NOTIFY authenticatingPidChanged)
Q_PROPERTY(int authenticatingProcess READ authenticatingPid NOTIFY authenticatingPidChanged)
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
Q_PROPERTY(bool registered READ isRegistered WRITE setRegistered NOTIFY registeredChanged)
Q_PROPERTY(int minimumCodeLength READ minimumCodeLength CONSTANT)
Expand All @@ -76,6 +76,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
Q_PROPERTY(CodeGeneration codeGeneration READ codeGeneration NOTIFY codeGenerationChanged)
public:
enum Feedback {
Authorize,
EnterSecurityCode,
EnterNewSecurityCode,
RepeatNewSecurityCode,
Expand Down Expand Up @@ -150,6 +151,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec

Q_INVOKABLE void enterSecurityCode(const QString &code);
Q_INVOKABLE void requestSecurityCode();
Q_INVOKABLE void authorize();
Q_INVOKABLE void cancel();

signals:
Expand All @@ -164,7 +166,7 @@ class NEMODEVICELOCK_EXPORT AuthenticationInput : public QObject, private Connec
void codeGenerationChanged();
void codeInputIsKeyboardChanged();

void authenticationStarted(Feedback feedback, const QVariant &data);
void authenticationStarted(Feedback feedback, const QVariantMap &data);
void authenticationUnavailable(Error error);
void authenticationEvaluating();
void authenticationProgress(int current, int maximum);
Expand Down
56 changes: 56 additions & 0 deletions src/nemo-devicelock/authenticator.cpp
Expand Up @@ -49,6 +49,11 @@ void AuthenticatorAdaptor::Authenticated(const QDBusVariant &authenticationToken
m_authenticator->handleAuthentication(authenticationToken.variant());
}

void AuthenticatorAdaptor::PermissionGranted(uint method)
{
m_authenticator->handlePermissionGranted(Authenticator::Method(method));
}

void AuthenticatorAdaptor::Aborted()
{
m_authenticator->handleAborted();
Expand Down Expand Up @@ -142,6 +147,40 @@ void Authenticator::authenticate(const QVariant &challengeCode, Methods methods)
emit authenticatingChanged();
}

/*!
Requests the user grant permission for an action described by \a message and \a properties
using one of the given authentication \a methods.
The properties map may contain one of the following values:
\table
\header
\li Key
\li Value
\row
\li authenticatingPid
\li The PID of the application permissions are being requested for.
\endtable
*/

void Authenticator::requestPermission(
const QString &message, const QVariantMap &properties, Methods methods)
{
const auto response = call(
QStringLiteral("RequestPermission"), m_localPath, message, properties, uint(methods));

m_authenticating = true;

response->onError([this](const QDBusError &) {
m_authenticating = false;

emit aborted();
emit authenticatingChanged();
});

emit authenticatingChanged();
}

/*!
Cancels an active authentication request.
*/
Expand Down Expand Up @@ -174,6 +213,23 @@ void Authenticator::handleAuthentication(const QVariant &authenticationToken)
}
}

/*!
\signal NemoDeviceLock::Authenticator::permissionGranted(Method method)
Signals that the user has successfully granted permission for the requested
action using the given authentication \a method.
*/

void Authenticator::handlePermissionGranted(Method method)
{
if (m_authenticating) {
m_authenticating = false;

emit permissionGranted(method);
emit authenticatingChanged();
}
}

/*!
\signal NemoDeviceLock::Authenticator::aborted()
Expand Down
15 changes: 11 additions & 4 deletions src/nemo-devicelock/authenticator.h
Expand Up @@ -52,6 +52,7 @@ class AuthenticatorAdaptor : public QDBusAbstractAdaptor

public slots:
Q_NOREPLY void Authenticated(const QDBusVariant &authenticationToken);
Q_NOREPLY void PermissionGranted(uint method);
Q_NOREPLY void Aborted();

private:
Expand All @@ -67,9 +68,11 @@ class NEMODEVICELOCK_EXPORT Authenticator : public QObject, private ConnectionCl
Q_FLAGS(Methods)
public:
enum Method {
NoAuthentication = 0x00,
SecurityCode = 0x01,
Fingerprint = 0x02
NoAuthentication = 0x000,
SecurityCode = 0x0001,
Fingerprint = 0x0002,
Confirmation = 0x1000,
AllAvailable = SecurityCode | Fingerprint | Confirmation
};

Q_DECLARE_FLAGS(Methods, Method)
Expand All @@ -81,14 +84,17 @@ class NEMODEVICELOCK_EXPORT Authenticator : public QObject, private ConnectionCl
bool isAuthenticating() const;

Q_INVOKABLE void authenticate(
const QVariant &challengeCode, Methods methods = Methods(SecurityCode | Fingerprint));
const QVariant &challengeCode, Methods methods = AllAvailable);
Q_INVOKABLE void requestPermission(
const QString &message, const QVariantMap &properties, Methods methods = AllAvailable);
Q_INVOKABLE void cancel();

signals:
void availableMethodsChanged();
void authenticatingChanged();

void authenticated(const QVariant &authenticationToken);
void permissionGranted(Method method);
void aborted();

private:
Expand All @@ -97,6 +103,7 @@ class NEMODEVICELOCK_EXPORT Authenticator : public QObject, private ConnectionCl
inline void connected();

inline void handleAuthentication(const QVariant &authenticationToken);
inline void handlePermissionGranted(Method method);
inline void handleAborted();

AuthenticatorAdaptor m_adaptor;
Expand Down
2 changes: 1 addition & 1 deletion src/nemo-devicelock/host/cli/cliauthenticator.cpp
Expand Up @@ -103,7 +103,7 @@ void CliAuthenticator::enterSecurityCode(const QString &code)
m_securityCode.clear();
}

QVariant CliAuthenticator::authenticateChallengeCode(const QVariant &)
QVariant CliAuthenticator::authenticateChallengeCode(const QVariant &, Authenticator::Method, uint)
{
return m_securityCode;
}
Expand Down
3 changes: 2 additions & 1 deletion src/nemo-devicelock/host/cli/cliauthenticator.h
Expand Up @@ -58,7 +58,8 @@ class CliAuthenticator : public HostAuthenticator
bool clearCode(const QString &code) override;

void enterSecurityCode(const QString &code);
QVariant authenticateChallengeCode(const QVariant &challengeCode);
QVariant authenticateChallengeCode(
const QVariant &challengeCode, Authenticator::Method method, uint authenticatingPid) override;

private:
QExplicitlySharedDataPointer<LockCodeWatcher> m_watcher;
Expand Down
61 changes: 49 additions & 12 deletions src/nemo-devicelock/host/hostauthenticationinput.cpp
Expand Up @@ -73,12 +73,17 @@ void HostAuthenticationInputAdaptor::Cancel(const QDBusObjectPath &path)
m_authenticationInput->handleCancel(path.path());
}

void HostAuthenticationInputAdaptor::Authorize(const QDBusObjectPath &path)
{
m_authenticationInput->handleAuthorize(path.path());
}

HostAuthenticationInput::HostAuthenticationInput(
const QString &path, Authenticator::Methods supportedMethods, QObject *parent)
: HostObject(path, parent)
, m_adaptor(this)
, m_settings(SettingsWatcher::instance())
, m_supportedMethods(supportedMethods)
, m_supportedMethods(supportedMethods | Authenticator::Confirmation) // Basic yes/no confirmation is always supported.
, m_activeMethods()
, m_authenticating(false)
{
Expand All @@ -88,60 +93,81 @@ HostAuthenticationInput::~HostAuthenticationInput()
{
}

void HostAuthenticationInput::authorize()
{
}

void HostAuthenticationInput::authenticationStarted(
Authenticator::Methods methods,
uint authenticatingPid,
AuthenticationInput::Feedback)
{
Q_UNUSED(authenticatingPid);

qCDebug(daemon, "Authentication started");

m_authenticating = true;
m_activeMethods = methods & m_supportedMethods;
}

void HostAuthenticationInput::startAuthentication(
AuthenticationInput::Feedback feedback,
const QVariantMap &data,
Authenticator::Methods methods)
{
const uint pid = connectionPid(QDBusContext::connection());
if (pid != 0) {
startAuthentication(feedback, pid, data, methods);
}
}

void HostAuthenticationInput::startAuthentication(
AuthenticationInput::Feedback feedback,
uint authenticatingPid,
const QVariantMap &data,
Authenticator::Methods methods)
{
qCDebug(daemon, "Authentication started");

const uint pid = connectionPid(QDBusContext::connection());

if (pid != 0 && !m_inputStack.isEmpty()) {
authenticationStarted(methods, feedback);
if (!m_inputStack.isEmpty()) {
authenticationStarted(methods, authenticatingPid, feedback);

NemoDBus::send(
m_inputStack.last().connection,
m_inputStack.last().path,
clientInterface,
QStringLiteral("AuthenticationStarted"),
pid,
authenticatingPid,
uint(m_activeMethods),
uint(feedback),
data);
}
}


void HostAuthenticationInput::authenticationUnavailable(AuthenticationInput::Error error)
{
qCDebug(daemon, "Authentication unavailable");

const uint pid = connectionPid(QDBusContext::connection());
if (pid != 0) {
authenticationUnavailable(error, pid);
}
}

if (pid != 0 && !m_inputStack.isEmpty()) {
void HostAuthenticationInput::authenticationUnavailable(
AuthenticationInput::Error error, uint authenticatingPid)
{
qCDebug(daemon, "Authentication unavailable");

if (!m_inputStack.isEmpty()) {
NemoDBus::send(
m_inputStack.last().connection,
m_inputStack.last().path,
clientInterface,
QStringLiteral("AuthenticationUnavailable"),
pid,
authenticatingPid,
uint(error));
}
}


void HostAuthenticationInput::authenticationResumed(
AuthenticationInput::Feedback feedback,
const QVariantMap &data,
Expand Down Expand Up @@ -213,6 +239,7 @@ void HostAuthenticationInput::authenticationEnded(bool confirmed)
void HostAuthenticationInput::setRegistered(const QString &path, bool registered)
{
const auto pid = connectionPid(QDBusContext::connection());

if (pid == 0 || !authorizeInput(pid)) {
QDBusContext::sendErrorReply(QDBusError::AccessDenied);
return;
Expand Down Expand Up @@ -440,4 +467,14 @@ void HostAuthenticationInput::handleCancel(const QString &path)
}
}

void HostAuthenticationInput::handleAuthorize(const QString &path)
{
const auto connection = QDBusContext::connection().name();
if (!m_inputStack.isEmpty()
&& m_inputStack.last().connection == connection
&& m_inputStack.last().path == path) {
authorize();
}
}

}

0 comments on commit 573c5c9

Please sign in to comment.