2012-07-17 20:54:07 +02:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2023-07-10 02:53:00 -07:00
|
|
|
|
|
|
|
import Clutter from 'gi://Clutter';
|
|
|
|
import Gdm from 'gi://Gdm';
|
|
|
|
import Gio from 'gi://Gio';
|
|
|
|
import GLib from 'gi://GLib';
|
|
|
|
import * as Signals from '../misc/signals.js';
|
|
|
|
|
|
|
|
import * as Batch from './batch.js';
|
|
|
|
import * as OVirt from './oVirt.js';
|
|
|
|
import * as Vmware from './vmware.js';
|
|
|
|
import * as Main from '../ui/main.js';
|
|
|
|
import {loadInterfaceXML} from '../misc/fileUtils.js';
|
|
|
|
import * as Params from '../misc/params.js';
|
|
|
|
import * as SmartcardManager from '../misc/smartcardManager.js';
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2022-10-25 03:51:30 +02:00
|
|
|
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(
|
|
|
|
loadInterfaceXML('net.reactivated.Fprint.Manager'));
|
2021-01-30 20:14:04 +01:00
|
|
|
const FprintDeviceIface = loadInterfaceXML('net.reactivated.Fprint.Device');
|
|
|
|
const FprintDeviceProxy = Gio.DBusProxy.makeProxyWrapper(FprintDeviceIface);
|
2021-01-30 20:10:03 +01:00
|
|
|
|
2022-02-11 00:09:54 +01:00
|
|
|
Gio._promisify(Gdm.Client.prototype, 'open_reauthentication_channel');
|
|
|
|
Gio._promisify(Gdm.Client.prototype, 'get_user_verifier');
|
2019-12-19 20:50:37 +01:00
|
|
|
Gio._promisify(Gdm.UserVerifierProxy.prototype,
|
2022-02-11 00:09:54 +01:00
|
|
|
'call_begin_verification_for_user');
|
|
|
|
Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification');
|
2019-12-19 20:50:37 +01:00
|
|
|
|
2023-07-10 02:53:00 -07:00
|
|
|
export const PASSWORD_SERVICE_NAME = 'gdm-password';
|
|
|
|
export const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
|
|
|
export const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
|
|
|
const CLONE_FADE_ANIMATION_TIME = 250;
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2023-07-10 02:53:00 -07:00
|
|
|
export const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
|
|
|
export const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
|
|
|
|
export const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
|
|
|
export const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication';
|
|
|
|
export const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
|
|
|
export const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
|
|
|
export const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2023-07-10 02:53:00 -07:00
|
|
|
export const LOGO_KEY = 'logo';
|
|
|
|
export const DISABLE_USER_LIST_KEY = 'disable-user-list';
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2015-03-27 14:36:05 +01:00
|
|
|
// Give user 48ms to read each character of a PAM message
|
2023-07-10 02:53:00 -07:00
|
|
|
const USER_READ_TIME = 48;
|
2021-02-16 04:18:18 +01:00
|
|
|
const FINGERPRINT_ERROR_TIMEOUT_WAIT = 15;
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2023-07-30 15:56:59 +03:00
|
|
|
/**
|
|
|
|
* Keep messages in order by priority
|
|
|
|
*
|
|
|
|
* @enum {number}
|
|
|
|
*/
|
2023-07-10 02:53:00 -07:00
|
|
|
export const MessageType = {
|
2013-08-19 12:00:33 -04:00
|
|
|
NONE: 0,
|
2021-02-16 03:08:38 +01:00
|
|
|
HINT: 1,
|
2013-08-19 12:00:33 -04:00
|
|
|
INFO: 2,
|
2021-02-16 03:08:38 +01:00
|
|
|
ERROR: 3,
|
2013-08-19 12:00:33 -04:00
|
|
|
};
|
|
|
|
|
2021-01-30 20:14:04 +01:00
|
|
|
const FingerprintReaderType = {
|
|
|
|
NONE: 0,
|
|
|
|
PRESS: 1,
|
|
|
|
SWIPE: 2,
|
|
|
|
};
|
|
|
|
|
2023-07-30 15:56:59 +03:00
|
|
|
/**
|
|
|
|
* @param {Clutter.Actor} actor
|
|
|
|
*/
|
2023-07-10 02:53:00 -07:00
|
|
|
export function cloneAndFadeOutActor(actor) {
|
2013-02-06 14:18:26 -05:00
|
|
|
// Immediately hide actor so its sibling can have its space
|
|
|
|
// and position, but leave a non-reactive clone on-screen,
|
|
|
|
// so from the user's point of view it smoothly fades away
|
|
|
|
// and reveals its sibling.
|
|
|
|
actor.hide();
|
|
|
|
|
2020-03-29 23:51:13 +02:00
|
|
|
const clone = new Clutter.Clone({
|
|
|
|
source: actor,
|
|
|
|
reactive: false,
|
|
|
|
});
|
2013-02-06 14:18:26 -05:00
|
|
|
|
|
|
|
Main.uiGroup.add_child(clone);
|
|
|
|
|
|
|
|
let [x, y] = actor.get_transformed_position();
|
|
|
|
clone.set_position(x, y);
|
|
|
|
|
|
|
|
let hold = new Batch.Hold();
|
2018-07-20 21:46:19 +02:00
|
|
|
clone.ease({
|
|
|
|
opacity: 0,
|
|
|
|
duration: CLONE_FADE_ANIMATION_TIME,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
|
|
onComplete: () => {
|
|
|
|
clone.destroy();
|
|
|
|
hold.release();
|
2019-08-20 23:43:54 +02:00
|
|
|
},
|
2018-07-20 21:46:19 +02:00
|
|
|
});
|
2013-02-06 14:18:26 -05:00
|
|
|
return hold;
|
|
|
|
}
|
|
|
|
|
2023-07-10 02:53:00 -07:00
|
|
|
export class ShellUserVerifier extends Signals.EventEmitter {
|
2017-10-31 02:19:44 +01:00
|
|
|
constructor(client, params) {
|
2022-07-04 18:30:44 -04:00
|
|
|
super();
|
2023-08-07 00:40:20 +02:00
|
|
|
params = Params.parse(params, {reauthenticationOnly: false});
|
2012-08-03 17:10:45 +02:00
|
|
|
this._reauthOnly = params.reauthenticationOnly;
|
|
|
|
|
2012-07-17 20:54:07 +02:00
|
|
|
this._client = client;
|
2022-10-21 19:09:09 +02:00
|
|
|
this._cancellable = null;
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-06-13 04:24:12 +02:00
|
|
|
this._defaultService = null;
|
|
|
|
this._preemptingService = null;
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
2017-06-13 04:24:12 +02:00
|
|
|
|
2022-10-21 19:09:09 +02:00
|
|
|
this._messageQueue = [];
|
|
|
|
this._messageQueueTimeoutId = 0;
|
|
|
|
|
|
|
|
this._failCounter = 0;
|
2022-10-21 17:47:15 +02:00
|
|
|
this._activeServices = new Set();
|
2022-10-21 19:09:09 +02:00
|
|
|
this._unavailableServices = new Set();
|
|
|
|
|
|
|
|
this._credentialManagers = {};
|
|
|
|
|
|
|
|
this.reauthenticating = false;
|
|
|
|
this.smartcardDetected = false;
|
|
|
|
|
2023-08-07 00:40:20 +02:00
|
|
|
this._settings = new Gio.Settings({schema_id: LOGIN_SCREEN_SCHEMA});
|
2022-03-01 11:57:20 +01:00
|
|
|
this._settings.connect('changed', () => this._onSettingsChanged());
|
|
|
|
this._updateEnabledServices();
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
this._updateDefaultService();
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2022-08-03 15:34:10 +02:00
|
|
|
this.addCredentialManager(OVirt.SERVICE_NAME, OVirt.getOVirtCredentialsManager());
|
|
|
|
this.addCredentialManager(Vmware.SERVICE_NAME, Vmware.getVmwareCredentialsManager());
|
|
|
|
}
|
2013-10-10 10:21:47 +02:00
|
|
|
|
2022-08-03 15:34:10 +02:00
|
|
|
addCredentialManager(serviceName, credentialManager) {
|
|
|
|
if (this._credentialManagers[serviceName])
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._credentialManagers[serviceName] = credentialManager;
|
|
|
|
if (credentialManager.token) {
|
|
|
|
this._onCredentialManagerAuthenticated(credentialManager,
|
|
|
|
credentialManager.token);
|
2020-01-04 00:31:15 +08:00
|
|
|
}
|
2022-08-03 15:34:10 +02:00
|
|
|
|
|
|
|
credentialManager.connectObject('user-authenticated',
|
|
|
|
this._onCredentialManagerAuthenticated.bind(this), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
removeCredentialManager(serviceName) {
|
|
|
|
let credentialManager = this._credentialManagers[serviceName];
|
|
|
|
if (!credentialManager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
credentialManager.disconnectObject(this);
|
|
|
|
delete this._credentialManagers[serviceName];
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2021-02-16 02:00:41 +01:00
|
|
|
get hasPendingMessages() {
|
|
|
|
return !!this._messageQueue.length;
|
|
|
|
}
|
|
|
|
|
2021-02-01 13:10:45 +01:00
|
|
|
get allowedFailures() {
|
|
|
|
return this._settings.get_int(ALLOWED_FAILURES_KEY);
|
|
|
|
}
|
|
|
|
|
2021-02-16 02:00:41 +01:00
|
|
|
get currentMessage() {
|
|
|
|
return this._messageQueue ? this._messageQueue[0] : null;
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
begin(userName, hold) {
|
2012-08-26 14:54:02 +02:00
|
|
|
this._cancellable = new Gio.Cancellable();
|
2012-07-17 20:54:07 +02:00
|
|
|
this._hold = hold;
|
|
|
|
this._userName = userName;
|
2013-07-22 10:59:57 -04:00
|
|
|
this.reauthenticating = false;
|
2012-07-17 20:54:07 +02:00
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
this._checkForFingerprintReader().catch(e =>
|
|
|
|
this._handleFingerprintError(e));
|
2012-08-26 14:54:02 +02:00
|
|
|
|
2019-12-19 20:50:37 +01:00
|
|
|
// If possible, reauthenticate an already running session,
|
|
|
|
// so any session specific credentials get updated appropriately
|
|
|
|
if (userName)
|
|
|
|
this._openReauthenticationChannel(userName);
|
|
|
|
else
|
|
|
|
this._getUserVerifier();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
cancel() {
|
2012-08-26 14:54:02 +02:00
|
|
|
if (this._cancellable)
|
|
|
|
this._cancellable.cancel();
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2013-07-29 10:52:02 -04:00
|
|
|
if (this._userVerifier) {
|
2012-07-17 20:54:07 +02:00
|
|
|
this._userVerifier.call_cancel_sync(null);
|
2013-07-29 10:52:02 -04:00
|
|
|
this.clear();
|
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_clearUserVerifier() {
|
2014-10-09 14:10:12 -04:00
|
|
|
if (this._userVerifier) {
|
2021-02-02 15:08:10 +01:00
|
|
|
this._disconnectSignals();
|
2014-10-09 14:10:12 -04:00
|
|
|
this._userVerifier.run_dispose();
|
|
|
|
this._userVerifier = null;
|
2017-07-17 16:48:03 -04:00
|
|
|
if (this._userVerifierChoiceList) {
|
|
|
|
this._userVerifierChoiceList.run_dispose();
|
|
|
|
this._userVerifierChoiceList = null;
|
|
|
|
}
|
2014-10-09 14:10:12 -04:00
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2014-10-09 14:10:12 -04:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
clear() {
|
2012-08-26 14:54:02 +02:00
|
|
|
if (this._cancellable) {
|
|
|
|
this._cancellable.cancel();
|
|
|
|
this._cancellable = null;
|
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2014-10-09 14:10:12 -04:00
|
|
|
this._clearUserVerifier();
|
2013-03-18 00:59:56 -04:00
|
|
|
this._clearMessageQueue();
|
2022-10-21 17:47:15 +02:00
|
|
|
this._activeServices.clear();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
destroy() {
|
2021-01-30 01:53:59 +01:00
|
|
|
this.cancel();
|
2014-10-09 14:10:12 -04:00
|
|
|
|
|
|
|
this._settings.run_dispose();
|
|
|
|
this._settings = null;
|
|
|
|
|
2022-03-01 11:57:20 +01:00
|
|
|
this._smartcardManager?.disconnectObject(this);
|
2014-10-09 14:10:12 -04:00
|
|
|
this._smartcardManager = null;
|
|
|
|
|
2022-03-01 11:57:20 +01:00
|
|
|
this._fingerprintManager = null;
|
|
|
|
|
2022-08-03 15:34:10 +02:00
|
|
|
for (let service in this._credentialManagers)
|
|
|
|
this.removeCredentialManager(service);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2014-10-09 14:10:12 -04:00
|
|
|
|
2017-07-17 16:48:03 -04:00
|
|
|
selectChoice(serviceName, key) {
|
|
|
|
this._userVerifierChoiceList.call_select_choice(serviceName, key, this._cancellable, null);
|
|
|
|
}
|
|
|
|
|
2022-08-08 12:19:51 +02:00
|
|
|
async answerQuery(serviceName, answer) {
|
|
|
|
try {
|
|
|
|
await this._handlePendingMessages();
|
2013-03-18 00:59:56 -04:00
|
|
|
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
2022-08-08 12:19:51 +02:00
|
|
|
} catch (e) {
|
|
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
logError(e);
|
2013-03-18 00:59:56 -04:00
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_getIntervalForMessage(message) {
|
2021-02-16 03:45:14 +01:00
|
|
|
if (!message)
|
|
|
|
return 0;
|
|
|
|
|
2013-03-18 00:59:56 -04:00
|
|
|
// We probably could be smarter here
|
|
|
|
return message.length * USER_READ_TIME;
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
finishMessageQueue() {
|
2013-03-18 00:59:56 -04:00
|
|
|
if (!this.hasPendingMessages)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._messageQueue = [];
|
2012-10-29 17:39:00 +01:00
|
|
|
|
2013-03-18 00:59:56 -04:00
|
|
|
this.emit('no-more-messages');
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2021-02-08 19:34:09 +01:00
|
|
|
increaseCurrentMessageTimeout(interval) {
|
|
|
|
if (!this._messageQueueTimeoutId && interval > 0)
|
|
|
|
this._currentMessageExtraInterval = interval;
|
|
|
|
}
|
|
|
|
|
2021-02-16 03:45:14 +01:00
|
|
|
_serviceHasPendingMessages(serviceName) {
|
|
|
|
return this._messageQueue.some(m => m.serviceName === serviceName);
|
|
|
|
}
|
|
|
|
|
|
|
|
_filterServiceMessages(serviceName, messageType) {
|
|
|
|
// This function allows to remove queued messages for the @serviceName
|
|
|
|
// whose type has lower priority than @messageType, replacing them
|
|
|
|
// with a null message that will lead to clearing the prompt once done.
|
|
|
|
if (this._serviceHasPendingMessages(serviceName))
|
|
|
|
this._queuePriorityMessage(serviceName, null, messageType);
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_queueMessageTimeout() {
|
2023-08-07 02:51:19 +02:00
|
|
|
if (this._messageQueueTimeoutId !== 0)
|
2013-03-18 00:59:56 -04:00
|
|
|
return;
|
|
|
|
|
2021-02-16 02:00:41 +01:00
|
|
|
const message = this.currentMessage;
|
2013-08-19 12:00:33 -04:00
|
|
|
|
2021-02-08 19:34:09 +01:00
|
|
|
delete this._currentMessageExtraInterval;
|
2021-02-01 19:36:49 +01:00
|
|
|
this.emit('show-message', message.serviceName, message.text, message.type);
|
2013-03-18 00:59:56 -04:00
|
|
|
|
|
|
|
this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
2021-02-16 02:00:41 +01:00
|
|
|
message.interval + (this._currentMessageExtraInterval | 0), () => {
|
|
|
|
this._messageQueueTimeoutId = 0;
|
|
|
|
|
|
|
|
if (this._messageQueue.length > 1) {
|
|
|
|
this._messageQueue.shift();
|
|
|
|
this._queueMessageTimeout();
|
|
|
|
} else {
|
|
|
|
this.finishMessageQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
|
|
});
|
2014-04-10 19:26:52 +02:00
|
|
|
GLib.Source.set_name_by_id(this._messageQueueTimeoutId, '[gnome-shell] this._queueMessageTimeout');
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2021-02-01 19:36:49 +01:00
|
|
|
_queueMessage(serviceName, message, messageType) {
|
2013-03-18 00:59:56 -04:00
|
|
|
let interval = this._getIntervalForMessage(message);
|
|
|
|
|
2023-08-07 00:40:20 +02:00
|
|
|
this._messageQueue.push({serviceName, text: message, type: messageType, interval});
|
2013-03-18 00:59:56 -04:00
|
|
|
this._queueMessageTimeout();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2021-02-16 03:08:38 +01:00
|
|
|
_queuePriorityMessage(serviceName, message, messageType) {
|
|
|
|
const newQueue = this._messageQueue.filter(m => {
|
|
|
|
if (m.serviceName !== serviceName || m.type >= messageType)
|
|
|
|
return m.text !== message;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!newQueue.includes(this.currentMessage))
|
|
|
|
this._clearMessageQueue();
|
|
|
|
|
|
|
|
this._messageQueue = newQueue;
|
|
|
|
this._queueMessage(serviceName, message, messageType);
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_clearMessageQueue() {
|
2013-03-18 00:59:56 -04:00
|
|
|
this.finishMessageQueue();
|
|
|
|
|
2023-08-07 02:51:19 +02:00
|
|
|
if (this._messageQueueTimeoutId !== 0) {
|
2013-03-18 00:59:56 -04:00
|
|
|
GLib.source_remove(this._messageQueueTimeoutId);
|
|
|
|
this._messageQueueTimeoutId = 0;
|
|
|
|
}
|
2021-02-01 19:36:49 +01:00
|
|
|
this.emit('show-message', null, null, MessageType.NONE);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
async _initFingerprintManager() {
|
2022-03-01 11:57:20 +01:00
|
|
|
if (this._fprintManager)
|
|
|
|
return;
|
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
const fprintManager = new Gio.DBusProxy({
|
2022-03-01 11:57:20 +01:00
|
|
|
g_connection: Gio.DBus.system,
|
|
|
|
g_name: 'net.reactivated.Fprint',
|
|
|
|
g_object_path: '/net/reactivated/Fprint/Manager',
|
|
|
|
g_interface_name: FprintManagerInfo.name,
|
|
|
|
g_interface_info: FprintManagerInfo,
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES |
|
|
|
|
Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION |
|
|
|
|
Gio.DBusProxyFlags.DO_NOT_CONNECT_SIGNALS,
|
2022-03-01 11:57:20 +01:00
|
|
|
});
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
if (!this._getDetectedDefaultService()) {
|
|
|
|
// Other authentication methods would have already been detected by
|
|
|
|
// now as possibilities if they were available.
|
|
|
|
// If we're here it means that FINGERPRINT_AUTHENTICATION_KEY is
|
|
|
|
// true and so fingerprint authentication is our last potential
|
|
|
|
// option, so go ahead a synchronously look for a fingerprint device
|
|
|
|
// during startup or default service update.
|
|
|
|
fprintManager.init(null);
|
|
|
|
const [devicePath] = fprintManager.GetDefaultDeviceSync();
|
|
|
|
this._fprintManager = fprintManager;
|
|
|
|
|
|
|
|
const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
|
|
|
|
'net.reactivated.Fprint', devicePath, null, null,
|
|
|
|
Gio.DBusProxyFlags.NOT_CONNECT_SIGNALS);
|
|
|
|
this._setFingerprintReaderType(fprintDeviceProxy['scan-type']);
|
|
|
|
} else {
|
|
|
|
// Ensure fingerprint service starts, but do not wait for it
|
|
|
|
const cancellable = this._cancellable;
|
|
|
|
await fprintManager.init_async(GLib.PRIORITY_DEFAULT, cancellable);
|
|
|
|
await this._updateFingerprintReaderType(fprintManager, cancellable);
|
|
|
|
this._fprintManager = fprintManager;
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
this._handleFingerprintError(e);
|
|
|
|
}
|
2022-03-01 11:57:20 +01:00
|
|
|
}
|
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
_handleFingerprintError(e) {
|
2021-01-30 20:14:04 +01:00
|
|
|
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
2012-07-17 20:54:07 +02:00
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
return;
|
|
|
|
if (e.matches(Gio.DBusError, Gio.DBusError.SERVICE_UNKNOWN))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Gio.DBusError.is_remote_error(e) &&
|
|
|
|
Gio.DBusError.get_remote_error(e) ===
|
|
|
|
'net.reactivated.Fprint.Error.NoSuchDevice')
|
|
|
|
return;
|
|
|
|
|
|
|
|
logError(e, 'Failed to interact with fprintd service');
|
|
|
|
}
|
|
|
|
|
|
|
|
async _checkForFingerprintReader() {
|
2022-03-01 11:57:20 +01:00
|
|
|
if (!this._fprintManager) {
|
2013-07-29 14:18:30 -04:00
|
|
|
this._updateDefaultService();
|
2012-07-17 20:54:07 +02:00
|
|
|
return;
|
2013-07-29 14:18:30 -04:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
await this._updateFingerprintReaderType(this._fprintManager, this._cancellable);
|
|
|
|
}
|
|
|
|
|
|
|
|
async _updateFingerprintReaderType(fprintManager, cancellable) {
|
|
|
|
// Wrappers don't support null cancellable, so let's ignore it in case
|
|
|
|
const args = cancellable ? [cancellable] : [];
|
|
|
|
const [devicePath] = await fprintManager.GetDefaultDeviceAsync(...args);
|
2022-10-25 04:47:08 +02:00
|
|
|
const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
|
|
|
|
'net.reactivated.Fprint',
|
2024-02-28 21:52:55 +01:00
|
|
|
devicePath);
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
this._setFingerprintReaderType(fprintDeviceProxy['scan-type']);
|
2022-10-25 04:47:08 +02:00
|
|
|
this._updateDefaultService();
|
2022-04-12 16:38:40 +02:00
|
|
|
|
|
|
|
if (this._userVerifier &&
|
|
|
|
!this._activeServices.has(FINGERPRINT_SERVICE_NAME)) {
|
|
|
|
if (!this._hold?.isAcquired())
|
|
|
|
this._hold = new Batch.Hold();
|
|
|
|
await this._maybeStartFingerprintVerification();
|
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
_setFingerprintReaderType(fprintDeviceType) {
|
|
|
|
this._fingerprintReaderType =
|
|
|
|
FingerprintReaderType[fprintDeviceType.toUpperCase()];
|
|
|
|
|
|
|
|
if (this._fingerprintReaderType === undefined)
|
|
|
|
throw new Error(`Unexpected fingerprint device type '${fprintDeviceType}'`);
|
|
|
|
}
|
|
|
|
|
2020-01-04 00:31:15 +08:00
|
|
|
_onCredentialManagerAuthenticated(credentialManager, _token) {
|
|
|
|
this._preemptingService = credentialManager.service;
|
|
|
|
this.emit('credential-manager-authenticated');
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-10-10 10:21:47 +02:00
|
|
|
|
2022-03-01 11:57:20 +01:00
|
|
|
_initSmartcardManager() {
|
|
|
|
if (this._smartcardManager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
|
|
|
|
|
|
|
// We check for smartcards right away, since an inserted smartcard
|
|
|
|
// at startup should result in immediately initiating authentication.
|
|
|
|
// This is different than fingerprint readers, where we only check them
|
|
|
|
// after a user has been picked.
|
|
|
|
this.smartcardDetected = false;
|
|
|
|
this._checkForSmartcard();
|
|
|
|
|
|
|
|
this._smartcardManager.connectObject(
|
|
|
|
'smartcard-inserted', () => this._checkForSmartcard(),
|
|
|
|
'smartcard-removed', () => this._checkForSmartcard(), this);
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_checkForSmartcard() {
|
2013-06-27 08:54:19 -04:00
|
|
|
let smartcardDetected;
|
|
|
|
|
|
|
|
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
|
|
|
smartcardDetected = false;
|
2014-03-13 13:47:50 -04:00
|
|
|
else if (this._reauthOnly)
|
2013-06-27 08:54:19 -04:00
|
|
|
smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
|
|
|
|
else
|
|
|
|
smartcardDetected = this._smartcardManager.hasInsertedTokens();
|
|
|
|
|
2023-08-07 02:51:19 +02:00
|
|
|
if (smartcardDetected !== this.smartcardDetected) {
|
2013-06-27 08:54:19 -04:00
|
|
|
this.smartcardDetected = smartcardDetected;
|
|
|
|
|
|
|
|
if (this.smartcardDetected)
|
|
|
|
this._preemptingService = SMARTCARD_SERVICE_NAME;
|
2023-08-07 02:51:19 +02:00
|
|
|
else if (this._preemptingService === SMARTCARD_SERVICE_NAME)
|
2013-06-27 08:54:19 -04:00
|
|
|
this._preemptingService = null;
|
|
|
|
|
|
|
|
this.emit('smartcard-status-changed');
|
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-06-27 08:54:19 -04:00
|
|
|
|
2021-02-01 19:36:49 +01:00
|
|
|
_reportInitError(where, error, serviceName) {
|
2012-09-06 16:40:13 +02:00
|
|
|
logError(error, where);
|
2012-10-03 21:25:49 +02:00
|
|
|
this._hold.release();
|
2012-09-06 16:40:13 +02:00
|
|
|
|
2021-02-01 19:36:49 +01:00
|
|
|
this._queueMessage(serviceName, _('Authentication error'), MessageType.ERROR);
|
2021-02-08 18:43:16 +01:00
|
|
|
this._failCounter++;
|
2021-02-01 19:36:49 +01:00
|
|
|
this._verificationFailed(serviceName, false);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-09-06 16:40:13 +02:00
|
|
|
|
2019-12-19 20:50:37 +01:00
|
|
|
async _openReauthenticationChannel(userName) {
|
2012-07-17 20:54:07 +02:00
|
|
|
try {
|
2014-10-09 14:10:12 -04:00
|
|
|
this._clearUserVerifier();
|
2019-12-19 20:50:37 +01:00
|
|
|
this._userVerifier = await this._client.open_reauthentication_channel(
|
|
|
|
userName, this._cancellable);
|
2019-01-29 02:26:39 +01:00
|
|
|
} catch (e) {
|
2018-07-15 03:17:42 +02:00
|
|
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
return;
|
|
|
|
if (e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
|
|
|
|
!this._reauthOnly) {
|
|
|
|
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there
|
|
|
|
// is no session to reauthenticate. Fall back to performing
|
|
|
|
// verification from this login session
|
2019-12-19 20:50:37 +01:00
|
|
|
this._getUserVerifier();
|
2018-07-15 03:17:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-06 16:40:13 +02:00
|
|
|
this._reportInitError('Failed to open reauthentication channel', e);
|
|
|
|
return;
|
2012-07-17 20:54:07 +02:00
|
|
|
}
|
2012-09-06 16:40:13 +02:00
|
|
|
|
2017-07-17 16:48:03 -04:00
|
|
|
if (this._client.get_user_verifier_choice_list)
|
|
|
|
this._userVerifierChoiceList = this._client.get_user_verifier_choice_list();
|
|
|
|
else
|
|
|
|
this._userVerifierChoiceList = null;
|
|
|
|
|
2013-07-22 10:59:57 -04:00
|
|
|
this.reauthenticating = true;
|
2012-09-06 16:40:13 +02:00
|
|
|
this._connectSignals();
|
|
|
|
this._beginVerification();
|
|
|
|
this._hold.release();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2019-12-19 20:50:37 +01:00
|
|
|
async _getUserVerifier() {
|
2012-08-26 14:54:02 +02:00
|
|
|
try {
|
2014-10-09 14:10:12 -04:00
|
|
|
this._clearUserVerifier();
|
2019-12-19 20:50:37 +01:00
|
|
|
this._userVerifier =
|
|
|
|
await this._client.get_user_verifier(this._cancellable);
|
2019-01-29 02:26:39 +01:00
|
|
|
} catch (e) {
|
2018-07-15 03:17:42 +02:00
|
|
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
return;
|
2012-09-06 16:40:13 +02:00
|
|
|
this._reportInitError('Failed to obtain user verifier', e);
|
2012-08-26 14:54:02 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-17 16:48:03 -04:00
|
|
|
if (this._client.get_user_verifier_choice_list)
|
|
|
|
this._userVerifierChoiceList = this._client.get_user_verifier_choice_list();
|
|
|
|
else
|
|
|
|
this._userVerifierChoiceList = null;
|
|
|
|
|
2012-07-17 20:54:07 +02:00
|
|
|
this._connectSignals();
|
|
|
|
this._beginVerification();
|
|
|
|
this._hold.release();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_connectSignals() {
|
2021-02-02 15:08:10 +01:00
|
|
|
this._disconnectSignals();
|
2021-08-16 00:36:59 +02:00
|
|
|
|
|
|
|
this._userVerifier.connectObject(
|
|
|
|
'info', this._onInfo.bind(this),
|
|
|
|
'problem', this._onProblem.bind(this),
|
|
|
|
'info-query', this._onInfoQuery.bind(this),
|
|
|
|
'secret-info-query', this._onSecretInfoQuery.bind(this),
|
2022-10-21 17:47:15 +02:00
|
|
|
'conversation-started', this._onConversationStarted.bind(this),
|
2021-08-16 00:36:59 +02:00
|
|
|
'conversation-stopped', this._onConversationStopped.bind(this),
|
|
|
|
'service-unavailable', this._onServiceUnavailable.bind(this),
|
|
|
|
'reset', this._onReset.bind(this),
|
|
|
|
'verification-complete', this._onVerificationComplete.bind(this),
|
|
|
|
this);
|
|
|
|
|
|
|
|
if (this._userVerifierChoiceList) {
|
|
|
|
this._userVerifierChoiceList.connectObject('choice-query',
|
|
|
|
this._onChoiceListQuery.bind(this), this);
|
|
|
|
}
|
2021-02-02 15:08:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
_disconnectSignals() {
|
2021-08-16 00:36:59 +02:00
|
|
|
this._userVerifier?.disconnectObject(this);
|
2023-02-12 18:20:15 +01:00
|
|
|
this._userVerifierChoiceList?.disconnectObject(this);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_getForegroundService() {
|
2013-06-27 08:54:19 -04:00
|
|
|
if (this._preemptingService)
|
|
|
|
return this._preemptingService;
|
|
|
|
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
return this._defaultService;
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
serviceIsForeground(serviceName) {
|
2023-06-07 21:53:07 -07:00
|
|
|
return serviceName === this._getForegroundService();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
|
2022-08-03 15:08:07 +02:00
|
|
|
foregroundServiceDeterminesUsername() {
|
|
|
|
for (let serviceName in this._credentialManagers) {
|
|
|
|
if (this.serviceIsForeground(serviceName))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.serviceIsForeground(SMARTCARD_SERVICE_NAME);
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
serviceIsDefault(serviceName) {
|
2023-08-07 02:51:19 +02:00
|
|
|
return serviceName === this._defaultService;
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-06-27 08:54:19 -04:00
|
|
|
|
2021-02-08 17:07:45 +01:00
|
|
|
serviceIsFingerprint(serviceName) {
|
|
|
|
return this._fingerprintReaderType !== FingerprintReaderType.NONE &&
|
|
|
|
serviceName === FINGERPRINT_SERVICE_NAME;
|
|
|
|
}
|
|
|
|
|
2022-03-01 11:57:20 +01:00
|
|
|
_onSettingsChanged() {
|
|
|
|
this._updateEnabledServices();
|
|
|
|
this._updateDefaultService();
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateEnabledServices() {
|
|
|
|
let needsReset = false;
|
|
|
|
|
|
|
|
if (this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) {
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
this._initFingerprintManager().catch(logError);
|
2022-03-01 11:57:20 +01:00
|
|
|
} else if (this._fingerprintManager) {
|
|
|
|
this._fingerprintManager = null;
|
|
|
|
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
|
|
|
|
|
|
|
if (this._activeServices.has(FINGERPRINT_SERVICE_NAME))
|
|
|
|
needsReset = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY)) {
|
|
|
|
this._initSmartcardManager();
|
|
|
|
} else if (this._smartcardManager) {
|
|
|
|
this._smartcardManager.disconnectObject(this);
|
|
|
|
this._smartcardManager = null;
|
|
|
|
|
|
|
|
if (this._activeServices.has(SMARTCARD_SERVICE_NAME))
|
|
|
|
needsReset = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (needsReset)
|
|
|
|
this._cancelAndReset();
|
|
|
|
}
|
|
|
|
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
_getDetectedDefaultService() {
|
2013-07-29 14:18:30 -04:00
|
|
|
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
return PASSWORD_SERVICE_NAME;
|
2022-03-01 11:57:20 +01:00
|
|
|
else if (this._smartcardManager)
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
return SMARTCARD_SERVICE_NAME;
|
2021-01-30 20:14:04 +01:00
|
|
|
else if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
|
gdm/util: Only start fingerprint service synchronously when it's default
On ShellUserVerifier construction we used to start fprintd in a sync
fashion all the times, however in case the daemon had startup failures
or was hanging for whatever reason (like due to devices probing, given
that fprintd synchronously wait for them all to be initialized) we used
to just fail, leaving gdm or the lockscreen in a not usable state.
While this could be prevented with a try/catch statement, there's no
much point to wait for fprintd if that's not the default authentication
service, and so:
- If we use gdm-fingerprint as default auth method, use a sync call to
initialize it and in case of failures, just continue with fallback
authentication mechanism (password)
- Otherwise, asynchronously initialize fprintd and continue with the
ShellUserVerifier without fingerprint support until we got a reply.
In case the service fails to deliver us a result, we don't give up
but we will try doing that at each authentication via
_checkForFingerprintReader().
In case all works properly, as per the previous commit, once the
initialization is done, we'll start the fingerprint PAM gdm service.
Fixes #5168
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2267>
2022-04-12 16:51:21 +02:00
|
|
|
return FINGERPRINT_SERVICE_NAME;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
_updateDefaultService() {
|
|
|
|
const oldDefaultService = this._defaultService;
|
|
|
|
this._defaultService = this._getDetectedDefaultService();
|
2015-07-01 11:18:44 -04:00
|
|
|
|
|
|
|
if (!this._defaultService) {
|
2023-08-07 00:34:20 +02:00
|
|
|
log('no authentication service is enabled, using password authentication');
|
2015-07-01 11:18:44 -04:00
|
|
|
this._defaultService = PASSWORD_SERVICE_NAME;
|
|
|
|
}
|
2022-10-21 19:05:04 +02:00
|
|
|
|
|
|
|
if (oldDefaultService &&
|
|
|
|
oldDefaultService !== this._defaultService &&
|
|
|
|
this._activeServices.has(oldDefaultService))
|
|
|
|
this._cancelAndReset();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
|
2019-12-19 20:50:37 +01:00
|
|
|
async _startService(serviceName) {
|
2012-07-17 20:54:07 +02:00
|
|
|
this._hold.acquire();
|
2019-12-19 20:50:37 +01:00
|
|
|
try {
|
2022-10-21 17:47:15 +02:00
|
|
|
this._activeServices.add(serviceName);
|
2019-12-19 20:50:37 +01:00
|
|
|
if (this._userName) {
|
|
|
|
await this._userVerifier.call_begin_verification_for_user(
|
|
|
|
serviceName, this._userName, this._cancellable);
|
|
|
|
} else {
|
|
|
|
await this._userVerifier.call_begin_verification(
|
|
|
|
serviceName, this._cancellable);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
2022-10-21 17:47:15 +02:00
|
|
|
this._activeServices.delete(serviceName);
|
2019-12-19 20:50:37 +01:00
|
|
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
return;
|
2021-02-02 16:30:11 +01:00
|
|
|
if (!this.serviceIsForeground(serviceName)) {
|
2022-02-07 15:14:06 +01:00
|
|
|
logError(e,
|
|
|
|
`Failed to start ${serviceName} for ${this._userName}`);
|
2021-02-02 16:30:11 +01:00
|
|
|
this._hold.release();
|
|
|
|
return;
|
|
|
|
}
|
2022-02-07 15:14:06 +01:00
|
|
|
this._reportInitError(
|
|
|
|
this._userName
|
|
|
|
? `Failed to start ${serviceName} verification for user`
|
|
|
|
: `Failed to start ${serviceName} verification`,
|
|
|
|
e, serviceName);
|
2019-12-19 20:50:37 +01:00
|
|
|
return;
|
2013-08-21 18:05:55 -04:00
|
|
|
}
|
2019-12-19 20:50:37 +01:00
|
|
|
this._hold.release();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_beginVerification() {
|
2013-08-16 10:29:26 -04:00
|
|
|
this._startService(this._getForegroundService());
|
2022-04-12 16:38:40 +02:00
|
|
|
this._maybeStartFingerprintVerification().catch(logError);
|
|
|
|
}
|
2013-08-16 10:29:26 -04:00
|
|
|
|
2022-04-12 16:38:40 +02:00
|
|
|
async _maybeStartFingerprintVerification() {
|
2021-01-30 20:14:04 +01:00
|
|
|
if (this._userName &&
|
|
|
|
this._fingerprintReaderType !== FingerprintReaderType.NONE &&
|
|
|
|
!this.serviceIsForeground(FINGERPRINT_SERVICE_NAME))
|
2022-04-12 16:38:40 +02:00
|
|
|
await this._startService(FINGERPRINT_SERVICE_NAME);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-07-17 16:48:03 -04:00
|
|
|
_onChoiceListQuery(client, serviceName, promptMessage, list) {
|
|
|
|
if (!this.serviceIsForeground(serviceName))
|
|
|
|
return;
|
|
|
|
|
2022-08-10 11:56:14 +02:00
|
|
|
this.emit('show-choice-list', serviceName, promptMessage, list.deepUnpack());
|
2017-07-17 16:48:03 -04:00
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onInfo(client, serviceName, info) {
|
2013-07-29 14:23:45 -04:00
|
|
|
if (this.serviceIsForeground(serviceName)) {
|
2021-02-01 19:36:49 +01:00
|
|
|
this._queueMessage(serviceName, info, MessageType.INFO);
|
2021-02-08 17:07:45 +01:00
|
|
|
} else if (this.serviceIsFingerprint(serviceName)) {
|
2013-07-29 14:23:45 -04:00
|
|
|
// We don't show fingerprint messages directly since it's
|
|
|
|
// not the main auth service. Instead we use the messages
|
|
|
|
// as a cue to display our own message.
|
2021-01-30 20:14:04 +01:00
|
|
|
if (this._fingerprintReaderType === FingerprintReaderType.SWIPE) {
|
|
|
|
// Translators: this message is shown below the password entry field
|
|
|
|
// to indicate the user can swipe their finger on the fingerprint reader
|
2021-02-01 19:36:49 +01:00
|
|
|
this._queueMessage(serviceName, _('(or swipe finger across reader)'),
|
|
|
|
MessageType.HINT);
|
2021-01-30 20:14:04 +01:00
|
|
|
} else {
|
|
|
|
// Translators: this message is shown below the password entry field
|
|
|
|
// to indicate the user can place their finger on the fingerprint reader instead
|
2021-02-01 19:36:49 +01:00
|
|
|
this._queueMessage(serviceName, _('(or place finger on reader)'),
|
|
|
|
MessageType.HINT);
|
2021-01-30 20:14:04 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onProblem(client, serviceName, problem) {
|
2020-11-24 19:19:22 +01:00
|
|
|
const isFingerprint = this.serviceIsFingerprint(serviceName);
|
|
|
|
|
|
|
|
if (!this.serviceIsForeground(serviceName) && !isFingerprint)
|
2012-07-17 20:54:07 +02:00
|
|
|
return;
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
|
2021-02-16 03:56:09 +01:00
|
|
|
this._queuePriorityMessage(serviceName, problem, MessageType.ERROR);
|
|
|
|
|
2021-02-01 18:40:03 +01:00
|
|
|
if (isFingerprint) {
|
2021-02-16 04:18:18 +01:00
|
|
|
// pam_fprintd allows the user to retry multiple (maybe even infinite!
|
|
|
|
// times before failing the authentication conversation.
|
|
|
|
// We don't want this behavior to bypass the max-tries setting the user has set,
|
|
|
|
// so we count the problem messages to know how many times the user has failed.
|
|
|
|
// Once we hit the max number of failures we allow, it's time to failure the
|
|
|
|
// conversation from our side. We can't do that right away, however, because
|
|
|
|
// we may drop pending messages coming from pam_fprintd. In order to make sure
|
|
|
|
// the user sees everything, we queue the failure up to get handled in the
|
|
|
|
// near future, after we've finished up the current round of messages.
|
2021-02-01 18:40:03 +01:00
|
|
|
this._failCounter++;
|
|
|
|
|
2021-02-16 04:18:18 +01:00
|
|
|
if (!this._canRetry()) {
|
|
|
|
if (this._fingerprintFailedId)
|
|
|
|
GLib.source_remove(this._fingerprintFailedId);
|
|
|
|
|
|
|
|
const cancellable = this._cancellable;
|
|
|
|
this._fingerprintFailedId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
|
|
|
FINGERPRINT_ERROR_TIMEOUT_WAIT, () => {
|
|
|
|
this._fingerprintFailedId = 0;
|
|
|
|
if (!cancellable.is_cancelled())
|
|
|
|
this._verificationFailed(serviceName, false);
|
|
|
|
return GLib.SOURCE_REMOVE;
|
|
|
|
});
|
|
|
|
}
|
2021-02-01 18:40:03 +01:00
|
|
|
}
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onInfoQuery(client, serviceName, question) {
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
if (!this.serviceIsForeground(serviceName))
|
2012-07-17 20:54:07 +02:00
|
|
|
return;
|
|
|
|
|
2019-12-12 15:02:53 +05:30
|
|
|
this.emit('ask-question', serviceName, question, false);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onSecretInfoQuery(client, serviceName, secretQuestion) {
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
if (!this.serviceIsForeground(serviceName))
|
2012-07-17 20:54:07 +02:00
|
|
|
return;
|
|
|
|
|
2020-01-04 00:31:15 +08:00
|
|
|
let token = null;
|
|
|
|
if (this._credentialManagers[serviceName])
|
|
|
|
token = this._credentialManagers[serviceName].token;
|
|
|
|
|
|
|
|
if (token) {
|
|
|
|
this.answerQuery(serviceName, token);
|
2013-10-10 10:21:47 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-12 15:02:53 +05:30
|
|
|
this.emit('ask-question', serviceName, secretQuestion, true);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onReset() {
|
2012-08-07 16:49:22 +02:00
|
|
|
// Clear previous attempts to authenticate
|
|
|
|
this._failCounter = 0;
|
2022-10-21 17:47:15 +02:00
|
|
|
this._activeServices.clear();
|
2021-02-15 20:59:57 +01:00
|
|
|
this._unavailableServices.clear();
|
util: abstract out default auth service in code
Right now, the primary way a user logs in is with
a password. They can also swipe their finger, if their
fingerprint is enrolled, but it's expected the fingerprint
auth service won't ask questions the user has to respond to
by typing. As such, we ignore questions that comes from
anything but the main auth service: gdm-password.
In the future, if a user inserts a smartcard, we'll want
to treat the gdm-smartcard service as the main auth service,
and let any questions from it get to the user.
This commit tries to prepare for that eventuality by storing
the name of the default auth service away in a _defaultService variable
before verification has begun, and then later checking incoming
queries against that service instead of checking against
string 'gdm-password' directly.
Of course, right now, _defaultService is always gdm-password.
https://bugzilla.gnome.org/show_bug.cgi?id=683437
2013-07-28 19:42:26 -04:00
|
|
|
this._updateDefaultService();
|
2012-07-17 20:54:07 +02:00
|
|
|
|
|
|
|
this.emit('reset');
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onVerificationComplete() {
|
2012-07-17 20:54:07 +02:00
|
|
|
this.emit('verification-complete');
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-07-17 20:54:07 +02:00
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_cancelAndReset() {
|
2013-03-18 00:59:56 -04:00
|
|
|
this.cancel();
|
|
|
|
this._onReset();
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2021-02-02 17:57:45 +01:00
|
|
|
_retry(serviceName) {
|
|
|
|
this._hold = new Batch.Hold();
|
|
|
|
this._connectSignals();
|
|
|
|
this._startService(serviceName);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2013-03-18 00:59:56 -04:00
|
|
|
|
2021-02-01 18:40:03 +01:00
|
|
|
_canRetry() {
|
|
|
|
return this._userName &&
|
|
|
|
(this._reauthOnly || this._failCounter < this.allowedFailures);
|
|
|
|
}
|
|
|
|
|
2022-08-08 12:19:51 +02:00
|
|
|
async _verificationFailed(serviceName, shouldRetry) {
|
2021-04-28 18:32:22 +02:00
|
|
|
if (serviceName === FINGERPRINT_SERVICE_NAME) {
|
|
|
|
if (this._fingerprintFailedId)
|
|
|
|
GLib.source_remove(this._fingerprintFailedId);
|
|
|
|
}
|
|
|
|
|
2012-08-07 16:49:22 +02:00
|
|
|
// For Not Listed / enterprise logins, immediately reset
|
|
|
|
// the dialog
|
2018-05-29 03:10:09 +03:00
|
|
|
// Otherwise, when in login mode we allow ALLOWED_FAILURES attempts.
|
|
|
|
// After that, we go back to the welcome screen.
|
2021-02-16 03:45:14 +01:00
|
|
|
this._filterServiceMessages(serviceName, MessageType.ERROR);
|
2021-02-02 15:08:10 +01:00
|
|
|
|
2021-04-28 10:42:14 -04:00
|
|
|
const doneTrying = !shouldRetry || !this._canRetry();
|
|
|
|
|
2022-08-08 12:19:51 +02:00
|
|
|
this.emit('verification-failed', serviceName, !doneTrying);
|
|
|
|
try {
|
|
|
|
if (doneTrying) {
|
|
|
|
this._disconnectSignals();
|
|
|
|
await this._handlePendingMessages();
|
2013-03-18 00:59:56 -04:00
|
|
|
this._cancelAndReset();
|
2022-08-08 12:29:47 +02:00
|
|
|
} else {
|
|
|
|
await this._handlePendingMessages();
|
|
|
|
this._retry(serviceName);
|
2013-03-18 00:59:56 -04:00
|
|
|
}
|
2022-08-08 12:19:51 +02:00
|
|
|
} catch (e) {
|
|
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
logError(e);
|
2012-08-07 16:49:22 +02:00
|
|
|
}
|
2022-08-08 12:19:51 +02:00
|
|
|
}
|
2012-08-07 16:49:22 +02:00
|
|
|
|
2022-08-08 12:19:51 +02:00
|
|
|
_handlePendingMessages() {
|
|
|
|
if (!this.hasPendingMessage)
|
|
|
|
return Promise.resolve();
|
2021-04-28 10:42:14 -04:00
|
|
|
|
2022-08-08 12:19:51 +02:00
|
|
|
const cancellable = this._cancellable;
|
|
|
|
return new Promise((resolve, reject) => {
|
2021-04-28 10:42:14 -04:00
|
|
|
let signalId = this.connect('no-more-messages', () => {
|
|
|
|
this.disconnect(signalId);
|
2022-08-08 12:19:51 +02:00
|
|
|
if (cancellable.is_cancelled())
|
|
|
|
reject(new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, 'Operation was cancelled'));
|
|
|
|
else
|
|
|
|
resolve();
|
2021-04-28 10:42:14 -04:00
|
|
|
});
|
2022-08-08 12:19:51 +02:00
|
|
|
});
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2012-08-07 16:49:22 +02:00
|
|
|
|
2021-02-15 20:59:57 +01:00
|
|
|
_onServiceUnavailable(_client, serviceName, errorMessage) {
|
|
|
|
this._unavailableServices.add(serviceName);
|
|
|
|
|
|
|
|
if (!errorMessage)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (this.serviceIsForeground(serviceName) || this.serviceIsFingerprint(serviceName))
|
|
|
|
this._queueMessage(serviceName, errorMessage, MessageType.ERROR);
|
|
|
|
}
|
|
|
|
|
2022-10-21 17:47:15 +02:00
|
|
|
_onConversationStarted(client, serviceName) {
|
|
|
|
this._activeServices.add(serviceName);
|
|
|
|
}
|
|
|
|
|
2017-10-31 01:03:21 +01:00
|
|
|
_onConversationStopped(client, serviceName) {
|
2022-10-21 17:47:15 +02:00
|
|
|
this._activeServices.delete(serviceName);
|
|
|
|
|
2013-10-10 10:21:47 +02:00
|
|
|
// If the login failed with the preauthenticated oVirt credentials
|
|
|
|
// then discard the credentials and revert to default authentication
|
|
|
|
// mechanism.
|
2020-01-04 00:31:15 +08:00
|
|
|
let foregroundService = Object.keys(this._credentialManagers).find(service =>
|
|
|
|
this.serviceIsForeground(service));
|
|
|
|
if (foregroundService) {
|
|
|
|
this._credentialManagers[foregroundService].token = null;
|
2013-10-10 10:21:47 +02:00
|
|
|
this._preemptingService = null;
|
2021-02-01 19:36:49 +01:00
|
|
|
this._verificationFailed(serviceName, false);
|
2013-10-10 10:21:47 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-16 03:45:14 +01:00
|
|
|
this._filterServiceMessages(serviceName, MessageType.ERROR);
|
|
|
|
|
2021-02-15 20:59:57 +01:00
|
|
|
if (this._unavailableServices.has(serviceName))
|
|
|
|
return;
|
|
|
|
|
2012-07-17 20:54:07 +02:00
|
|
|
// if the password service fails, then cancel everything.
|
|
|
|
// But if, e.g., fingerprint fails, still give
|
|
|
|
// password authentication a chance to succeed
|
2021-02-08 18:57:06 +01:00
|
|
|
if (this.serviceIsForeground(serviceName))
|
2021-02-08 18:43:16 +01:00
|
|
|
this._failCounter++;
|
2021-02-08 18:57:06 +01:00
|
|
|
|
|
|
|
this._verificationFailed(serviceName, true);
|
2017-10-31 02:19:44 +01:00
|
|
|
}
|
2023-07-10 02:53:00 -07:00
|
|
|
}
|