|
|
b97e22 |
From 70c1cc7ed45ff4f6fa3cf0601c98ca40a168ac57 Mon Sep 17 00:00:00 2001
|
|
|
b97e22 |
From: Vinzenz Feenstra <evilissimo@redhat.com>
|
|
|
b97e22 |
Date: Thu, 10 Oct 2013 10:21:47 +0200
|
|
|
b97e22 |
Subject: [PATCH] gdm: support pre-authenticated logins from oVirt
|
|
|
b97e22 |
|
|
|
b97e22 |
oVirt is software for managing medium-to-large scale deployments of
|
|
|
b97e22 |
virtual machine guests across multiple hosts. It supports a feature
|
|
|
b97e22 |
where users can authenticate with a central server and get
|
|
|
b97e22 |
transparently connected to a guest system and then automatically get logged
|
|
|
b97e22 |
into that guest to an associated user session.
|
|
|
b97e22 |
|
|
|
b97e22 |
Guests using old versions of GDM support this single-sign-on capability
|
|
|
b97e22 |
by means of a greeter plugin, using the old greeter's extension
|
|
|
b97e22 |
API.
|
|
|
b97e22 |
|
|
|
b97e22 |
This commit adds similar support to the gnome-shell based login screen.
|
|
|
b97e22 |
|
|
|
b97e22 |
How it works:
|
|
|
b97e22 |
|
|
|
b97e22 |
* The OVirtCredentialsManager singleton listens for
|
|
|
b97e22 |
|
|
|
b97e22 |
'org.ovirt.vdsm.Credentials.UserAuthenticated'
|
|
|
b97e22 |
|
|
|
b97e22 |
D-Bus signal on the system bus from the
|
|
|
b97e22 |
|
|
|
b97e22 |
'org.ovirt.vdsm.Credentials'
|
|
|
b97e22 |
|
|
|
b97e22 |
bus name. The service that provides that bus name is called
|
|
|
b97e22 |
the oVirt guest agent. It is also responsible for interacting
|
|
|
b97e22 |
with the the central server to get user credentials.
|
|
|
b97e22 |
|
|
|
b97e22 |
* This UserAuthenticated signal passes, as a parameter, the a token
|
|
|
b97e22 |
which needs to be passed through to the PAM service that is specifically
|
|
|
b97e22 |
set up to integrate with the oVirt authentication architecture.
|
|
|
b97e22 |
The singleton object keeps the token internally so it can be queried
|
|
|
b97e22 |
later on.
|
|
|
b97e22 |
|
|
|
b97e22 |
* The OVirtCredentialsManager emits a signal 'user-authenticated' on
|
|
|
b97e22 |
it's object once the dbus signal is triggered
|
|
|
b97e22 |
|
|
|
b97e22 |
* When the 'user-authenticated' signal is emitted, the login screen
|
|
|
b97e22 |
tells GDM to start user verification using the PAM service. The
|
|
|
b97e22 |
authentication stack of the service includes a PAM module
|
|
|
b97e22 |
provided by oVirt that securely retrieves user credentials
|
|
|
b97e22 |
from the oVirt guest agent. The PAM module then forwards those
|
|
|
b97e22 |
credentials on to other modules in the stack so, e.g.,
|
|
|
b97e22 |
the user's gnome keyring can be automatically unlocked.
|
|
|
b97e22 |
|
|
|
b97e22 |
* In case of the screen shield being visible, it also will react on that
|
|
|
b97e22 |
'user-authenticated' signal and lift the shield.
|
|
|
b97e22 |
In that case the login screen will check on construction time if
|
|
|
b97e22 |
the signal has already been triggered, and a token is available.
|
|
|
b97e22 |
If a token is available it will immediately trigger the functionality
|
|
|
b97e22 |
as described above.
|
|
|
b97e22 |
|
|
|
b97e22 |
Upstream-Bug-Url: https://bugzilla.gnome.org/show_bug.cgi?id=702162
|
|
|
b97e22 |
Signed-off-by: Vinzenz Feenstra <evilissimo@redhat.com>
|
|
|
b97e22 |
Bug-Url: https://bugzilla.redhat.com/854712
|
|
|
b97e22 |
---
|
|
|
b97e22 |
js/Makefile.am | 1 +
|
|
|
b97e22 |
js/gdm/authPrompt.js | 13 ++++++++---
|
|
|
b97e22 |
js/gdm/oVirt.js | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
b97e22 |
js/gdm/util.js | 31 ++++++++++++++++++++++++++
|
|
|
b97e22 |
js/ui/screenShield.js | 8 +++++++
|
|
|
b97e22 |
5 files changed, 112 insertions(+), 3 deletions(-)
|
|
|
b97e22 |
create mode 100644 js/gdm/oVirt.js
|
|
|
b97e22 |
|
|
|
b97e22 |
diff --git a/js/Makefile.am b/js/Makefile.am
|
|
|
b97e22 |
index 425b6fb..bfcc714 100644
|
|
|
b97e22 |
--- a/js/Makefile.am
|
|
|
b97e22 |
+++ b/js/Makefile.am
|
|
|
b97e22 |
@@ -21,6 +21,7 @@ nobase_dist_js_DATA = \
|
|
|
b97e22 |
gdm/batch.js \
|
|
|
b97e22 |
gdm/fingerprint.js \
|
|
|
b97e22 |
gdm/loginDialog.js \
|
|
|
b97e22 |
+ gdm/oVirt.js \
|
|
|
b97e22 |
gdm/powerMenu.js \
|
|
|
b97e22 |
gdm/realmd.js \
|
|
|
b97e22 |
gdm/util.js \
|
|
|
b97e22 |
diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
|
|
|
b97e22 |
index 2121f2e..ba66c42 100644
|
|
|
b97e22 |
--- a/js/gdm/authPrompt.js
|
|
|
b97e22 |
+++ b/js/gdm/authPrompt.js
|
|
|
b97e22 |
@@ -59,6 +59,7 @@ const AuthPrompt = new Lang.Class({
|
|
|
b97e22 |
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
|
|
b97e22 |
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
|
|
b97e22 |
this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
|
|
|
b97e22 |
+ this._userVerifier.connect('ovirt-user-authenticated', Lang.bind(this, this._onOVirtUserAuthenticated));
|
|
|
b97e22 |
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
|
|
b97e22 |
|
|
|
b97e22 |
this.connect('next', Lang.bind(this, function() {
|
|
|
b97e22 |
@@ -219,6 +220,11 @@ const AuthPrompt = new Lang.Class({
|
|
|
b97e22 |
this.emit('prompted');
|
|
|
b97e22 |
},
|
|
|
b97e22 |
|
|
|
b97e22 |
+ _onOVirtUserAuthenticated: function() {
|
|
|
b97e22 |
+ if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
|
|
b97e22 |
+ this.reset();
|
|
|
b97e22 |
+ },
|
|
|
b97e22 |
+
|
|
|
b97e22 |
_onSmartcardStatusChanged: function() {
|
|
|
b97e22 |
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
|
|
b97e22 |
|
|
|
4c1248 |
@@ -443,9 +449,10 @@ const AuthPrompt = new Lang.Class({
|
|
|
b97e22 |
// The user is constant at the unlock screen, so it will immediately
|
|
|
b97e22 |
// respond to the request with the username
|
|
|
b97e22 |
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
|
|
4c1248 |
- } else if (this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
|
|
b97e22 |
+ } else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) ||
|
|
|
4c1248 |
+ this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
|
|
b97e22 |
// We don't need to know the username if the user preempted the login screen
|
|
|
b97e22 |
- // with a smartcard.
|
|
|
b97e22 |
+ // with a smartcard or with preauthenticated oVirt credentials
|
|
|
b97e22 |
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
|
|
|
b97e22 |
} else {
|
|
|
b97e22 |
// In all other cases, we should get the username up front.
|
|
|
b97e22 |
diff --git a/js/gdm/oVirt.js b/js/gdm/oVirt.js
|
|
|
b97e22 |
new file mode 100644
|
|
|
b97e22 |
index 0000000..1a31f43
|
|
|
b97e22 |
--- /dev/null
|
|
|
b97e22 |
+++ b/js/gdm/oVirt.js
|
|
|
b97e22 |
@@ -0,0 +1,62 @@
|
|
|
b97e22 |
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+const Gio = imports.gi.Gio;
|
|
|
b97e22 |
+const Lang = imports.lang;
|
|
|
b97e22 |
+const Signals = imports.signals;
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+const OVirtCredentialsIface = <interface name='org.ovirt.vdsm.Credentials'>
|
|
|
b97e22 |
+<signal name="UserAuthenticated">
|
|
|
b97e22 |
+ <arg type="s" name="token"/>
|
|
|
b97e22 |
+</signal>
|
|
|
b97e22 |
+</interface>;
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+const OVirtCredentialsInfo = Gio.DBusInterfaceInfo.new_for_xml(OVirtCredentialsIface);
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+let _oVirtCredentialsManager = null;
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+function OVirtCredentials() {
|
|
|
b97e22 |
+ var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
|
|
|
b97e22 |
+ g_interface_name: OVirtCredentialsInfo.name,
|
|
|
b97e22 |
+ g_interface_info: OVirtCredentialsInfo,
|
|
|
b97e22 |
+ g_name: 'org.ovirt.vdsm.Credentials',
|
|
|
b97e22 |
+ g_object_path: '/org/ovirt/vdsm/Credentials',
|
|
|
b97e22 |
+ g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
|
|
b97e22 |
+ self.init(null);
|
|
|
b97e22 |
+ return self;
|
|
|
b97e22 |
+}
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+const OVirtCredentialsManager = new Lang.Class({
|
|
|
b97e22 |
+ Name: 'OVirtCredentialsManager',
|
|
|
b97e22 |
+ _init: function() {
|
|
|
b97e22 |
+ this._token = null;
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ this._credentials = new OVirtCredentials();
|
|
|
b97e22 |
+ this._credentials.connectSignal('UserAuthenticated',
|
|
|
b97e22 |
+ Lang.bind(this, this._onUserAuthenticated));
|
|
|
b97e22 |
+ },
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ _onUserAuthenticated: function(proxy, sender, [token]) {
|
|
|
b97e22 |
+ this._token = token;
|
|
|
b97e22 |
+ this.emit('user-authenticated', token);
|
|
|
b97e22 |
+ },
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ hasToken: function() {
|
|
|
b97e22 |
+ return this._token != null;
|
|
|
b97e22 |
+ },
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ getToken: function() {
|
|
|
b97e22 |
+ return this._token;
|
|
|
b97e22 |
+ },
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ resetToken: function() {
|
|
|
b97e22 |
+ this._token = null;
|
|
|
b97e22 |
+ }
|
|
|
b97e22 |
+});
|
|
|
b97e22 |
+Signals.addSignalMethods(OVirtCredentialsManager.prototype);
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+function getOVirtCredentialsManager() {
|
|
|
b97e22 |
+ if (!_oVirtCredentialsManager)
|
|
|
b97e22 |
+ _oVirtCredentialsManager = new OVirtCredentialsManager();
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ return _oVirtCredentialsManager;
|
|
|
b97e22 |
+}
|
|
|
b97e22 |
diff --git a/js/gdm/util.js b/js/gdm/util.js
|
|
|
b97e22 |
index f421902..66852fd 100644
|
|
|
b97e22 |
--- a/js/gdm/util.js
|
|
|
b97e22 |
+++ b/js/gdm/util.js
|
|
|
b97e22 |
@@ -10,6 +10,7 @@ const St = imports.gi.St;
|
|
|
b97e22 |
|
|
|
b97e22 |
const Batch = imports.gdm.batch;
|
|
|
b97e22 |
const Fprint = imports.gdm.fingerprint;
|
|
|
b97e22 |
+const OVirt = imports.gdm.oVirt;
|
|
|
b97e22 |
const Main = imports.ui.main;
|
|
|
b97e22 |
const Params = imports.misc.params;
|
|
|
b97e22 |
const ShellEntry = imports.ui.shellEntry;
|
|
|
b97e22 |
@@ -19,6 +20,7 @@ const Tweener = imports.ui.tweener;
|
|
|
b97e22 |
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
|
|
b97e22 |
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
|
|
b97e22 |
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
|
|
b97e22 |
+const OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
|
|
|
b97e22 |
const FADE_ANIMATION_TIME = 0.16;
|
|
|
b97e22 |
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
|
|
b97e22 |
|
|
|
b97e22 |
@@ -151,6 +153,14 @@ const ShellUserVerifier = new Lang.Class({
|
|
|
b97e22 |
this.reauthenticating = false;
|
|
|
b97e22 |
|
|
|
b97e22 |
this._failCounter = 0;
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ if (this._oVirtCredentialsManager.hasToken())
|
|
|
b97e22 |
+ this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
|
|
|
b97e22 |
+
|
|
|
b97e22 |
+ this._oVirtCredentialsManager.connect('user-authenticated',
|
|
|
b97e22 |
+ Lang.bind(this, this._oVirtUserAuthenticated));
|
|
|
b97e22 |
},
|
|
|
b97e22 |
|
|
|
b97e22 |
begin: function(userName, hold) {
|
|
|
b97e22 |
@@ -277,6 +287,11 @@ const ShellUserVerifier = new Lang.Class({
|
|
|
b97e22 |
}));
|
|
|
b97e22 |
},
|
|
|
b97e22 |
|
|
|
b97e22 |
+ _oVirtUserAuthenticated: function(token) {
|
|
|
b97e22 |
+ this._preemptingService = OVIRT_SERVICE_NAME;
|
|
|
b97e22 |
+ this.emit('ovirt-user-authenticated');
|
|
|
b97e22 |
+ },
|
|
|
b97e22 |
+
|
|
|
b97e22 |
_checkForSmartcard: function() {
|
|
|
b97e22 |
let smartcardDetected;
|
|
|
b97e22 |
|
|
|
b97e22 |
@@ -455,6 +470,12 @@ const ShellUserVerifier = new Lang.Class({
|
|
|
b97e22 |
if (!this.serviceIsForeground(serviceName))
|
|
|
b97e22 |
return;
|
|
|
b97e22 |
|
|
|
b97e22 |
+ if (serviceName == OVIRT_SERVICE_NAME) {
|
|
|
b97e22 |
+ // The only question asked by this service is "Token?"
|
|
|
b97e22 |
+ this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken());
|
|
|
b97e22 |
+ return;
|
|
|
b97e22 |
+ }
|
|
|
b97e22 |
+
|
|
|
b97e22 |
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
|
|
b97e22 |
},
|
|
|
b97e22 |
|
|
|
b97e22 |
@@ -515,6 +536,16 @@ const ShellUserVerifier = new Lang.Class({
|
|
|
b97e22 |
},
|
|
|
b97e22 |
|
|
|
b97e22 |
_onConversationStopped: function(client, serviceName) {
|
|
|
b97e22 |
+ // If the login failed with the preauthenticated oVirt credentials
|
|
|
b97e22 |
+ // then discard the credentials and revert to default authentication
|
|
|
b97e22 |
+ // mechanism.
|
|
|
b97e22 |
+ if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) {
|
|
|
b97e22 |
+ this._oVirtCredentialsManager.resetToken();
|
|
|
b97e22 |
+ this._preemptingService = null;
|
|
|
b97e22 |
+ this._verificationFailed(false);
|
|
|
b97e22 |
+ return;
|
|
|
b97e22 |
+ }
|
|
|
b97e22 |
+
|
|
|
b97e22 |
// if the password service fails, then cancel everything.
|
|
|
b97e22 |
// But if, e.g., fingerprint fails, still give
|
|
|
b97e22 |
// password authentication a chance to succeed
|
|
|
b97e22 |
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
|
|
|
b97e22 |
index 1d296a2..ecc0bfa 100644
|
|
|
b97e22 |
--- a/js/ui/screenShield.js
|
|
|
b97e22 |
+++ b/js/ui/screenShield.js
|
|
|
b97e22 |
@@ -17,6 +17,7 @@ const Background = imports.ui.background;
|
|
|
b97e22 |
const GnomeSession = imports.misc.gnomeSession;
|
|
|
b97e22 |
const Hash = imports.misc.hash;
|
|
|
b97e22 |
const Layout = imports.ui.layout;
|
|
|
b97e22 |
+const OVirt = imports.gdm.oVirt;
|
|
|
b97e22 |
const LoginManager = imports.misc.loginManager;
|
|
|
b97e22 |
const Lightbox = imports.ui.lightbox;
|
|
|
b97e22 |
const Main = imports.ui.main;
|
|
|
b97e22 |
@@ -514,6 +515,13 @@ const ScreenShield = new Lang.Class({
|
|
|
b97e22 |
this._liftShield(true, 0);
|
|
|
b97e22 |
}));
|
|
|
b97e22 |
|
|
|
b97e22 |
+ this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
|
|
|
b97e22 |
+ this._oVirtCredentialsManager.connect('user-authenticated',
|
|
|
b97e22 |
+ Lang.bind(this, function() {
|
|
|
b97e22 |
+ if (this._isLocked)
|
|
|
b97e22 |
+ this._liftShield(true, 0);
|
|
|
b97e22 |
+ }));
|
|
|
b97e22 |
+
|
|
|
b97e22 |
this._inhibitor = null;
|
|
|
b97e22 |
this._aboutToSuspend = false;
|
|
|
b97e22 |
this._loginManager = LoginManager.getLoginManager();
|
|
|
b97e22 |
--
|
|
|
b97e22 |
1.8.3.1
|
|
|
b97e22 |
|