Avanpost FAM/MFA+ : 10.4. Разработка скрипта 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 - внутренний идентификатор пользователя в формате UUID;
  • Name - полное ФИО пользователя;
  • FirstName - имя;
  • LastName - фамилия;
  • MiddleName - отчество;
  • Domain - домен;
  • Email - почтовый адрес;
  • PhoneNumber - номер телефона;
  • Groups - коллекция групп, в которых состоит пользователь;
  • Roles - коллекция ролей, которыми обладает пользователь;
  • CreationDate - метка времени, обозначающая дату создания пользователя;
  • Attributes - коллекция дополнительных атрибутов пользователя.

context.GetUserDevices()

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

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

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

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-запроса и возвращение результата

  • url - URL запроса;
  • method - тип запроса;
  • headers - заголовок запроса;
  • body - тело запроса;

context.StopProcess()

Показ пользователю сообщения из скрипта

Текст, выводящийся в GUI.


Приложение 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.

push

Аутентификация через Avanpost Authenticator (использование push).

Приложение 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 - название производителя устройства.

Обсуждение