Skip to content

Migration Guide - MAF Logon to HttpConversation

Here you can find the comprehensive guide on how to migrate applications based on the MAF Logon framework to the HttpConversation libraries. This document is strongly recommended for anyone who is considering to upgrade their MAF Logon based apps created using SMP SDK 3.0 to SMP SDK 3.1.

A solid understanding of the HttpConversation libraries is a must before proceeding with this guide. It is recommended to read the HttpC Developer Guide and some parts of the API docs before reading further.

Background

MAF Logon framework contains a lot of components to help applications build their onboarding and user authentication functionalities. It consists of mainly two parts: a core (implemented by the MAFLogonManagerNG library) and a UI (implemented by the MAFLogonUING library).

These two components work in conjunction to show the related onboarding user interfaces and perform registration, unregistration, secure store management, etc.. Typically, when the application starts up for the first time, MAF Logon UI can be instructed to show a screen on which the server coordinates (host, port, etc.) can be specified. Then, the onboarding usually continues by asking for the user credentials. Finally, a successfully authenticated session is established using which data requests (typically, OData requests) may be fired against the endpoint.

The MAF Logon framework offers a very wide range of features, making it rather versatile. However, it also has a couple of limitations. Namely:

  • The framework is inherently single-user. Building a multi-user solution is not currently supported, although there are parts of the framework which point in that direction. In short: if you want your app to be used by more than one user then building the solution with Logon is going to be more difficult.
  • Logon supports only proactive authentication, that is, when you establish the session upfront. The data requests then rely on the availability of this session. If it expires, the application has to catch the relevant authentication failures occurring in data requests and re-route the application back to the Logon screens.

Furthermore, the wide range of features that are included in Logon over time made its API rather complex and oftentimes hard to work with. Experience shows that in the majority of the cases this level of complexity is not required, thus a simpler solution would suffice.

With the experiences gained the MAF Logon framework has been deprecated in SMP SDK 3.0 SP16 and is removed from SMP SDK 3.1. This guide helps you move away from MAF Logon to pure HttpConversation library which offers a lot more flexibility meanwhile helping you to build the most sensitive parts with greater ease.

Scope

This section discusses the scope of the guide in terms of which MAF Logon features are covered. Certain features of Logon are taken over by other libraries.

One of the most important features of Logon is that it is capable of performing authentication in a variety of ways (BasicAuth, X.509 client credentials, SAML2, etc.). All of these authentication mechanisms (and more) can be implemented using the HttpConversation and HttpConvAuthFlows libraries.

The goal of this guide therefore is to help you rewrite the parts that perform authentication using MAF Logon to use HttpC instead.

Proactive vs. reactive

As mentioned already, MAF Logon treats the authentication step as a prerequisite that needs to be fulfilled before doing anything else. Your application therefore is likely to follow (roughly) the below flow after startup:

  1. (if application is not configured) Obtain configuration, if required then via MAF Logon UI screens.
  2. Login screen to log the user in.
  3. (if SMP server or Mobile Services on SAPcp is used) Registration with the server.
  4. Application main screen is entered. Data requests may be fired from this point onward. The app is ready for use.
  5. If the session expires in the middle of data requests, the application has to handle the error and re-route the user back to the Logon screens.

Recall that this guide deals with only the authentication-related features of MAF Logon. For example, the passcode management steps that take place as part of step no. 3 are not elaborated any further.

The proactive nature of MAF Logon is more than obvious from the above. With HttpC, the flow on the other hand is quite different:

  1. (if application is not configured) Obtain configuration, if required then via some configuration screens.
  2. Configure the HttpConversationManagers that are going to be used for data requests. This configuration is often done with the help of the HttpConvAuthFlows library.
  3. Application main screen is entered. Data requests may be fired from this point onwards. As the servers require authentication, the running HTTP conversations will react to the challenges and display the login screens as required.

The difference is more than outstanding. The user is not bothered with login screens 'till it is absolutely necessary. Note that how the reactive philosophy of HttpC also takes care of the use case when the session expires. In that case the server will issue another authentication challenge that a properly configured HttpConversationManager will handle under the hood.

If required, adding some proactive behaviour to a HttpC-based application is rather easy. If you prefer to have the login screens show as soon as possible then simply send a preflight request to your data endpoints to provoke the server to present an authentication challenge If you're using an OData endpoint, this preflight request can be as simple as an HTTP HEAD sent to the service document endpoint, for example.

Note on user interfaces

In the previous section we did not mention what the fate of MAF Logon UI screens would be and how to migrate away from them. Below we summarize the key ideas regarding this.

MAF Logon comes with a range of pre-built user interfaces for the login screens, configuration screens, passcode management screens, etc.. These intended to help the application developer integrate and customize these screens with ease and without having to deal with building a UI on their own.

As the iOS mobile platform evolved, creating responsive user interfaces that can be tailored to various screen sizes and orientations became easier and easier. Today, with Xcode Interface Builder one can easily build a storyboard-based UI. Drag & dropping new UI elements, defining auto-layout constraints or using vertical or horizontal stack views is easier than ever and can be pulled off without writing a single line of code. Connecting the UI controls to the view controller is also a breeze using outlets that can be created directly from the IB.

Therefore, the need for easily configurable pre-built user interfaces is now gone. This is why HttpC does not have any UI components at all. If you want to create your own onboarding, configuration or login screens, simply build your own UIs with Xcode. The goal of HttpC is instead to allow you to easily integrate such solutions into your application.

Let's build a username/password provider that uses a storyboard and a corresponding view controller:

#import "HttpConversationManager.h"
#import "CommonAuthenticationConfigurator.h"
#import <UIKit/UIKit.h>

@interface UserPassScreenViewController : UIViewController

/**
 Completion block set by the 'UserPassScreenProvider' class when an authentication challenge is detected.
 */
@property (nonatomic, strong) username_password_provider_completion_t completionBlock;

/**
 The 'IBOutlet' linking to the username input field on the screen.
 */
@property (weak, nonatomic) IBOutlet UITextView* userName;

/**
 This 'IBOutlet' is for the password input displayed on the screen.
 */
@property (weak, nonatomic) IBOutlet UITextView* password;

@end

@interface UserPassScreenProvider : NSObject <UsernamePasswordProviderProtocol> @end
@implementation UserPassScreenProvider

-(void)provideUsernamePasswordForAuthChallenge:(NSURLAuthenticationChallenge*)authChallenge 
       completionBlock:(username_password_provider_completion_t)completionBlock {
    // Load your storyboard file from the main bundle. This needs to be done only once.
    static UIStoryboard* storyboard;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSBundle* mainBundle = [NSBundle mainBundle];
        storyboard = [UIStoryboard storyboardWithName:@"UsernamePasswordScreen" bundle:mainBundle];
    });

    // The storyboard is expected to reference the 'UserPassScreenViewController' from its
    // initial screen in this example. Create the view controller with it.
    UserPassScreenViewController* vc = (UserPassScreenViewController*) [storyboard instantiateViewControllerWithIdentifier:@"UsernamePasswordScreen"];

    // The completion block is passed to it so that when the user enters the credentials
    // the view controller can call back via the block.
    vc.completionBlock = completionBlock;

    // Create a UI window, set its root view controller and show it.
    dispatch_async(dispatch_get_main_queue(), ^{
        UIWindow* window = [UIWindow new];
        window.rootViewController = vc;
        [window makeKeyAndVisible];
    });
}

@end

@implementation UserPassScreenViewController

/**
 This action is linked to the 'Login' button on the screen.
 */
-(IBAction)loginButtonPressed:(id)sender {
    // Get the username and the password.
    NSString* userName = self.userName.text;
    NSString* password = self.password.text;

    // Create the credential object.
    NSURLCredential* credential = [NSURLCredential credentialWithUser:userName
                                                   password:password
                                                   persistence:NSURLCredentialPersistenceForSession];

    // Call the completion block.
    self.completionBlock(credential, nil);
}

/**
 This action is what deals with the 'Cancel' button.
 */
-(IBAction)cancelButtonPressed:(id)sender {
    // Just call the completion block with nil.
    self.completionBlock(nil, nil);
}

@end

The above, overly minimalistic example does not deal with failure counts in the provider or that multiple requests might run into the same kind of challenge at the same time. However, it hopefully makes the picture clearer.

The storyboard file is not included in this guide for brevity but building one for the above code is absolutely not hard. If you have the UI controls in place, a simple click-and-drag action is enough in Xcode Interface Builder to link the widgets and their related events to the IBOutlet and IBAction elements of the view controller.

In short, whatever screens you might want to integrate with HttpC, you'll be able to find similar asynchronous method signatures like the above provideUsernamePasswordForAuthChallenge:completionBlock: of the UsernamePasswordProviderProtocol. These were designed with the intention to make it possible to integrate arbitrary UI flows like the one in this example.

Migrating away from MAF Logon UI therefore requires you to build the authentication and onboarding screens yourself. However, with the flexibility offered by the platform you'll be able to customize these screens precisely to your needs and then integrate them into HttpC at certain parts as you wish.

NOTE: SMP SDK includes a library, called UserInteractionMultiplexer which is an orchestrator displaying arbitrary screens. It's used internally by HttpConvAuthFlows to ensure that a single SAML2/OAuth2/... auth. screen is displayed even in case multiple challenges are received from the same server endpoint in parallel. We'd recommend you to check out this library.

The API documentation of the UserInteractionMultiplexer class defined in the same-named header file is a good starting point to become familiar with it.

Preparing for the migration

This section covers the preparation steps to perform before starting the migration. The actual migration guide is separated per use cases and describe how to rebuild the functionality you created using MAF Logon with HttpC.

Changes in the project setup

The below guide assumes your application is using SMP SDK 3.0 SP16, however most of the steps are applicable to earlier Service Packs too.

If your application is using an earlier SP and you are not sure how all this applies to your project then first upgrade your app to SP16, verify that it's working and then perform the below steps.

The first step is to remove MAF Logon libraries from the project setup. Luckily, for quite a few SPs by now, MAF Logon itself uses HttpC internally. This means that HttpC need not be added to the project as it should already be there.

Therefore, remove the libMAFLogonManagerNG.a and libMAFLogonUING.a from the linked libraries and also remove the MAFLogonUING.bundle from the bundled resources. If your app is using only the core component then you just need to remove the MAFLogonManagerNG library.

All this can be done in Xcode, on the Build Phases tab of the target settings of your app.

After this move your project, quite obviously, will not compile. That's your starting point.

Implications on the application logic

The philosophy of how MAF Logon and HttpC approach the question of onboarding and authentication is so fundamentally different that there's little room for a migration guide that could give you a comprehensive before/after picture of your code.

Of course, where this is possible, these comparisons are made to make your job easier. You can find them among the various documented use cases.

Here we'd like to recommend a different approach. Instead of thinking in how to replace MAF Logon with HttpC, we recommend you think through the onboarding and authentication flows of your application again. What are your exact requirements? How would you like to obtain configuration? What kind of authentication types does your app support?

As mentioned previously, the most complex task is to recreate the UIs with the standard developer tools available for iOS. Below is a table that summarizes what you'll likely have to do, depending on the authentication type your application is working with currently:

Auth. type Onboarding/Configuration Authentication Challenge
BasicAuth No upfront configuration is required. Build your own username/password UI with storyboards or UIAlertControllers, as needed. Integrating with HttpC means creating a UsernamePasswordProviderProtocol implementation that can show the screen and have its view controller call the completion block when the credentials are entered.
Mutual SSL/TLS Consider integrating one of the certificate providers (see the related guides and API docs for the details), if they suit your needs. For simpler cases, obtaining certificates from the KeyChain can be enough. Authentication screen is not recommended as per the HttpC Developer Guide (as the screen would block the SSL/TLS handshake process very likely resulting in a timeout).
SAML2 SAML2 configuration needs to be provided which is dependent on the server address. If it's fixed and thus can be hard-coded then no onboarding UI is needed. Otherwise a UI might be required to let the user enter the server coordinates. The challenge screen is taken care of by HttpConvAuthFlows transparently. No development is required.
OAuth2 Same as SAML2... Same as SAML2...
OTP The configuration is fixed in 99.9% of the cases and is independent of the server address. Very likely nothing else needs to be done on top of what the HttpC Developer Guide already covers. Same as SAML2...

The above table reflects the requirements and the possible options for the most likely scenarios. As you can see, in many cases performing onboarding can be a lot more simpler than it was with MAF Logon. In several cases, you can simply get away with a configuration screen that asks for the server address once and then saves it to a persistent storage for subsequent application startups.

The key resides in how authentication challenges are handled. The complex web-based auth. types (SAML2, OAuth2, OTP) already have their own UIWebView-based UIs out of the box. Creating a UI for Mutual SSL/TLS is not recommended. The only authentication type that might require you to create your own user interface is BasicAuth, but it's also one of the simplest thing to do. That's why the code examples in this guide and in the HttpC Developer Guide concentrate on it so much.

Use cases

You can find the - more or less - step-by-step guides in this chapter for the most important use cases. This lets you replace calls to MAF Logon libraries with those targeting HttpConversation instead.

Registration with an SMP/SAPcpms server

Registration is the act when a mobile application is registered with a SAP Mobile Platform or a Mobile Services for SAPcp server. As part of the registration, a new application connection is created which is represented by the Application Connection Identifier (shortly: APPCID).

The registered connection belongs to the device + app + user trio. A different user on the same device within the same app would have a different application connection, for example.

With MAF Logon, this step is performed as follows:

  • When using MAFLogonUING: the logon method of the MAFLogonNGPublicAPI object is called.
  • When using only MAFLogonManagerNG: the registerWithContext: method of the MAFLogonCore object is called.

Find these calls in your application and remove them, along with any code that assembles the parameters and prepares these calls. For example, registerWithContext: requires a MAFLogonContext object. The code that creates that object can be removed as well.

MAF Logon (both UI and Core) reported the result of the registration via delegates you had to implement and pass to the framework. With HttpC, all you have to do is send the registration request:

-(void)registerWithManager:(HttpConversationManager*)manager
                  toServer:(NSString*)rawServerUrl
                  andAppId:(NSString*)appId
                completion:(void(^)(NSString* applicationConnectionId))completionBlock {
    // Compose the request to the registration endpoint.
    NSURL* registrationUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@/odata/applications/latest/%@/Connections", rawServerUrl, appId]];
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:registrationUrl];

    // Set the method and the headers.
    request.HTTPMethod = @"POST";
    [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [request setValue:@"application/xml,application/atom+xml" forHTTPHeaderField:@"Accept"];

    // Compose the request body.
    request.HTTPBody = [NSJSONSerialization dataWithJSONObject:@{@"DeviceType" : @"iOS", @"DeviceModel" : @"iPhone"} options:NSJSONWritingPrettyPrinted error:nil];

    // Fire the request.
    [manager executeRequest:request completionHandler:^(NSData* data, NSURLResponse* response, NSError* error) {
        // Check the status code.
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        NSInteger statusCode = httpResponse.statusCode;
        if (statusCode == 201) {
            // Look through the cookies.
            for (NSHTTPCookie* cookie in [NSHTTPCookie cookiesWithResponseHeaderFields:httpResponse.allHeaderFields forURL:httpResponse.URL]) {
                if ([cookie.name isEqualToString:@"X-SMP-APPCID"]) {
                    // Got the application connection ID. Go on.
                    completionBlock(cookie.value);
                    return;
                }
            }
        }

        // Some error occurred. Call the block with no connection ID.
        completionBlock(nil);
    }];
}

This method expects a properly configured HttpConversationManager, the URL to the server, the application ID (as registered on SMP/SAPcpms) and a completion block. The result will be an application connection ID upon success or nil if an error occurred. Give the above code some sophisticated error handling and you're good to go.

MAF Logon performed additional actions after a successful registration request, like initializing the data vault. In this guide it is not covered as we're concentrating only on the authentication and onboarding topics (with emphasis on the former). Please read the MAF Logon to DataVault migration guide to cover that part. The instructions contained therein can be applied using the above code rather easily: just call registerWithManager:toServer:andAppId:completion: with a completion block that when given a non-nil APPCID initializes a new data vault.

Delete registration

Similarly to how registration is performed, deletion can be carried out as well:

-(void)deleteRegistration:(NSString*)applicationConnectionId
       withManager:(HttpConversationManager*)manager
       fromServer:(NSString*)rawServerUrl
       withAppId:(NSString*)appId
       completion:(void(^)(BOOL success))completionBlock {
    // Compose the request to the registration endpoint.
    NSURL* deregistrationUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@/odata/applications/latest/%@/Connections('%@')",
                                                     rawServerUrl, appId, applicationConnectionId]];
    NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:deregistrationUrl];

    // Set the method.
    request.HTTPMethod = @"DELETE";

    // Send it.
    [manager executeRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        // Verify the status code.
        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
        NSInteger statusCode = httpResponse.statusCode;
        if (statusCode == 200) {
            // Completed successfully.
            completionBlock(YES);
        } else {
            // Some problem occurred.
            completionBlock(NO);
        }
    }];
}

Again, the same things are required: a properly configured HttpConversationManager that can process the authentication challenges the server might send. To perform the removal of the registration properly, the APPCID acquired during registration must be specified.

With MAF Logon, this operation is performed as follows:

  • When using MAFLogonUING: the deleteUser method of the MAFLogonNGPublicAPI object is called.
  • When using only MAFLogonManagerNG: the unregister method of the MAFLogonCore object is called.

Just like with registration, find the calls to this method in your app and simply replace them with the HttpC-based solution.

Using the ODataOnline library

SAP Mobile Platform server and Mobile Services on SAPcp provide additional features that the client is able to use, such as:

  • Application settings retrieval & update
  • Push Tokens management
  • Security Policy management
  • ...

Fortunately, these servers expose these features via OData services. Previously, MAF Logon provided functions built on top of these features but with an HttpC-based stack you no longer need that.

The OData service through which these features are made available can be accessed using the following URL:

http[s]://<host:port>/[public/]odata/applications/<service version>/<appid>

The application ID can be taken from the SMP Admin/Mobile Services Cockpit. This is usually a reverse-domain syntax identifier.

For the service version, look up the REST API documentation of the SMP/SAPcpms server. At the time of writing this guide v1, v2, v3, v4 and latest were accepted values where latest pointed to v4.

You can use this URL with the ODataOnline library found in the SMP SDK to open an online store and send OData requests to this service. The registration and delete registration requests that the previous section discussed can also be implemented using ODataOnline.

In fact, the recommended approach is to use our online OData client solution together with HttpC to manage your application registration, settings, etc.. As such, migrating away from MAF Logon is merely about removing the related calls to the Logon libraries and replacing them with calls to the above OData service.

For the rest of the details, consult the below links:

Setting up an SODataOnlineStore requires only a properly configured HttpConversationManager. Earlier versions of the above guides might still contain references to MAF Logon but that can be ignored. All that matters is that the ODataOnline library be driven by a conversation manager that is ready to take care of the authentication challenges as needed.