gdm: Refactor oVirt to a generic CredentialManager interface

Commit 4cda61a1 added support for pre-authenticated logins in
    oVirt environments. This feature prevents a user from having
    to type their password twice (once to the oVirt management machine,
    and then immediately again in the provisioned guest running gnome-shell).
    That feature is currently oVirt specific, but a similar feature would
    be useful in non-oVirt based virt farm environments.

    Toward that end, this commit generalizes the various aspects of the
    oVirt integration code, so that it can be reused in a subsequent
    commit for adding single sign on support in vmware deployments, too.

    Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1983
This commit is contained in:
yun341 2020-01-04 00:31:15 +08:00
parent 75235624b2
commit 809f820cd4
5 changed files with 64 additions and 39 deletions

View File

@ -71,7 +71,7 @@ var AuthPrompt = GObject.registerClass({
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)); this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
this._userVerifier.connect('reset', this._onReset.bind(this)); this._userVerifier.connect('reset', this._onReset.bind(this));
this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this)); this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this));
this._userVerifier.connect('ovirt-user-authenticated', this._onOVirtUserAuthenticated.bind(this)); this._userVerifier.connect('credential-manager-authenticated', this._onCredentialManagerAuthenticated.bind(this));
this.smartcardDetected = this._userVerifier.smartcardDetected; this.smartcardDetected = this._userVerifier.smartcardDetected;
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
@ -242,7 +242,7 @@ var AuthPrompt = GObject.registerClass({
this.emit('prompted'); this.emit('prompted');
} }
_onOVirtUserAuthenticated() { _onCredentialManagerAuthenticated() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset(); this.reset();
} }

View File

@ -0,0 +1,24 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported CredentialManager */
class CredentialManager {
constructor(service) {
this._token = null;
this._service = service;
this._authenticatedSignalId = null;
}
get token() {
return this._token;
}
set token(t) {
this._token = t;
if (this._token)
this.emit('user-authenticated', this._token);
}
get service() {
return this._service;
}
}

View File

@ -3,6 +3,9 @@
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Signals = imports.signals; const Signals = imports.signals;
const Credential = imports.gdm.credentialManager;
var SERVICE_NAME = 'gdm-ovirtcred';
const OVirtCredentialsIface = ` const OVirtCredentialsIface = `
<node> <node>
@ -28,30 +31,14 @@ function OVirtCredentials() {
return self; return self;
} }
var OVirtCredentialsManager = class { var OVirtCredentialsManager = class OVirtCredentialsManager extends Credential.CredentialManager {
constructor() { constructor() {
this._token = null; super(SERVICE_NAME);
this._credentials = new OVirtCredentials(); this._credentials = new OVirtCredentials();
this._credentials.connectSignal('UserAuthenticated', this._credentials.connectSignal('UserAuthenticated',
this._onUserAuthenticated.bind(this)); (proxy, sender, [token]) => {
} this.token = token;
});
_onUserAuthenticated(proxy, sender, [token]) {
this._token = token;
this.emit('user-authenticated', token);
}
hasToken() {
return this._token != null;
}
getToken() {
return this._token;
}
resetToken() {
this._token = null;
} }
}; };
Signals.addSignalMethods(OVirtCredentialsManager.prototype); Signals.addSignalMethods(OVirtCredentialsManager.prototype);

View File

@ -24,7 +24,6 @@ Gio._promisify(Gdm.UserVerifierProxy.prototype,
var PASSWORD_SERVICE_NAME = 'gdm-password'; var PASSWORD_SERVICE_NAME = 'gdm-password';
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
var OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
var FADE_ANIMATION_TIME = 160; var FADE_ANIMATION_TIME = 160;
var CLONE_FADE_ANIMATION_TIME = 250; var CLONE_FADE_ANIMATION_TIME = 250;
@ -160,13 +159,19 @@ var ShellUserVerifier = class {
this._failCounter = 0; this._failCounter = 0;
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager(); this._credentialManagers = {};
this._credentialManagers[OVirt.SERVICE_NAME] = OVirt.getOVirtCredentialsManager();
if (this._oVirtCredentialsManager.hasToken()) for (let service in this._credentialManagers) {
this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken()); if (this._credentialManagers[service].token) {
this._onCredentialManagerAuthenticated(this._credentialManagers[service],
this._credentialManagers[service].token);
}
this._oVirtUserAuthenticatedId = this._oVirtCredentialsManager.connect('user-authenticated', this._credentialManagers[service]._authenticatedSignalId =
this._oVirtUserAuthenticated.bind(this)); this._credentialManagers[service].connect('user-authenticated',
this._onCredentialManagerAuthenticated.bind(this));
}
} }
begin(userName, hold) { begin(userName, hold) {
@ -222,8 +227,11 @@ var ShellUserVerifier = class {
this._smartcardManager.disconnect(this._smartcardRemovedId); this._smartcardManager.disconnect(this._smartcardRemovedId);
this._smartcardManager = null; this._smartcardManager = null;
this._oVirtCredentialsManager.disconnect(this._oVirtUserAuthenticatedId); for (let service in this._credentialManagers) {
this._oVirtCredentialsManager = null; let credentialManager = this._credentialManagers[service];
credentialManager.disconnect(credentialManager._authenticatedSignalId);
credentialManager = null;
}
} }
answerQuery(serviceName, answer) { answerQuery(serviceName, answer) {
@ -311,9 +319,9 @@ var ShellUserVerifier = class {
}); });
} }
_oVirtUserAuthenticated(_token) { _onCredentialManagerAuthenticated(credentialManager, _token) {
this._preemptingService = OVIRT_SERVICE_NAME; this._preemptingService = credentialManager.service;
this.emit('ovirt-user-authenticated'); this.emit('credential-manager-authenticated');
} }
_checkForSmartcard() { _checkForSmartcard() {
@ -490,9 +498,12 @@ var ShellUserVerifier = class {
if (!this.serviceIsForeground(serviceName)) if (!this.serviceIsForeground(serviceName))
return; return;
if (serviceName == OVIRT_SERVICE_NAME) { let token = null;
// The only question asked by this service is "Token?" if (this._credentialManagers[serviceName])
this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken()); token = this._credentialManagers[serviceName].token;
if (token) {
this.answerQuery(serviceName, token);
return; return;
} }
@ -560,8 +571,10 @@ var ShellUserVerifier = class {
// If the login failed with the preauthenticated oVirt credentials // If the login failed with the preauthenticated oVirt credentials
// then discard the credentials and revert to default authentication // then discard the credentials and revert to default authentication
// mechanism. // mechanism.
if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) { let foregroundService = Object.keys(this._credentialManagers).find(service =>
this._oVirtCredentialsManager.resetToken(); this.serviceIsForeground(service));
if (foregroundService) {
this._credentialManagers[foregroundService].token = null;
this._preemptingService = null; this._preemptingService = null;
this._verificationFailed(false); this._verificationFailed(false);
return; return;

View File

@ -6,6 +6,7 @@
<file>gdm/fingerprint.js</file> <file>gdm/fingerprint.js</file>
<file>gdm/loginDialog.js</file> <file>gdm/loginDialog.js</file>
<file>gdm/oVirt.js</file> <file>gdm/oVirt.js</file>
<file>gdm/credentialManager.js</file>
<file>gdm/realmd.js</file> <file>gdm/realmd.js</file>
<file>gdm/util.js</file> <file>gdm/util.js</file>