The iOS SAP Mobile SDK version 3 SP05 has some truly awesome new features, ranging from a major upgrade to the networking layer, to a new “harmonized” API for working with OData services online and offline, to a Usage collection API, to a new cloud-hosted ‘Discovery Service’, that allows mobile apps distributed through public app stores to discover their connection settings with an end-user’s email address. In this post, I'll cover the HttpConversationManager, the new networking library for the SDK, which adds support for SAML2, OAuth2, and provides a flexible framework for enterprise authentication in your apps.
Successful mobile app development in the enterprise, particularly on-premise, really hinges on highly-usable solutions for networking and authentication. To this end, I’m very proud to share the HttpConversationManager
, the new networking API for the mobile SDK in Release 3 SP05.
Earlier generations of the mobile SDK networking on iOS depended on networking layers implemented on the CFNetworking
API set, commonly known as SDMRequesting
, SDMConnectivity
, or simply <Requesting>
. The core libraries implemented support for basic, mutual-auth, and session-token (including CA Siteminder(c)) authentication types, and were instrumented for traceability with SAP Passport.
The limitations of the API demonstrated themselves in two main areas: ease-of-use, and extensibility. When the API’s were first developed, in 2010 and 2011, the concept of standardizing on Apple’s native API’s for lowering the developer learning curve really hadn’t taken hold in the industry; the methodology of joining NSURLConnection and NSOperation (a la AFNetworking) wasn’t fully fleshed-out, So, -requestDidFinish:
and -requestDidFail
were relatively straightforward implementation choices. But, as iOS 5, 6, 7, 8 evolved, Apple built up the stack on the NSURL
API set, including powerful tools like NSURLProtocol
, NSURLSessionDataTask, completion blocks, Kerberos support, etc. It was only natural that we should upgrade our communication stack to take advantage of this wide variety of features.
The basic concept for the HttpConversationManager is the NSURLSession, and the input for the request is a standard NSMutableURLRequest
! This was one of the core design principles: “reuse, then invent.” In fact, a side-by-side comparison shows that the HttpConversationManager and NSURLSession request interfaces are quite similar:
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURL *location, NSURLResponse *response, NSError *error))completionHandler
-(void) executeRequest:(NSMutableURLRequest*)urlRequest completionHandler:(void (^)(NSData* data, NSURLResponse* response, NSError* error))completionHandler;
Note that the NSURLSession method returns a NSURLSessionDataTask; the HttpConversationManager -executeRequest:
method creates a NSURLSessionDataTask internally, by invoking the above method. Both have similar completion handler interfaces, with the HttpConversationManager also returning the raw NSData of the reponse.
If we are so committed to reusing standard iOS API’s, why implement the HttpConversationManager at all? In fact, our initial prototype was implemented as a category on NSURLSession directly (NSURLSession+HttpConversationManager.h
). The answer goes to the point of why we chose this moment to do the update: support for SAML2 (and OAuth2) authentication, for working with SAP HANA Cloud Platform, and the upcoming SAP HANA Mobile release.
The NSURL delegate APIs are robust and well-known for handling authentication challenges over HTTP/s, and the NSURLProtocol is an elegant, if lesser known (and minimally documented) method for globally over-riding the URL loader behavior. But, SAML2 support for native applications presented a challenge: SAML2 is really designed around interactions taking place in a browser or webview–not in a native client.
Specifically, the HTTP Web Post Profile, which is standard on SAP ID Service, relies on the browser to load HTML content with an embedded onLoad()
function to redirect to the SAML identity provider (“IdP”). Unfortunately, this HTML content doesn’t come back as a 401 authentication challenge: it returns with a 200! And, once the redirect to the SAML IdP occurs, the authentication challenge often comes as a HTML form. So, there is a major benefit in using a browser or webview to handle this interaction, and some filter needs to be available to discover responses which happen to be SAML authentication challenges, create a webview, and then manage the interaction with the IdP culminating in the redirect to the original service provider, where the SessionID token is obtained.
The solution we adopted requires some configuration on the server (these are already implemented by SAP ID Service, and HANA Mobile, so no additional action is required):
For additional info on integrating a corporate SAML2 IdP, see here.
The configurations required on-device to make this work are set to the HttpConversationManager by registering and implementing a SAML2 Configuration Provider. See in the following example how a SAML2ConfigProvider is added to the CommonAuthenticationConfigurator
, which then sets the configurations to the HttpConversationManager. We’ll go into detail on the CommonAuthenticationConfigurator in the next section, but in this case, just think of it as a sort of NSURLSessionConfiguration for the HttpConversationManager.
-(void) initConversationManagerWithSAMLProvider {
CommonAuthenticationConfigurator* commonConfig = [[CommonAuthenticationConfigurator alloc] init];
[commonConfig addSAML2ConfigProvider:self];
HttpConversationManager* manager = [[HttpConversationManager alloc] init];
[commonConfig configureManager:manager];
}
/**
* SAML2 Configuration Provider implementation
*/
-(void) provideSAML2ConfigurationForURL:(NSURL*)url completionBlock:(void (^)(NSString* responseHeader, NSString* finishEndPoint, NSString* finishParameters))completionBlock {
completionBlock(@"com.sap.cloud.security.login", @"<protocol>://<host>:<port>/SAMLAuthLauncher", @"finishEndpointParam");
}
The end-to-end flow in the HttpConversationManager is then:
ResponseFilter
) looks for the presence of the responseHeader
(e.g. com.sap.cloud.security.login
, then the HTML content with “SAMLRequest” string. This indicates that SAML2 authentication sequence is required.finishEndPoint
(e.g. /SAMLAuthLauncher
). This is GET, and should not be a modifying request.responseHeader
, and SAMLRequest body. This time, the HTML is not intercepted, but is loaded normally in the UIWebView. This allows the onLoad()
function in the page to execute, which POSTs the SAMLRequest blob to the SAML IdP.Provider
to obtain the SecIdentityRef, which will be described shortly.onLoad()
function to POST the SAMLResponse body to the original Service Provider.finishEndPoint
, which attempts to redirect the UIWebView to a URL with the finishParameters
query parameter(/s) (e.g.: finishEndpointParam
).finishParameters
, determines that the authentication was successful. It dismisses the UIWebView.completionHandler:
.A few components were introduced in the above description, so let’s take a look at they way they work together:
CommonAuthenticationConfigurator
RequestFilter
ResponseFilter
ChallengeFilter
CredentialProvider
ConfigurationProvider
In brief, the heirarchy is:
+ HttpConversationManager
- is decorated by:
+ CommonAuthenticationConfigurator
- containing:
+ RequestFilters
+ ReponseFilters
+ ChallengeFilters
- which obtain their configurations from:
+ CredentialProviders
+ ConfigurationProviders
So, after the HttpConversationManager is configured, you may see something resembling the following properties set on the object. (This is the default set which is provided by the logonConfigurator
factory method on the <MAFLogonNGDelegate>
protocol).
Note the logic of the implementation: OAuth2 authentication requires checks at the start of a request (does bearer token exist?), and in the absence of the token, management of a multi-step procedure with checks on the response from the auth token provider. So, OAuth2 support is implemented with both a RequestFilter and a ResponseFilter.
SAML2 authentication (as described above) requires checks on 200-type HTTP responses, to detect payloads related to redirects to the SAML2 IdP. That logic is encapsulated in a ResponseFilter. The configuration for the SAML2 interaction is supplied by a ConfigurationProvider
.
Basic and Client Certificate authentication can both be handled within the regular HTTP authentication challenge framework. The NSURLSessionDelegate invokes -didReceiveChallenge:
, passing the NSURLAuthenticationChallenge
. The UsernamePasswordChallengeFilter
and ClientCertChallengeFilter
execute on the challenge, and supply the correct credential provider: If the challenge is for basic auth, the UsernamePasswordProviders
will be tried; if for client certificate, then the ClientCertificateProviders
will be tried. Providers are tried sequentially in their containing NSArray.
In short, you have a very flexible framework around the NSURLSession for managing the authentication, and any custom behavior you need to attach to your networking.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
17 | |
14 | |
14 | |
12 | |
11 | |
9 | |
9 | |
8 | |
8 | |
7 |