Generic Provider Connection

Introduction


Generic Provider Authentication Connection is a plug-in that allows clients to create their own input view, error view, and the handler to validate credentials. Safewhere*Identify sends a set of key-value pairs collected from the views as well as some other connection settings to the handler, receives the result, and processes it accordingly.

The configuration settings offered by this Authentication Connection type are:

  • Second-factor Authentication Connection: If you want this WS-Federation Authentication Connection to have a second factor, you must choose this second factor among the different Authentication Connections that have been set up in the system. This includes all the One-Time Password Connections.
  • Two-factor identities condition: When using two different Authentication Connections together (which is basically what you are doing when setting up two-factor authentication), the two might try to Safewhere*Identify the incoming user based on two different identity bearing claims. This drop-down is activated when a user has chosen that the connection will have a second factor. Options in the drop-down are:
    • Use the first identity: The system disregards the “identity bearing claim” value of the second factor and just focuses on identifying the user based on the first one.
    • Two identities must be the same: The user is not allowed to log in unless the identity of the user for the first factor is identical to that of the second factor.
  • Use as second factor only: If you just want the Authentication Connection to be used as the second factor for other connections and not have it offered to users as a primary connection option, this check box must be enabled.
  • Ignored by second factor roles claim type: If there are subsets of users that you will allow to log in without also having to authenticate using the second factor, you must specify whom these users are based on a rule. The rule states that any users who have a specific value for a specific claim type will be excluded from the second factor. This setting specifies which claim will be tested. The setting below (“Ignored by second factor roles”) states which roles will be ignored. Safewhere*Identify will search in both the received assertion and the local store.
  • Ignored by second factor roles: This setting specifies the list of roles (claims type values) that a user must have at least one of in order to avoid having to authenticate via the second factor. You should use colons as separators for these roles.
  • Ignore roles check: If you do not want to let anyone log in without also authenticating via the second factor (in effect ignoring the preceding two parameters), you should enable this check box.
  • Federated session lifetime (minutes): This setting specifies how long a federated session, which is established when a user uses this Authentication Connection to log in, will last.
  • Enabled for mobile use: This setting should be enabled if you also want to allow mobile users to authenticate using this connection.
  • IP-based filter for Home Realm Discovery: This setting specifies IP addresses of RPs for the filter. An IP address consists of four sections of numbers between 1 and 255. The four sections of numbers are separated by periods. An IP range consists of two IP addresses separated by a dash. You can enter multiple IP addresses or IP ranges by separating them with semicolons, for example, 192.168.1.1;192.168.1.2;192.168.0.0-192.168.1.255.
  • Credentials validator: This drop-down provides a list of external DLLs. Choose the one that should be used to validate credentials. Safewhere*Identify then sends credentials collected from the "Login View" as well as “Key-value pairs” (as specified in the “Key-value pairs to pass the external provider” setting) to this DLL.
  • Login view name: This setting specifies the name of the view that Safewhere*Identify shows to the user to collect credentials.
  • Error view name: This setting specifies the name of the view that Safewhere*Identify shows to the user when an error/exception happens or when the maximum allowed attempts are exceeded.
  • Error view URL: Similar to the above, but this time it is a URL. Either Error view name or Error view URL must have a value. If both have values, the Error view name takes precedence.
  • Key-value pairs to pass to the external provider: This setting specifies sets of static key-value pairs that Safewhere*Identify passes to the external provider every time it calls the method to validate a user’s credentials. Multiple pairs can be added.

There is a whole range of fields that will help you set up a two-factor authentication process, which are explained in the above list:

  • Use as second factor only.
  • Ignored by second factor roles claim type.
  • Ignored by second factor roles.
  • Ignore roles check.

Case Example for using Generic Provider


DummyGenericProvideris a demo generic provider for external authentication. It validates a user’s credentials against a database. First, we need to set up a database for it:

  • Create a database named DummyGenericProvider
  • Execute the following script to create users for testing:

It is assumed that Safewhere*Identify was installed in the default folder and that the tenant name is identify1.

Use the Identify*Admin connections page to create a new Generic Provider Authentication Connection with the following settings:

  • Credentials validator: select the ExternalSamples from the dropdown list, named Safewhere.External.Samples.DummyGenericValidatorUsernamePassword, Safewhere.External.Samples
  • Login view name: Set the value to  DummyGenericUsernamePasswordLogin
  • Error view name: Set the value to DummyGenericUsernamePasswordError
  • Error view url: Leave it empty or set the value to redirected URL if Error view name is empty.
  • Add key/value to allow the ExternalSamples handler to connect to the user’s table created above:
    • Key = “ConnectionString” (case sensitive)
    • Value = “Server=localhost; Database=DummyGenericProvider; Trusted_Connection=True; MultipleActiveResultSets=true;” (If using local SQL Server, use localhost; otherwise, change to SQL Server Name)

Clients are also able to allow users to return to the Selector page to select another Authentication Connection when at the login page by adding the section @Html.Partial("ReturnToLoginSelectorLink") to their login view.

The Generic Provider Login page using ExternalSamples will look as follows:

Generic Connection 1

Technical Information for Implementing External Handlers


The following chapter explains the technical requirements for implementing the external handlers.

General Requirements

  • Implementing a custom generic provider for external authentication requires the following steps:
    • Implement the IGenericCredentialsProvider.
    • Create a login view and an error view.
    • Add text resources if needed.

The interfaces

The Result Code Enumeration

  • Define all the possible results of a login.
  • A result can contain more than one state; for example, it can be UserDisabled | UserLocked.
  • The Success state cannot be combined with any other states.

The Validator Interface

  • The interface has a method called Validate, which receives all the necessary parameters and returns a result object.
  • Parameters:
    • input: A dictionary of key-value pairs. It contains all the static key-value settings of a connection and all the input values collected from the login view. Please note that the keys are not case sensitive.
    • logWriter: A logging object that the external implementation can use to log to Safewhere*Identify’s event log.

The Result Model Class

  • The result object contains three properties:
    • UserIdentity: Of all the key-value pairs that Safewhere*Identify passes to an external provider, there should always be one that is the user’s identity. It can, for example, be a username, email, or CPR. The external provider is responsible for setting that value to the UserIdentity property so that Safewhere*Identify can use it to build the identity bearing claim.
    • ResultCode: An instance of the result code enumeration mentioned above.
    • ExternalErrorMessages: A list of error messages that the external implementation wants to pass to Safewhere*Identify.

View’s Model

  • The object containing the data that Safewhere*Identify wants to pass to the login view.
  • The idea here is that Safewhere*Identify tries to pass as much information as possible to the custom login view. The view itself decides what and how the error messages are shown.

Processing flow

The processing flow is:

  1. A generic provider connection is selected.
  2. A custom login view is shown to a user.
  3. The user enters all the required fields and submits.
  4. Safewhere*Identify collects all the entered values whose keys are names of the controls, combines them with all the static key-value pairs, and passes them to the configured external handler.
  5. The external handler returns a result object to Safewhere*Identify.
  6. Safewhere*Identify checks the result object:
    1. If the result code is Success, it authenticates the user.
    2. If the result code is a combination of Success and the code “invalid state,” it redirects to the error view.
    3. If the result code is not Success:
      1. For each invalid state it contains, look up the corresponding error message and add it to the ErrorMessages list.
      2. Copy the ExternalErrorMessages list from the result object to the model object.
  7. Initialize all the other properties of the model object.
    1. Show the login view.
    2. The login view will decide what and how error messages will be shown to the user.

Localization

  • The plug-in follows the standard localization design that other plug-ins use.
  • The external DLL needs its own text resources. These text resources are also used for the custom views.
  • Safewhere*Identify’s text resource framework is built so that the default language is changeable. In addition, it is also possible to override default texts with some user-specific ones. The point is that these features didn’t come for free. In other words, a piece of magic code is required. Meanwhile, because we assume that external DLLs are meant only for a specific organization that already knows what default language it wants and also controls the text resource files completely, it means we have chosen to use a simpler text resource model for external DLLs:
    • Add some resource files to the project.
    • Text resource files’ properties must be set correctly:
      • Build Action: None
      • Copy to output: Do not copy
      • Custom tool: GlobalResourceProxyGenerator
    • Upon deploying the DLL, also copy the resource files to appropriate folders.
  • It is recommended that when logging messages to the event log, the external DLL should hard-code messages in the language of its choice instead of reading from text resources. Otherwise, messages may be logged in the user’s preferred language.

Event ids

  • Event IDs that are used by Safewhere*Identify for the new plug-in:
    • 4810: GenericProviderCommonError.
    • 4811: GenericProviderCouldNotLoadExternalProviderError.
    • 4812: GenericProviderUnhandledExceptionFromExternalProviderError.
    • 4813: GenericProviderNameClaimIsEmptyOrCanNotParsed.
  • External providers are encouraged to use event IDs between 4830 and 4899 for their errors.