URL: https://github.com/freeipa/freeipa/pull/559 Author: pvomacka Title: #559: WebUI: Certificate login Action: opened
PR body: """ https://pagure.io/freeipa/issue/6225 """ To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/559/head:pr559 git checkout pr559
From 23f356c60d951457b0052349934a6d6e0958de51 Mon Sep 17 00:00:00 2001 From: Pavel Vomacka <pvoma...@redhat.com> Date: Fri, 27 Jan 2017 10:13:26 +0100 Subject: [PATCH] WebUI: Certificate login --- freeipa.spec.in | 1 + install/conf/ipa.conf | 24 +++++++- install/ui/src/freeipa/auth.js | 4 +- install/ui/src/freeipa/widgets/LoginScreen.js | 73 ++++++++++++++++++++++- install/ui/src/freeipa/widgets/LoginScreenBase.js | 5 ++ ipaclient/install/client.py | 16 +++++ ipaserver/install/httpinstance.py | 1 + 7 files changed, 119 insertions(+), 5 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index db591e0..af76a7d 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -255,6 +255,7 @@ Requires: mod_wsgi Requires: mod_auth_gssapi >= 1.5.0 Requires: mod_nss >= 1.0.8-26 Requires: mod_session +Requires: mod_lookup_identity Requires: python-ldap >= 2.4.15 Requires: python-gssapi >= 1.2.0 Requires: acl diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf index 419d4e3..1c1e874 100644 --- a/install/conf/ipa.conf +++ b/install/conf/ipa.conf @@ -4,8 +4,13 @@ # This file may be overwritten on upgrades. # -ProxyRequests Off +# Load lookup_identity module in case it has not been loaded yet +# The module is used to search users according the certificate. +<IfModule !lookup_identity_module> + LoadModule lookup_identity_module modules/mod_lookup_identity.so +</IfModule> +ProxyRequests Off #We use xhtml, a file format that the browser validates DirectoryIndex index.html @@ -97,6 +102,23 @@ Alias /ipa/session/cookie "/usr/share/ipa/gssapi.login" Allow from all </Location> +# Login with user certificate/smartcard configuration +# This configuration needs to be loaded after <Location "/ipa"> +<Location "/ipa/session/login_x509"> + AuthType none + GssapiCredStore keytab:/var/lib/ipa/gssproxy/http.keytab + GssapiCredStore client_keytab:/var/lib/ipa/gssproxy/http.keytab + GssapiDelegCcacheDir /var/run/ipa/ccaches + GssapiDelegCcachePerms mode:0660 gid:ipaapi + GssapiImpersonate On + NSSVerifyClient require + NSSOCSP on + NSSUserName SSL_CLIENT_CERT + LookupUserByCertificate On + WSGIProcessGroup ipa + WSGIApplicationGroup ipa +</Location> + <Location "/ipa/session/change_password"> Satisfy Any Order Deny,Allow diff --git a/install/ui/src/freeipa/auth.js b/install/ui/src/freeipa/auth.js index 5e160a7..992b54a 100644 --- a/install/ui/src/freeipa/auth.js +++ b/install/ui/src/freeipa/auth.js @@ -111,7 +111,7 @@ auth.Auth = declare([Stateful, Evented], { * Enabled auth methods * @property {string[]} */ - auth_methods: ['kerberos', 'password'], + auth_methods: ['kerberos', 'password', 'certificate'], /** * Authenticated user's Kerberos principal @@ -249,4 +249,4 @@ auth.Auth = declare([Stateful, Evented], { auth.current = new auth.Auth(); return auth; -}); \ No newline at end of file +}); diff --git a/install/ui/src/freeipa/widgets/LoginScreen.js b/install/ui/src/freeipa/widgets/LoginScreen.js index 0096433..b99b517 100644 --- a/install/ui/src/freeipa/widgets/LoginScreen.js +++ b/install/ui/src/freeipa/widgets/LoginScreen.js @@ -19,10 +19,12 @@ */ define(['dojo/_base/declare', + 'dojo/Deferred', 'dojo/dom-construct', 'dojo/dom-style', 'dojo/query', 'dojo/on', + 'dojo/topic', '../ipa', '../auth', '../reg', @@ -31,7 +33,7 @@ define(['dojo/_base/declare', '../util', './LoginScreenBase' ], - function(declare, construct, dom_style, query, on, + function(declare, Deferred, construct, dom_style, query, on, topic, IPA, auth, reg, FieldBinder, text, util, LoginScreenBase) { @@ -55,11 +57,15 @@ define(['dojo/_base/declare', " have valid tickets (obtainable via kinit) and " + "<a href='http://${host}/ipa/config/unauthorized.html'>configured</a>" + " the browser correctly, then click Login. ", + cert_msg: "<i class=\"fa fa-info-circle\"></i> To login with <strong>Smart Card</strong>," + + " please make sure you have valid personal certificate. ", form_auth_failed: "Login failed due to an unknown reason. ", krb_auth_failed: "Authentication with Kerberos failed", + cert_auth_failed: "Authentication with personal certificate failed", + password_expired: "Your password has expired. Please enter a new password.", password_change_complete: "Password change complete", @@ -72,9 +78,12 @@ define(['dojo/_base/declare', user_locked: "The user account you entered is locked. ", + login_url: '/ipa/session/login_x509', + //nodes: login_btn_node: null, reset_btn_node: null, + cert_btn_node: null, /** * View this form is in. @@ -86,6 +95,16 @@ define(['dojo/_base/declare', render_buttons: function(container) { + this.cert_btn_node = IPA.button({ + name: 'cert_auth', + title:"Login using personal certificate", + label: "Smart Card Login", + button_class: 'btn btn-link', + click: this.login_with_cert.bind(this) + })[0]; + construct.place(this.cert_btn_node, container); + construct.place(document.createTextNode(" "), container); + this.sync_btn_node = IPA.button({ name: 'sync', label: text.get('@i18n:login.sync_otp_token', "Sync OTP Token"), @@ -251,6 +270,18 @@ define(['dojo/_base/declare', }.bind(this)); }, + login_with_cert: function() { + + this.lookup_credentials().then(function(status) { + if (status === 200) { + this.emit('logged_in'); + } else { + var val_summary = this.get_widget('validation'); + val_summary.add_error('login', this.cert_auth_failed); + } + }.bind(this)); + }, + login_and_reset: function() { var val_summary = this.get_widget('validation'); @@ -293,6 +324,40 @@ define(['dojo/_base/declare', }, + lookup_credentials: function() { + + var status; + var d = new Deferred(); + + function error_handler(xhr, text_status, error_thrown) { + d.resolve(xhr.status); + topic.publish('rpc-end'); + } + + function success_handler(data, text_status, xhr) { + auth.current.set_authenticated(true, 'kerberos'); + d.resolve(xhr.status); + topic.publish('rpc-end'); + } + + var login = this.get_field('username').get_value()[0]; + + var request = { + url: this.login_url, + cache: false, + type: "GET", + data: $.param({ + 'username': login + }), + success: success_handler, + error: error_handler + }; + topic.publish('rpc-start'); + $.ajax(request); + + return d.promise; + }, + refresh: function() { if (this.view === 'reset') { this.show_reset_view(); @@ -307,7 +372,7 @@ define(['dojo/_base/declare', var val_summary = this.get_widget('validation'); val_summary.add_info('expired', this.expired_msg); } - this.set_visible_buttons(['sync', 'login']); + this.set_visible_buttons(['cert_auth', 'sync', 'login']); if (this.password_enabled()) { this.use_fields(['username', 'password']); var username_f = this.get_field('username'); @@ -344,6 +409,10 @@ define(['dojo/_base/declare', if (this.kerberos_enabled()) { aside += "<p>"+this.kerberos_msg+"<p/>"; } + if (this.certificate_enabled()) { + aside += "<p>"+this.cert_msg+"<p/>"; + } + this.set('aside', aside); }, diff --git a/install/ui/src/freeipa/widgets/LoginScreenBase.js b/install/ui/src/freeipa/widgets/LoginScreenBase.js index a1c986e..a8c207f 100644 --- a/install/ui/src/freeipa/widgets/LoginScreenBase.js +++ b/install/ui/src/freeipa/widgets/LoginScreenBase.js @@ -328,6 +328,11 @@ define(['dojo/_base/declare', return auth.current.auth_methods.indexOf('password') > -1; }, + certificate_enabled: function() { + return auth.current.auth_methods.indexOf('certificate') > -1; + }, + + postscript: function(args) { this.create_fields(); }, diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py index 774eaaf..11a0cc0 100644 --- a/ipaclient/install/client.py +++ b/ipaclient/install/client.py @@ -846,6 +846,22 @@ def configure_sssd_conf( sssdconfig.new_config() domain = sssdconfig.new_domain(cli_domain) + if options.on_master: + try: + sssdconfig.new_service('ifp') + except SSSDConfig.ServiceAlreadyExists: + pass + except SSSDConfig.ServiceNotRecognizedError: + root_logger.error( + "Unable to activate the IFP service in SSSD config.") + root_logger.info( + "Please make sure you have SSSD built with IFP support " + "installed.") + root_logger.info( + "Configure IFP support manually in /etc/sssd/sssd.conf.") + + sssdconfig.activate_service('ifp') + if ( (options.conf_ssh and file_exists(paths.SSH_CONFIG)) or (options.conf_sshd and file_exists(paths.SSHD_CONFIG)) diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py index 0c2216e..b1f5986 100644 --- a/ipaserver/install/httpinstance.py +++ b/ipaserver/install/httpinstance.py @@ -53,6 +53,7 @@ httpd_can_network_connect='on', httpd_manage_ipa='on', httpd_run_ipa='on', + httpd_dbus_sssd='on', ) HTTPD_USER = constants.HTTPD_USER
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code