2012-07-17 18:54:07 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2023-07-10 09:53:00 +00: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 18:54:07 +00:00
|
|
|
|
2021-01-30 19:10:03 +00:00
|
|
|
const FprintManagerIface = loadInterfaceXML('net.reactivated.Fprint.Manager');
|
|
|
|
const FprintManagerProxy = Gio.DBusProxy.makeProxyWrapper(FprintManagerIface);
|
2021-01-30 19:14:04 +00:00
|
|
|
const FprintDeviceIface = loadInterfaceXML('net.reactivated.Fprint.Device');
|
|
|
|
const FprintDeviceProxy = Gio.DBusProxy.makeProxyWrapper(FprintDeviceIface);
|
2021-01-30 19:10:03 +00:00
|
|
|
|
2022-02-10 23:09:54 +00:00
|
|
|
Gio._promisify(Gdm.Client.prototype, 'open_reauthentication_channel');
|
|
|
|
Gio._promisify(Gdm.Client.prototype, 'get_user_verifier');
|
2019-12-19 19:50:37 +00:00
|
|
|
Gio._promisify(Gdm.UserVerifierProxy.prototype,
|
2022-02-10 23:09:54 +00:00
|
|
|
'call_begin_verification_for_user');
|
|
|
|
Gio._promisify(Gdm.UserVerifierProxy.prototype, 'call_begin_verification');
|
2019-12-19 19:50:37 +00:00
|
|
|
|
2023-07-10 09:53:00 +00: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 18:54:07 +00:00
|
|
|
|
2023-07-10 09:53:00 +00: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 18:54:07 +00:00
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export const LOGO_KEY = 'logo';
|
|
|
|
export const DISABLE_USER_LIST_KEY = 'disable-user-list';
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2015-03-27 13:36:05 +00:00
|
|
|
// Give user 48ms to read each character of a PAM message
|
2023-07-10 09:53:00 +00:00
|
|
|
const USER_READ_TIME = 48;
|
2021-02-16 03:18:18 +00:00
|
|
|
const FINGERPRINT_ERROR_TIMEOUT_WAIT = 15;
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2023-07-30 12:56:59 +00:00
|
|
|
/**
|
|
|
|
* Keep messages in order by priority
|
|
|
|
*
|
|
|
|
* @enum {number}
|
|
|
|
*/
|
2023-07-10 09:53:00 +00:00
|
|
|
export const MessageType = {
|
2013-08-19 16:00:33 +00:00
|
|
|
NONE: 0,
|
2021-02-16 02:08:38 +00:00
|
|
|
HINT: 1,
|
2013-08-19 16:00:33 +00:00
|
|
|
INFO: 2,
|
2021-02-16 02:08:38 +00:00
|
|
|
ERROR: 3,
|
2013-08-19 16:00:33 +00:00
|
|
|
};
|
|
|
|
|
2021-01-30 19:14:04 +00:00
|
|
|
const FingerprintReaderType = {
|
|
|
|
NONE: 0,
|
|
|
|
PRESS: 1,
|
|
|
|
SWIPE: 2,
|
|
|
|
};
|
|
|
|
|
2023-07-30 12:56:59 +00:00
|
|
|
/**
|
|
|
|
* @param {Clutter.Actor} actor
|
|
|
|
*/
|
2023-07-10 09:53:00 +00:00
|
|
|
export function cloneAndFadeOutActor(actor) {
|
2013-02-06 19:18:26 +00: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 21:51:13 +00:00
|
|
|
const clone = new Clutter.Clone({
|
|
|
|
source: actor,
|
|
|
|
reactive: false,
|
|
|
|
});
|
2013-02-06 19:18:26 +00: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 19:46:19 +00:00
|
|
|
clone.ease({
|
|
|
|
opacity: 0,
|
|
|
|
duration: CLONE_FADE_ANIMATION_TIME,
|
|
|
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
|
|
|
onComplete: () => {
|
|
|
|
clone.destroy();
|
|
|
|
hold.release();
|
2019-08-20 21:43:54 +00:00
|
|
|
},
|
2018-07-20 19:46:19 +00:00
|
|
|
});
|
2013-02-06 19:18:26 +00:00
|
|
|
return hold;
|
|
|
|
}
|
|
|
|
|
2023-07-10 09:53:00 +00:00
|
|
|
export class ShellUserVerifier extends Signals.EventEmitter {
|
2017-10-31 01:19:44 +00:00
|
|
|
constructor(client, params) {
|
2022-07-04 22:30:44 +00:00
|
|
|
super();
|
2012-08-03 15:10:45 +00:00
|
|
|
params = Params.parse(params, { reauthenticationOnly: false });
|
|
|
|
this._reauthOnly = params.reauthenticationOnly;
|
|
|
|
|
2012-07-17 18:54:07 +00:00
|
|
|
this._client = client;
|
|
|
|
|
2017-06-13 02:24:12 +00:00
|
|
|
this._defaultService = null;
|
|
|
|
this._preemptingService = null;
|
|
|
|
|
2014-06-24 19:17:09 +00:00
|
|
|
this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
|
2013-07-29 18:18:30 +00:00
|
|
|
this._settings.connect('changed',
|
2017-12-02 00:27:35 +00:00
|
|
|
this._updateDefaultService.bind(this));
|
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 23:42:26 +00:00
|
|
|
this._updateDefaultService();
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2021-01-30 19:10:03 +00:00
|
|
|
this._fprintManager = new FprintManagerProxy(Gio.DBus.system,
|
|
|
|
'net.reactivated.Fprint',
|
|
|
|
'/net/reactivated/Fprint/Manager',
|
|
|
|
null,
|
|
|
|
null,
|
|
|
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES);
|
2013-06-27 12:54:19 +00:00
|
|
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
|
|
|
|
|
|
|
// We check for smartcards right away, since an inserted smartcard
|
|
|
|
// at startup should result in immediately initiating authentication.
|
2017-06-26 18:47:19 +00:00
|
|
|
// This is different than fingerprint readers, where we only check them
|
2013-06-27 12:54:19 +00:00
|
|
|
// after a user has been picked.
|
2017-06-13 02:24:12 +00:00
|
|
|
this.smartcardDetected = false;
|
2013-06-27 12:54:19 +00:00
|
|
|
this._checkForSmartcard();
|
|
|
|
|
2021-08-15 22:36:59 +00:00
|
|
|
this._smartcardManager.connectObject(
|
|
|
|
'smartcard-inserted', this._checkForSmartcard.bind(this),
|
|
|
|
'smartcard-removed', this._checkForSmartcard.bind(this), this);
|
2013-06-27 12:54:19 +00:00
|
|
|
|
2013-03-18 04:59:56 +00:00
|
|
|
this._messageQueue = [];
|
|
|
|
this._messageQueueTimeoutId = 0;
|
2013-07-22 14:59:57 +00:00
|
|
|
this.reauthenticating = false;
|
2012-08-07 14:49:22 +00:00
|
|
|
|
|
|
|
this._failCounter = 0;
|
2021-02-15 19:59:57 +00:00
|
|
|
this._unavailableServices = new Set();
|
2013-10-10 08:21:47 +00:00
|
|
|
|
2020-01-03 16:31:15 +00:00
|
|
|
this._credentialManagers = {};
|
2013-10-10 08:21:47 +00:00
|
|
|
|
2022-08-03 13:34:10 +00:00
|
|
|
this.addCredentialManager(OVirt.SERVICE_NAME, OVirt.getOVirtCredentialsManager());
|
|
|
|
this.addCredentialManager(Vmware.SERVICE_NAME, Vmware.getVmwareCredentialsManager());
|
|
|
|
}
|
2013-10-10 08:21:47 +00:00
|
|
|
|
2022-08-03 13:34:10 +00:00
|
|
|
addCredentialManager(serviceName, credentialManager) {
|
|
|
|
if (this._credentialManagers[serviceName])
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._credentialManagers[serviceName] = credentialManager;
|
|
|
|
if (credentialManager.token) {
|
|
|
|
this._onCredentialManagerAuthenticated(credentialManager,
|
|
|
|
credentialManager.token);
|
2020-01-03 16:31:15 +00:00
|
|
|
}
|
2022-08-03 13:34:10 +00: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 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2021-02-16 01:00:41 +00:00
|
|
|
get hasPendingMessages() {
|
|
|
|
return !!this._messageQueue.length;
|
|
|
|
}
|
|
|
|
|
2021-02-01 12:10:45 +00:00
|
|
|
get allowedFailures() {
|
|
|
|
return this._settings.get_int(ALLOWED_FAILURES_KEY);
|
|
|
|
}
|
|
|
|
|
2021-02-16 01:00:41 +00:00
|
|
|
get currentMessage() {
|
|
|
|
return this._messageQueue ? this._messageQueue[0] : null;
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
begin(userName, hold) {
|
2012-08-26 12:54:02 +00:00
|
|
|
this._cancellable = new Gio.Cancellable();
|
2012-07-17 18:54:07 +00:00
|
|
|
this._hold = hold;
|
|
|
|
this._userName = userName;
|
2013-07-22 14:59:57 +00:00
|
|
|
this.reauthenticating = false;
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2012-08-26 12:54:02 +00:00
|
|
|
this._checkForFingerprintReader();
|
|
|
|
|
2019-12-19 19:50:37 +00: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 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
cancel() {
|
2012-08-26 12:54:02 +00:00
|
|
|
if (this._cancellable)
|
|
|
|
this._cancellable.cancel();
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2013-07-29 14:52:02 +00:00
|
|
|
if (this._userVerifier) {
|
2012-07-17 18:54:07 +00:00
|
|
|
this._userVerifier.call_cancel_sync(null);
|
2013-07-29 14:52:02 +00:00
|
|
|
this.clear();
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_clearUserVerifier() {
|
2014-10-09 18:10:12 +00:00
|
|
|
if (this._userVerifier) {
|
2021-02-02 14:08:10 +00:00
|
|
|
this._disconnectSignals();
|
2014-10-09 18:10:12 +00:00
|
|
|
this._userVerifier.run_dispose();
|
|
|
|
this._userVerifier = null;
|
2017-07-17 20:48:03 +00:00
|
|
|
if (this._userVerifierChoiceList) {
|
|
|
|
this._userVerifierChoiceList.run_dispose();
|
|
|
|
this._userVerifierChoiceList = null;
|
|
|
|
}
|
2014-10-09 18:10:12 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-10-09 18:10:12 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
clear() {
|
2012-08-26 12:54:02 +00:00
|
|
|
if (this._cancellable) {
|
|
|
|
this._cancellable.cancel();
|
|
|
|
this._cancellable = null;
|
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2014-10-09 18:10:12 +00:00
|
|
|
this._clearUserVerifier();
|
2013-03-18 04:59:56 +00:00
|
|
|
this._clearMessageQueue();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
destroy() {
|
2021-01-30 00:53:59 +00:00
|
|
|
this.cancel();
|
2014-10-09 18:10:12 +00:00
|
|
|
|
|
|
|
this._settings.run_dispose();
|
|
|
|
this._settings = null;
|
|
|
|
|
2021-08-15 22:36:59 +00:00
|
|
|
this._smartcardManager.disconnectObject(this);
|
2014-10-09 18:10:12 +00:00
|
|
|
this._smartcardManager = null;
|
|
|
|
|
2022-08-03 13:34:10 +00:00
|
|
|
for (let service in this._credentialManagers)
|
|
|
|
this.removeCredentialManager(service);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2014-10-09 18:10:12 +00:00
|
|
|
|
2017-07-17 20:48:03 +00:00
|
|
|
selectChoice(serviceName, key) {
|
|
|
|
this._userVerifierChoiceList.call_select_choice(serviceName, key, this._cancellable, null);
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:19:51 +00:00
|
|
|
async answerQuery(serviceName, answer) {
|
|
|
|
try {
|
|
|
|
await this._handlePendingMessages();
|
2013-03-18 04:59:56 +00:00
|
|
|
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
2022-08-08 10:19:51 +00:00
|
|
|
} catch (e) {
|
|
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
logError(e);
|
2013-03-18 04:59:56 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_getIntervalForMessage(message) {
|
2021-02-16 02:45:14 +00:00
|
|
|
if (!message)
|
|
|
|
return 0;
|
|
|
|
|
2013-03-18 04:59:56 +00:00
|
|
|
// We probably could be smarter here
|
|
|
|
return message.length * USER_READ_TIME;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
finishMessageQueue() {
|
2013-03-18 04:59:56 +00:00
|
|
|
if (!this.hasPendingMessages)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this._messageQueue = [];
|
2012-10-29 16:39:00 +00:00
|
|
|
|
2013-03-18 04:59:56 +00:00
|
|
|
this.emit('no-more-messages');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2021-02-08 18:34:09 +00:00
|
|
|
increaseCurrentMessageTimeout(interval) {
|
|
|
|
if (!this._messageQueueTimeoutId && interval > 0)
|
|
|
|
this._currentMessageExtraInterval = interval;
|
|
|
|
}
|
|
|
|
|
2021-02-16 02:45:14 +00: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 00:03:21 +00:00
|
|
|
_queueMessageTimeout() {
|
2013-03-18 04:59:56 +00:00
|
|
|
if (this._messageQueueTimeoutId != 0)
|
|
|
|
return;
|
|
|
|
|
2021-02-16 01:00:41 +00:00
|
|
|
const message = this.currentMessage;
|
2013-08-19 16:00:33 +00:00
|
|
|
|
2021-02-08 18:34:09 +00:00
|
|
|
delete this._currentMessageExtraInterval;
|
2021-02-01 18:36:49 +00:00
|
|
|
this.emit('show-message', message.serviceName, message.text, message.type);
|
2013-03-18 04:59:56 +00:00
|
|
|
|
|
|
|
this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
2021-02-16 01:00:41 +00: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 17:26:52 +00:00
|
|
|
GLib.Source.set_name_by_id(this._messageQueueTimeoutId, '[gnome-shell] this._queueMessageTimeout');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2021-02-01 18:36:49 +00:00
|
|
|
_queueMessage(serviceName, message, messageType) {
|
2013-03-18 04:59:56 +00:00
|
|
|
let interval = this._getIntervalForMessage(message);
|
|
|
|
|
2021-02-01 18:36:49 +00:00
|
|
|
this._messageQueue.push({ serviceName, text: message, type: messageType, interval });
|
2013-03-18 04:59:56 +00:00
|
|
|
this._queueMessageTimeout();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2021-02-16 02:08:38 +00: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 00:03:21 +00:00
|
|
|
_clearMessageQueue() {
|
2013-03-18 04:59:56 +00:00
|
|
|
this.finishMessageQueue();
|
|
|
|
|
|
|
|
if (this._messageQueueTimeoutId != 0) {
|
|
|
|
GLib.source_remove(this._messageQueueTimeoutId);
|
|
|
|
this._messageQueueTimeoutId = 0;
|
|
|
|
}
|
2021-02-01 18:36:49 +00:00
|
|
|
this.emit('show-message', null, null, MessageType.NONE);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2022-06-23 12:53:29 +00:00
|
|
|
async _checkForFingerprintReader() {
|
2021-01-30 19:14:04 +00:00
|
|
|
this._fingerprintReaderType = FingerprintReaderType.NONE;
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-03-14 20:02:51 +00:00
|
|
|
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY) ||
|
|
|
|
this._fprintManager == null) {
|
2013-07-29 18:18:30 +00:00
|
|
|
this._updateDefaultService();
|
2012-07-17 18:54:07 +00:00
|
|
|
return;
|
2013-07-29 18:18:30 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2022-06-23 12:53:29 +00:00
|
|
|
try {
|
|
|
|
const [device] = await this._fprintManager.GetDefaultDeviceAsync(
|
|
|
|
Gio.DBusCallFlags.NONE, this._cancellable);
|
|
|
|
const fprintDeviceProxy = new FprintDeviceProxy(Gio.DBus.system,
|
|
|
|
'net.reactivated.Fprint',
|
|
|
|
device);
|
|
|
|
const fprintDeviceType = fprintDeviceProxy['scan-type'];
|
|
|
|
|
|
|
|
this._fingerprintReaderType = fprintDeviceType === 'swipe'
|
|
|
|
? FingerprintReaderType.SWIPE
|
|
|
|
: FingerprintReaderType.PRESS;
|
|
|
|
this._updateDefaultService();
|
|
|
|
} catch (e) {}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2020-01-03 16:31:15 +00:00
|
|
|
_onCredentialManagerAuthenticated(credentialManager, _token) {
|
|
|
|
this._preemptingService = credentialManager.service;
|
|
|
|
this.emit('credential-manager-authenticated');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-10-10 08:21:47 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_checkForSmartcard() {
|
2013-06-27 12:54:19 +00:00
|
|
|
let smartcardDetected;
|
|
|
|
|
|
|
|
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
|
|
|
smartcardDetected = false;
|
2014-03-13 17:47:50 +00:00
|
|
|
else if (this._reauthOnly)
|
2013-06-27 12:54:19 +00:00
|
|
|
smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
|
|
|
|
else
|
|
|
|
smartcardDetected = this._smartcardManager.hasInsertedTokens();
|
|
|
|
|
|
|
|
if (smartcardDetected != this.smartcardDetected) {
|
|
|
|
this.smartcardDetected = smartcardDetected;
|
|
|
|
|
|
|
|
if (this.smartcardDetected)
|
|
|
|
this._preemptingService = SMARTCARD_SERVICE_NAME;
|
|
|
|
else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
|
|
|
|
this._preemptingService = null;
|
|
|
|
|
|
|
|
this.emit('smartcard-status-changed');
|
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-27 12:54:19 +00:00
|
|
|
|
2021-02-01 18:36:49 +00:00
|
|
|
_reportInitError(where, error, serviceName) {
|
2012-09-06 14:40:13 +00:00
|
|
|
logError(error, where);
|
2012-10-03 19:25:49 +00:00
|
|
|
this._hold.release();
|
2012-09-06 14:40:13 +00:00
|
|
|
|
2021-02-01 18:36:49 +00:00
|
|
|
this._queueMessage(serviceName, _('Authentication error'), MessageType.ERROR);
|
2021-02-08 17:43:16 +00:00
|
|
|
this._failCounter++;
|
2021-02-01 18:36:49 +00:00
|
|
|
this._verificationFailed(serviceName, false);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-09-06 14:40:13 +00:00
|
|
|
|
2019-12-19 19:50:37 +00:00
|
|
|
async _openReauthenticationChannel(userName) {
|
2012-07-17 18:54:07 +00:00
|
|
|
try {
|
2014-10-09 18:10:12 +00:00
|
|
|
this._clearUserVerifier();
|
2019-12-19 19:50:37 +00:00
|
|
|
this._userVerifier = await this._client.open_reauthentication_channel(
|
|
|
|
userName, this._cancellable);
|
2019-01-29 01:26:39 +00:00
|
|
|
} catch (e) {
|
2018-07-15 01:17:42 +00: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 19:50:37 +00:00
|
|
|
this._getUserVerifier();
|
2018-07-15 01:17:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-09-06 14:40:13 +00:00
|
|
|
this._reportInitError('Failed to open reauthentication channel', e);
|
|
|
|
return;
|
2012-07-17 18:54:07 +00:00
|
|
|
}
|
2012-09-06 14:40:13 +00:00
|
|
|
|
2017-07-17 20:48:03 +00: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 14:59:57 +00:00
|
|
|
this.reauthenticating = true;
|
2012-09-06 14:40:13 +00:00
|
|
|
this._connectSignals();
|
|
|
|
this._beginVerification();
|
|
|
|
this._hold.release();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2019-12-19 19:50:37 +00:00
|
|
|
async _getUserVerifier() {
|
2012-08-26 12:54:02 +00:00
|
|
|
try {
|
2014-10-09 18:10:12 +00:00
|
|
|
this._clearUserVerifier();
|
2019-12-19 19:50:37 +00:00
|
|
|
this._userVerifier =
|
|
|
|
await this._client.get_user_verifier(this._cancellable);
|
2019-01-29 01:26:39 +00:00
|
|
|
} catch (e) {
|
2018-07-15 01:17:42 +00:00
|
|
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
return;
|
2012-09-06 14:40:13 +00:00
|
|
|
this._reportInitError('Failed to obtain user verifier', e);
|
2012-08-26 12:54:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-17 20:48:03 +00: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 18:54:07 +00:00
|
|
|
this._connectSignals();
|
|
|
|
this._beginVerification();
|
|
|
|
this._hold.release();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_connectSignals() {
|
2021-02-02 14:08:10 +00:00
|
|
|
this._disconnectSignals();
|
2021-08-15 22:36:59 +00: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),
|
|
|
|
'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 14:08:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
_disconnectSignals() {
|
2021-08-15 22:36:59 +00:00
|
|
|
this._userVerifier?.disconnectObject(this);
|
2023-02-12 17:20:15 +00:00
|
|
|
this._userVerifierChoiceList?.disconnectObject(this);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_getForegroundService() {
|
2013-06-27 12:54:19 +00: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 23:42:26 +00:00
|
|
|
return this._defaultService;
|
2017-10-31 01:19:44 +00: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 23:42:26 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
serviceIsForeground(serviceName) {
|
2023-06-08 04:53:07 +00:00
|
|
|
return serviceName === this._getForegroundService();
|
2017-10-31 01:19:44 +00: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 23:42:26 +00:00
|
|
|
|
2022-08-03 13:08:07 +00:00
|
|
|
foregroundServiceDeterminesUsername() {
|
|
|
|
for (let serviceName in this._credentialManagers) {
|
|
|
|
if (this.serviceIsForeground(serviceName))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.serviceIsForeground(SMARTCARD_SERVICE_NAME);
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
serviceIsDefault(serviceName) {
|
2013-06-27 12:54:19 +00:00
|
|
|
return serviceName == this._defaultService;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-27 12:54:19 +00:00
|
|
|
|
2021-02-08 16:07:45 +00:00
|
|
|
serviceIsFingerprint(serviceName) {
|
|
|
|
return this._fingerprintReaderType !== FingerprintReaderType.NONE &&
|
|
|
|
serviceName === FINGERPRINT_SERVICE_NAME;
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_updateDefaultService() {
|
2013-07-29 18:18:30 +00:00
|
|
|
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
|
|
|
this._defaultService = PASSWORD_SERVICE_NAME;
|
2014-11-14 20:57:16 +00:00
|
|
|
else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
2013-06-27 12:54:19 +00:00
|
|
|
this._defaultService = SMARTCARD_SERVICE_NAME;
|
2021-01-30 19:14:04 +00:00
|
|
|
else if (this._fingerprintReaderType !== FingerprintReaderType.NONE)
|
2013-07-29 18:18:30 +00:00
|
|
|
this._defaultService = FINGERPRINT_SERVICE_NAME;
|
2015-07-01 15:18:44 +00:00
|
|
|
|
|
|
|
if (!this._defaultService) {
|
2023-08-06 22:34:20 +00:00
|
|
|
log('no authentication service is enabled, using password authentication');
|
2015-07-01 15:18:44 +00:00
|
|
|
this._defaultService = PASSWORD_SERVICE_NAME;
|
|
|
|
}
|
2017-10-31 01:19:44 +00: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 23:42:26 +00:00
|
|
|
|
2019-12-19 19:50:37 +00:00
|
|
|
async _startService(serviceName) {
|
2012-07-17 18:54:07 +00:00
|
|
|
this._hold.acquire();
|
2019-12-19 19:50:37 +00:00
|
|
|
try {
|
|
|
|
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) {
|
|
|
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
return;
|
2021-02-02 15:30:11 +00:00
|
|
|
if (!this.serviceIsForeground(serviceName)) {
|
2022-02-07 14:14:06 +00:00
|
|
|
logError(e,
|
|
|
|
`Failed to start ${serviceName} for ${this._userName}`);
|
2021-02-02 15:30:11 +00:00
|
|
|
this._hold.release();
|
|
|
|
return;
|
|
|
|
}
|
2022-02-07 14:14:06 +00:00
|
|
|
this._reportInitError(
|
|
|
|
this._userName
|
|
|
|
? `Failed to start ${serviceName} verification for user`
|
|
|
|
: `Failed to start ${serviceName} verification`,
|
|
|
|
e, serviceName);
|
2019-12-19 19:50:37 +00:00
|
|
|
return;
|
2013-08-21 22:05:55 +00:00
|
|
|
}
|
2019-12-19 19:50:37 +00:00
|
|
|
this._hold.release();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_beginVerification() {
|
2013-08-16 14:29:26 +00:00
|
|
|
this._startService(this._getForegroundService());
|
|
|
|
|
2021-01-30 19:14:04 +00:00
|
|
|
if (this._userName &&
|
|
|
|
this._fingerprintReaderType !== FingerprintReaderType.NONE &&
|
|
|
|
!this.serviceIsForeground(FINGERPRINT_SERVICE_NAME))
|
2013-08-16 14:29:26 +00:00
|
|
|
this._startService(FINGERPRINT_SERVICE_NAME);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-07-17 20:48:03 +00:00
|
|
|
_onChoiceListQuery(client, serviceName, promptMessage, list) {
|
|
|
|
if (!this.serviceIsForeground(serviceName))
|
|
|
|
return;
|
|
|
|
|
2022-08-10 09:56:14 +00:00
|
|
|
this.emit('show-choice-list', serviceName, promptMessage, list.deepUnpack());
|
2017-07-17 20:48:03 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onInfo(client, serviceName, info) {
|
2013-07-29 18:23:45 +00:00
|
|
|
if (this.serviceIsForeground(serviceName)) {
|
2021-02-01 18:36:49 +00:00
|
|
|
this._queueMessage(serviceName, info, MessageType.INFO);
|
2021-02-08 16:07:45 +00:00
|
|
|
} else if (this.serviceIsFingerprint(serviceName)) {
|
2013-07-29 18:23:45 +00: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 19:14:04 +00: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 18:36:49 +00:00
|
|
|
this._queueMessage(serviceName, _('(or swipe finger across reader)'),
|
|
|
|
MessageType.HINT);
|
2021-01-30 19:14:04 +00: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 18:36:49 +00:00
|
|
|
this._queueMessage(serviceName, _('(or place finger on reader)'),
|
|
|
|
MessageType.HINT);
|
2021-01-30 19:14:04 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onProblem(client, serviceName, problem) {
|
2020-11-24 18:19:22 +00:00
|
|
|
const isFingerprint = this.serviceIsFingerprint(serviceName);
|
|
|
|
|
|
|
|
if (!this.serviceIsForeground(serviceName) && !isFingerprint)
|
2012-07-17 18:54:07 +00: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 23:42:26 +00:00
|
|
|
|
2021-02-16 02:56:09 +00:00
|
|
|
this._queuePriorityMessage(serviceName, problem, MessageType.ERROR);
|
|
|
|
|
2021-02-01 17:40:03 +00:00
|
|
|
if (isFingerprint) {
|
2021-02-16 03:18:18 +00: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 17:40:03 +00:00
|
|
|
this._failCounter++;
|
|
|
|
|
2021-02-16 03:18:18 +00: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 17:40:03 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00: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 23:42:26 +00:00
|
|
|
if (!this.serviceIsForeground(serviceName))
|
2012-07-17 18:54:07 +00:00
|
|
|
return;
|
|
|
|
|
2019-12-12 09:32:53 +00:00
|
|
|
this.emit('ask-question', serviceName, question, false);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00: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 23:42:26 +00:00
|
|
|
if (!this.serviceIsForeground(serviceName))
|
2012-07-17 18:54:07 +00:00
|
|
|
return;
|
|
|
|
|
2020-01-03 16:31:15 +00:00
|
|
|
let token = null;
|
|
|
|
if (this._credentialManagers[serviceName])
|
|
|
|
token = this._credentialManagers[serviceName].token;
|
|
|
|
|
|
|
|
if (token) {
|
|
|
|
this.answerQuery(serviceName, token);
|
2013-10-10 08:21:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-12 09:32:53 +00:00
|
|
|
this.emit('ask-question', serviceName, secretQuestion, true);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onReset() {
|
2012-08-07 14:49:22 +00:00
|
|
|
// Clear previous attempts to authenticate
|
|
|
|
this._failCounter = 0;
|
2021-02-15 19:59:57 +00: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 23:42:26 +00:00
|
|
|
this._updateDefaultService();
|
2012-07-17 18:54:07 +00:00
|
|
|
|
|
|
|
this.emit('reset');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onVerificationComplete() {
|
2012-07-17 18:54:07 +00:00
|
|
|
this.emit('verification-complete');
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-07-17 18:54:07 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_cancelAndReset() {
|
2013-03-18 04:59:56 +00:00
|
|
|
this.cancel();
|
|
|
|
this._onReset();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2021-02-02 16:57:45 +00:00
|
|
|
_retry(serviceName) {
|
|
|
|
this._hold = new Batch.Hold();
|
|
|
|
this._connectSignals();
|
|
|
|
this._startService(serviceName);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-03-18 04:59:56 +00:00
|
|
|
|
2021-02-01 17:40:03 +00:00
|
|
|
_canRetry() {
|
|
|
|
return this._userName &&
|
|
|
|
(this._reauthOnly || this._failCounter < this.allowedFailures);
|
|
|
|
}
|
|
|
|
|
2022-08-08 10:19:51 +00:00
|
|
|
async _verificationFailed(serviceName, shouldRetry) {
|
2021-04-28 16:32:22 +00:00
|
|
|
if (serviceName === FINGERPRINT_SERVICE_NAME) {
|
|
|
|
if (this._fingerprintFailedId)
|
|
|
|
GLib.source_remove(this._fingerprintFailedId);
|
|
|
|
}
|
|
|
|
|
2012-08-07 14:49:22 +00:00
|
|
|
// For Not Listed / enterprise logins, immediately reset
|
|
|
|
// the dialog
|
2018-05-29 00:10:09 +00:00
|
|
|
// Otherwise, when in login mode we allow ALLOWED_FAILURES attempts.
|
|
|
|
// After that, we go back to the welcome screen.
|
2021-02-16 02:45:14 +00:00
|
|
|
this._filterServiceMessages(serviceName, MessageType.ERROR);
|
2021-02-02 14:08:10 +00:00
|
|
|
|
2021-04-28 14:42:14 +00:00
|
|
|
const doneTrying = !shouldRetry || !this._canRetry();
|
|
|
|
|
2022-08-08 10:19:51 +00:00
|
|
|
this.emit('verification-failed', serviceName, !doneTrying);
|
|
|
|
try {
|
|
|
|
if (doneTrying) {
|
|
|
|
this._disconnectSignals();
|
|
|
|
await this._handlePendingMessages();
|
2013-03-18 04:59:56 +00:00
|
|
|
this._cancelAndReset();
|
2022-08-08 10:29:47 +00:00
|
|
|
} else {
|
|
|
|
await this._handlePendingMessages();
|
|
|
|
this._retry(serviceName);
|
2013-03-18 04:59:56 +00:00
|
|
|
}
|
2022-08-08 10:19:51 +00:00
|
|
|
} catch (e) {
|
|
|
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
|
|
logError(e);
|
2012-08-07 14:49:22 +00:00
|
|
|
}
|
2022-08-08 10:19:51 +00:00
|
|
|
}
|
2012-08-07 14:49:22 +00:00
|
|
|
|
2022-08-08 10:19:51 +00:00
|
|
|
_handlePendingMessages() {
|
|
|
|
if (!this.hasPendingMessage)
|
|
|
|
return Promise.resolve();
|
2021-04-28 14:42:14 +00:00
|
|
|
|
2022-08-08 10:19:51 +00:00
|
|
|
const cancellable = this._cancellable;
|
|
|
|
return new Promise((resolve, reject) => {
|
2021-04-28 14:42:14 +00:00
|
|
|
let signalId = this.connect('no-more-messages', () => {
|
|
|
|
this.disconnect(signalId);
|
2022-08-08 10:19:51 +00:00
|
|
|
if (cancellable.is_cancelled())
|
|
|
|
reject(new GLib.Error(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, 'Operation was cancelled'));
|
|
|
|
else
|
|
|
|
resolve();
|
2021-04-28 14:42:14 +00:00
|
|
|
});
|
2022-08-08 10:19:51 +00:00
|
|
|
});
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2012-08-07 14:49:22 +00:00
|
|
|
|
2021-02-15 19:59:57 +00: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);
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onConversationStopped(client, serviceName) {
|
2013-10-10 08:21:47 +00:00
|
|
|
// If the login failed with the preauthenticated oVirt credentials
|
|
|
|
// then discard the credentials and revert to default authentication
|
|
|
|
// mechanism.
|
2020-01-03 16:31:15 +00:00
|
|
|
let foregroundService = Object.keys(this._credentialManagers).find(service =>
|
|
|
|
this.serviceIsForeground(service));
|
|
|
|
if (foregroundService) {
|
|
|
|
this._credentialManagers[foregroundService].token = null;
|
2013-10-10 08:21:47 +00:00
|
|
|
this._preemptingService = null;
|
2021-02-01 18:36:49 +00:00
|
|
|
this._verificationFailed(serviceName, false);
|
2013-10-10 08:21:47 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-16 02:45:14 +00:00
|
|
|
this._filterServiceMessages(serviceName, MessageType.ERROR);
|
|
|
|
|
2021-02-15 19:59:57 +00:00
|
|
|
if (this._unavailableServices.has(serviceName))
|
|
|
|
return;
|
|
|
|
|
2012-07-17 18:54:07 +00: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 17:57:06 +00:00
|
|
|
if (this.serviceIsForeground(serviceName))
|
2021-02-08 17:43:16 +00:00
|
|
|
this._failCounter++;
|
2021-02-08 17:57:06 +00:00
|
|
|
|
|
|
|
this._verificationFailed(serviceName, true);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2023-07-10 09:53:00 +00:00
|
|
|
}
|