Hi,

I have extended my previous patch for authentication with user
certificate/smartcard. This patch includes patches and plugin described
here: http://www.freeipa.org/page/V4/External_Authentication/Setup
Page also contains steps to configure and test this feature. Once this
patch is merged and released we will simplify this page to not confuse
customers.
Addressing ticket: https://fedorahosted.org/freeipa/ticket/5764

Thanks.

-- 
Tibor Dudlák
Intern - Identity management Special Projects
Red Hat
From e22843f6ab1556528b307951fbcc2476a61a417f Mon Sep 17 00:00:00 2001
From: Tiboris <tibor.dud...@gmail.com>
Date: Fri, 5 Aug 2016 11:47:06 +0200
Subject: [PATCH] Added support for authentication with user certificate

https://fedorahosted.org/freeipa/ticket/5764
---
 freeipa.spec.in                             |   5 +
 install/conf/ipa.conf                       |  14 +++
 install/ui/src/freeipa/plugins/cert_auth.js | 179 ++++++++++++++++++++++++++++
 ipaserver/plugins/xmlserver.py              |   3 +-
 ipaserver/rpcserver.py                      |   5 +
 5 files changed, 205 insertions(+), 1 deletion(-)
 create mode 100644 install/ui/src/freeipa/plugins/cert_auth.js

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 135e9c980011c6c2730c6c29a3c22098e48270d5..2b95b83613ca3720c95f255f7f64dc029195452c 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -817,6 +817,8 @@ install daemons/dnssec/ipa-ods-exporter %{buildroot}%{_libexecdir}/ipa/ipa-ods-e
 
 # Web UI plugin dir
 mkdir -p %{buildroot}%{_usr}/share/ipa/ui/js/plugins
+mkdir -p %{buildroot}%{_usr}/share/ipa/ui/js/plugins-dist/cert_auth
+install install/ui/src/freeipa/plugins/cert_auth.js %{buildroot}%{_usr}/share/ipa/ui/js/plugins-dist/cert_auth/cert_auth.js
 
 # DNSSEC config
 mkdir -p %{buildroot}%{_sysconfdir}/ipa/dnssec
@@ -1210,6 +1212,9 @@ fi
 %{_usr}/share/ipa/ui/js/freeipa/app.js
 %{_usr}/share/ipa/ui/js/freeipa/core.js
 %dir %{_usr}/share/ipa/ui/js/plugins
+%dir %{_usr}/share/ipa/ui/js/plugins-dist
+%dir %{_usr}/share/ipa/ui/js/plugins-dist/cert_auth
+%{_usr}/share/ipa/ui/js/plugins-dist/cert_auth/cert_auth.js
 %dir %{_usr}/share/ipa/ui/images
 %{_usr}/share/ipa/ui/images/*.jpg
 %{_usr}/share/ipa/ui/images/*.png
diff --git a/install/conf/ipa.conf b/install/conf/ipa.conf
index 3e7435903b2ad8c4ae5bfc48c0c9fca733757d5d..c37819ff2bd2c045404a383631435ad6c24fdaa3 100644
--- a/install/conf/ipa.conf
+++ b/install/conf/ipa.conf
@@ -77,6 +77,20 @@ WSGIScriptReloading Off
   Header always append Content-Security-Policy "frame-ancestors 'none'"
 </Location>
 
+# Login with user certificate/smartcard configuration
+<Location "/ipa/session/login_x509">
+  AuthType none
+  GssapiCredStore keytab:/etc/httpd/conf/ipa.keytab
+  GssapiCredStore client_keytab:/etc/httpd/conf/ipa.keytab
+  GssapiDelegCcacheDir /var/run/httpd/ipa/clientcaches
+  GssapiImpersonate On
+  NSSVerifyClient require
+  NSSUserName SSL_CLIENT_CERT
+  LookupUserByCertificate On
+  WSGIProcessGroup ipa
+  WSGIApplicationGroup ipa
+</Location>
+
 # Turn off Apache authentication for sessions
 <Location "/ipa/session/json">
   Satisfy Any
diff --git a/install/ui/src/freeipa/plugins/cert_auth.js b/install/ui/src/freeipa/plugins/cert_auth.js
new file mode 100644
index 0000000000000000000000000000000000000000..282883d6fe82258405afb167dd61b5d6b0f1a7bd
--- /dev/null
+++ b/install/ui/src/freeipa/plugins/cert_auth.js
@@ -0,0 +1,179 @@
+/*  Authors:
+ *    Petr Vobornik <pvobo...@redhat.com>
+ *    Tibor Dudlák <tdud...@redhat.com>
+ *
+ * Copyright (C) 2016 Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+/*
+    Plugin to add a button with aside text to FreeiPA login screen
+
+    Tested against FreeIPA 4.4
+
+    Limitation: only one such plugin can be installed - one can override
+    functionality of the other
+ */
+
+// we can also depend on other plugin
+define([
+        'dojo/Deferred',
+        'dojo/dom-construct',
+        'dojo/_base/declare',
+        'freeipa/jquery',
+        'freeipa/_base/Spec_mod',
+        'freeipa/ipa',
+        'freeipa/auth',
+        'freeipa/phases',
+        'freeipa/reg',
+        'freeipa/plugins/login',
+        'freeipa/widgets/LoginScreen',
+        ],
+            function(Deferred, construct, declare, $, SpecMod, IPA, auth, phases,
+                      reg, mod_login, LoginScreen) {
+
+
+var exp = {}; // module object (export)
+
+exp.CustomLoginScreen = declare([LoginScreen], {
+
+    crtauth_btn_node: null,
+
+    auth_failed: "Authentication with personal certificate failed",
+
+    msg: "<p><i class=\"fa fa-info-circle\"></i> To login with <strong>Smart Card</strong>," +
+          "please make sure you have valid personal certificate. </p>",
+
+    login_url: '/ipa/session/login_x509',
+
+    render_buttons: function(container) {
+        // add button node to DOM
+        this.crtauth_btn_node = IPA.button({
+            name: 'crtauth',
+            title:"Login using personal certificate",
+            label: "Smart Card Login",
+            button_class: 'btn btn-link',
+            click: this.crt_login.bind(this)
+        })[0];
+
+        // similar to jquery.append(node, container)
+        construct.place(this.crtauth_btn_node, container);
+        construct.place(document.createTextNode(" "), container);
+
+        // call base class method to create other buttons
+        this.inherited(arguments);
+    },
+
+    crt_login: function() {
+        // add custom auth login here
+        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.auth_failed);
+            }
+        }.bind(this));
+    },
+
+    lookup_credentials: function() {
+        var status;
+        var d = new Deferred();
+
+        function error_handler(xhr, text_status, error_thrown) {
+            d.resolve(xhr.status);
+            IPA.hide_activity_icon();
+        }
+
+        function success_handler(data, text_status, xhr) {
+            auth.current.set_authenticated(true, 'kerberos');
+            d.resolve(xhr.status);
+            IPA.hide_activity_icon();
+        }
+
+        var request = {
+            url: this.login_url,
+            cache: false,
+            type: "GET",
+            success: success_handler,
+            error: error_handler
+        };
+        IPA.display_activity_icon();
+        $.ajax(request);
+
+        return d.promise;
+    },
+
+    show_login_view: function() {
+
+        this.inherited(arguments);
+        // make sure that crtauth button is also shown when switching from sync form
+        // a bit of hack because, we need to use the exact buttons which were defined
+        // in original LoginScreen -> does't scale if some button is added in later
+        // versions
+        this.set_visible_buttons(['crtauth', 'sync', 'login']);
+    },
+
+    set_login_aside_text: function() {
+        // allow to set aside text (the text on right side with help text)
+
+        // generate original
+        this.inherited(arguments);
+
+        // add own
+        var aside = this.aside;
+        aside += this.msg;
+        this.set('aside', aside);
+
+        //alternative solution:
+        // $(this.aside_node).append($("<p/>", { text: "My text"}));
+    }
+});
+
+
+exp.replace_login_screen_spec = function(entity) {
+
+    var mod = new SpecMod();
+
+    var diff = {
+        $replace: [
+            [
+                'widgets',
+                [[{ name: 'login_screen'},
+                {
+                    $type: 'custom_login_screen',
+                    name: 'login_screen'
+                }]]
+            ]
+        ]
+    };
+    mod.mod(mod_login.facet_spec, diff);
+};
+
+exp.override = function() {
+
+    exp.replace_login_screen_spec();
+};
+
+exp.register = function() {
+    var w = reg.widget;
+    w.register('custom_login_screen', exp.CustomLoginScreen );
+};
+
+phases.on('registration', exp.register);
+phases.on('customization', exp.override);
+
+return exp;
+});
diff --git a/ipaserver/plugins/xmlserver.py b/ipaserver/plugins/xmlserver.py
index d8fe24e0cb407603e9898e934229c9373f3c8b62..1843c0568543951f2c817616d9e988deaab47056 100644
--- a/ipaserver/plugins/xmlserver.py
+++ b/ipaserver/plugins/xmlserver.py
@@ -28,12 +28,13 @@ register = Registry()
 
 
 if api.env.context in ('server', 'lite'):
-    from ipaserver.rpcserver import wsgi_dispatch, xmlserver, jsonserver_kerb, jsonserver_session, login_kerberos, login_password, change_password, sync_token, xmlserver_session
+    from ipaserver.rpcserver import wsgi_dispatch, xmlserver, jsonserver_kerb, jsonserver_session, login_kerberos, login_x509, login_password, change_password, sync_token, xmlserver_session
     register()(wsgi_dispatch)
     register()(xmlserver)
     register()(jsonserver_kerb)
     register()(jsonserver_session)
     register()(login_kerberos)
+    register()(login_x509)
     register()(login_password)
     register()(change_password)
     register()(sync_token)
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index d036f3c27521f17709672b830d5aa58167c76b34..a181ecfcb1d01b1c2dd5ee6cb9721d69be8c1863 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -876,6 +876,11 @@ class login_kerberos(Backend, KerberosSession, HTTP_Status):
 
         return self.finalize_kerberos_acquisition('login_kerberos', user_ccache_name, environ, start_response)
 
+
+class login_x509(login_kerberos, KerberosSession, HTTP_Status):
+    key = '/session/login_x509'
+
+
 class login_password(Backend, KerberosSession, HTTP_Status):
 
     content_type = 'text/plain'
-- 
2.7.4

-- 
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