Skip to content

Commit

Permalink
adding support for login with otp-code field (#233)
Browse files Browse the repository at this point in the history
* adding support for login with otp-code field

* disabling user_id field for smart-link

Smart-link authentication method will be able to be done
by both the external application and Sequent IAM backend.

This means that Sequent will be able to verify the voter
authentication credentials. One of the credentials is the
user_id, which is a mandatory extra-field for smart-link
authnetication and comes from the auth-token received by
the external application. As such, it cannot be edited
by the user, and thus we are making it a filled-in and
disabled field in the login screen.

Future work will include allowing to hide a field and
showing it under a different name, to make mandatory
fields like user_id more user-friendly.

* fixing automatic request of otp code
  • Loading branch information
edulix authored and Findeton committed Sep 20, 2022
1 parent 792ee4d commit e853140
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 25 deletions.
27 changes: 24 additions & 3 deletions avRegistration/auth-method-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,20 @@ angular.module('avRegistration')
return fields;
};

authmethod.hasOtpCodeField = function (viewEventData)
{
var fields = authmethod.getRegisterFields(
viewEventData
);
for (var i=0; i<fields.length; i++) {
if (fields[i]['type'] === "otp-code") {
return true;
}
}

return false;
};

authmethod.getCensusQueryFields = function (viewEventData)
{
var fields = angular.copy(viewEventData.extra_fields);
Expand Down Expand Up @@ -444,6 +458,8 @@ angular.module('avRegistration')
var fields = authmethod.getRegisterFields(
viewEventData
);
var hasOtpCodeField = authmethod.hasOtpCodeField(viewEventData);

if (_.contains(["sms", "email"], viewEventData.auth_method))
{
fields.push({
Expand All @@ -452,8 +468,10 @@ angular.module('avRegistration')
"required": true,
"required_on_authentication": true
});
} else if (_.contains(["sms-otp", "email-otp"], viewEventData.auth_method))
{
} else if (
hasOtpCodeField ||
_.contains(["sms-otp", "email-otp"], viewEventData.auth_method)
) {
fields.push({
"name": "code",
"type": "code",
Expand All @@ -463,7 +481,10 @@ angular.module('avRegistration')
});
}

fields = _.filter(fields, function (field) {return field.required_on_authentication;});
fields = _.filter(
fields,
function (field) {return field.required_on_authentication;}
);

// put captha the last
for (var i=0; i<fields.length; i++) {
Expand Down
68 changes: 54 additions & 14 deletions avRegistration/login-directive/login-directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,28 @@ angular.module('avRegistration')
// if invalid method or already sending data, do not proceed
if (
scope.sendingData ||
!_.contains(["email", "email-otp", "sms", "sms-otp"], scope.method)
!(
scope.hasOtpFieldsCode ||
_.contains(["email", "email-otp", "sms", "sms-otp"], scope.method)
)
) {
return;
}

// if telIndex or emailIndex not set when needed, do not proceed
if (
(
_.contains(["sms", "sms-otp"], scope.method) &&
scope.telIndex === -1 &&
!scope.hide_default_login_lookup_field
) || (
_.contains(["email", "email-otp"], scope.method) &&
scope.emailIndex === -1 &&
!scope.hide_default_login_lookup_field
!scope.hasOtpFieldsCode &&
(
(
_.contains(["sms", "sms-otp"], scope.method) &&
scope.telIndex === -1 &&
!scope.hide_default_login_lookup_field
) ||
(
_.contains(["email", "email-otp"], scope.method) &&
scope.emailIndex === -1 &&
!scope.hide_default_login_lookup_field
)
)
) {
return;
Expand Down Expand Up @@ -194,6 +201,18 @@ angular.module('avRegistration')
scope.sendingData = false;
};

scope.parseAuthToken = function () {
if (scope.method !== 'smart-link') {
return;
}
scope.authToken = $location.search()['auth-token'];

var length = 'khmac:///'.length;
var tails = scope.authToken.substr(length);
var message = tails.split('/')[1];
scope.user_id = message.split(':')[0];
};

scope.checkCensus = function(valid) {
if (!valid) {
return;
Expand Down Expand Up @@ -237,7 +256,10 @@ angular.module('avRegistration')
// loginUser
if (
!scope.withCode &&
_.contains(['sms-otp', 'email-otp'], scope.method) &&
(
scope.hasOtpFieldsCode ||
_.contains(['sms-otp', 'email-otp'], scope.method)
) &&
scope.currentFormStep === 0
) {
scope.resendAuthCode();
Expand Down Expand Up @@ -372,8 +394,10 @@ angular.module('avRegistration')
};

scope.apply = function(authevent) {
scope.hasOtpFieldsCode = Authmethod.hasOtpCodeField(authevent);
scope.method = authevent['auth_method'];
scope.name = authevent['name'];
scope.parseAuthToken();
scope.registrationAllowed = (
(authevent['census'] === 'open') &&
(autheventid !== adminId || ConfigService.allowAdminRegistration)
Expand Down Expand Up @@ -448,14 +472,30 @@ angular.module('avRegistration')
} else if (el.name === '__username' && scope.withCode) {
el.value = scope.username;
el.disabled = true;
} else if (
el.name === 'user_id' &&
scope.method === 'smart-link'
) {
el.value = scope.user_id;
el.disabled = true;
}
return el;
});
var filled_fields = _.filter(fields,
function (el) { return el.value !== null; });

// if not all the fields all filled at this point, then we stop here
if (filled_fields.length !== scope.login_fields.length) {
// if not all the fields all filled at this point, then we stop
// here. otp-code or code fields do not count, because loginUser
// function will send the appropiate OTP code if required
var filledFields = _.filter(
fields,
function (el) {
return (
el.value !== null ||
el.type === 'otp-code' ||
el.type === 'code'
);
}
);
if (filledFields.length !== scope.login_fields.length) {
return;
}

Expand Down
27 changes: 19 additions & 8 deletions dist/appCommon-v7.0.0-beta.1.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
}
return fields;
},
hasOtpCodeField: function(viewEventData) {
for (var fields = authmethod.getRegisterFields(viewEventData), i = 0; i < fields.length; i++) if ("otp-code" === fields[i].type) return !0;
return !1;
},
getCensusQueryFields: function(fields) {
fields = angular.copy(fields.extra_fields);
return fields = _.filter(fields, function(field) {
Expand All @@ -230,13 +234,13 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
} ];
},
getLoginFields: function(viewEventData) {
var fields = authmethod.getRegisterFields(viewEventData);
var fields = authmethod.getRegisterFields(viewEventData), hasOtpCodeField = authmethod.hasOtpCodeField(viewEventData);
_.contains([ "sms", "email" ], viewEventData.auth_method) ? fields.push({
name: "code",
type: "code",
required: !0,
required_on_authentication: !0
}) : _.contains([ "sms-otp", "email-otp" ], viewEventData.auth_method) && fields.push({
}) : (hasOtpCodeField || _.contains([ "sms-otp", "email-otp" ], viewEventData.auth_method)) && fields.push({
name: "code",
type: "code",
required: !0,
Expand Down Expand Up @@ -425,7 +429,7 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
scope.email = null, attrs.email && 0 < attrs.email.length && (scope.email = attrs.email),
scope.isAdmin = !1, autheventid === adminId && (scope.isAdmin = !0), scope.resendAuthCode = function(field) {
var stop, data;
!scope.sendingData && _.contains([ "email", "email-otp", "sms", "sms-otp" ], scope.method) && (_.contains([ "sms", "sms-otp" ], scope.method) && -1 === scope.telIndex && !scope.hide_default_login_lookup_field || _.contains([ "email", "email-otp" ], scope.method) && -1 === scope.emailIndex && !scope.hide_default_login_lookup_field || (stop = !1,
scope.sendingData || !scope.hasOtpFieldsCode && !_.contains([ "email", "email-otp", "sms", "sms-otp" ], scope.method) || !scope.hasOtpFieldsCode && (_.contains([ "sms", "sms-otp" ], scope.method) && -1 === scope.telIndex && !scope.hide_default_login_lookup_field || _.contains([ "email", "email-otp" ], scope.method) && -1 === scope.emailIndex && !scope.hide_default_login_lookup_field) || (stop = !1,
data = _.object(_.filter(scope.login_fields, function(element, index) {
return element.index = index, void 0 === element.steps || -1 !== element.steps.indexOf(0);
}).map(function(element) {
Expand All @@ -440,9 +444,14 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
}), scope.currentFormStep = 1, scope.error = null, $timeout(scope.sendingDataTimeout, 3e3);
}, function(response) {
$timeout(scope.sendingDataTimeout, 3e3), scope.error = $i18next("avRegistration.errorSendingAuthCode");
}))));
})));
}, scope.sendingDataTimeout = function() {
scope.sendingData = !1;
}, scope.parseAuthToken = function() {
var message;
"smart-link" === scope.method && (scope.authToken = $location.search()["auth-token"],
message = "khmac:///".length, message = scope.authToken.substr(message).split("/")[1],
scope.user_id = message.split(":")[0]);
}, scope.checkCensus = function(valid) {
var data;
valid && (scope.sendingData || (scope.censusQuery = "querying", data = {
Expand All @@ -456,7 +465,7 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
})));
}, scope.loginUser = function(valid) {
var data;
valid && (scope.sendingData || (scope.withCode || !_.contains([ "sms-otp", "email-otp" ], scope.method) || 0 !== scope.currentFormStep ? (data = {
valid && (scope.sendingData || (scope.withCode || !scope.hasOtpFieldsCode && !_.contains([ "sms-otp", "email-otp" ], scope.method) || 0 !== scope.currentFormStep ? (data = {
captcha_code: Authmethod.captcha_code
}, _.each(scope.login_fields, function(field) {
"email" === field.name ? scope.email = field.value : "code" === field.name && (field.value = field.value.trim().replace(/ |\n|\t|-|_/g, "").toUpperCase()),
Expand Down Expand Up @@ -505,7 +514,8 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
});
})) : scope.resendAuthCode()));
}, scope.apply = function(authevent) {
scope.method = authevent.auth_method, scope.name = authevent.name, scope.registrationAllowed = "open" === authevent.census && (autheventid !== adminId || ConfigService.allowAdminRegistration),
scope.hasOtpFieldsCode = Authmethod.hasOtpCodeField(authevent), scope.method = authevent.auth_method,
scope.name = authevent.name, scope.parseAuthToken(), scope.registrationAllowed = "open" === authevent.census && (autheventid !== adminId || ConfigService.allowAdminRegistration),
scope.isCensusQuery || scope.withCode ? scope.withCode ? scope.login_fields = Authmethod.getLoginWithCode(authevent) : scope.login_fields = Authmethod.getCensusQueryFields(authevent) : scope.login_fields = Authmethod.getLoginFields(authevent),
scope.hide_default_login_lookup_field = authevent.hide_default_login_lookup_field,
scope.telIndex = -1, scope.emailIndex = -1, scope.telField = null, scope.allowUserResend = function() {
Expand All @@ -521,11 +531,12 @@ angular.module("avRegistration").config(function() {}), angular.module("avRegist
scope.emailIndex = index) : "code" === el.type && null !== scope.code ? (el.value = scope.code.trim().replace(/ |\n|\t|-|_/g, "").toUpperCase(),
el.disabled = !0) : "tlf" === el.type && "sms" === scope.method ? (null !== scope.email && -1 === scope.email.indexOf("@") && (el.value = scope.email,
el.disabled = !0), scope.telIndex = index + 1, scope.telField = el) : "tlf" === el.type && "sms-otp" === scope.method ? (null !== scope.email && -1 === scope.email.indexOf("@") && (el.value = scope.email,
el.disabled = !0, scope.currentFormStep = 1), scope.telIndex = index + 1, scope.telField = el) : "__username" === el.name && scope.withCode && (el.value = scope.username,
el.disabled = !0, scope.currentFormStep = 1), scope.telIndex = index + 1, scope.telField = el) : "__username" === el.name && scope.withCode ? (el.value = scope.username,
el.disabled = !0) : "user_id" === el.name && "smart-link" === scope.method && (el.value = scope.user_id,
el.disabled = !0), el;
});
_.filter(fields, function(el) {
return null !== el.value;
return null !== el.value || "otp-code" === el.type || "code" === el.type;
}).length === scope.login_fields.length && "openid-connect" !== scope.method && scope.loginUser(!0);
}, scope.view = function(id) {
Authmethod.viewEvent(id).then(function(response) {
Expand Down

0 comments on commit e853140

Please sign in to comment.