Certificate authentication with PKI

View inUWPWPFWinUIView on GitHubSample viewer app

Access secured portals using a certificate.

Image of certificate authentication with PKI

Use case

PKI (Public Key Infrastructure) is a certificate authentication method to secure resources without requiring users to remember passwords. Government agencies commonly issue smart cards using PKI to access computer systems.

How to use the sample

NOTE: You must provide your own ArcGIS Portal with PKI authentication configured.

Provide a URL to a PKI-enabled server, then use the certificate selection UI to select an appropriate certificate for that server.

How it works

  1. Create the X.509 certificate store, referring to the user's certificates.
  2. Open the certificate store in read-only mode.
  3. Find all certificates that are currently valid.
  4. Display the Windows certificate selection UI to choose from the returned certificates.
  5. Create the credential with the chosen certificate.
  6. Create the Portal, explicitly passing in the credential that was created.

Relevant API

  • CertificateCredential

Additional information

ArcGIS Enterprise requires special configuration to enable support for PKI. See Using Windows Active Directory and PKI to secure access to your portal and Use LDAP and PKI to secure access to your portal in Portal for ArcGIS.

Tags

authentication, certificate, login, passwordless, PKI, smartcard, store, X509

Sample Code

CertificateAuthenticationWithPKI.xaml.csCertificateAuthenticationWithPKI.xaml.csCertificateAuthenticationWithPKI.xaml
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Copyright 2019 Esri.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
// language governing permissions and limitations under the License.

using Esri.ArcGISRuntime.Portal;
using Esri.ArcGISRuntime.Security;
using System;
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using System.Windows;

namespace ArcGIS.WPF.Samples.CertificateAuthenticationWithPKI
{
    [ArcGIS.Samples.Shared.Attributes.Sample(
        name: "Certificate authentication with PKI",
        category: "Security",
        description: "Access secured portals using a certificate.",
        instructions: "> **NOTE**: You must provide your own ArcGIS Portal with PKI authentication configured.",
        tags: new[] { "PKI", "X509", "authentication", "certificate", "login", "passwordless", "smartcard", "store" })]
    [ArcGIS.Samples.Shared.Attributes.OfflineData()]
    public partial class CertificateAuthenticationWithPKI
    {
        private string _serverUrl = "";

        public CertificateAuthenticationWithPKI()
        {
            InitializeComponent();
        }

        private async Task<Credential> CreateCertCredential(CredentialRequestInfo info)
        {
            // Handle challenges for a secured resource by prompting for a client certificate.
            Esri.ArcGISRuntime.Security.Credential credential = null;

            try
            {
                // Create an X509 store for reading certificates for the current user.
                var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);

                // Open the store in read-only mode.
                store.Open(OpenFlags.ReadOnly);

                // Get a list of certificates that are currently valid.
                X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByTimeValid, DateTime.Now, true);

                // Prompt the user to select a certificate using the built-in certificate selection UI.
                var selection = X509Certificate2UI.SelectFromCollection(certificates, "Select Certificate",
                    "Select the certificate to use for authentication.", X509SelectionFlag.SingleSelection);

                // Make sure the user chose a certificate.
                if (selection.Count > 0)
                {
                    // Create a new CertificateCredential using the chosen certificate.
                    credential = new CertificateCredential(new Uri(_serverUrl), selection[0]);
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
            }

            // Return the CertificateCredential for the secured portal.
            return await Task.FromResult(credential);
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Store the server url for later reference.
                _serverUrl = PortalUrlTextbox.Text;

                // Configure the challenge handler.
                AuthenticationManager.Current.ChallengeHandler = new ChallengeHandler(CreateCertCredential);

                // Create the portal.
                ArcGISPortal portal = await ArcGISPortal.CreateAsync(new Uri(_serverUrl));

                // Update the UI with the logged in user.
                LoggedInUserName.Text = portal.User.FullName;
            }
            catch (HttpRequestException ex)
            {
                if (ex.Message.Contains("404"))
                {
                    MessageBox.Show("404: Not Found");
                }
                else if (ex.Message.Contains("403"))
                {
                    MessageBox.Show("403: Not authorized; did you use the right certificate?");
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine(ex);
                    MessageBox.Show("Couldn't authenticate. See debug output for details.");
                }
            }
            catch (UriFormatException)
            {
                MessageBox.Show("Couldn't authenticate. Enter a valid URL first.");
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex);
                MessageBox.Show("Couldn't authenticate. See debug output for details.");
            }
        }
    }
}

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.