How to write and apply MFA (2-factor) authentication policy script

Introduction

This document is the guideline for how to write a custom C# two factor policy script to force or ignore two factor authentications. The samples will address some use cases that our customers usually ask for: client IP is/is not in a specific range, existence of a specific claim, or logging in user comes from a specific service provider.

Where to write the script

The policy script is per authentication connection configuration. You need to go to connection setting and write some C# script.

  image3

Syntax and built-in functions

The script supports C# 5.0 and .NET Framework 4.0. We provide a Rules object to store your custom rules. Here are the supported functions:

  • Rules.ApplyIPAddressRange(string ipRange)
  • Rules.NotApplyIPAddressRange (string ipRange)
  • Rules.ApplyExpression(Func<bool, RuleContextfunc)

The supported IP Address range formats are:

  • 192.168.0.0/255.255.255.0
  • 192.168.0.10 – 192.168.10.20
  • 192.168.10.10-20
  • fe80::/10
  • 192.168.0.0/16

The RuleContext object has following attributes:

  • HttpContext is current HttpContext object of logging in request.
  • FirstFactorPrincipal is the ClaimsPrincipal returned by the first factor provider.
  • EndpointContext is used for advanced user only.
  • TemporaryProtocolContext is used for advanced user only.
  • ProtocolConnectionId is GUID of the in-use service provider (aka. protocol connection id).
  • ProtocolConnectionEntityId is entity id the service provider whose type is string.
  • AuthenticationConnectionId is GUID of the in-use identity provide.
  • AuthenticationConnectionEntityId is entity id of the in-use identify provider (aka authentication connection id).

Multiple rules can be chained together. If all rules are satisfied, second factor authentication will be used.

You can use Rules.ApplyExpression(Func<bool> func) to create a custom rule that fits your need. It should return true to indicate that the rule is satisfied, otherwise it should return false.

The order of rules is very important. If one rule is not satisfied or return false, all later rules are ignored.

If the second factor policy script is empty, second factor authentication will be used.

Common use cases

1. Force second factor for IP Addresses from 192.168.1.15 to 192.168.1.20 and ignore second factor for IP Addresses from 192.168.1.0 to 192.168.1.14.

 

Rules

.ApplyIPAddressRange(“192.168.1.1 – 192.168.1.20″)

.NotApplyIPAddressRange(“192.168.1.17 – 192.168.1.18“);

2. Force second factor for users that have specific claim.

Rules

.ApplyExpression((RuleContext) => {

return RuleContext.FirstFactorPrincipal.HasClaim(“urn:identify:rest-api:role”, “Administrator”);

});

3. Enable second factor for a specific service provider.

Rules

.ApplyExpression((RuleContext) => {

return RuleContext.ProtocolConnectionEntityId == “ServiceProvider1″;

});

4. Examining HttpContext:

Rules.ApplyExpression((RuleContext) => {

if (HttpContext.Current.Request.Cookies[“AlwaysNeedSecondFactor“].Value == “false”) // Note: please don’t do this in reality. Your users can edit cookies easily.

{

    (RuleContext.FirstFactorPrincipal.Identity as ClaimIdentity).AddClaim(new Claim(“skippingSecondFactorClaimType“, “true”));

    return false;

}

});