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

Reply via email to