authPrompt: support smartcard authentication
This commit detects when a user inserts a smartcard, and then initiates user verification using the gdm-smartcard PAM service. Likewise, if a user removes their smartcard, password verification (or the user list depending on auth mode and configuration) are initiated https://bugzilla.gnome.org/show_bug.cgi?id=683437
This commit is contained in:
parent
35fa42ca56
commit
059b75cdbb
@ -60,6 +60,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
|
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
|
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
|
||||||
|
this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
|
||||||
|
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||||
|
|
||||||
this.connect('next', Lang.bind(this, function() {
|
this.connect('next', Lang.bind(this, function() {
|
||||||
this.updateSensitivity(false);
|
this.updateSensitivity(false);
|
||||||
@ -221,6 +223,25 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.emit('prompted');
|
this.emit('prompted');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onSmartcardStatusChanged: function() {
|
||||||
|
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||||
|
|
||||||
|
// Most of the time we want to reset if the user inserts or removes
|
||||||
|
// a smartcard. Smartcard insertion "preempts" what the user was
|
||||||
|
// doing, and smartcard removal aborts the preemption.
|
||||||
|
// The exceptions are: 1) Don't reset on smartcard insertion if we're already verifying
|
||||||
|
// with a smartcard
|
||||||
|
// 2) Don't reset if we've already succeeded at verification and
|
||||||
|
// the user is getting logged in.
|
||||||
|
if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) &&
|
||||||
|
this.verificationStatus == AuthPromptStatus.VERIFYING &&
|
||||||
|
this.smartcardDetected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
|
||||||
_onShowMessage: function(userVerifier, message, styleClass) {
|
_onShowMessage: function(userVerifier, message, styleClass) {
|
||||||
this.setMessage(message, styleClass);
|
this.setMessage(message, styleClass);
|
||||||
this.emit('prompted');
|
this.emit('prompted');
|
||||||
@ -437,7 +458,23 @@ const AuthPrompt = new Lang.Class({
|
|||||||
if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED)
|
if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED)
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
|
|
||||||
this.emit('reset', BeginRequestType.PROVIDE_USERNAME);
|
let beginRequestType;
|
||||||
|
|
||||||
|
if (this._mode == AuthPromptMode.UNLOCK_ONLY) {
|
||||||
|
// The user is constant at the unlock screen, so it will immediately
|
||||||
|
// respond to the request with the username
|
||||||
|
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||||
|
} else if (this.smartcardDetected &&
|
||||||
|
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
||||||
|
// We don't need to know the username if the user preempted the login screen
|
||||||
|
// with a smartcard.
|
||||||
|
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
|
||||||
|
} else {
|
||||||
|
// In all other cases, we should get the username up front.
|
||||||
|
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('reset', beginRequestType);
|
||||||
},
|
},
|
||||||
|
|
||||||
addCharacter: function(unichar) {
|
addCharacter: function(unichar) {
|
||||||
|
@ -13,16 +13,19 @@ const Fprint = imports.gdm.fingerprint;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
|
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||||
const FADE_ANIMATION_TIME = 0.16;
|
const FADE_ANIMATION_TIME = 0.16;
|
||||||
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||||
const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
|
const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
|
||||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
|
const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication';
|
||||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
||||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
||||||
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
||||||
@ -122,6 +125,19 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._updateDefaultService();
|
this._updateDefaultService();
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
|
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 fingeprint readers, where we only check them
|
||||||
|
// after a user has been picked.
|
||||||
|
this._checkForSmartcard();
|
||||||
|
|
||||||
|
this._smartcardManager.connect('smartcard-inserted',
|
||||||
|
Lang.bind(this, this._checkForSmartcard));
|
||||||
|
this._smartcardManager.connect('smartcard-removed',
|
||||||
|
Lang.bind(this, this._checkForSmartcard));
|
||||||
|
|
||||||
this._messageQueue = [];
|
this._messageQueue = [];
|
||||||
this._messageQueueTimeoutId = 0;
|
this._messageQueueTimeoutId = 0;
|
||||||
this.hasPendingMessages = false;
|
this.hasPendingMessages = false;
|
||||||
@ -253,6 +269,28 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_checkForSmartcard: function() {
|
||||||
|
let smartcardDetected;
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||||
|
smartcardDetected = false;
|
||||||
|
else if (this.reauthenticating)
|
||||||
|
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');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_reportInitError: function(where, error) {
|
_reportInitError: function(where, error) {
|
||||||
logError(error, where);
|
logError(error, where);
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
@ -310,7 +348,9 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_getForegroundService: function() {
|
_getForegroundService: function() {
|
||||||
// For now, the foreground service is always the default service
|
if (this._preemptingService)
|
||||||
|
return this._preemptingService;
|
||||||
|
|
||||||
return this._defaultService;
|
return this._defaultService;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -318,9 +358,15 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
return serviceName == this._getForegroundService();
|
return serviceName == this._getForegroundService();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
serviceIsDefault: function(serviceName) {
|
||||||
|
return serviceName == this._defaultService;
|
||||||
|
},
|
||||||
|
|
||||||
_updateDefaultService: function() {
|
_updateDefaultService: function() {
|
||||||
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||||
this._defaultService = PASSWORD_SERVICE_NAME;
|
this._defaultService = PASSWORD_SERVICE_NAME;
|
||||||
|
else if (this.smartcardDetected)
|
||||||
|
this._defaultService = SMARTCARD_SERVICE_NAME;
|
||||||
else if (this._haveFingerprintReader)
|
else if (this._haveFingerprintReader)
|
||||||
this._defaultService = FINGERPRINT_SERVICE_NAME;
|
this._defaultService = FINGERPRINT_SERVICE_NAME;
|
||||||
},
|
},
|
||||||
|
@ -25,6 +25,7 @@ const Main = imports.ui.main;
|
|||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
@ -546,6 +547,13 @@ const ScreenShield = new Lang.Class({
|
|||||||
|
|
||||||
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
||||||
|
|
||||||
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||||
|
this._smartcardManager.connect('smartcard-inserted',
|
||||||
|
Lang.bind(this, function(token) {
|
||||||
|
if (this._isLocked && token.UsedToLogin)
|
||||||
|
this._liftShield(true, 0);
|
||||||
|
}));
|
||||||
|
|
||||||
this._inhibitor = null;
|
this._inhibitor = null;
|
||||||
this._aboutToSuspend = false;
|
this._aboutToSuspend = false;
|
||||||
this._loginManager = LoginManager.getLoginManager();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
|
Loading…
Reference in New Issue
Block a user