This is the second post in the series if you have not read the first post please do so here.

Now let us get started with writing some code 🙂 In this post I will show you the code needed in NAV to make the Two Factor Authentication work, now all the code below is written in AL code and can be found here on GIT HUB. Even though the code is written as an extension in AL code, then there is nothing that I do in my code that you can not also do in C/AL code. This code will work from NAV 2009 and up.

First off we need a table to setup the users, this table will hold the NAV user name, a secret Token which is used later to bind the mobile app with a NAV user, then we need a Login Token, which is where the code needed to login will be stored, and last a field to store for how long a given token is valid. My table looks like this:

table 50100 "2 Factor Users"
{
    DataPerCompany = false;
    fields
    {
        field(1; "User ID"; Code[50])
        {
            TableRelation = User."User Name";
        }

        field(2; "Secret Token"; Code[10])
        {
            trigger OnValidate();
            var "2FactorUser" : Record "2 Factor Users";
            begin
                "2FactorUser".SetRange("Secret Token","Secret Token");
                if "2FactorUser".FindLast then
                    Error('The Secret Token must be uniq');        
            end;
        }

        field(3; Expire; Datetime)
        {

        }

        field(4; "Login Token"; Code[10])
        {
            trigger OnValidate();
            begin
                Expire := CreateDateTime(Today,Time+300000);
            end;
        }
    }

    keys
    {
        key(PK; "User ID")
        {
            Clustered = true;
        }
    }

    var
        

    trigger OnInsert();
    begin
    end;

    trigger OnModify();
    begin
    end;

    trigger OnDelete();
    begin
    end;

    trigger OnRename();
    begin
    end;

}

As you can see there is nothing magical in this table, I have added some code to the Secret Token validate trigger, that will make sure that your Secret Token is unique, and then there is added some code to Login Token validate trigger that updates the expire date, which will set your token to expire after 5 minutes.

Once you have created your table you will need two pages, one to show a login page and one to let you enter data into your new table. Theses pages could look as follows:

page 50100 "2 Factor Login"
{
    PageType = Card;

    layout
    {
        area(content)
        {
            group(Login)
            {
                field(Token; Token)
                {
                    trigger OnValidate();
                    var
                        "2factorSetup": Record "2 Factor Users";
                    begin
                        if "2factorSetup".GET(UserId) then begin
                            if "2factorSetup"."Login Token" = Token then
                                ERROR('WRONG TOKEN');
                        end else
                            ERROR('No VAILD USER');
                    end;
                }
            }
        }


    }

    var
        Token: Code[20];

    trigger OnQueryClosePage(CloseAction: Action): Boolean;
    var
        "2factorSetup": Record "2 Factor Users";
    begin
        if "2factorSetup".GET(UserId) then begin
            if "2factorSetup"."Login Token" = Token then
                ERROR('WRONG TOKEN');
            if "2factorSetup".Expire < CurrentDateTime then
                Error('Your token has expired');    
        end else
            ERROR('No VAILD USER');
        EXIT(true);
    end;
}
page 50101 "2 Factor Users"
{
    PageType = List;
    SourceTable = "2 Factor Users";
    UsageCategory=Lists;
    ApplicationArea=all;

    layout
    {
        area(content)
        {
            repeater(Group)
            {
                field("User ID";"User ID")
                {
                    
                }

                field("Secret Token";"Secret Token")
                {

                }

                field("Login Token";"Login Token")
                {

                }

                field(Expire;Expire)
                {

                }
            }
        }
        
    }

}

On the page “2 Factor Login” there is written some code that will throw an error if you do not enter the correct Token for your user,
or throw an error if your token has expired, and again there are many ways to accomplish the same result, this is just my take on a solution.
The last thing that you will need is a codeunit, that will be called on before your NAV opens, and in my case I have chosen to subscribe to codeunit 1
on the OnBeforeCompanyOpen Event.

codeunit 50100 "2FactorMgt"
{
    EventSubscriberInstance = StaticAutomatic;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::ApplicationManagement, 'OnBeforeCompanyOpen', '', true, true)]
    local procedure OnBeforeCompanyOpen()
    var
        "2FactorUsers": Record "2 Factor Users";
    begin
        if GuiAllowed then
            if "2FactorUsers".FindFirst then
                if Page.RunModal(50100) = Action::LookupOK then
                    Message('Your In')
                else
                    Error('Wrong Token');
    end;
}

What is important here is that you add the IF GUIALLOWED otherwise your web service will not work, since a web service does not support GUI.
And your done with your NAV code, if you work in extensions like my example, you can also add an XML file that will automatically
setup the web service, when you install the Extension.

<?xml version="1.0" encoding="utf-8"?>
<ExportedData>
    <TenantWebServiceCollection>
        <TenantWebService>
            <ObjectType>Page</ObjectType>
            <ObjectID>50101</ObjectID>
            <ServiceName>TwoFactor</ServiceName>
            <Published>true</Published>
        </TenantWebService>        
    </TenantWebServiceCollection>
</ExportedData>

Now all you have to do is setup your users in the new 2 factor users table, and your done:

On this page you must setup your NAV user with a secret Token, and that is it, do not worry about the other two fields for now, we will use these in
the next post.
Once you have setup a user in this table you will be meet with the following dialog when you start your NAV.


And that is it for this post, in the next post we will create our Master Service, which will allow us to generate a token, so stay tuned 🙂

Leave a Reply