Visual Basic (Declaration) | |
---|---|
Public Property ClientCertificate As X509Certificate |
C# | |
---|---|
public X509Certificate ClientCertificate {get; set;} |
A client certificate is an electronic document which uses a digital signature to bind a public key with an identity. A client certificate is used to verify that a public key belongs to an individual or an organization. When a client certificate is valid, access to secured content over the https:// is enabled. Client certificates fall under the technology umbrella known as a Public-Key Infrastructure (PKI). PKI is a large complex body of standards, policies, protocols, and practices that are beyond the scope this documentation. The following Microsoft document should give the developer a starting point to understand PKI: Public Key Infrastructure.
ArcGIS Server version 10.1 and higher has the ability to leverage PKI solutions in 'Commercial Off the Shelf' (COTS) Web servers such as: Microsoft Internet Information Server (IIS), Oracle WebLogic, IBM WebSphere, etc. through the use of the ArcGIS Web Adaptor. The requirements for using PKI in ArcGIS Server include:
- The ArcGIS Web Adaptor must be setup as the gateway to ArcGIS Server.
- The Web Server hosting the ArcGIS Web Adaptor must be configured to require client certificates for user authentication.
- ArcGIS Server Site must be configured to: (a) Delegate user authentication to the Web Tier and (b) Use an identity store (LDAP, Windows Active Directory, etc.) supported by the Web Server.
When a request is made for a resource on ArcGIS Server, the Web Server will authenticate the user by validating the client certificate provided. The request (along with the user name) is then forwarded to ArcGIS Server via the Web Adaptor. ArcGIS Server will verify that the specified user has access to the requested resource before sending back the appropriate response. For more information on using PKI techniques to set up and use client certificates, see the ArcGIS Server documentation.
The ArcGIS Runtime for WPF requires supplying a valid Microsoft System.Security.Cryptography.X509Certificates.X509Certificate object as the .ClientCertificate Property in order to gain access to a secured (https://) ArcGIS Server web service based upon PKI. The Microsoft System.Security.Cryptography.X509Certificates Namespace API documentation provides a starting point for developers to learn how to programmatically access X509Certificate objects. If no client certificates have been set up on a client machine and a user tries to access using an X509Certificate from your custom ArcGIS WPF application, a Windows Security dialog stating "No certificate available. No certificates meet the application. Click OK to continue" will appear:
Whenever an ArcGIS Runtime for WPF based application uses PKI to secure web services, it is important that error checking be added to the application to ensure that the correct X509Certificate is used to access those secured web services. If a user of your ArcGIS WPF client application provides/uses an X509Certificate that is not accepted by the PKI security set up on the ArcGIS Server machine, then an error will be thrown. The following are a couple of different error messages that could occur:
"Error initializing layer: The remote server returned an error: (403) Forbidden.":
"Error initializing layer: The remote server returned an error: (401) Unauthorized.":
Depending on the particular ArcGIS Runtime for WPF object that is used, the developer will need to write code in the appropriate error handling event. For example: an ArcGISDynmaicMapServiceLayer should have error trapping code in the InitializationFailed Event; a QueryTask should have error trapping code in the Failed Event, a PrintTask should have error trapping code in the ExecuteCompleted Event (via the PrintEventArgs), etc.
The .ClientCertificate Property has been added to numerous ArcGIS Runtime for WPF objects. Accessing and using an X509Certificate is basically the same for each of the ArcGIS Runtime for WPF objects with a .ClientCertificate Property. There are code examples of using the X509Certificate in the DynamicMapServiceLayer.ClientCertificate Property, ArcGISTiledMapServiceLayer.ClientCertificate Property, Printing.PrintTask.ClientCertificate Property (code-behind only options) and FeatureLayer.ClientCertificate Property (Model-View-View-Model (MVVM) pattern using XAML and code-behind). Remember the key to accessing a PKI based secured ArcGIS Server web service is to first provide the appropriate .ClientCertificate Property credentials during construction of the object and prior to using (i.e Set/Write) any of the other properties/methods of the ArcGIS Runtime for WPF object, otherwise an error accessing that object will result.
Property Value
The client certificate used for authentication.How to use:
A Model-View-View-Model (MVVM) approach to loading an https:// secured FeatureLayer using PKI is displayed. The .ClientCertificate Property is used to consume a X509Certificate. It is required to edit the XAML and specify your https:// Url for the secured FeatureLayer.
NOTE: It is assumed that your organization already has an ArcGIS Server set up using PKI security protocols. Additionally, a crediential certificate has been set up for the user login that will be testing this example code.
The XAML code in this example is used in conjunction with the code-behind (C# or VB.NET) to demonstrate the functionality.
The following screen shot corresponds to the code example in this page.
XAML | Copy Code |
---|---|
<Grid x:Name="LayoutRoot"> <!-- Use XAML Resources to hold a MVVM strategy for accessing a PKI secured ArcGIS FeatureLayer. --> <!-- NOTE: Don't forget to add the xml namespace for 'local' to match your client application's name at the top of the x:Class declaration. Ex: xmlns:local="clr-namespace:WpfApplication1"--> <Grid.Resources> <local:MyViewModel x:Key="MyViewModel"/> </Grid.Resources> <!-- Add a Map Control. --> <esri:Map x:Name="MyMap" Height="288" VerticalAlignment="Bottom"> <!-- Set the default Extent and SpatialReference of the Map Control. --> <esri:Map.Extent > <esri:Envelope XMin="-178.21" YMin="18.92" XMax="-66.96" YMax="71.40"> <esri:Envelope.SpatialReference> <esri:SpatialReference WKID="4269"/> </esri:Envelope.SpatialReference> </esri:Envelope> </esri:Map.Extent> <esri:LayerCollection> <!-- Add a secured FeatureLayer. The .InitializationFailed Event is wired up in code-behind to provide feedback if something is wrong accessing the secured web service. The .ClientCertificate Property using XAML binding to consume the MVVM class called 'MyMiewModel' in the code-behind. A .Where clause is added to the FeatureLayer to restrict the number of features returned to speed up display. TODO: You need to specify the correct .Url to the secured https:// ArcGIS Server web service and .Where clause if desired. --> <esri:FeatureLayer Url="https://www.yoursite.com/arcgis/rest/services/test/us_states/MapServer/0" InitializationFailed="FeatureLayer_InitializationFailed" ClientCertificate="{Binding Certificate, Source={StaticResource MyViewModel}}" Where="POP1990>10000000"/> </esri:LayerCollection> </esri:Map> <!-- Provide the instructions on how to use the sample code. --> <TextBlock Height="42" HorizontalAlignment="Left" Name="TextBlock1" VerticalAlignment="Top" Width="578" TextWrapping="Wrap" Text="A Model-View-View-Model (MVVM) approach to loading an https:// secured FeatureLayer using PKI is displayed. The .ClientCertificate Property is used to consume a X509Certificate." /> </Grid> |
C# | Copy Code |
---|---|
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void FeatureLayer_InitializationFailed(object sender, EventArgs e) { // Display a MessageBox with Error information if there is a problem loading the FeatureLayer. ESRI.ArcGIS.Client.Layer theLayer = (ESRI.ArcGIS.Client.Layer)sender; MessageBox.Show("Error initializing layer: " + theLayer.InitializationFailure.Message); } } // Create a Model-View-View-Model (MVVM) class to be used in the XAML. public class MyViewModel : System.ComponentModel.INotifyPropertyChanged { public MyViewModel() { // Create a new instance of a X509Store object (which is a physical store where certificates are persisted and managed). // The X509Store object uses a StoreName based upon a 'personal certificate' and a StoreLocation for the user that // is currently logged in. The X509Store is accessed as ReadOnly to obtain the certificate. // NOTE: Don't forget to add a Reference to the System.Security Assembly. System.Security.Cryptography.X509Certificates.X509Store theX509Store = null; System.Security.Cryptography.X509Certificates.StoreName theStoreName = System.Security.Cryptography.X509Certificates.StoreName.My; System.Security.Cryptography.X509Certificates.StoreLocation theStoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser; theX509Store = new System.Security.Cryptography.X509Certificates.X509Store(theStoreName, theStoreLocation); theX509Store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly); // Obtain the collection of certificates in the X509Store. Note: depending on your organization there may multiple certificates! System.Security.Cryptography.X509Certificates.X509Certificate2Collection theCertificates = theX509Store.Certificates; // Find a specific certificate by it's unique name. // TODO: You need to supply the correct certificate name (i.e. the 2nd parameter 'FindValue'). theCertificates = theX509Store.Certificates.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName, "adftest", true); // Only continue if at least one certificate is available. if (theCertificates.Count > 0) { // Set the X509Certificate to the first certificate in the collection. This will be used in constructing the FeatureLayer. Certificate = theCertificates[0]; } } // This returns the certificate in the following XAML binding sytnax: // ClientCertificate="{Binding Certificate, Source={StaticResource MyViewModel}}" private System.Security.Cryptography.X509Certificates.X509Certificate theCertificate; public System.Security.Cryptography.X509Certificates.X509Certificate Certificate { get { return theCertificate; } set { if (theCertificate != value) { theCertificate = value; OnPropertyChanged("Certificate"); } } } // This wired up Event occurs whenever the Certificate Property changes, which braodcasts the certificate. public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string property) { if (PropertyChanged != null) PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(property)); } } |
VB.NET | Copy Code |
---|---|
Class MainWindow Public Sub New() InitializeComponent() End Sub Private Sub FeatureLayer_InitializationFailed(sender As System.Object, e As System.EventArgs) ' Display a MessageBox with Error information if there is a problem loading the FeatureLayer. Dim theLayer As ESRI.ArcGIS.Client.Layer = CType(sender, ESRI.ArcGIS.Client.Layer) MessageBox.Show("Error initializing layer: " + theLayer.InitializationFailure.Message) End Sub End Class ' Create a Model-View-View-Model (MVVM) class to be used in the XAML. Public Class MyViewModel Implements ComponentModel.INotifyPropertyChanged Public Sub New() ' Create a new instance of a X509Store object (which is a physical store where certificates are persisted and managed). ' The X509Store object uses a StoreName based upon a 'personal certificate' and a StoreLocation for the user that ' is currently logged in. The X509Store is accessed as ReadOnly to obtain the certificate. ' NOTE: Don't forget to add a Reference to the System.Security Assembly. Dim theX509Store As System.Security.Cryptography.X509Certificates.X509Store = Nothing Dim theStoreName As System.Security.Cryptography.X509Certificates.StoreName = System.Security.Cryptography.X509Certificates.StoreName.My Dim theStoreLocation As System.Security.Cryptography.X509Certificates.StoreLocation = System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser theX509Store = New System.Security.Cryptography.X509Certificates.X509Store(theStoreName, theStoreLocation) theX509Store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly) ' Obtain the collection of certificates in the X509Store. Note: depending on your organization there may multiple certificates! Dim theCertificates As System.Security.Cryptography.X509Certificates.X509Certificate2Collection = theX509Store.Certificates ' Find a specific certificate by it's unique name. ' TODO: You need to supply the correct certificate name (i.e. the 2nd parameter 'FindValue'). theCertificates = theX509Store.Certificates.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindBySubjectName, "adftest", True) ' Only continue if at least one certificate is available. If theCertificates.Count > 0 Then ' Set the X509Certificate to the first certificate in the collection. This will be used in constructing the FeatureLayer. Certificate = theCertificates(0) End If End Sub ' This returns the certificate in the following XAML binding sytnax: ' ClientCertificate="{Binding Certificate, Source={StaticResource MyViewModel}}" Private theCertificate As System.Security.Cryptography.X509Certificates.X509Certificate Public Property Certificate() As System.Security.Cryptography.X509Certificates.X509Certificate Get Return theCertificate End Get Set(ByVal value As System.Security.Cryptography.X509Certificates.X509Certificate) If theCertificate IsNot value Then theCertificate = value OnPropertyChanged("Certificate") End If End Set End Property ' This wired up Event occurs whenever the Certificate Property changes, which braodcasts the certificate. Public Event PropertyChanged As ComponentModel.PropertyChangedEventHandler Implements ComponentModel.INotifyPropertyChanged.PropertyChanged Private Sub OnPropertyChanged(ByVal [property] As String) RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs([property])) End Sub End Class |
Target Platforms: Windows XP Professional, Windows Server 2003 family, Windows Vista, Windows Server 2008 family, Windows 7, Windows 8