Hi,

I have improved my previous patch for authentication with user
certificate/smartcard.
This patch includes patches and plugin and apache configuration described
here: http://www.freeipa.org/page/V4/External_Authentication/Setup
It also contains steps to configure and test this feature. Once this patch
is merged and released I will simplify this page to not confuse customers.

On Fri, Aug 5, 2016 at 3:58 PM, Petr Vobornik <pvobo...@redhat.com> wrote:

> On 08/05/2016 02:57 PM, Tibor Dudlak wrote:
> >...
>
> Let's assume that we will go with this approach and not separate RPM.
>
> 1. ipa.conf version needs to be bumped
>

We have found another problem with ipa.conf approach so I have moved
configuration of apache for plugin from ipa.conf into completely separated
file to be not configured in FreeIPA by default. As you said it may cause
some security issues and it definitely causes errors when plugin
dependences are not installed nor configured.

2. Do not put the web ui plugin in src/freeipa/plugins dir. That is a
> dir for core UI plugins. This one is sort of hybrid - basically a third
> party plugin added to core package  but enabled as third party because
> the feature is experimental.
>
> Create rather a new dir for that. E.g. plugins.d as Alexander suggested
> ->  freeipa/install/ui/src/plugins.d/cert_auth/cert_auth.js
>
> 3. unrelated and "alternative solution"  comments needs to be removed
> from the UI plugin. They were added to the example plugin
> https://pvoborni.fedorapeople.org/plugins/loginauth/loginauth.js mostly
> to help you with the development.
>
> 4. Add comment to freeipa.spec.in describing what the plugin is and why
> it is put there this way.
>
> 5. The plugin itself deserves better description as well. Right now
> there is the general description.
>
> 6. I have not tried it, but make sure that it passes jslint (`jsl -conf
> jsl.conf`) Easiest may be to use temp(i.e. do not include it here)
> jsl.conf e.g.: https://pvoborni.fedorapeople.
> org/plugins/loginauth/jsl.conf
>
> --
> Petr Vobornik
>

I hope result of jsl http://pastebin.test.redhat.com/400076 means that
things passed.
Thanks Petr for review and I hope this patch will cover all concerns he
had.

Addressing ticket: https://fedorahosted.org/freeipa/ticket/5764

Thank you.

-- 
Tibor Dudlák
Intern - Identity management Special Projects
Red Hat
From 6f5f0632a238182bbd98be9ecd89121a58e1e17a 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                                    |   8 +
 install/conf/Makefile.am                           |   1 +
 install/conf/xx-ipa-cert-auth.conf                 |  14 ++
 .../freeipa/plugins-dist/cert_auth/cert_auth.js    | 169 +++++++++++++++++++++
 ipaserver/plugins/xmlserver.py                     |   3 +-
 ipaserver/rpcserver.py                             |   5 +
 6 files changed, 199 insertions(+), 1 deletion(-)
 create mode 100644 install/conf/xx-ipa-cert-auth.conf
 create mode 100644 install/ui/src/freeipa/plugins-dist/cert_auth/cert_auth.js

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 135e9c980011c6c2730c6c29a3c22098e48270d5..19828bc84f1f1d13d4bb0e08a4749da626e9dbb3 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -818,6 +818,10 @@ 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
 
+# Experimental external authentication UI plugin - moved into plugins-dist to be disabled by default
+mkdir -p %{buildroot}%{_usr}/share/ipa/ui/js/plugins-dist/cert_auth
+install install/ui/src/freeipa/plugins-dist/cert_auth/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 +1214,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
@@ -1232,6 +1239,7 @@ fi
 %{_usr}/share/ipa/ipa-rewrite.conf
 %{_usr}/share/ipa/ipa-pki-proxy.conf
 %{_usr}/share/ipa/kdcproxy.conf
+%{_usr}/share/ipa/xx-ipa-cert-auth.conf
 %ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt
 %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/kerberosauth.xpi
 %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.con
diff --git a/install/conf/Makefile.am b/install/conf/Makefile.am
index 5daac776f71c5d01187b46d51044a07bf5fd717a..2e6fbb84902c843fa6e43a96191d5cc58a1213c1 100644
--- a/install/conf/Makefile.am
+++ b/install/conf/Makefile.am
@@ -6,6 +6,7 @@ app_DATA =                              \
 	ipa-kdc-proxy.conf.template	\
 	ipa-pki-proxy.conf		\
 	ipa-rewrite.conf		\
+	xx-ipa-cert-auth.conf		\
 	$(NULL)
 
 EXTRA_DIST =                            \
diff --git a/install/conf/xx-ipa-cert-auth.conf b/install/conf/xx-ipa-cert-auth.conf
new file mode 100644
index 0000000000000000000000000000000000000000..824d33113446176c0d1a9f6c99e95aa48a7a99c9
--- /dev/null
+++ b/install/conf/xx-ipa-cert-auth.conf
@@ -0,0 +1,14 @@
+# Login with user certificate/smartcard configuration
+# This configuration needs to be loaded after <Location "/ipa">
+<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>
diff --git a/install/ui/src/freeipa/plugins-dist/cert_auth/cert_auth.js b/install/ui/src/freeipa/plugins-dist/cert_auth/cert_auth.js
new file mode 100644
index 0000000000000000000000000000000000000000..7dd0c17c83ab34f0c8dc37c789f202ce42d52f52
--- /dev/null
+++ b/install/ui/src/freeipa/plugins-dist/cert_auth/cert_auth.js
@@ -0,0 +1,169 @@
+/*  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 adds a button-link with aside text to FreeIPA login screen to
+    support x509 authentication for experimental use
+
+    Disabled by default
+
+    Tested against FreeIPA 4.3 and 4.4
+
+    Limitation: only one such plugin can be installed - one can override
+    functionality of the other
+ */
+
+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 = {};
+
+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) {
+
+        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];
+
+        construct.place(this.crtauth_btn_node, container);
+        construct.place(document.createTextNode(" "), container);
+
+        this.inherited(arguments);
+    },
+
+    crt_login: 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.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);
+        this.set_visible_buttons(['crtauth', 'sync', 'login']);
+    },
+
+    set_login_aside_text: function() {
+
+        this.inherited(arguments);
+        var aside = this.aside;
+        aside += this.msg;
+        this.set('aside', aside);
+    }
+});
+
+
+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