Use ArcGIS token authentication

You can access services that have been secured using ArcGIS tokens in your ArcGIS Runtime SDK for .NET app by authenticating with the portal on which they are hosted. To authenticate, you must provide a valid user name and password. In return, you will receive a token that is included in all requests for secured content on the portal.

When working with any type of security, the IdentityManager is a vital component. See the Security topic for more information about working with the identity manager.

Note:

Accessing secured services has major differences between the three APIs that make up ArcGIS Runtime SDK for .NET (Desktop, Store, and Phone). Consult the documentation for each platform for which you need to work with secured content.

Prompt the user for login information

If an attempt is made to access secured content in your ArcGIS Runtime SDK for .NET Windows Store app, a login dialog automatically displays so the user can provide a user name and password. The login UI indicates the URL of the resource for which a login is required. The user is warned if incorrect login information is entered, and can continue trying to log in. If the login UI is dismissed, the map displays without the secured resource.

Login dialog box when accessing a secured service
Note:

The user can check the Remember my credentials check box to store credentials for this portal in the app's local storage for use between sessions of your app.

To verify what's happening in your app when access to a secured resource is attempted, review the HTTP traffic using a tool like Fiddler. Here's a summary of what you'll see:

  1. A request is made to a secured resource. The server responds with an unauthorized access error.
  2. Information about the portal that hosts the resource is requested. The response contains a tokenServicesUrl for obtaining ArcGIS tokens with an authorized user name and password.
  3. A user name and password are sent to the tokenServicesUrl. If the login is successful, the response contains a token (a long alphanumeric string).
  4. The request to the secured service is resent, this time with the token included in the URL query string. A successful response returns.
  5. All subsequent requests to the service (or any others hosted on the same portal) include the token.

Use a hard-coded login

If needed, provide a user name and password in your app code to authenticate for a secured resource you need to access. While this may sometimes be a valid use case and spares your user from interacting with a login dialog box, it's not very secure. A malicious user can retrieve login information by decompiling your app code or by viewing the HTTP traffic from your app.

In the following example, the IdentityManager is used to generate a credential for the specified portal. A user name and password are hard-coded into the call to GenerateCredentialAsync. The credential is then stored with the IdentityManager before a secured resource hosted by the portal is accessed.

try
{
    var opts = new GenerateTokenOptions();
    opts.TokenAuthenticationType = TokenAuthenticationType.ArcGISToken;

    // generate an ArcGIS token credential with a hard-coded user name and password
    // (if authentication fails, an ArcGISWebException will be thrown)
    var cred = await IdentityManager.Current.GenerateCredentialAsync(
                                 "http://serverapps10.esri.com/arcgis/rest/services/", 
                                 "user1", 
                                 "pass.word1", 
                                 opts);

    // add the credential to the IdentityManager (will be included in all requests to this portal)
    IdentityManager.Current.AddCredential(cred);

    // load a layer based on a secured resource on the portal
    var layer = new ArcGISDynamicMapServiceLayer(new Uri
                        ("http://serverapps10.esri.com/arcgis/rest/services/GulfLawrenceSecureUser1/MapServer"));
    await layer.InitializeAsync();

    // add the layer to the map and zoom to its extent
    this.MyMapView.Map.Layers.Add(layer);
    await this.MyMapView.SetViewAsync(layer.FullExtent);
}
catch (ArcGISWebException webExp)
{
    var msgBox = new MessageDialog("Unable to authenticate with portal: " + webExp.Message);
    msgBox.ShowAsync();
}
catch (Exception exp)
{
    var msgBox = new MessageDialog("Unable to load secured layer: " + exp.Message);
    msgBox.ShowAsync();
}

In the previous example, accessing the secured content is transparent to the user. A credential is generated and stored with the identity manager before an attempt is made to access data on the portal. With the request to the secured resource, the identity manager automatically includes the required credential (ArcGIS token). From the user's perspective, the layer loads like any unsecured layer would. Additionally, any other secured resources on the same portal to which the provided login has permission can also be accessed without having to authenticate again.

Use a challenge handler to generate a credential

When loading layers in your ArcGIS Runtime app, an ArcGISWebException is thrown when an attempt is made to access a secured resource if the identity manager does not have the required credential. Since you have the ability to catch such exceptions when creating or initializing a layer, you may want to respond by generating the required credential and trying to access the resource again. Fortunately, ArcGIS Runtime SDK for .NET provides a framework that allows you to respond to requests for secured content without having to directly handle the exceptions that are raised. To do so, create a challenge handler component.

Note:

Assigning a challenge handler removes the default one used by the identity manager. To disable challenges for secured content, for example, set IdentityManager.ChallengeHandler to null.

A challenge handler class must implement the IChallengeHandler interface, which defines a single method, CreateCredentialAsync. The signature for this method is shown in the following example.

public async Task<Credential> CreateCredentialAsync(CredentialRequestInfo requestInfo)

As you can see, the challenge handler is responsible for returning a Credential. The CredentialRequestInfo that is passed into CreateCredentialAsync can be used to discover the URI of the service.

The following example shows an implementation of CreateCredentialAsync that returns a credential for one of several portals using hard-coded login information.

private async Task<Credential> CreateHardCodedCredentialAsync(CredentialRequestInfo requestInfo)
{
    Credential cred = null;

    if (requestInfo.ServiceUri.Contains("serverapps10.esri.com"))
    {
        cred = await IdentityManager.Current.GenerateCredentialAsync(
                            requestInfo.ServiceUri,
                            "user1",
                            "pass.word1");
    }
    else if (requestInfo.ServiceUri.Contains("server6.esri.com"))
    {
        cred = await IdentityManager.Current.GenerateCredentialAsync(
                            requestInfo.ServiceUri,
                            "user1",
                            "user1");
    }
    else if (requestInfo.ServiceUri.Contains("my.server.com"))
    {
        cred = await IdentityManager.Current.GenerateCredentialAsync(
                            requestInfo.ServiceUri,
                            "Ted",
                            "Im.Ted.Be11");
    }

    return cred;
}

To put this code into action, it must be a method of a class that implements IChallengeHandler, which must be assigned to the IdentityManager.ChallengeHandler property. The following example creates a new challenge handler and sets the ChallengeHandler property.

var myChallenger = new MyChallengeHandler(); // custom class that implements IChallengeHander
IdentityManager.Current.ChallengeHandler = myChallenger;

As a shortcut, you can create a new challenge handler using the Esri.ArcGISRuntime.Security.ChallengeHandler utility class and passing in a function with the proper signature for the IChallengeHandler.CreateCredentialAsync method. The following example shows creating a new challenge handler using this utility class.

var myChallenger = new Esri.ArcGISRuntime.Security.ChallengeHandler
                                                       (this.CreateHardCodedCredentialAsync);
IdentityManager.Current.ChallengeHandler = myChallenger;

Once the ChallengeHandler property is assigned, attempts to access secured resources will be funnelled through your challenge handler (specifically, through the IChallengeHandler.CreateCredentialAsync method).

Caution:

Specifying your challenge handler disables the default behavior that prompts for a user name and password for secured services. If using the challenge handler illustrated above, for example, you would not be prompted for a user name and password for secured resources hosted on a portal other than the three for which credentials are provided.