Secure Services

Layers and Tasks in ArcGIS Runtime SDK for iOS communicate with ArcGIS Server web services through their REST interface. These services might be secured to permit access only to authorized users. An ArcGIS Server instance can use one of two authentication methods: token-based authentication or HTTP authentication. Both types of authentication modes are supported by the API.

Accessing secure services using credentials

If you know the credentials (username and password) needed to access a secure service, you can pass these credentials to the layer/task through an AGSCredential object.

//create the credential
AGSCredential* cred = [[[AGSCredential alloc] initWithUser:@"<user>" password:@"<password>"] autorelease];    

//pass the credential to layer or task
AGSDynamicMapServiceLayer* layer = [AGSDynamicMapServiceLayer dynamicMapServiceLayerWithURL:url credential:cred ];    
AGSQueryTask* task = [AGSQueryTask queryTaskWithURL:url credential:cred];
The API will automatically try to discover the type of authentication (token or HTTP) being used by the service.

HTTP authentication

If the service is using HTTP authentication, the credentials (username and password) will be propagated to the service using HTTP request headers.

Token authentication

If the service is using token-based authentication, the API will attempt to discover the URL of the token service where tokens can be acquired. If you know this information in advance, you can provide it to the AGSCredential object so that that API does not make any unnecessary network requests to discover the same information.

AGSCredential* cred = [[[AGSCredential alloc] 
   initWithUser:@"<user>" password:@"<password>" authenticationType:AGSAuthenticationTypeToken tokenUrl:url
 ]autorelease];

The layer/task will propogate your credentials to the token service and transparently acquire a token on your behalf. The token will then be included in every request to the service. When the token expires, the layer/task will automatically acquire a fresh token.

Accessing secure services using tokens

If you do not feel comfortable exchanging credentials over the network, and the services you are trying to access are secured using token based authentication, you can pre-acquire a token manually and then use it to initalize an AGSCredential object.

//when using a short lived token
AGSCredential* cred = [[[AGSCredential alloc] initWithToken:@"<token>"] autorelease];

//when using a long lived token.
//also need to provide the referer used when generating the token
 AGSCredential* cred = [[[AGSCredential alloc] initWithToken:@"<token>" referer:@"<referer>"] autorelease];

The API will then simply include the token in every request to the service. It is your reponsibility to periodically update the AGSCredential object's token, otherwise the layer/task will stop working unexpectedly when the token expires.

Encrypting data

To safeguard content exchanged over the network from eavesdroppers and man-in-the-middle attacks, you should use HTTPS whenever supported by the service. This will ensure that your data, credentials, or tokens are not compromised. HTTPS connections use Secure Sockets Layer (SSL) to encrypt information exchanged over the network and digital certificates to verify identities of the parties involved.

Using self-signed certificates

There may be times when you encounter servers using a self-signed certificate with SSL. As a security measure, HTTPS connections are not established with a server that uses self-signed certificates. Digital certificates are a means to prove the identity of an entity and should ideally be endorsed (signed) by a known trusted authority to be credible. Just about anyone can create a digital certificate and sign it themselves to establish a misleading identity.

Whenever the API fails to establish an HTTPS connection, it provides an NSError object which can be inspected to check whether the failure was because the server was using a self-signed certificate.

If you chose to trust a server that is using a self-signed certificate, for instance, if that server is being used for development purposes, you can add the hostname of the server to the trustedHosts property on NSURLConnection class.

The following code snippet checks to see if a layer failed to load because the server was using a self-signed certificate, and if so, adds the server to trustedHosts and reloads the layer -

- (void)mapView:(AGSMapView *)mapView failedLoadingLayerForLayerView:(UIView<AGSLayerView> *)layerView baseLayer:(BOOL)baseLayer withError:(NSError *)error {

  //if error was becasue server was using a self-signed certificate
  if ([error code]== NSURLErrorServerCertificateUntrusted) {

   //You may want to prompt the user and ask if it is okay to establish connection with the server
   ...

   //Assuming here that the layer was a tiled layer. 
   //You will need to change this code to typecast it to the correct type
   AGSTiledMapServiceLayer* tiledLayer = (AGSTiledMapServiceLayer*)layerView.agslayer;
   
   //Add the server to the trusted hosts list
   [[NSURLConnection trustedHosts] addObject:[tiledLayer.URL host]];
   
   //Reload the layer
   [tiledLayer resubmitWithURL:tiledLayer.URL credential:scredential];
  }
}

Alternatively, if you know in advance the server you will be connecting to uses a self-signed certificate, you can add it to the trustedHosts list as soon as the application starts. The following code snippet does so in the application delegate -

- (void)applicationDidFinishLaunching:(UIApplication *)application {

  ...

 [[NSURLConnection trustedHosts] addObject:@"<my_server>"];


}

5/9/2012