%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