Разработка скрипта MFA - Avanpost FAM/MFA+

Общие сведения

Система позволяет использовать механизм скриптов для динамического вычисления шагов сценария MFA (сценария аутентификации). Данный способ определения сценария используется в качестве альтернативы классическому механизму, использующему графический интерфейс настройки сценария MFA. Также он обладает дополнительными преимуществами перед классическим способом настройки MFA, позволяя использовать:

  • Основные и дополнительные атрибуты профиля пользователя в логических условиях;
  • Признаки наличия групп, ролей и прав у пользователя;
  • Параметры входящего сетевого запроса, который был отправлен в рамках текущего запроса;

Текущая инструкция описывает методику разработки скрипта аутентификации на языке JavaScript.

Предполагается, что разработчик сценария MFA обладает следующими компетенциями:

  • владение языком программирования ECMAScript 5.1 или JavaScript;
  • понимание механизма многофакторной аутентификации, реализуемого системой, и способов его диагностики.

Процесс выполнения скрипта

Сценарий, описанный на языке JavaScript, выполняется в процессе аутентификации в определённое подключенное к системе приложение.

В первую очередь система определяет, в какое приложение осуществляется аутентификация пользователя. После определения приложения система проверяет, какой сценарий настроен на вкладке MFA данного приложения. Если в качестве метода входа выбран скрипт MFA, то система вычисляет сценарий аутентификации динамически на основе скрипта. Если скрипт не был выбран для конкретного приложения, то параметры сценария аутентификации будут определяться настройками, заданными на вкладке MFA приложения без выполнения скрипта аутентификации.

Методика разработки скрипта

Для разработки скрипта необходимо:

  1. Чтобы была доступна тестовая среда с приложением, на примере которого выполняется тестирование и отладка разрабатываемого скрипта, предполагающая отсутствие влияния на реальных пользователей;
  2. Чтобы была выполнена корректная интеграция приложения с системой через один из интеграционных механизмов:
    1. OAuth/OpenID Connect;
    2. SAML;
    3. RADIUS;
    4. Reverse Proxy;
    5. Enterprise SSO.
  3. В разделе «Редактор скриптов» должен быть создан как минимум пустой скрипт аутентификации с типом «Multi Factor Authentication».
  4. На вкладке MFA для данного приложения в качестве первого и единственного шага должен быть выбран созданный на предыдущем шаге скрипт.

Для отладки скрипта у пользователя должны присутствовать все необходимые настроенные факторы. Отладка осуществляется только путём выполнения аутентификации в целевое тестовое приложение.

Сценарии использования

Определение специфического сценария MFA на основе значения атрибута пользователя

В сценарии решается задача определения специфического набора факторов для пользователей, определённый атрибут которых содержит определённое значение.

Пример скрипта, настроенного в разделе «Редактор скриптов»:

var user = context.GetUser()

if (typeof user === 'undefined') {
    context.AddStep(
        [
            { factor: "pwd" }
        ]);
} else {
     var hasViceUserAttribute = user.Attributes['vice'] === 'false';

     if (hasViceUserAttribute) {
        context.AddStep([
            { factor: "pwd" }
        ]);
        context.AddStep([
            { factor: "sms" }
        ]);
    } else {
        context.AddStep([
            { factor: "pwd" }
        ]);
        context.AddStep([
            { factor: "totp" }
        ]);
    }
}

Расширенный сценарий аутентификации

В сценарии решается задача комплексной оценки сценария аутентификации:

// пример скрипта
var user = context.GetUser()
// console.log(context.Session.AuthFlags);
var session = context.GetSession();
console.log(session.AuthFlags);
var request = context.GetRequest();
console.log(request.IPAddress);
// нужна идентификация либо ввод логина пароля для идентификации пользователя
if (typeof user === 'undefined') {
    context.AddStep(
        [

            { factor: "pwd" }
        ]);
} else {
    console.log(user.Domain, user.Name, user.FirstName, user.LastName, user.Email)

    var hasViceUserAttribute = user.Attributes['vice'] === 'false';
    var memmberOfGroup1 = false;
    var hasRoleRight1 = false;

    for (var i = 0; i < user.Groups.length; i++) {
        if (user.Groups[i].Name === 'desktop_applications') { 
            console.log("groupName", user.Groups[i].Name);
            memmberOfGroup1 = true; 
        }
        // console.log("GR1", user.Groups[i].ID, user.Groups[i].Name);
    }
    for (var i = 0; i < user.Roles.length; i++) {
        if (user.Roles[i].Name === 'Right1') { hasRoleRight1 = true; }
        // console.log("RL1", user.Roles[i].ID, user.Roles[i].Name);
    }
    console.log("hasViceUserAttribute", hasViceUserAttribute, "memmberOfGroup1", memmberOfGroup1, "hasRoleRight1", hasRoleRight1);

    if (hasViceUserAttribute) {
        context.AddStep([
            { factor: "pwd" }
        ]);
        context.AddStep([
            { factor: "ip", parameters: ["127.0.0.0/8", "::1"] },
            { factor: "sms" }
        ]);
    } else if (memmberOfGroup1) {
        context.AddStep([
            { factor: "pwd" }
        ]);
        context.AddStep([
            { factor: "totp" }
        ]);
    } else if (hasRoleRight1) {
        context.AddStep([
            { factor: "pwd" }
        ]);
        context.AddStep([
            { factor: "telegram" }
        ]);
    }
}

Определение сценария аутентификации на основе признаков устройств

Функция доступна начиная с версии FAM/MFA+ 1.12

Пример настройки упрощенной аутентификации с использованием информации об агенте-устройстве пользователя:

// Пример настройки упрощенной аутентификации с использованием информации об агенте-устройстве пользователя
// Получаем пользователя из контекста текущего запроса (1)
// Если пользователь не найден, то устаналиваем шаг для идентификации (2).
// Получаем текущий запрос (3).
// Получаем данные агента и устройства из текущего запроса (4).
// Получаем список зарегистрованных устройств пользователя (5).
// Поиск устройства из текущего запроса в списке зарегистрированных по идентификатору (6).
// Если устройство найдено, то добавляем только проверку временного пароля (7).
// Иначе добавляем два шага: проверка пароля и проверка TOTP.

// 1
var user = context.GetUser();
// 2
if (typeof user === 'undefined') {
    context.AddStep([{ factor: "identification" }]);
}else{
    // 3
    var req = context.GetRequest();
    // 4
    var reqDevice = req.Device;
    // 5
    var userDevices = context.GetUserDevices();
    if(reqDevice.Type !== "Unknown" && userDevices.length > 0){
        // 6
        var hasTrusted = userDevices.some(function(userDevice){
            return userDevice.ID === reqDevice.ID;
        })
        // 7
        if(hasTrusted) {
            context.AddStep([{ factor: "totp" }]);
        } else {
            context.AddStep([{ factor: "pwd" }]);
            context.AddStep([{ factor: "totp" }]);
        }
    }else{
        context.AddStep([{ factor: "pwd" }]);
        context.AddStep([{ factor: "totp" }]);
    }
}

Пропуск проверки факторов аутентификации на основе сессии другого приложения или другого механизма интеграции («SSO для RADIUS»)

Функция доступна начиная с версии FAM/MFA+ 1.11

FAM часто применяется в сценариях аутентификации пользователя сразу в нескольких приложениях, подключенных по различным протоколам и механизмам. При этом достаточно часто применяется комбинация веб-приложений, подключаемых по OIDC/SAML, с приложениями, подключаемыми по RADIUS, или приложениями, подключаемымим по gRPC (через дополнительные прикладные компоненты типа Windows Logon или Linux Logon).

Ожидаемые сценарии использования:

  1. У пользователя на рабочую станцию с Windows Logon (gRPC) и в веб-приложение 1С:Предприятие Тонкий клиент (OIDC) настроен идентичный сценарий аутентификации (предположим, логин-пароль, затем push в Avanpost Authenticator). Пользователь аутентифицируется на рабочую станцию, а после этого - в веб-приложение. При этом администратор считает, что если пользователь уже подтверждал второй фактор в течение определённого времени при входе на рабочую станцию (к примеру, в течение 5 минут) - то push повторно у пользователя не должен повторно запрашиваться и проверяться.
  2. У пользователя в Cisco Any Connect VPN (RADIUS) и веб-приложение Atlassian Jira (SAML), доступное после подключения к VPN, настроен идентичный сценарий аутентификации (предположим, логин-пароль, затем TOTP). Пользователь проходит аутентификацию в VPN, а после этого в веб-приложение. При этом администратор считает, что если пользователь уже подтвердил второй фактор в течение 3 минут после подключения к VPN, то повторно TOTP при аутентификации в веб-приложение запрашиваться не должен.

Также предполагается, что администратор может для принятия решения о пропуске проверки фактора в указанных выше сценариях использовать:

  1. Факт успешной проверки фактора при аутентификации пользователя в любом из приложений, которым доверяет текущее приложение, с учётом времени проверки фактора.
  2. Факт успешной проверки фактора при аутентификации пользователя в любом из приложений, которым доверяет текущее приложение. с проверкой успешного прохождения аутентификации именно в это приложение по указанному фактору и с учётом времени проверки фактора в рамках этого приложения.
  3. Факт успешной проверки фактора при аутентификации пользователя в любом из приложений, которым доверяет текущее приложение. с проверкой успешного прохождения аутентификации именно в это приложение по указанному фактору и с учётом времени проверки фактора в рамках этого приложения и совпадения IP-адреса пользователя, который зафиксирован в указанной сессии.

Пример настройки упрощенной аутентификации между доверенными приложениями:

// Пример настройки упрощенной аутентификации между доверенными приложениями
// Получаем пользователя из контекста текущего запроса (1)
// Если пользователь не найден, то устаналиваем шаг для идентификации (2).
// Иначе получаем все активные сессии пользователя по его идентификатору (3).
// Если у польователя не существует активных сессий, то устаналиваем шаг для проверки пароля (4).
// Иначе проверяем в сессиях приложений наличие сессии для заданного приложения и ограничение по времени (5).
// Если сессия найдена и время создания удолетворяет ограничению, то запрашиваем только push-уведомление.
// Дополнительно проверяем ip текущего запроса. (6)
// Иначе добавляем два шага: для проверки пароля, а потом для проверки временного пароля (7).

// 1
var user = context.GetUser();
// 2
if (typeof user === 'undefined') {
    context.AddStep([{ factor: "identification" }]);
} else {
    // 3
    var activeSessions = context.GetActiveUserSessions();
    // 4
    if (activeSessions.length == 0) {
        context.AddStep([{ factor: "pwd" }]);
    } else {
        // 5
        var currentDate = new Date();
        var hasTrustedAppSession = activeSessions.some(function (ses) {
            var ok = false;
            if (typeof ses.AppSessions !== 'undefined' && ses.AppSessions.length > 0) {
                ok = ses.AppSessions.some(function (appSes) {
                    var c = appSes.CreatedAt;
                    var appSesDate = new Date(c.Year(), c.Month() - 1, c.Day(), c.Hour(), c.Minute(), c.Second(), 0);
                    var diffSeconds = Math.round((currentDate - appSesDate) / 1000);
                    if (appSes.AppID == 'dfc03ec7-7787-4d1a-affc-52ca6128afd3' && diffSeconds < 30) {
                        console.log("Found AppID:" + appSes.AppID + ",diff in seconds:" + diffSeconds)
                        return true;
                    }
                    return false;
                });
            }
            return ok;
        });
        // 6
        var req = context.GetRequest();
        if (hasTrustedAppSession && context.InSubNet(req.IPAddress, '10.0.0.0/8')) {
            context.AddStep([{ factor: "push" }]);
        } else {
            // 7
            context.AddStep([{ factor: "pwd" }]);
            context.AddStep([{ factor: "totp" }]);
        }
    }
}

Приложение 1. Спецификация функций

В рамках механизма скриптинга доступен ряд дополнительных функций, вызов которых позволяет выполнять специфические для сценария MFA операции:

ФункцияНазначениеПараметры

context.GetUser()

Получение контекста пользователя
  • ID 
  • Name
  • Domain
  • FirstName
  • LastName
  • MiddleName
  • Email
  • PhoneNumber
  • Attributes
  • Groups
  • Roles
  • CreationDate

context.GetUserDevices()

Получение устройств пользователя

Функция доступна начиная с версии FAM/MFA+ 1.12

  • ID - внутренний идентификатор устройства;
  • Type - тип устройства;
  • Agent - тип агента (mobauthn, browser и т.д.);
  • LastUse - метка времени;
  • LastUseIPAddr - значение последнего зафиксированного IP-адреса;
  • Profile - коллекция признаков устройства; состав зависит от типа устройства; см. приложение 3;
  • RegisteredIn - дата-время регистрации;
  • UUID - платформозависимый UUID устройства.

context.GetSession()

Получение контекста сессии
  • ID
  • Factors
  • AppSessions
    • ID
    • AppID
    • CreatedAt

context.GetRequest()

Получение контекста запроса
  • IPAddress

  • Device - устройство, с которого выполнен текущий запрос; доступно начиная с версии FAM/MFA+ 1.12: 
    • ID - внутренний идентификатор устройства;
    • Type - тип устройства (Desktop, Mobile);
    • Agent - тип агента (mobauthn, browser и т.д.);
    • Profile - коллекция признаков устройства; состав зависит от типа устройства; см. приложение 3;

context.AddStep()

Добавление шага аутентификации
  • factor

context.GetActiveUserSessions()

Получение списка активных сессий пользователя, открытых в том числе посредством других механизмов

Функция доступна начиная с версии FAM/MFA+ 1.11

  • CreatedAt
  • AppID

context.Send()

Отправка HTTP-запроса



Приложение 2. Перечень ключей для выбора факторов аутентификации

Для отладки скрипта у пользователя должны присутствовать все необходимые настроенные факторы. Перечень всех доступных ключей для выбора факторов в рамках вызова функции context.AddStep() приведен ниже.

ФакторНазначение

ip

Аутентификация пользователя по IP.

sms

Аутентификация посредством SMS OTP, через использование одноразового кода, полученного из текстового сообщения (SMS).

telegram

Аутентификация через доставку push-уведомлений в Telegram пользователю.

pwd

Аутентификация пользователя по паролю.

totp

Аутентификация через TOTP. через использование временных паролей, создаваемых на основе текущего времени и специального шифрования.

identification

Аутентификация по идентификатору, который хранится в памяти сервера или базе данных, содержит информацию о пользователе и представляет собой любое значение, вводимое в качестве логина.

emailotp

Аутентификация посредством одноразовых кодов (OTP), доставляемых по E-mail.

external

Аутентификация пользователя по внешнему IDP.

paycontrol

Аутентификация пользователя  посредством PayControl. 

cert

Аутентификация при помощи сертификатов, которые установлены на рабочие места пользователей или на подключенных ключевых носителях. Также аутентификация по ЭП на смарт-картах типа Рутокен и JaCarta

qrsignin

Аутентификация пользователя по QR-коду.

webauthn

Аутентификация по FIDO WebAuthn/U2F-аутентификаторам с использованием встроенной в операционную систему и устройство криптографии.

hardware

Аутентификация посредством Hardware фактора аутентификации с использованием JaCarta или (и) RuToken.

Приложение 3. Состав ключей profile устройства

  • browser - название браузера (Chrome, Safari, Firefox);
  • browserFingerprint - значение Fingerprint, вычисленное JS-библиотекой в пользовательском браузере;
  • browserUseragent - значение строки HTTP-заголовка User-Agent;
  • browserUseragentSHA1 - значение SHA1, вычисленное на основе значения User-Agent;
  • browserVersion - версия браузера;
  • os - название операционной системы (Windows, Android, macOS, Linux и т.д.);
  • osVersion - версия операционной системы;
  • app - название приложения-агента (Avanpost Authenticator, Avanpost Windows Logon, Avanpost Linux Logon, Avanpost Agent);
  • appVersion - версия приложения-агента;
  • device - имя устройства;
  • fingerprint - значение Fingerprint для устанавливаемых агентов;
  • vendor - название производителя устройства.

Обсуждение