Skip to content

Handling authentication issues

Brent Moberly edited this page Jan 12, 2015 · 1 revision

Overview

This tutorial will show you how to use error branches to intervene when client issues occur. Here, we will be adding a "retry" dialog to the authentication process that we have been refining in the last two tutorials. This will allow users to re-enter their credentials if they type something wrong, etc.

Requirements

In order to complete this tutorial, you will need the following:

  • A web-server to host your content files
  • An operational InCert server
  • An xml or text editor

Setup

This tutorial assumes that you have created the tutorial, Refining the authentication dialog, and have a version of the engine that will start and attempt to contact your web-server.

Using branches to group tasks

Up to this point, we have just been editing two branches, the local initialization branch and the remote main branch. It's possible, though, to create any number of sub-branches. One advantage to doing this is that it allows us to encapsulate various processes into corresponding branches. This not only makes the xml a little more readable, but it facilitates handling issues when they occur.

Currently, our authentication process consists of 6 or 7 tasks. It's certainly possible to implement error handling for each of these tasks, but it's much easier to group all of these tasks into a single authentication branch, and just implement error handling on the branch level. Let's do that now.

  1. Add the following to the Branches block of tasklist.xml
<TaskBranch name="authenticate">
</TaskBranch>

We'll add content in the next step, but, for now, this is all that you need to do to initialize a new task branch. The name attribute is required, as this serves as the key for the branch in the engine's branch collection. Task branch names are case sensitive, so the engine will treat a branch named Authenticate as different from one named authenticate. If multiple branches have the same name, the branch that is loaded last will replace those loaded before it.

  1. Now, let's move all of our authentication tasks from the main branch to our new authentication branch.
<TaskBranch name="authenticate">
  <UserInterface.ShowBorderedBannerModal>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <Banner>LoginBanner</Banner>
    </Properties>
  </UserInterface.ShowBorderedBannerModal>
  <Settings.SetSettingText>
    <Properties>
      <Setter key="authenticating">true</Setter>
    </Properties>
  </Settings.SetSettingText>
  <UserInterface.DisableAllBannerDialogControls>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ExcludeControlKey>HelpButton</ExcludeControlKey>
      <ExcludeControlKey>AuthenticatingMessage</ExcludeControlKey>
    </Properties>
  </UserInterface.DisableAllBannerDialogControls>
  <UserInterface.CollapseBannerControl>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ControlKey>Instructions</ControlKey>
    </Properties>
  </UserInterface.CollapseBannerControl>
  <UserInterface.ShowBannerControl>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ControlKey>AuthenticatingMessage</ControlKey>
    </Properties>
  </UserInterface.ShowBannerControl>
  <UserInterface.StartMessageTimer>
    <Properties>
      <SettingKey>AuthenticatingMessage</SettingKey>
    </Properties>
  </UserInterface.StartMessageTimer>
  <Authentication.AuthenticateUser minimumTaskTime="10">
    <Properties>
      <UsernameKey>username</UsernameKey>
      <PassphraseKey>passphrase</PassphraseKey>
      <Credential2Key>credential2</Credential2Key>
      <Credential3Key>credential3</Credential3Key>
      <Credential4Key>credential4</Credential4Key>
      <CertificateProvider>incommontest.org</CertificateProvider>
    </Properties>
  </Authentication.AuthenticateUser>
</TaskBranch>
  1. Now, add a Control.ReturnBranchResult to the end of the main task branch:
<Control.ReturnBranchResult>
  <Properties>
    <Branch>authenticate</Branch>
  </Properties>
</Control.ReturnBranchResult>

This xml block will tell the engine to run the authentication branch and process the result. Here, the Branch property identifies the branch to run. Again, the key is the name of the branch as defined by the branch's name attribute.

  1. Your tasklist.xml file should be as follows:
<Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://incert.incommon.org/schemas ../Schemas/tasklist.xsd">
  <Branches>
    <RoleBranch name="main" role="Remote" roleMode="Normal">
      <Control.GetContentFromEndpoint>
        <Properties>
          <ContentName>banners.xml</ContentName>
        </Properties>
      </Control.GetContentFromEndpoint>
      <UserInterface.StopMessageTimer>
        <Properties>
          <SettingKey>Splash screen progress text</SettingKey>
        </Properties>
      </UserInterface.StopMessageTimer>
      <UserInterface.HideDialog>
        <Properties>
          <Dialog>Splash screen dialog</Dialog>
        </Properties>
      </UserInterface.HideDialog>
      <Control.ReturnBranchResult>
        <Properties>
          <Branch>authenticate</Branch>
        </Properties>
      </Control.ReturnBranchResult>
    </RoleBranch>
  
    <TaskBranch name="authenticate">
      <UserInterface.ShowBorderedBannerModal>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <Banner>LoginBanner</Banner>
        </Properties>
      </UserInterface.ShowBorderedBannerModal>
      <Settings.SetSettingText>
        <Properties>
          <Setter key="authenticating">true</Setter>
        </Properties>
      </Settings.SetSettingText>
      <UserInterface.DisableAllBannerDialogControls>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <ExcludeControlKey>HelpButton</ExcludeControlKey>
          <ExcludeControlKey>AuthenticatingMessage</ExcludeControlKey>
        </Properties>
      </UserInterface.DisableAllBannerDialogControls>
      <UserInterface.CollapseBannerControl>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <ControlKey>Instructions</ControlKey>
        </Properties>
      </UserInterface.CollapseBannerControl>
      <UserInterface.ShowBannerControl>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <ControlKey>AuthenticatingMessage</ControlKey>
        </Properties>
      </UserInterface.ShowBannerControl>
      <UserInterface.StartMessageTimer>
        <Properties>
          <SettingKey>AuthenticatingMessage</SettingKey>
        </Properties>
      </UserInterface.StartMessageTimer>
      <Authentication.AuthenticateUser minimumTaskTime="10">
        <Properties>
          <UsernameKey>username</UsernameKey>
          <PassphraseKey>passphrase</PassphraseKey>
          <Credential2Key>credential2</Credential2Key>
          <Credential3Key>credential3</Credential3Key>
          <Credential4Key>credential4</Credential4Key>
          <CertificateProvider>incommontest.org</CertificateProvider>
        </Properties>
      </Authentication.AuthenticateUser>
    </TaskBranch>
  </Branches>
</Content>
  1. Upload tasklist.xml to your server and run engine.exe. Things should work exactly like before.

  2. Now let's add an error-handling branch for our authentication process. This is the branch that should be called if our authentication branch returns an issue. Add the following to the bottom of the Branches block of tasklist.xml:

<TaskBranch name="handle authentication issues">
  <Control.PreserveLastResult>
    <Properties>
      <SettingKey>generic issue retry banner stored result</SettingKey>
    </Properties>
  </Control.PreserveLastResult>
  <UserInterface.StopMessageTimer>
    <Properties>
      <SettingKey>AuthenticatingMessage</SettingKey>
    </Properties>
  </UserInterface.StopMessageTimer>
  <Settings.SetSettingText>
    <Properties>
      <Setter key="generic issue retry banner title">Authentication Failed - Retry?</Setter>
      <Setter key="generic issue retry banner description">!ApplicationTitle! could not verify your network credentials.</Setter>
      <Setter key="generic issue retry banner retry cancel text">Click Retry to try again or Cancel to exit.</Setter>
    </Properties>
  </Settings.SetSettingText>
  <UserInterface.ShowChildBannerModal>
    <Properties>
      <ParentDialog>Main dialog</ParentDialog>
      <ChildDialog>notification dialog manager</ChildDialog>
      <Banner>Generic issue retry banner</Banner>
    </Properties>
  </UserInterface.ShowChildBannerModal>
</TaskBranch>

Here, we're using the predefined banner, Generic issue retry banner, to prompt the user for action. After storing the result that was passed in from the engine, this branch stops the AuthenticatingMessage timer, sets the settings that determine the retry banner's title and content and then shows the banner.

The Generic issue retry banner is configured by setting the following settings: generic issue retry banner stored result stores the result (here the issue result) that was passed into the branch from the engine, and generic issue retry banner title, generic issue retry banner description, and generic issue retry banner retry cancel text determine the banner's title and text.

If users click 'Retry' on the Generic issue retry banner dialog, the dialog will return a ControlResults.RepeatBranchingTaskResult, which will cause the branch that raised an issue (here, our authentication branch) to repeat.

  1. Now, we need to wire-in our error-handling branch. To do this, add an errorBranch attribute to the Control.ReturnBranchResult task that we added in step 3:
<Control.ReturnBranchResult errorBranch="handle authentication issues">
  <Properties>
    <Branch>authenticate</Branch>
  </Properties>
</Control.ReturnBranchResult>

You can add an errorBranch attribute to any task. If this attribute it present, the engine will execute the referenced branch if the task in question returns an issue result. The engine will then return the result of the error branch instead of the original issue result.

In the case of our authentication process, for example, if the authentication branch returns an issue result, the engine will run our handle authentication issues branch. This branch will either return ControlResults.RepeatBranchingTaskResult, which will cause the authentication branch to repeat, or the original issue passed to the error branch, which will cause the engine to raise its error dialog and exit.

  1. Your tasklist.xml should now be as follows:
<Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://incert.incommon.org/schemas ../Schemas/tasklist.xsd">
  <Branches>
    <RoleBranch name="main" role="Remote" roleMode="Normal">
      <Control.GetContentFromEndpoint>
        <Properties>
          <ContentName>banners.xml</ContentName>
        </Properties>
      </Control.GetContentFromEndpoint>
      <UserInterface.StopMessageTimer>
        <Properties>
          <SettingKey>Splash screen progress text</SettingKey>
        </Properties>
      </UserInterface.StopMessageTimer>
      <UserInterface.HideDialog>
        <Properties>
          <Dialog>Splash screen dialog</Dialog>
        </Properties>
      </UserInterface.HideDialog>
      <Control.ReturnBranchResult errorBranch="handle authentication issues">
        <Properties>
          <Branch>authenticate</Branch>
        </Properties>
      </Control.ReturnBranchResult>
    </RoleBranch>

    <TaskBranch name="authenticate">
      <UserInterface.ShowBorderedBannerModal>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <Banner>LoginBanner</Banner>
        </Properties>
      </UserInterface.ShowBorderedBannerModal>
      <Settings.SetSettingText>
        <Properties>
          <Setter key="authenticating">true</Setter>
        </Properties>
      </Settings.SetSettingText>
      <UserInterface.DisableAllBannerDialogControls>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <ExcludeControlKey>HelpButton</ExcludeControlKey>
          <ExcludeControlKey>AuthenticatingMessage</ExcludeControlKey>
        </Properties>
      </UserInterface.DisableAllBannerDialogControls>
      <UserInterface.CollapseBannerControl>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <ControlKey>Instructions</ControlKey>
        </Properties>
      </UserInterface.CollapseBannerControl>
      <UserInterface.ShowBannerControl>
        <Properties>
          <Dialog>Main dialog</Dialog>
          <ControlKey>AuthenticatingMessage</ControlKey>
        </Properties>
      </UserInterface.ShowBannerControl>
      <UserInterface.StartMessageTimer>
        <Properties>
          <SettingKey>AuthenticatingMessage</SettingKey>
        </Properties>
      </UserInterface.StartMessageTimer>
      <Authentication.AuthenticateUser minimumTaskTime="10">
        <Properties>
          <UsernameKey>username</UsernameKey>
          <PassphraseKey>passphrase</PassphraseKey>
          <Credential2Key>credential2</Credential2Key>
          <Credential3Key>credential3</Credential3Key>
          <Credential4Key>credential4</Credential4Key>
          <CertificateProvider>incommontest.org</CertificateProvider>
        </Properties>
      </Authentication.AuthenticateUser>
    </TaskBranch>

    <TaskBranch name="handle authentication issues">
      <Control.PreserveLastResult>
        <Properties>
          <SettingKey>generic issue retry banner stored result</SettingKey>
        </Properties>
      </Control.PreserveLastResult>
      <UserInterface.StopMessageTimer>
        <Properties>
          <SettingKey>AuthenticatingMessage</SettingKey>
        </Properties>
      </UserInterface.StopMessageTimer>
      <Settings.SetSettingText>
        <Properties>
          <Setter key="generic issue retry banner title">Authentication Failed - Retry?</Setter>
          <Setter key="generic issue retry banner description">!ApplicationTitle! could not verify your network credentials.</Setter>
          <Setter key="generic issue retry banner retry cancel text">Click Retry to try again or Cancel to exit.</Setter>
        </Properties>
      </Settings.SetSettingText>
      <UserInterface.ShowChildBannerModal>
        <Properties>
          <ParentDialog>Main dialog</ParentDialog>
          <ChildDialog>notification dialog manager</ChildDialog>
          <Banner>Generic issue retry banner</Banner>
        </Properties>
      </UserInterface.ShowChildBannerModal>
    </TaskBranch>
  </Branches>
</Content>
  1. Upload tasklist.xml to your server and run engine.exe. If you enter invalid credentials, you should now be prompted to retry the authentication process:

retry authorization dialog

If you hit cancel, or close the dialog, the engine should raise its error dialog:

authorization failed error

But if you hit retry, the engine should return you to the authentication dialog:

retrying authentication

Things aren't perfect here, though. The instructions block is missing and the "Login" button will not enable. This is because we collapsed the instructions text and set the setting "authenticating" to true after the user initially clicked "Login."

  1. To fix these things, modify the authenticate branch to 'reset' the authentication dialog before it is shown:
<TaskBranch name="authenticate">
  <UserInterface.StopMessageTimer>
    <Conditions.Any>
      <UserInterface.TimedMessageExists key="AuthenticatingMessage"/>
    </Conditions.Any>
    <Properties>
      <SettingKey>AuthenticatingMessage</SettingKey>
    </Properties>
  </UserInterface.StopMessageTimer>
  <UserInterface.HideBannerControl>
    <Conditions.Any>
      <UserInterface.BannerControlExists key="AuthenticatingMessage" dialog="Main dialog"/>
    </Conditions.Any>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ControlKey>AuthenticatingMessage</ControlKey>
    </Properties>
  </UserInterface.HideBannerControl>
  <UserInterface.ShowBannerControl>
    <Conditions.Any>
      <UserInterface.BannerControlExists key="Instructions" dialog="Main dialog"/>
    </Conditions.Any>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ControlKey>Instructions</ControlKey>
    </Properties>
  </UserInterface.ShowBannerControl>
  <Settings.SetSettingText>
    <Properties>
      <Setter key="authenticating">false</Setter>
    </Properties>
  </Settings.SetSettingText>
  <UserInterface.ShowBorderedBannerModal>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <Banner>LoginBanner</Banner>
    </Properties>
  </UserInterface.ShowBorderedBannerModal>
  <Settings.SetSettingText>
    <Properties>
      <Setter key="authenticating">true</Setter>
    </Properties>
  </Settings.SetSettingText>
  <UserInterface.DisableAllBannerDialogControls>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ExcludeControlKey>HelpButton</ExcludeControlKey>
      <ExcludeControlKey>AuthenticatingMessage</ExcludeControlKey>
    </Properties>
  </UserInterface.DisableAllBannerDialogControls>
  <UserInterface.CollapseBannerControl>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ControlKey>Instructions</ControlKey>
    </Properties>
  </UserInterface.CollapseBannerControl>
  <UserInterface.ShowBannerControl>
    <Properties>
      <Dialog>Main dialog</Dialog>
      <ControlKey>AuthenticatingMessage</ControlKey>
    </Properties>
  </UserInterface.ShowBannerControl>
  <UserInterface.StartMessageTimer>
    <Properties>
      <SettingKey>AuthenticatingMessage</SettingKey>
    </Properties>
  </UserInterface.StartMessageTimer>
  <Authentication.AuthenticateUser minimumTaskTime="10">
    <Properties>
      <UsernameKey>username</UsernameKey>
      <PassphraseKey>passphrase</PassphraseKey>
      <Credential2Key>credential2</Credential2Key>
      <Credential3Key>credential3</Credential3Key>
      <Credential4Key>credential4</Credential4Key>
      <CertificateProvider>incommontest.org</CertificateProvider>
    </Properties>
  </Authentication.AuthenticateUser>
</TaskBranch>

Here, we've added four tasks to the start of our authenticating branch. The first, UserInterface.StopMessageTimer stops the authenticating message timer if it exists; the next two, UserInterface.HideBannerControl and UserInterface.ShowBannerControl hide the authenticating paragraph and show the instruction paragraph; the last task, Settings.SetSettingText sets the authenticating temporary setting to false.

Note that the UserInterface.StopMessageTimer, UserInterface.HideBannerControl, and UserInterface.ShowBannerControl task blocks all specify conditions to test whether the targets are defined. We do this because these elements are only defined after LoginBanner is loaded for the first time. None of these tasks will fail if the specified elements are not yet defined, but many will raise warnings in the event log. Hence the conditions.

  1. Upload tasklist.xml to your server and run the engine again. The authentication dialog should now behave correctly if users click 'Retry.'

retrying authentication

Conclusion

Our authentication dialog is now, for the most part, complete. It activates correctly, displays the correct processing messages, and allows users to retry in the case of an authentication issue. There are still some polishing to be done, though. It would be nice, for example, if the engine would remember the user's username. We'll cover this and some other small improvements in the next tutorial.