summaryrefslogtreecommitdiffstats
path: root/install
diff options
context:
space:
mode:
authorPetr Vobornik <pvoborni@redhat.com>2014-06-03 18:21:25 +0200
committerPetr Vobornik <pvoborni@redhat.com>2014-06-30 12:27:03 +0200
commit30b1256b6231610812b394e3363394690a297201 (patch)
tree04295334466b89a3fa97a09ef0f2af47c30cc79c /install
parentd159662aded445418516c3ccb492bca33fbb11e5 (diff)
downloadfreeipa-30b1256b6231610812b394e3363394690a297201.tar.gz
freeipa-30b1256b6231610812b394e3363394690a297201.tar.xz
freeipa-30b1256b6231610812b394e3363394690a297201.zip
webui: add OTP token synchronization
New SyncOTPScreen widget and related facet. https://fedorahosted.org/freeipa/ticket/4218 Reviewed-By: Endi Sukma Dewata <edewata@redhat.com>
Diffstat (limited to 'install')
-rw-r--r--install/ui/doc/categories.json3
-rw-r--r--install/ui/src/freeipa/app.js1
-rw-r--r--install/ui/src/freeipa/plugins/sync_otp.js103
-rw-r--r--install/ui/src/freeipa/widgets/SyncOTPScreen.js238
-rw-r--r--install/ui/test/data/ipa_init.json6
5 files changed, 350 insertions, 1 deletions
diff --git a/install/ui/doc/categories.json b/install/ui/doc/categories.json
index 8bc0d8b1a..b55fb81a0 100644
--- a/install/ui/doc/categories.json
+++ b/install/ui/doc/categories.json
@@ -245,7 +245,8 @@
"radiusproxy",
"user",
"plugins.load",
- "plugins.login"
+ "plugins.login",
+ "plugins.sync_otp"
]
}
]
diff --git a/install/ui/src/freeipa/app.js b/install/ui/src/freeipa/app.js
index 1915ccbe6..d87ce6611 100644
--- a/install/ui/src/freeipa/app.js
+++ b/install/ui/src/freeipa/app.js
@@ -23,6 +23,7 @@ define([
'./app_container',
'./plugins/load_page',
'./plugins/login',
+ './plugins/sync_otp',
// entities
'./aci',
'./automember',
diff --git a/install/ui/src/freeipa/plugins/sync_otp.js b/install/ui/src/freeipa/plugins/sync_otp.js
new file mode 100644
index 000000000..810503dc7
--- /dev/null
+++ b/install/ui/src/freeipa/plugins/sync_otp.js
@@ -0,0 +1,103 @@
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2013 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/>.
+*/
+
+define(['dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/on',
+ '../facets/Facet',
+ '../auth',
+ '../navigation',
+ '../phases',
+ '../reg',
+ '../widget',
+ '../widgets/SyncOTPScreen'
+ ],
+ function(declare, lang, on, Facet, auth, navigation, phases, reg, widget, SyncOTPScreen) {
+
+ /**
+ * Sync OTP Facet plugin
+ *
+ * Creates and registers a facet with sync otp page.
+ *
+ * @class plugins.sync_otp
+ * @singleton
+ */
+ var sync_otp = {};
+
+ sync_otp.facet_spec = {
+ name: 'sync-otp',
+ 'class': 'login-pf-body',
+ preferred_container: 'simple',
+ requires_auth: false,
+ widgets: [
+ {
+ $type: 'activity',
+ name: 'activity',
+ text: 'Synchronizing',
+ visible: false
+ },
+ {
+ $type: 'sync_otp_screen',
+ name: 'sync_screen'
+ }
+ ]
+ };
+
+ sync_otp.SyncOTPFacet = declare([Facet], {
+
+ init: function() {
+ this.inherited(arguments);
+ var sync_screen = this.get_widget('sync_screen');
+ var self = this;
+ on(sync_screen, 'sync-success', function(args) {
+ self.emit('sync-success', args);
+ });
+
+ on(sync_screen, 'sync-cancel', function(args) {
+ self.emit('sync-cancel', args);
+ });
+
+ on(this, 'show', function(args) {
+ sync_screen.refresh();
+ });
+ },
+
+ set_user: function(user) {
+ var sync_screen = this.get_widget('sync_screen');
+ sync_screen.set('user', user);
+ }
+ });
+
+ phases.on('registration', function() {
+
+ var fa = reg.facet;
+ var w = reg.widget;
+
+ w.register('sync_otp_screen', SyncOTPScreen);
+
+ fa.register({
+ type: 'sync-otp',
+ factory: sync_otp.SyncOTPFacet,
+ spec: sync_otp.facet_spec
+ });
+ });
+
+ return sync_otp;
+}); \ No newline at end of file
diff --git a/install/ui/src/freeipa/widgets/SyncOTPScreen.js b/install/ui/src/freeipa/widgets/SyncOTPScreen.js
new file mode 100644
index 000000000..13c47ae88
--- /dev/null
+++ b/install/ui/src/freeipa/widgets/SyncOTPScreen.js
@@ -0,0 +1,238 @@
+/* Authors:
+ * Petr Vobornik <pvoborni@redhat.com>
+ *
+ * Copyright (C) 2013 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/>.
+*/
+
+define(['dojo/_base/declare',
+ 'dojo/_base/lang',
+ 'dojo/Deferred',
+ 'dojo/dom-construct',
+ 'dojo/dom-style',
+ 'dojo/query',
+ 'dojo/on',
+ '../ipa',
+ '../auth',
+ '../reg',
+ '../FieldBinder',
+ '../text',
+ '../util',
+ './LoginScreenBase'
+ ],
+ function(declare, lang, Deferred, construct, dom_style, query, on,
+ IPA, auth, reg, FieldBinder, text, util, LoginScreenBase) {
+
+
+ /**
+ * Widget with OTP sync form.
+ *
+ * @class widgets.SyncOTPScreen
+ */
+ var SyncOTPScreen = declare([LoginScreenBase], {
+
+ sync_fail: "Token synchronization failed",
+
+ invalid_credentials: "The username, password or token codes are not correct",
+
+ sync_success: "Token was synchronized",
+
+ allow_cancel: true,
+
+ user: null,
+
+ //nodes:
+ cancel_btn_node: null,
+ sync_btn_node: null,
+
+ render_buttons: function(container) {
+ this.cancel_btn_node = IPA.button({
+ name: 'cancel',
+ label: 'Cancel',
+ 'class': 'btn-default btn-lg',
+ click: lang.hitch(this, this.on_cancel)
+ })[0];
+ if (this.allow_cancel) {
+ construct.place(this.cancel_btn_node, container);
+ }
+ this.sync_btn_node = IPA.button({
+ label: text.get('@i18n:password.sync_otp_token', "Sync OTP Token"),
+ 'class': 'btn-primary btn-lg',
+ click: lang.hitch(this, this.on_confirm)
+ })[0];
+ construct.place(this.sync_btn_node, container);
+ },
+
+ refresh: function() {
+ this.reset();
+ this.get_widget('validation').remove('sync');
+ if (this.user) {
+ this.get_field('user').set_value([this.user]);
+ this.get_widget('password').focus_input();
+ } else {
+ this.get_widget('user').focus_input();
+ }
+ if (this.buttons_node) {
+ this.buttons_node.innerHTML = "";
+ if (this.allow_cancel) {
+ construct.place(this.cancel_btn_node, this.buttons_node);
+ }
+ construct.create('span', { innerHTML: ' '}, this.buttons_node);
+ construct.place(this.sync_btn_node, this.buttons_node);
+ }
+ },
+
+ on_cancel: function() {
+ this.emit('sync-cancel', { source: this });
+ },
+
+ on_confirm: function() {
+ this.sync();
+ },
+
+ sync: function() {
+
+ var val_summary = this.get_widget('validation');
+ val_summary.remove('sync');
+
+ if (!this.validate()) return;
+
+ var user = this.get_field('user').get_value()[0];
+ var password_f = this.get_field('password');
+ var password = password_f.get_value()[0];
+ var otp1 = this.get_field('first_code').get_value()[0];
+ var otp2 = this.get_field('second_code').get_value()[0];
+ var token = this.get_field('token').get_value()[0];
+
+ var p = this.sync_core(user, password, otp1, otp2, token);
+ p.then(lang.hitch(this, function(result) {
+ var msg = this.sync_fail;
+ var evt = 'sync-fail';
+ var type = 'error';
+ this.refresh();
+ if (result === 'ok') {
+ evt = 'sync-success';
+ msg = this.sync_success;
+ val_summary.add_success('sync', msg);
+ } else if (result === 'invalid-credentials') {
+ msg = this.invalid_credentials;
+ val_summary.add_error('sync', msg);
+ } else {
+ val_summary.add_error('sync', msg);
+ }
+ this.emit(evt, { source: this, message: msg, status: result });
+ }));
+ },
+
+ sync_core: function(user, password, otp1, otp2, token) {
+
+ var d = new Deferred();
+ var data = {
+ user: user,
+ password: password,
+ first_code: otp1,
+ second_code: otp2
+ };
+ if (token) data.token = token;
+
+ var handler = function(data, text_status, xhr) {
+ var result = xhr.getResponseHeader("X-IPA-TokenSync-Result");
+ result = result || 'error';
+ IPA.hide_activity_icon();
+ d.resolve(result);
+ };
+
+ var request = {
+ url: '/ipa/session/sync_token',
+ data: data,
+ contentType: 'application/x-www-form-urlencoded',
+ processData: true,
+ dataType: 'html',
+ type: 'POST',
+ success: handler,
+ error: handler
+ };
+
+ IPA.display_activity_icon();
+ $.ajax(request);
+ return d.promise;
+ },
+
+ setUser: function(value) {
+ this.user = value;
+ this.get_field('user').set_value([value]);
+ },
+
+ constructor: function(spec) {
+ spec = spec || {};
+
+ this.sync_fail = text.get(spec.sync_fail || '@i18n:password.otp_sync_fail',
+ this.sync_fail);
+
+ this.sync_success = text.get(spec.sync_success || '@i18n:password.otp_sync_success',
+ this.sync_success);
+
+ this.invalid_credentials = text.get(spec.invalid_credentials || '@i18n:password.otp_sync_invalid',
+ this.invalid_credentials);
+
+ this.field_specs = SyncOTPScreen.field_specs;
+ }
+ });
+
+ SyncOTPScreen.field_specs = [
+ {
+ $type: 'text',
+ name: 'user',
+ label: text.get('@i18n:login.username', "Username"),
+ show_errors: false,
+ undo: false,
+ required: true
+ },
+ {
+ $type: 'password',
+ name: 'password',
+ label: text.get('@i18n:login.password', "Password"),
+ show_errors: false,
+ undo: false,
+ required: true
+ },
+ {
+ $type: 'password',
+ name: 'first_code',
+ label: text.get('@i18n:password.first_otp', "First OTP"),
+ show_errors: false,
+ undo: false,
+ required: true
+ },
+ {
+ $type: 'password',
+ name: 'second_code',
+ label: text.get('@i18n:password.second_otp', "Second OTP"),
+ show_errors: false,
+ undo: false,
+ required: true
+ },
+ {
+ $type: 'text',
+ name: 'token',
+ label: text.get('@i18n:password.token_id', "Token ID"),
+ show_errors: false,
+ undo: false
+ }
+ ];
+
+ return SyncOTPScreen;
+}); \ No newline at end of file
diff --git a/install/ui/test/data/ipa_init.json b/install/ui/test/data/ipa_init.json
index 0c32395ee..3da2b4f4a 100644
--- a/install/ui/test/data/ipa_init.json
+++ b/install/ui/test/data/ipa_init.json
@@ -506,11 +506,15 @@
"current_password": "Current Password",
"current_password_required": "Current password is required",
"expires_in": "Your password expires in ${days} days.",
+ "first_otp": "First OTP",
"invalid_password": "The password or username you entered is incorrect.",
"new_password": "New Password",
"new_password_required": "New password is required",
"otp": "OTP",
"otp_long": "One-Time-Password",
+ "otp_sync_fail": "Token synchronization failed",
+ "otp_sync_invalid": "The username, password or token codes are not correct",
+ "otp_sync_success": "Token was synchronized",
"password": "Password",
"password_and_otp": "Password or Password+One-Time-Password",
"password_change_complete": "Password change complete",
@@ -518,6 +522,8 @@
"reset_failure": "Password reset was not successful.",
"reset_password": "Reset Password",
"reset_password_sentence": "Reset your password.",
+ "second_otp": "Second OTP",
+ "token_id": "Token ID",
"verify_password": "Verify Password"
},
"search": {