You are on page 1of 135

Kapsel Development

PDF download from SAP Help Portal:


http://help.sap.com/saphelp_smp303sdk/helpdata/en/7c/05514870061014ae31b35a27134786/frameset.htm

Created on February 13, 2015

The documentation may have changed since you downloaded the PDF. You can always find the latest information on SAP Help Portal.

Note

This PDF document contains the selected topic and its subtopics (max. 150) in the selected structure. Subtopics from other structures are not included.
The selected structure has more than 150 subtopics. This download contains only the first 150 subtopics. You can manually download the missing subtopics.

© 2015 SAP SE or an SAP affiliate company. All rights reserved. No part of this publication may be reproduced or transmitted in any form or for any purpose
without the express permission of SAP SE. The information contained herein may be changed without prior notice. Some software products marketed by SAP SE
and its distributors contain proprietary software components of other software vendors. National product specifications may vary. These materials are provided by
SAP SE and its affiliated companies ("SAP Group") for informational purposes only, without representation or warranty of any kind, and SAP Group shall not be
liable for errors or omissions with respect to the materials. The only warranties for SAP Group products and services are those that are set forth in the express
warranty statements accompanying such products and services, if any. Nothing herein should be construed as constituting an additional warranty. SAP and other
SAP products and services mentioned herein as well as their respective logos are trademarks or registered trademarks of SAP SE in Germany and other
countries. Please see www.sap.com/corporate-en/legal/copyright/index.epx#trademark for additional trademark information and notices.

Table of content

PUBLIC Page 1 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Table of content
1 Kapsel Development
1.1 Developing Kapsel Applications
1.2 Setting Up the Development Environment
1.3 Configuring the Application in the Management Cockpit
1.3.1 Defining Applications
1.3.2 Defining Back-end Connections for Native and Hybrid Apps
1.3.3 Defining Application Authentication
1.4 Creating an Apache Cordova Project
1.4.1 Project Settings
1.5 Using UI Development Frameworks
1.6 Configuring the Client for Authentication
1.6.1 Configuring the iOS Client for Basic Authentication over HTTP(S)
1.6.2 Configuring the iOS Client for Mutual Authentication over HTTP(S)
1.6.3 Configuring the Android Client for Basic Authentication over HTTP(S)
1.6.4 Configuring the Android Client for Mutual Authentication over HTTP(S)
1.7 Managing Application Registration Using Client Hub
1.8 Provisioning Applications Using Afaria
1.8.1 Preparing the Kapsel Application for Afaria Provisioning
1.9 Kapsel Plugins
1.9.1 Using the Logon Plugin
1.9.1.1 Logon Plugin Overview
1.9.1.2 Adding the Logon Plugin
1.9.1.3 Configuring Default Values
1.9.1.4 Running the Logon Application on iOS
1.9.1.5 Removing Fields From the Registration Screen
1.9.1.6 Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers
1.9.1.6.1 Creating a Custom Certificate Provider
1.9.1.6.2 Creating a Resource to Display a UI View
1.9.1.6.3 Building and Running an iOS Project
1.9.1.6.4 Building and Running an Android Project
1.9.1.6.5 Enabling a CertificateProvider in an Application
1.9.1.6.6 CertificateProvider Interface Reference
1.9.1.6.6.1 iOS
1.9.1.6.6.1.1 onGetCertificateSuccess Method
1.9.1.6.6.1.2 onGetCertificateFailure Method
1.9.1.6.6.1.3 showUI Method
1.9.1.6.6.1.4 getCertificate Method
1.9.1.6.6.1.5 getStoredCertificate Method
1.9.1.6.6.1.6 deleteStoredCertificateWithError Method
1.9.1.6.6.1.7 setParameters Method
1.9.1.6.6.2 Android
1.9.1.6.6.2.1 onGetCertificateSuccess Method
1.9.1.6.6.2.2 onGetCertificateFailure Method
1.9.1.6.6.2.3 showUI Method
1.9.1.6.6.2.4 getCertificate Method
1.9.1.6.6.2.5 getStoredCertificate Method
1.9.1.6.6.2.6 deleteStoredCertificate Method
1.9.1.6.6.2.7 setParameters Method
1.9.1.6.7 CertificateProvider Samples
1.9.1.6.7.1 iOS Certificate Provider Sample
1.9.1.6.7.1.1 CertificateProvider.h
1.9.1.6.7.1.1.1 CertificateProviderDelegate Protocol
1.9.1.6.7.1.1.2 CertificateProvider Interface
1.9.1.6.7.1.2 X509FileCertificateProvider Code
1.9.1.6.7.1.3 X509FileCertificateProvider Sample
1.9.1.6.7.2 Android Certificate Provider Sample
1.9.1.6.7.2.1 CustomCertificateProvider.java
1.9.1.6.7.2.2 CustomKeyManager.java
1.9.1.6.8 Localizing a CertificateProvider
1.9.1.7 Kapsel Logon API Reference

PUBLIC Page 2 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.1.7.1 Logon namespace
1.9.1.7.1.1 applicationId member
1.9.1.7.1.2 core member
1.9.1.7.1.3 changePassword( onsuccess, onerror ) method
1.9.1.7.1.4 deletePasscodeManager( successCallback, errorCallback ) method
1.9.1.7.1.5 get( onsuccess, onerror, key ) method
1.9.1.7.1.6 init( successCallback, errorCallback, applicationId, [context], [logonView] ) method
1.9.1.7.1.7 initPasscodeManager( successCallback, errorCallback, applicationId, [logonView] ) method
1.9.1.7.1.8 lock( onsuccess, onerror ) method
1.9.1.7.1.9 managePasscode( onsuccess, onerror ) method
1.9.1.7.1.10 refreshCertificate( onsuccess, onerror ) method
1.9.1.7.1.11 set( onsuccess, onerror, key, value ) method
1.9.1.7.1.12 showCertificateProviderScreen( onsuccess, onerror ) method
1.9.1.7.1.13 showRegistrationData( onsuccess, onerror ) method
1.9.1.7.1.14 unlock( onsuccess, onerror ) method
1.9.1.7.1.15 errorCallback( errorObject ) type
1.9.1.7.1.16 getSuccessCallback( value ) type
1.9.1.7.1.17 successCallback( context ) type
1.9.1.7.1.18 successCallbackNoParameters type
1.9.1.7.2 Source code
1.9.1.7.2.1 LogonController.js
1.9.2 Using the AuthProxy Plugin
1.9.2.1 AuthProxy Plugin Overview
1.9.2.2 Adding the AuthProxy Plugin
1.9.2.2.1 Adding User Permissions to the Android Manifest File
1.9.2.3 Adding Cookies to a Request
1.9.2.4 Using the AuthProxy Plugin to Register With SAP Mobile Platform Server
1.9.2.4.1 Generating Certificates and Keys
1.9.2.5 Kapsel AuthProxy API Reference
1.9.2.5.1 AuthProxy namespace
1.9.2.5.1.1 sap.AuthProxy.CertificateFromFile class
1.9.2.5.1.2 sap.AuthProxy.CertificateFromLogonManager class
1.9.2.5.1.3 sap.AuthProxy.CertificateFromStore class
1.9.2.5.1.4 ERR_CERTIFICATE_ALIAS_NOT_FOUND member
1.9.2.5.1.5 ERR_CERTIFICATE_FILE_NOT_EXIST member
1.9.2.5.1.6 ERR_CERTIFICATE_INVALID_FILE_FORMAT member
1.9.2.5.1.7 ERR_CLIENT_CERTIFICATE_VALIDATION member
1.9.2.5.1.8 ERR_DOMAIN_WHITELIST_REJECTION member
1.9.2.5.1.9 ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED member
1.9.2.5.1.10 ERR_GET_CERTIFICATE_FAILED member
1.9.2.5.1.11 ERR_HTTP_TIMEOUT member
1.9.2.5.1.12 ERR_INVALID_PARAMETER_VALUE member
1.9.2.5.1.13 ERR_LOGON_MANAGER_CERTIFICATE_METHOD_NOT_AVAILABLE member
1.9.2.5.1.14 ERR_LOGON_MANAGER_CORE_NOT_AVAILABLE member
1.9.2.5.1.15 ERR_MISSING_PARAMETER member
1.9.2.5.1.16 ERR_NO_SUCH_ACTION member
1.9.2.5.1.17 ERR_SERVER_CERTIFICATE_VALIDATION member
1.9.2.5.1.18 ERR_SERVER_REQUEST_FAILED member
1.9.2.5.1.19 ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED member
1.9.2.5.1.20 ERR_UNKNOWN member
1.9.2.5.1.21 deleteCertificateFromStore( successCB, [errorCB], certificateKey ) method
1.9.2.5.1.22 generateODataHttpClient() method
1.9.2.5.1.23 get( url, header, successCB, errorCB, [user], [password], [timeout], [certSource] ) method
1.9.2.5.1.24 sendRequest( method, url, header, requestBody, successCB, errorCB, [user], [password], [timeout], [certSource] ) method
1.9.2.5.1.25 deleteCertificateSuccessCallback type
1.9.2.5.1.26 errorCallback( errorObject ) type
1.9.2.5.1.27 successCallback( serverResponse ) type
1.9.2.5.2 Source code
1.9.2.5.2.1 authproxy.js
1.9.3 Using the AppUpdate Plugin
1.9.3.1 AppUpdate Plugin Overview
1.9.3.2 Adding the AppUpdate Plugin

PUBLIC Page 3 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.3.3 Kapsel AppUpdate API Reference
1.9.3.3.1 AppUpdate namespace
1.9.3.3.1.1 addEventListener( eventname, f ) method
1.9.3.3.1.2 reloadApp() method
1.9.3.3.1.3 removeEventListener( eventname, f ) method
1.9.3.3.1.4 reset() method
1.9.3.3.1.5 update() method
1.9.3.3.1.6 checking event
1.9.3.3.1.7 downloading event
1.9.3.3.1.8 error event
1.9.3.3.1.9 noupdate event
1.9.3.3.1.10 progress event
1.9.3.3.1.11 updateready event
1.9.3.3.2 Source code
1.9.3.3.2.1 appupdate.js
1.9.4 Using the Logger Plugin
1.9.4.1 Logger Plugin Overview
1.9.4.2 Adding the Logger Plugin
1.9.4.3 Viewing Client Logs
1.9.4.3.1 Client Logs
1.9.4.4 Testing Logging
1.9.4.5 Kapsel Logger API Reference
1.9.4.5.1 Logger namespace
1.9.4.5.1.1 Logger#DEBUG member
1.9.4.5.1.2 Logger#ERROR member
1.9.4.5.1.3 Logger#INFO member
1.9.4.5.1.4 Logger#WARN member
1.9.4.5.1.5 debug( message, [tag], [successCallback], [errorCallback] ) method

PUBLIC Page 4 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1 Kapsel Development
Kapsel is a set of SAP® plugins for Apache Cordova 3.4.
Apache Cordova provides a suite of APIs you can use to access native capabilities. The Cordova container provides JavaScript libraries that give you consistent
APIs you can call the same way on any supported device. The Cordova container is simply a holder in which any APIs and extensions are implemented as
plugins. Apache Cordova includes a command line interface for managing Cordova applications and the application development process.

Kapsel leverages the Cordova application container and provides SAP plugins to make the Cordova container enterprise-grade, allowing it to more seamlessly
integrate with SAP Mobile Platform Server. The Kapsel plugins provide capabilities like application life cycle management, implementation of a common logon
manager and single sign-on (SSO), integration with SAP Mobile Platform Server-based push notifications and so on. Since Kapsel is implemented without
modifying the Cordova container, it is compatible with anything else you develop with Cordova. Kapsel supports Cordova 3.4, which allows you access to the
latest Cordova features and bug fixes when you build your Kapsel application.

In this section:

PUBLIC Page 5 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Developing Kapsel Applications
Setting Up the Development Environment
Configuring the Application in the Management Cockpit
Creating an Apache Cordova Project
Using UI Development Frameworks
Configuring the Client for Authentication
Managing Application Registration Using Client Hub
Provisioning Applications Using Afaria
Kapsel Plugins
Developing a Kapsel Application With OData Online
Running and Testing Kapsel Applications
Package and Deploy Kapsel Applications
Removing Kapsel Plugins

Related Information
Developer

1.1 Developing Kapsel Applications


Once your application is developed, create a Cordova 3.4 project and install the Kapsel plugins.
1. Setting Up the Development Environment
2. Configuring the Application in the Management Cockpit
3. Creating an Apache Cordova Project
4. Using UI Development Frameworks
5. Configuring the Client for Authentication
6. Managing Application Registration Using Client Hub
7. Provisioning Applications Using Afaria
8. Kapsel Plugins
9. Running and Testing Kapsel Applications
10. Package and Deploy Kapsel Applications
Parent topic: Kapsel Development

1.2 Setting Up the Development Environment


To build Kapsel applications, you must first set up your development environment, which includes installing both SAP Mobile Platform Server, and the SAP
Mobile Platform SDK.

Prerequisites
Verify that you can access SAP Mobile Platform Server from your machine
If you are using Windows, download and extract Apache Ant and add it to the system variable path, PATH=%PATH%;C:\apache-ant-<version>\bin.
See http://ant.apache.org .
See http://service.sap.com/pam to verify that you are using the supported versions for the Kapsel development environment.

Android Requirements
Android tools run on Windows, Linux, and OS X. To build Kapsel apps for Android, you need:
Java Development Kit (JDK)
Android SDK
See the Apache Cordova documentation at http://cordova.apache.org/docs/en/3.0.0/guide_platforms_android_index.md.html#Android%20Platform%20Guide
for more information about getting started with Android.

Installing the Java SDK


See http://www.oracle.com/technetwork/java/javase/downloads/index.html .
After installing the Java SDK, define the JAVA_HOME environment variable.

Download the Plugins


Set up the Android Development Environment by downloading the required plugins.
Prerequisites:
Download the Java Standard Edition Development Kit from http://www.oracle.com/technetwork/java/javase/downloads/index.html
Download the ADT-supported version of Eclipse from http://www.eclipse.org/downloads/
1. Start the Eclipse environment.
2. From the Help menu, select Install New Software .
3. Click Add .
4. In the Add Repository dialog, enter a name for the new plugin.
5. Enter one of the following for URL:
https://dl-ssl.google.com/android/eclipse/
http://dl-ssl.google.com/android/eclipse/

PUBLIC Page 6 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
6. Click OK .
7. Select Developer Tools and click Next .
8. Review the tools to be downloaded.
9. Click Next .
10. Read and accept the license agreement and click Finish .
11. Once the installation is complete, restart Eclipse.

Installing the ADT Plugin


Follow the instructions for installing the ADT Plugin for Eclipse at http://developer.android.com/sdk/installing/installing-adt.html .
If you prefer to work in an IDE other than Eclipse, you do not need to install Eclipse or ADT. You can simply use the Android SDK tools to build and debug your
application.

Installing the Google USB Driver


The Google USB Driver for Windows is as an optional SDK component you need only if you are developing on Windows and want to connect a Google Android-
powered device (such as a Nexus 7) to your development environment over USB.
Download the Google USB driver package from http://developer.android.com/sdk/win-usb.html .

Installing the Android SDK


Install the Android SDK for plugin use with your IDE.
1. Confirm that your system meets the requirements at http://developer.android.com/sdk/requirements.html .
2. Download and install the supported version of the Android SDK starter package.
3. Add the Android SDK to your PATH environment variable:
On Windows, add <Android SDK Location>\tools to the PATH environment variable
On OS X, the command is: export PATH=$PATH:<path to Android SDK>/tools
4. Launch the Android SDK Manager and install the Android tools (SDK Tools and SDK Platform-tools) and the Android API.
5. Launch the Android Virtual Device Manager , and create an Android virtual device to use as your emulator.

Note
(For offline applications only) Due to limitation on the emulator, you cannot determine the network connection state. For more information on other
limitations, see Emulator Limitations in http://developer.android.com/tools/devices/emulator.html#limitations at the Android Developer Web site.

iOS Requirements
To build Kapsel apps for iOS, you need:
Mac OS X
Xcode and Xcode command line tools
For testing on iOS devices (not the simulator), you need:
An Apple Developer account
iOS development certificate
Provisioning files for each device you are testing with
See the Apache Cordova documentation at http://cordova.apache.org/docs/en/3.0.0/guide_platforms_ios_index.md.html#iOS%20Platform%20Guide for more
information about getting started with iOS.

Downloading the Xcode IDE


Download and install Xcode from the Apple Developers Web site.
1. Go to http://developer.apple.com/downloads/ .

Note
You must be a paying member of the iOS Developer Program. Free members cannot download the supported version.

2. Log in using your Apple Developer credentials.


3. (Optional) To narrow the search scope, unselect all Categories except Developer Tools.
4. Download the appropriate Xcode and SDK combination.

Installing Git
See http://git-scm.com/book/en/Getting-Started-Installing-Git .

Note
If you are using a proxy server you must configure git.
On Windows:
git config --global http.proxy http://proxy:8080
git config --global https.proxy http://proxy:8080
On Mac:
sudo git config --global http.proxy http://proxy:8080

PUBLIC Page 7 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
sudo git config --global https.proxy http://proxy:8080

Installing Node.js
Use Node.js v0.10.11 and later, and its package manager, npm, to install Apache Cordova. See http://nodejs.org/ . You can see the version installed by using
the node command: node –v .
You must add the Node.js folder to your system PATH.

Note
If you are using a proxy server you must configure npm. At the command prompt, enter:
On Windows:
npm config set proxy http://proxy_host:port
npm config set https-proxy http://proxy_host:port
On Mac:
sudo npm config set proxy http://proxy_host:port
sudo npm config set https-proxy http://proxy_host:port

Installing the Apache Cordova Command Line Interface


See http://cordova.apache.org/docs/en/3.0.0/guide_cli_index.md.html#The%20Command-line%20Interface . Follow all of the steps in the Cordova command
line interface readme.md.

1. Open a command prompt window, and enter:


On Windows: npm install -g cordova@<latest_supported_version>
On Mac: sudo npm install -g cordova@<latest_supported_version>
For example, to install the Cordova command line interface version 3.0.9, enter:
npm install -g cordova@3.0.9
-g indicates that Apache Cordova should be installed globally.

Note
If you are installing on Mac and you see a warning message that you are installing globally into a root-only directory, run this command to change the
owner of the command line interface installation folder:
sudo chown -R user_name /usr/local/lib/node_modules/cordova
You can copy the command text from the error message and paste it in at the command prompt at the bottom of the terminal window.

2. On Mac, when prompted, enter your root user password.


3. Verify the Cordova installation by entering this command at the command prompt, or in the terminal window: cordova –v
The output shows the Cordova version installed, for example, 3.0.9.
You should also scroll back through the entire installation history shown in the terminal and look for errors to verify the installation was successful.

Installing ios-sim
To allow the Cordova command line to start the iOS simulator on Mac, you must install ios-sim.
1. Download the ios-sim tool files from https://github.com/phonegap/ios-sim .
2. Open a terminal window, and enter: sudo npm install -g ios-sim
3. When prompted, enter your root user password.
4. Verify the ios-sim installation by entering this command in the terminal window: ios-sim --version
The output shows the ios-sim version installed, for example, 1.8.2.
Parent topic: Kapsel Development

Related Information
Creating an Apache Cordova Project
Adding the AppUpdate Plugin
Adding the Logon Plugin
Adding the AuthProxy Plugin
Adding the Logger Plugin
Adding the Push Notification Plugin
Adding the EncryptedStorage Plugin
Adding the Settings Plugin

1.3 Configuring the Application in the Management Cockpit


Configure the application settings in the Management Cockpit. These settings enable you to monitor and manage your applications.

Prerequisites
Make sure SAP Mobile Platform Server is installed.
Make sure the server is started.
Launch the Management Cockpit.
In this section:

PUBLIC Page 8 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Defining Applications
Defining Back-end Connections for Native and Hybrid Apps
Defining Application Authentication
Parent topic: Kapsel Development

Related Information
Adding the Logon Plugin

1.3.1 Defining Applications


Create a new native, hybrid, or Agentry application definition, which enables you to use Management Cockpit to manage the application.

Procedure
1. In Management Cockpit, select Applications , and click New .
2. In the New Application window, enter:

Field Value

ID Unique identifier for the application, in reverse domain notation. This is the application or bundled identifier that the
application developer assigns or generates during application development. The administrator uses the Application ID to
register the application to SAP Mobile Platform Server, and the client application code uses the Application ID while sending
requests to the server. Reverse domain notation means reversing a registered domain name; for example, reverse domain
notation for the object MyApp.sap.com is com.sap.MyApp.
The application identifier:
Must be unique.
Must start with an alphabetic character.
Can contain only alphanumeric characters, underscores (_), and periods (.).
Cannot include spaces.
Can be up to 64 characters long.

Note
The keywords that are not allowed to be entered as application identifiers include: Admin, AdminData, Push,
smp_cloud, resource, test-resources, resources, Scheduler, odata, applications, Connections, public, lcm (and its
variations, such as LCM, Lcm, lCM, LcM, lcM). These keywords are case sensitive.

Formatting guidelines:
SAP recommends that application IDs contain a minimum of two periods ("."). For example, this ID is valid:
com.sap.mobile.app1.
Application IDs cannot start with a period ("."). For example, this ID is invalid: .com.sap.mobile.app1.
Application IDs cannot include two consecutive periods ("."). For example, this ID is invalid:
com..sap.mobile.app1.

Name Application name. The name:


Can contain only alphanumeric characters, spaces, underscores (_), and periods (.).
Can be up to 80 characters long.

Vendor (Optional) Vendor who developed the application. The vendor name:
Can contain only alphanumeric characters, spaces, underscores (_), and periods (.).
Can be up to 255 characters long.

Type Application type.


Native – native applications, including Android, BlackBerry, iOS, Windows Mobile 8, and Windows 8.
Hybrid – Kapsel container-based applications.
Agentry – metadata-driven application. You can configure only one Agentry application per SAP Mobile Platform
Server; after that, Agentry no longer appears as an option.

Description (Optional) Short description of the application. The description:


Can contain alphanumeric characters.
Can contain most special characters, except percent signs (%) and ampersands (&).
Can be up to 255 characters long.

3. Click Save . You see application-related tabs, such as Back End, Authentication, Push, and so forth. The tabs you see differ by application type. You are
ready to configure the application, based on the application type.

Note
These tabs appear in Management Cockpit only after you define or select an application. The steps that follow assume you have selected the
application, and are working through each of the relevant tabs for your selected application. The steps use a "navigational shorthand"— such as "select
Applications Back End —to indicate the tab where tasks are performed, relative to that selected application, rather than repeating the entire
navigation instruction.

Parent topic: Configuring the Application in the Management Cockpit

1.3.2 Defining Back-end Connections for Native and Hybrid Apps


Define back-end connections for the selected native or hybrid application. SAP Mobile Platform supports one primary endpoint per application ID. However, the
administrator can create multiple secondary endpoints for other services used by the application; SAP Mobile Platform treats these additional endpoints as proxy
connections. For applications that access a Web service containing relative URLs, add the relative paths to enable SAP Mobile Platform Server to handle the
request correctly.

PUBLIC Page 9 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Procedure
1. From Management Cockpit, select the Home tab, then Configure Application . Alternatively, select the Applications tab.
2. On the Applications tab, select one of the applications. You see application-related tabs, such as Back End, Authentication, Push, and so forth. The tabs
you see differ by application type. You are ready to configure the application, based on the application type.

Note
These tabs appear in Management Cockpit only after you define or select an application. The steps that follow assume you have selected the
application, and are working through each of the relevant tabs for your selected application. The steps use a navigational shorthand— such as "select
Applications Back End "—to indicate the tab where tasks are performed, relative to that selected application, rather than repeating the entire
navigation instruction.

3. Enter values for the selected application:

Field Value

Connection Name (Appears only when adding a connection under Back-End Connections.) Identifies the
back-end connection by name. The connection name:
Must be unique.
Must start with an alphabetic character.
Can contain only alphanumeric characters, underscores (_), and periods (.).
Cannot include spaces.
Restricted keywords are not allowed.

Endpoint The URL (back-end connection, or service document) the application uses to access
business data on the back-end system or service. The service document URL is the
document destination you assigned to the service in Gateway Management Cockpit.
Include a trailing slash to avoid triggering a redirection of the URL, and losing
important HTTP header details. This is especially important when configuring the
application with security, such as SSOToken and Certificates, and when Rewrite
URL is enabled. Typical format:
http:// <host> : <port> /gateway/odata/ <namespace> / <Connection_or_ServiceName>

Examples:
http://testapp:65908/help/abc/app1/opg/sdata/TESTFLIGHT/
http://srvc3333.xyz.com:30003/sap/opu/odata/RMTSAMPLE/

Use System Proxy (Optional) Whether to use system proxy settings in the SAP Mobile Platform
props.ini file to access the back-end system. This setting is typically disabled,
because most back-end systems can be accessed on the intranet without a proxy.
Enable this setting only in unusual cases, where proxy settings are needed to access
a remote back-end system outside of the network. When enabled, this particular
connection is routed via the settings in props.ini file.

Rewrite URL (Optional) Whether to mask the back-end URL with the equivalent SAP Mobile
Platform Server URL. Enable this setting to ensure the client makes all requests via
SAP Mobile Platform Server, and directly to the back end. Rewriting the URL also
ensures that client applications need not do any additional steps to make requests to
the back end via SAP Mobile Platform Server. If enabled, the back-end URL is
rewritten with the SAP Mobile Platform Server URL. By default, this property is
enabled.

Allow Anonymous Access (Optional) Whether to enable anonymous access, which means the user can access
the application without entering a user name and password. However, the back-end
system still requires login credentials for data access, whether it is a read-only user,
or a back-end user with specific roles.
If enabled and the back end requires it, enter the login credential values used
to access the back-end system:
User name – supply the user name for the back-end system.
Password – (required if you set a user name) supply the password for
the back-end system.
If disabled (the default value) or the back end does not require it, you need not
provide these credentials.

Note
If you use Allow Anonymous Access for a native OData application, do not also
assign the No Authentication Challenge security profile to the application;
anonymous OData requests are not sent, and Status code: 401 is reported.

Maximum Connections The number of back-end connections that are available for connection pooling for this
application. The larger the pool, the larger the number of possible parallel connections
to this specific connection. For primary endpoints, the default and minimum is 500
connections. Factors to consider when resetting this property:
The expected number of concurrent users of the application.
The load that is acceptable to the back-end system.
The load that the underlying hardware and network can handle.
Increase the maximum number of connections only if SAP Mobile Platform Server
hardware can support the additional parallel connections, and if the underlying
hardware and network infrastructure can handle it.

Note
For secondary endpoints, there is no required minimum.

Certificate Alias If the back-end system has a mutual SSL authentication requirement, supply the
certificate alias name given to the private key and technical user certificate that is used

PUBLIC Page 10 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
to access the back-end system. The alias is located in smp_keystore. Otherwise,
leave the entry blank.

Relative Path If an application requires data from a back end that uses relative URLs, you must
configure those relative URL patterns in Management Cockpit. SAP Mobile Platform
Server rewrites the relative URLs to include the Connection ID (connection name),
enabling access to the back-end data. For example, a Web service application
requests an HTML page named abc.html, which contains the relative URLs
/sap/bc and /sap/public/bc in its src or href tags.
When a request is made, SAP Mobile Platform Server rewrites the relative URLs
contained in the response, so that subsequent requests (to these relative URLs in the
response) can be processed correctly. For example, if "webApp" is the connection
name and the response contains the relative URLs /sap/bc,/sap/public/bc;
SAP Mobile Platform rewrites these relative URLS to
/webApp/sap/bc,/webApp/sap/public/bc. Without the relative URLs, the
request cannot be processed.
To add relative paths, you can either enter one relative URL per table row (for
example, /sap/bc in one row, and /sap/public/bc in another); or you can enter
a comma-delimited list of relative URLs in one table row (for example,
/sap/bc,/sap/public/bc), and the URLs are redistributed to separate rows after
you Save.

Note
To use the Relative Path option, you must also enable the Rewrite URL option.

4. (Optional) Under Back-end Connections, view additional connections, or add new connections.
1. Click New , to add additional back-end connections in the server.
2. Enter values for the new back-end connection, using the values shown above.
3. Click Save . The new back-end connection is added to the list.
You can maintain the list of server-level back-end connections (including all the connections in SAP Mobile Platform Server), and of application-specific
back-end connections. Application-specific back-end connections are the secondary connections that are enabled for an application; by default, no
secondary connections are enabled. You must explicitly enable additional back-end connections for an application. Users who are registered to an
application can access only these back-end connections. If a user attempts to access a back-end connection (request-response) that is not enabled for an
application, it is not allowed and a 403, Forbidden error is thrown.
5. Select Application-specific Connections from the drop-down to show the back-end connections that are enabled for the application.
Select Server-level Connections from the drop-down to show all available connections for the server. Use the checkbox to enable additional connections for
the application.

Note
You can authenticate multiple back ends using various authentication provider options in the back-end security profile.
If the back-end system issues a “302 Redirect” or "307 Redirect" response, which means it is redirecting the request to a different URL, then you
must also add the target URL to the list of application-specific connections.

Parent topic: Configuring the Application in the Management Cockpit

Related Information
Configuring Push on SAP Mobile Platform Server

1.3.3 Defining Application Authentication


Assign a security profile to the selected application. The security profile defines parameters that control how the server authenticates the user during onboarding,
and request-response interactions with the back end.

Prerequisites
Before you define application authentication in a production environment, you must configure security profiles for application authentication. In a development or
test environment, you can use a security profile such as Default.

Context
Security profiles are made up of one or more authentication providers. These authentication providers can be shared across multiple security profiles, and can be
modified in Management Cockpit. For more information on authentication providers, see Authentication in SAP Mobile Platform.
You can stack multiple providers to take advantage of features in the order you chose; the Control Flag must be set for each enabled security provider in the
stack.

Procedure
1. From Management Cockpit, select Applications Authentication .
2. Click Existing Profile .

Note
You can also create a new profile.

PUBLIC Page 11 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
3. Select a security profile name from the Name list. The name appears under Security Properties, and the providers that are associated with the security
profile appear under Authentication Providers.
4. Under Security Profile Properties, view or enter values.

Field Value

Name A unique name for the application authentication profile.

Check Impersonation (Optional) In token-based authentication, whether to allow authentication to succeed when the user name
presented cannot be matched against any of the user names validated in the login modules. By default the
property is enabled, which prevents the user authentication from succeeding in this scenario.

5. Under Authentication Providers, you can select a security profile URL to view its settings. To change its settings, you must modify it using Settings
Security Profiles .
Parent topic: Configuring the Application in the Management Cockpit

Related Information
Application and Device Security Overview
Kapsel Security Matrix

1.4 Creating an Apache Cordova Project


To create an Apache Cordova 3.4 project for use with Kapsel, use the Cordova command line tool.

Prerequisites
Set up your development environment.

Context
You must run the commands from a Windows command prompt, or a terminal window on iOS. See
http://cordova.apache.org/docs/en/3.0.0/guide_cli_index.md.html#The%20Command-line%20Interface .

Procedure
1. Create a folder to hold your Kapsel Cordova projects. For example, on Windows, C:\Documents and
Settings\<your_account>\Kapsel_Projects, or on OS X, ~/Documents/Kapsel_Projects.
2. Open a Windows command prompt or terminal and navigate into the project folder you created.
3. At the command prompt, enter:
cordova -d create <Project_Folder> <Application_ID> <Application Name>
Use the appropriate delimiter for path names.
The -d flag indicates debug output and is optional.
This command may take a few minutes to complete, as an initial download of the template project that is used is downloaded to
C:\Users\user\.cordova on Windows, or ~/users/user/.cordova on Mac.
The parameters are:
(Required) < <Project_Folder> > – the directory to generate for the project.
(Optional) < <Application_ID> > – must match the Application ID as configured on SAP Mobile Platform Server for the application, which is reverse-
domain style, for example, com.sap.kapsel.

Note
<Application_ID> cannot be too simple. For example, you can have "a.b" for an ID, but you cannot have "MyApplicationId." The ID is used as
the package name (name space) for the application and it must be at least two pieces separated by a period, otherwise, you will get build errors.

(Optional) < <Application_Name> > – name for the application.


In this example, you create a project folder named LogonDemo in the Kapsel_Projects directory. The Application ID is "com.mycompany.logon" and
the application name is "LogonDemo." Running cordova -d allows you to see the progress of the project creation.
cordova -d create ~\Kapsel_Projects\LogonDemo com.mycompany.logon LogonDemo
Your new project includes scripts to build, emulate, and deploy your application.

Note
All of the Cordova command line interface commands operate against the current folder. The create command creates a folder structure for your
Cordova projects while the remaining commands must be issued from within the project folder created by create.

4. To add the platform, change to the folder you created in the previous step: cd <~Project_Name> This OS X example adds the Android and iOS
platforms, creating both an Xcode project and an Android project.
cd ~\Kapsel_Projects\LogonDemo
cordova platform add ios android

Note
Android is supported on both Windows and OS X, but iOS is supported only on OS X.

Note
You must add the platform before you add any Kapsel plugins.

PUBLIC Page 12 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
The project directory structure is similar to this:
LogonDemo/
|--.cordova/
|-- merges/
| |-- android/
| `-- ios/
|-- platforms/
| |-- android/
| `-- ios/
|-- plugins/
|-- www/
-- config.xml
`
.cordova – identifies the project as a Cordova project. The command line interface uses this folder for storing its lazy loaded files. The folder is
located immediately under your user’s home folder (On Windows, c:\users\user_name\ , and on Macintosh,
/users/user_name/.cordova).
merges – contains your Web application assets, such as HTML, CSS, and JavaScript files within platform-specific subfolders. Files in this folder
override matching files in the www/ folder for each respective platform.
www – this folder contains the main HTML, CSS, and JavaScript assets for your application. The index.html file is the default page of the
application. Once you finish editing your project's files, update the platform specific files using the cordova -d -prepare command.
config.xml – the config.xml file in the root directory contains meta data and native application information needed to generate the application.
platforms – native application project structures are contained in subfolders for the platforms you added to your application.
5. (Optional) You can test your Cordova project by opening it in the respective development environment, for example, Xcode or Eclipse with the ADT plugins,
and running it on the simulator or emulator.
6. Add the plugins. For example, to add the Cordova console plugin and the Kapsel Logon plugin on Windows, enter:
cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git
cordova -d plugin add C:\SAP\MobileSDK3\KapselSDK\plugins\logon

Note
The path you enter to the Kapsel plugin must be the absolute path (not relative path).

7. Edit the Web application content in the project's www folder and use the cordova prepare command to copy that content into the Android and iOS project
folders:
cordova -d prepare android
cordova -d prepare ios
In this section:
Project Settings
Parent topic: Kapsel Development

Related Information
Setting Up the Development Environment
Adding the AppUpdate Plugin
Adding the Logon Plugin
Adding the AuthProxy Plugin
Adding the Logger Plugin
Adding the Push Notification Plugin
Adding the EncryptedStorage Plugin
Adding the Settings Plugin

1.4.1 Project Settings


To set application configuration parameters, use the Cordova platform-independent config.xml file.

To modify application metadata, edit the config.xml file. The config.xml file is located in the root directory in your project. For information about the project
settings for each platform, see http://cordova.apache.org/docs/en/3.0.0/config_ref_index.md.html#Configuration%20Reference .
Parent topic: Creating an Apache Cordova Project

1.5 Using UI Development Frameworks


Kapsel is UI5 framework agnostic. You can use any third party framework with Kapsel that is compatible with Cordova. This section discusses framework
integration with Kapsel, and provides an overview of common UI libraries for standards-based Web development.

SAPUI5
If you have not already selected a framework for your UI development, selecting SAPUI5 allows you to efficiently leverage Kapsel's integration with SAPUI5.
Kapsel's Login plugin uses the UI5 framework. Another strength of UI5 is that you can write an application, for desktop and mobile, using a single code base.
SAPUI5, also known as SAP UI Development Toolkit for HTML5, is the SAP client-side HTML5 rendering library with a large set of RIA-like standard and
extension controls based on JavaScript (JS), and a lightweight programming model. The rendering control library is Open AJAX-compliant and based on open
source jQuery and can be used together with other client-side libraries.
For more information:
SAPUI5
SAPUI5 for Mobile
SAPUI5 Mobile Demo Apps

PUBLIC Page 13 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
jQuery Mobile
Some of the other popular open-source frameworks include:
jQuery Mobile is an HTML5 based user interface system for mobile devices.
For more information:
jQuery Mobile

Sencha Touch
Sencha Touch is an HTML5 mobile application framework that encourages a model, view, and controller pattern.
For more information:
Building SAP mobile apps with Sencha Touch
SAP and Sencha Touch

Kendo UI
Kendo UI is an HTML5/JavaScript framework for modern Web and mobile application development.
For more information:
Kendo UI
Parent topic: Kapsel Development
Parent topic: Developing Kapsel Applications
Previous topic: Creating an Apache Cordova Project
Next topic: Configuring the Client for Authentication

1.6 Configuring the Client for Authentication


You can configure a client for basic authentication or mutual certificate authentication with Afaria Server.

In this section:
Configuring the iOS Client for Basic Authentication over HTTP(S)
Configuring the iOS Client for Mutual Authentication over HTTP(S)
Configuring the Android Client for Basic Authentication over HTTP(S)
Configuring the Android Client for Mutual Authentication over HTTP(S)
Parent topic: Kapsel Development
Parent topic: Developing Kapsel Applications
Previous topic: Using UI Development Frameworks
Next topic: Managing Application Registration Using Client Hub

1.6.1 Configuring the iOS Client for Basic Authentication over


HTTP(S)
Configure the iOS client for basic authentication over HTTP or HTTPS.

Procedure
1. For HTTPS, import the root certificate to the iOS device.
2. Set the selected application ID in the sap.Logon.init method when initializing the application.
3. Set the project settings' keychain group to "clienthubEntitlements" and $(CFBundleIdentifier).
4. Start the application on device and register with the following settings:
Username
Username as assigned by your administrator.
Password
Password for your assigned username.
Host
Enter the hostname for your SAP Mobile Platform Server. This value must match the server name used for generating the server certificate.
Port
For HTTPS, enter 8081.
For HTTP, enter 8080.
Secure
For HTTPS, enter ON.
For HTTP, enter OFF.
Security configure
Enter the selected security configuration name for sharing the credentials with other applications.
5. After registering, a new registration appears in Management Cockpit for the application.
Parent topic: Configuring the Client for Authentication

1.6.2 Configuring the iOS Client for Mutual Authentication over


HTTP(S)
Configure the iOS client for mutual authentication using a certificate provisioned through Afaria Server.

PUBLIC Page 14 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Procedure
1. Verify that the application ID uploaded in Afaria Server's application deployment package matches the Application ID set on the device application.
2. If the SAP Mobile Platform Server uses a self-signed certificate for the HTTPS connection, then the device needs to import the server certificate to trust the
server certificate.
3. Open the Xcode project and in MAFLogonMangerNG.bundle set keyMAFUseAfaria to YES (launches Afaria if installed on the device).
4. Verify that the handleOpenURL() method is defined in index.js. If it is not defined, then define an empty method for it, so that the client application
functions properly when launched by the Afaria client. function handleOpenURL(url){}
5. Create the Url schemes and Url identifier items in the .plist file for Logon.
6. Register a custom URL scheme by creating the Url schemes and Url identifier items in the application's info .plist file, to allow communications
with the Afaria client.
7. The client connection settings can come from either the Afaria package configuration or the clienthub.plist file. The settings in the
clienthub.plist file are applied only if Client Hub is enabled for sharing credentials. If both settings are available, the settings in the
clienthub.plist file take priority over the Afaria package configuration.
Parent topic: Configuring the Client for Authentication
Parent topic: Provisioning Applications Using Afaria

1.6.3 Configuring the Android Client for Basic Authentication over


HTTP(S)
Configure the iOS client for basic authentication over HTTP or HTTPS.

Procedure
1. For HTTPS, import the root certificate to the device.
2. Start the application on device and register with the following settings:
Username
Username as assigned by your administrator.
Password
Password for your assigned username.
Host
Enter the hostname for your SAP Mobile Platform Server. This value must match the server name used for generating the server certificate.
Port
For HTTPS, enter 8081.
For HTTP, enter 8080.
Secure
For HTTPS, enter ON.
For HTTP, enter OFF.
Security configure
Enter BASIC.
3. After registering, a new registration appears in Management Cockpit for the application.
Parent topic: Configuring the Client for Authentication

1.6.4 Configuring the Android Client for Mutual Authentication


over HTTP(S)
Configure the Android client for mutual authentication using a certificate provisioned through Afaria Server.

Procedure
1. Verify that the application ID uploaded in Afaria Server's application deployment package matches the Application ID set on the device application.
2. Import the root certificate to the device. Note that the server's DNS name, not an IP address, must be described in the certificate's common name (CN) field.
3. Verify that the handleOpenURL() method is defined in index.js. If it is not defined, then define an empty method for it, so that the client application
functions properly when launched by the Afaria client. function handleOpenURL(url){}
4. When you use Client Hub, you can use an optional clienthub.property file to specify the registration settings. Update the file server connection
information based on your own server, and add clienthub.property file into the resource folder of the application project.
Parent topic: Configuring the Client for Authentication
Parent topic: Provisioning Applications Using Afaria

1.7 Managing Application Registration Using Client Hub


Kapsel applications can use the Client Hub, integrated with Logon Manager, to simplify user onboarding and configuration to enable easier and faster enterprise-
wide deployments.
The Client Hub saves the end user from managing multiple passwords for mobile applications, thereby improving the user experience. The Client Hub provides
these functions:
Manages single sign-on (SSO) on the device.
Enables cosigned business applications with the same security configuration to securely share credentials on the device.
Supports multiple security configurations per device.
Parent topic: Kapsel Development

PUBLIC Page 15 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Parent topic: Developing Kapsel Applications
Previous topic: Configuring the Client for Authentication
Next topic: Provisioning Applications Using Afaria

Related Information
Using the Logon Plugin
Managing iOS Application Registration Using Client Hub
Managing Android Application Registration Using Client Hub
Adding the AuthProxy Plugin

1.8 Provisioning Applications Using Afaria


SAP Mobile Platform supports Afaria device management and security functionality. You can use Afaria to provision native and hybrid applications that use the
MAF Logon UI component. You can generate certificate requests which in turn are passed through Afaria to the corporate PKI system for CA signature.
When provisioning an application, you must use the provisioning file method to configure the application configuration data, rather than entering application data in
the provisioning text box in Afaria. In this method, you create a provisioning file containing a set of parameters.
For information on setting up the Afaria environment, and the format for creating the provisioning file, see:
SAP Mobile Platform Server > Administrator > Application Administration > Provisioning Applications > Provisioning with Afaria.
In this section:
Preparing the Kapsel Application for Afaria Provisioning
Configuring the Android Client for Mutual Authentication over HTTP(S)
Configuring the iOS Client for Mutual Authentication over HTTP(S)
Parent topic: Kapsel Development
Parent topic: Developing Kapsel Applications
Previous topic: Managing Application Registration Using Client Hub
Next topic: Kapsel Plugins

Related Information
Using the Logon Plugin
Managing iOS Application Registration Using Client Hub
Managing Android Application Registration Using Client Hub
Adding the AuthProxy Plugin

1.8.1 Preparing the Kapsel Application for Afaria Provisioning


To prepare the Kapsel application to be provisioned through Afaria, provide an initial context to the Login plugin, and specify an application ID configured on SAP
Mobile Platform Server with an X.509 security profile.

Context
Specify information needed for provisioning in these files:
The clienthub.properties file (for Android) or clienthub.plist file (for iOS) provide an initial context to the Login plugin and instruct the Login
plugin that it is to use a certificate from Afaria for authentication.
The index.html file specifies an application ID that must match an application ID on the SAP Mobile Platform Server that is configured with a security
profile for X.509 authentication.

Procedure
Create an index.html which specifies an application ID that is configured on SAP Mobile Platform Server with a security profile for X.509 authentication. The
following is a sample index.html:
<html>
<head>
<script src="datajs-1.1.1beta2.js"></script>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script>
applicationContext = null;
var appId = "certAuth"; // Change this to app id on server

function init() {

// Optional initial connection context


var context = {
"serverHost": "example.corp", //Place your SMP 3.0 server name here
"https": "false",
"serverPort": "8080",
"user": "username", //Place your user name for the OData Endpoint here
"password": "xxxxxxx", //Place your password for the OData Endpoint here
"communicatorId": "REST",
"passcode": "password",
"unlockPasscode": "password"

PUBLIC Page 16 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
};
sap.Logon.init(logonSuccessCallback, errorCallback, appId, context, sap.logon.IabUi);
console.log("init completed");
}

function read() {
var url = applicationContext.applicationEndpointURL;
var logonCert = new sap.AuthProxy.CertificateFromLogonManager(appId);
var headers = {};
headers["X-SMP-APPCID"]=applicationContext.applicationConnectionId;
var errorCB = function(errorInfo){
alert("error: " + JSON.stringify(errorInfo));
}
var successCB = function(result){
alert("success: " + JSON.stringify(result));
}

sap.AuthProxy.get(url,headers,successCB,errorCB,null,null,null,logonCert);
}

function readSuccessCallback(data, response) {


alert("success: " + JSON.stringify(data));
/*var carrierTable = document.getElementById("carrierTable");

for (var i = data.results.length -1; i >= 0; i--) {


var row = carrierTable.insertRow(1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
cell1.innerHTML = data.results[i].carrid;
cell2.innerHTML = data.results[i].CARRNAME;
}*/
}

function clearTable() {
var carrierTable = document.getElementById("carrierTable");
while(carrierTable.rows.length > 1) {
carrierTable.deleteRow(1);
}
}

function logonSuccessCallback(result) {
console.log("logonSuccessCallback " + JSON.stringify(result));
if (result) { //calling registerOrUnlock returns null the second time it is called.
applicationContext = result;
}
}

function logonLockSuccessCallback(result) {
console.log("logonLockSuccessCallback " + JSON.stringify(result));
applicationContext = null;
}

function logonUnregisterSuccessCallback(result) {
console.log("logonUnregisterSuccessCallback " + JSON.stringify(result));
applicationContext = null;
}

function register() {
sap.Logon.registerOrUnlock(logonSuccessCallback, errorCallback);
}

function unRegister() {
sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, errorCallback);
clearTable();
}

function lock() {

function errorCallback(e) {
alert("An error occurred");
alert(JSON.stringify(e));
}
sap.Logon.lock(logonLockSuccessCallback,errorCallback);
clearTable();
}

function unlock() {
sap.Logon.unlock(logonSuccessCallback,errorCallback);

PUBLIC Page 17 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
}

document.addEventListener("deviceready", init, false);

</script>

</head>
<body>
<h1>Logon Sample</h1>
<button id="register" onclick="register()">Register</button>
<button id="read" onclick="read()">Read</button>
<button id="unregister" onclick="unRegister()">Unregister</button>
<button id="lock" onclick="lock()">Lock</button>
<button id="unlock" onclick="unlock()">Unlock</button>
<table id="carrierTable"><tr><th>Carrier ID</th><th>Carrier Name</th></tr></table>
</body>
</html>
Parent topic: Provisioning Applications Using Afaria

1.9 Kapsel Plugins


Developers use one or more Kapsel plugins in Cordova applications to add SAP Mobile Platform awareness and capabilities to the application. The plugins that
you use vary depending on your application’s requirements. As they are standard Cordova plugins, manage Kapsel plugins in a Cordova project using the
standard Cordova CLI plugin commands.

Kapsel Plugin Use

AppUpdate (Required) As the Kapsel lifecycle management plugin, AppUpdate manages application update downloads and installs updates
to the Kapsel application. The AppUpdate plugin initiates the check for an update when the application starts, and when it
resumes after being suspended. You can also start an app update manually, if required.
AppUpdate requires the Logon plugin; the two plugins are installed together.

Logon Manages user onboarding and the authentication process for SAP Mobile Platform applications. Most other Kapsel plugins use
capabilities that this plugin exposes. The plugin interfaces with the SAP Afaria® client as well as the Client Hub application to
help manage authentication and single sign-on.
You can install this plugin standalone, or it is automatically installed with AppUpdate.

AuthProxy Provides capabilities that are used in certain security scenarios such as mutual authentication and in SiteMinder environments.

Logger Lets you have an application write entries to a local log, which can be uploaded to the SAP Mobile Platform Server for analysis.
The SAP Mobile Platform administrator can manage setting the application log remotely from the server and upload device logs to
the server without user intervention.

Push Manages the process of registering for push requests as well as exposes events that help you code an application to respond to
push notifications. Once the push registration is completed, the plugin uses the Settings plugin to exchange application settings
information with SAP Mobile Platform Server so it knows how to manage delivery of push notifications to the application.

EncryptedStorage Adds an encrypted persistent store (key/value pair) to a Cordova application, which allows you to build an application that securely
stores application data while offline, or while the application is not running. Unlike the built-in local storage, EncryptedStorage is
nonblocking.

Settings Required if you are using the Push plugin. Manages the exchange of settings information between the Kapsel app and the SAP
Mobile Platform server. Used by the Push plugin.

In this section:
Using the Logon Plugin
Using the AuthProxy Plugin
Using the AppUpdate Plugin
Using the Logger Plugin
Using the Push Plugin
Using the EncryptedStorage Plugin
Using the Settings Plugin
Parent topic: Kapsel Development

1.9.1 Using the Logon Plugin


The Logon plugin helps register the application/user with the SAP Mobile Platform Server, and integrates with Afaria for provisioning X.509 settings and Client
Hub.

Note
Before implementing the Logon plugin, you should thoroughly understand the Client Hub service with which the plugin is integrated to enable onboarding. If you
are using an iOS device, you must add the "clienthubEntitlements" to the Keychain Groups in the Entitlement section in Xcode.

In this section:
Logon Plugin Overview
Adding the Logon Plugin
Configuring Default Values
Running the Logon Application on iOS
Removing Fields From the Registration Screen
Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers
Kapsel Logon API Reference

PUBLIC Page 18 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Parent topic: Kapsel Plugins

Related Information
Client Hub
Provisioning Applications Using Afaria
Managing Application Registration Using Client Hub
Adding the AuthProxy Plugin

1.9.1.1 Logon Plugin Overview


The Logon plugin manages the application registration and authentication processes either through SAP Mobile Platform Server, or through SAP Gateway server.
Most of the Kapsel plugins rely upon the services provided by the Logon plugin. This plugin manages the process of onboarding applications with SAP Mobile
Platform Server, and authenticating users. The Logon plugin, where available, interfaces with Client Hub and pulls certificates from Afaria.
The SAP Mobile Platform Server integrates with common security providers such as HTTP/HTTPS Authentication, Directory Service (LDAP), or X.509 user
certificate. The Logon plugin provides a login screen where the user can enter the values needed to connect to SAP Mobile Platform server using one of these
providers, and stores those values in its own secure data vault.

Data Vault and Passcode Policy


The data vault provided with the Login plugin is a separate data vault from the one provided with the EncryptedStorage plugin, and is used to store user names,
password, keys and certificates, while the EncryptedStorage plugin is suited to storing application data. The data vault stores the server connection details and, in
basic authentication, the username and password. In certificate-based authentication, the certificate is not stored in the data vault.
You set a passcode policy on the SAP Mobile Platform Server. The client downloads this policy after a successful user login. To unlock a data vault, you provide
a passcode if the policy requires one. If the policy does not require a passcode, you do not need to provide a passcode. However, a policy that does not require a
passcode is unsecure and is not recommended.
When not using the data vault, it can timeout and the data vault locks itself upon the time expiration in the passcode policy. Note: even though you could be using
an application actively, if you are not accessing the data vault, it can timeout. You can first notice the data vault lock, when you try to access the application.
The data vault is deleted if the user forgets their passcode while unlocking the application and expires the maximum number of attempts to login, or explictly
deletes the registration. Data stored by the EncryptedStorage plugin is also deleted, because once the data vault is deleted this data would no longer be
accessible. For security reasons, when the data vault is deleted, the Login plugin sends a notification to the other Kapsel plugins so they can clean up their data if
required.

Logon States During Application Onboarding


The following states occur in the Logon plugin during Kapsel application onboarding:
Unregistered: this state occurs when you launch the application for the first time, and prior to registration with the server.
Registered: this state occurs when you have successfully registered with SAP Mobile Platform or Netweaver Gateway. The registration information has not
been persisted into the data vault.
Fully registered: this state occurs when the registration information has been persisted into the data vault. The data vault is protected by the user selected
password, or by a system-generated default password. (If allowed by the application developer, and the user chooses to disable the password, then the
data vault is still encrypted, but a system-generated default password is used to protect the data vault).

Data Vault States


The Logon plugin lets the user lock and unlock the application, to protect sensitive data. If you call the unlock method with a system-generated password, you
can call the method without need to provide the password. Using a default password is less secure as the data vault can be unlocked without the user providing a
password. The data vault can be in the following states:
Data vault locked: the data vault is locked and requires a passcode to unlock it before accessing the application data.
Data vault unlocked: The passcode for the data vault has been verified, and the data vault is available for access.

Support for Online Applications


Kapsel supports online applications that do not require onboarding by providing a passcode management API in the Logon plugin. This support allows you to use
functionality such as passcode and encrypted storage in your online application, without requiring your application to onboard with SAP Mobile Platform Server.
The passcode management API in the Logon plugin allows you to create and delete a data vault without registering with SAP Mobile Platform. You can use the
passcodePolicy parameters to set the passcode policy, and the context parameter to set the default passcode shown in the setting passcode screen, so
the user does not need to type the passcode on the mobile device. You can return the passcode policy by calling the sap.Logon.core.getContext API.

initPasscodeManager(successCallback, errorCallback, applicationId, customView, passcodePolicy, context)


deletePasscodeManager
After the data vault is created, you manage the data vault using the existing data vault management API in the Logon plugin, including the methods
managePasscode , unlock , lock , set , and get .

Security Configurations
Kapsel supports the following security configurations:
Basic authentication (HTTP)
Basic authentication (HTTPS)
SiteMinder (non-network edge)
SiteMinder network edge (reverse proxy)

PUBLIC Page 19 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
SSO over HTTP
SSO over HTTPS
Mutual certificate authentication between the client and SAP Mobile Platform Server
SSO with certificate (X509) MCIM
SSO with token - MCIM
SSO with username password - MCIM
From the client perspective, the client authenticates either through basic authentication, or through mutual certificate authentication. In the basic authentication
scenario, tthe client must provide a client certificate that is signed by a certificate authority trusted by the server.
For more information on SAP Mobile Platform supported authentication scenarios, see Planning Your Security Landscape in Administrator.

Domain Whitelisting
Kapsel plugins support Apache Cordova's domain whitelisting model. Whitelisting allows you to control access to external network resources. Apache Cordova
whitelisting allows you to whitelist individual network resources (URLs), for example, http://www.google.com.
For information about the whitelist rules, see http://docs.phonegap.com/en/3.3.0/guide_appdev_whitelist_index.md.html .
Parent topic: Using the Logon Plugin

Related Information
Kapsel Logon API Reference

1.9.1.2 Adding the Logon Plugin


To install the Logon plugin, use the Cordova command line interface.

Prerequisites
Set up the development environment.
Create your Cordova Project.
Add your OS platforms.

Procedure
1. Add the plugin, by entering, at the command prompt:
On Windows:
cordova -d plugin add <SDK_HOME>\MobileSDK3\KapselSDK\plugins\logon
On Mac:
cordova -d plugin add ~<SDK_HOME>/MobileSDK3/KapselSDK/plugins/logon

Note
The path you enter to the Kapsel plugin must be the absolute path (not relative path).

2. (Optional) To see a list of installed plugins in your Cordova project, open a command prompt or terminal window, navigate to your Cordova project folder, and
enter: cordova plugins The Cordova command line interface returns a JSON array showing installed plugins, for example:
[ 'com.sap.mp.cordova.plugins.corelibs',
'com.sap.mp.cordova.plugins.logon',
'org.apache.cordova.console',
'org.apache.cordova.device',
'org.apache.cordova.device-orientation',
'org.apache.cordova.dialogs',
'org.apache.cordova.inappbrowser' ]
In this case, some core Cordova plugins were added, including corelibs, console, device, device-orientation, dialogs, and inAppBrowser. CoreLibs is a
utility plugin that is automatically added to every Kapsel project by the command line interface, so you need never add the CoreLibs plugin to a project
manually.
3. Configure the application in Management Cockpit.
4. Define a variable in the JavaScript code (typically, this is done in the index.html file of your Cordova application) to describe the app ID, for example:
var appId = "com.sap.kapsel.mykapselapp"; Kapsel uses an app ID to tell the server which application definition on the server to use for this
application. The app ID that is defined on the server must match what is entered here.
5. Define the connection to the server, for example:
var defaultContext = {
"serverHost" : "192.168.254.159",
"https" : "false",
"serverPort" : "8080",
};
This prepopulates the fields in the registration dialog that is shown to users during the initialization process.
6. Make a call to the Logon plugin’s init method as shown:
//Make call to Logon's Init method to get things registered and all set up
sap.Logon.init(logonSuccess, logonError, appId, defaultContext);
The init method gathers information about the environment’s security configuration by asking the Afaria client and Client Hub application, if available,
sets up and configures the DataVault, connects to the server to register the application connection and authenticate the user. As part of this process, the
appropriate screens are shown to gather user input and manage the entire process.
7. Verify the registration in Management Cockpit.

PUBLIC Page 20 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1. Log in to Management Cockpit.
2. Click Applications .
3. Click Registrations . You can see the registration ID following a successful registration.

8. Use the Android IDE or Xcode to deploy and run the project.

Note
If you are deploying to an iOS device, in Xcode, you must add the clienthubEntitlements and $(CFBundleIdentifier) to the keychain group in the
Entitlements section as well as the bundle identifier.

Parent topic: Using the Logon Plugin

Related Information
Adding the AppUpdate Plugin
Adding the AuthProxy Plugin
Adding the Logger Plugin
Adding the Push Notification Plugin
Adding the EncryptedStorage Plugin
Adding the Settings Plugin
Setting Up the Development Environment
Creating an Apache Cordova Project
Configuring the Application in the Management Cockpit

1.9.1.3 Configuring Default Values


Add JavaScript to configure default logon settings.

Procedure
1. Go to the <Project Name>/www folder and open the file where you want to add the JavaScript, for example, index.html.
2. Add your code, for example:
function logonSuccessCallback(context) {
console.log("logonSuccessCallback " + JSON.stringify(context));
}

function errorCallback(e) {
alert("An error occurred");
alert(JSON.stringify(e));
}

function deviceReady() {

var appId = "theAppId"; // Change this to app id on server

PUBLIC Page 21 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
// Optional initial connection context
var context = {
"serverHost": "example.com",
"https": "false",
"serverPort": "8080",
"communicatorId": "REST",
};
sap.Logon.init(logonSuccessCallback, errorCallback, appId, context);
}

document.addEventListener("deviceready", deviceReady, false);


This example shows the call to the sap.Logon.init function, as well as the success and error callbacks that are passed to the sap.Logon.init
function. It also shows how you can make sure the registration process is started as soon as possible by attaching a listener to the deviceready
event. Inside the deviceReady function, the app ID and the context are defined.
3. Save the file.
Parent topic: Using the Logon Plugin

1.9.1.4 Running the Logon Application on iOS


Deploy and run the Logon project on iOS.

Procedure
1. In a terminal window, make sure you are in the project folder and execute the command: cordova prepare ios
2. Open Xcode.
3. In a Finder window, browse to your Cordova project folder, <Project Name>/platforms/ios.
4. Double-click the <ProjectName>.xcodeproj file to open the project in Xcode.
5. Add the clienthubEntitlements and $(CFBundleIdentifier) keychain groups to the Capabilities (Xcode 5) or Entitlements section of the project. This shows
an example:

6. The Afaria client is opened after calling sap.Logon.init(...), but can be disabled by modifying the file MAFLogonManagerOptions.plist. In Xcode,
locate this file under Resources > MAFLogonManagerNG.bundle > MAFLogonManagerOptions.plist , and set keyMAFUseAfaria to false.
7. If modifying the build settings for an iOS7 or iOS7.1 Deployment Target, you may get a library link error. You can manually add the libstdc++.6.0.9.dylib to
fix the issue.
8. Select your Simulator type and click the Run button.
Parent topic: Using the Logon Plugin

Related Information
Running the Kapsel Application on Android
Running the Kapsel Application on iOS

1.9.1.5 Removing Fields From the Registration Screen


If your application does not use a relay server, a reverse proxy server, or connect to an SAP Mobile Platform 2.x server, you can remove some of the fields from
the registration screen, such as the URL Suffix, Company ID, and Security Config.

PUBLIC Page 22 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Procedure
1. Open the StaticScreens.js file, which is located in SDK_HOME\MobileSDK3\KapselSDK\plugins\logon\www\common\modules.
2. Find the SCR_REGISTRATION screen and reorder, or hide and show fields using the visible:false options. You can also delete unneeded entries. For
example:
SCR_REGISTRATION': {
id: 'SCR_REGISTRATION',
fields: {
user : {
uiKey:'FLD_USER'
},
password : {
uiKey:'FLD_PASS',
type: 'password'
},
serverHost : {
uiKey:'FLD_HOST',
editable:true
},
serverPort : {
uiKey:'FLD_PORT',
type: 'number',
editable:true,
visible:true
},
communicatorId : {
uiKey: 'FLD_COMMUNICATORID',
'default':'REST',
visible:false
},
https: {
uiKey:'FLD_IS_HTTPS',
type: 'switch',
'default':false,
visible:false
},

}
},
3. Save the file.
Parent topic: Using the Logon Plugin

Using the X.509 Certificate Provider Interface to Integrate with


Third-Party Certificate Providers
Use the X.509 certificate provider interface to integrate third-party certificate provider solutions into native and hybrid applications.
The CertificateProvider interface defines a provider class to wrap X.509 certificate generation, signing, and storage, and integrates with Logon for Kapsel
and native SDKs. All logic related to generating public/private keys, and presenting the UI to get user input (for example, username/password and common
name) for obtaining the certificate is encapsulated in the CertificateProvider.

Using the CertificateProvider Interface with Kapsel Applications


For Kapsel SDK applications, you can implement and integrate a customized CertificateProvider into the Kapsel Logon plugin to getting the signed certificate
(X509KeyManager for Android, or SecIdentityRef for iOS) for mutual authentication or application registration. The certificate provider can define its own UI screens
as an ASP UI5 JSView for collecting the user input required by the certificate provider to retrieve the certificate. The JSView is added into the Kapsel application
as a web resource and loaded by the Logon plugin when requested by the certificate provider.
In this section:
Creating a Custom Certificate Provider
Creating a Resource to Display a UI View
Building and Running an iOS Project
Building and Running an Android Project
Enabling a CertificateProvider in an Application
CertificateProvider Interface Reference
CertificateProvider Samples
Localizing a CertificateProvider
Parent topic: Using the Logon Plugin

1.9.1.6.1 Creating a Custom Certificate Provider


Create a CustomCertificateProvider that implements four methods in the CertificateProvider interface.
For iOS:
- (void) getCertificate:(id<CertificateProviderDelegate>) delegate;

PUBLIC Page 23 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
- (BOOL) getStoredCertificate:(SecIdentityRef *)identityRef error:(NSError**)anError;
- (BOOL) deleteStoredCertificateWithError:(NSError**)anError;
- (BOOL) setParameters:(NSDictionary*)params failedWithError:(NSError **)error;
For Android:
void getCertificate(CertificateProviderListener callbackObject)
X509KeyManager getStoredCertificate() throws CertificateProviderException
void deleteStoredCertificate() throws CertificateProviderException
void setParameters(Map params)
For each platform, the first three methods are required; setParameters is optional, and necessary only if using showUI with an HTML or JavaScript view.

getCertificate Method
The getCertificate method is the main method called by the Logon Plugin before application registration, if the UserCreationPolicy key is set to
certificate.

This method contains logic for combining the private key and signed public key, and constructing a SecRefIdentity (for iOS), or X509KeyManager (for
Android).
For iOS, when the SecRefIdentity is prepared, call [delegate onGetCertificateSuccess:mySecRefIdentity], to provide the Logon Plugin with
the identity to be used to authenticate the end user for registration.
In the case of an error, construct an NSError for the onGetCertificateFailure response. The error is logged. The specific Error Code numbers and
messages you select are flexible, but for simplicity and consistency, we recommend starting from the set defined in X509FileCertificateProvider.h.
#define Certificate_Provider_Error_Domain @"ERR_Certificate_Provider"
#define ERR_ShowUI_Delegate_Html -1
#define ERR_ShowUI_Delegate_ViewController -2
#define ERR_ShowUI_Delegate_No_UI_Settings -3
#define ERR_Set_Parameters_Failed -4
#define ERR_Certificate_File_Not_Exist -5
#define ERR_Load_Certificate_From_File_Failed -6
#define ERR_Save_Certificate_To_KeyChain_Failed -7
#define ERR_Read_KeyChain_Item_Failed -8
#define ERR_Delete_Saved_Certificate_Failed -9

getStoredCertificate Method
The getStoredCertificate method is different from getCertificate in one critical way: it is synchronous, and is designed to be called by the application
many times, for HTTP requests, instead of only once, for application registration. Therefore, the implementation should return either an identity already in
memory, or return an identity from the keychain or a similar 3rd-party API. You should not show UIs or execute long-running processes within this method.
If an identity cannot be returned from the keychain, return an error. The requesting library makes a call to the Logon Plugin, requesting that
it refreshCertificate. Logon Plugin then calls the next method, deleteStoredCertificate, then makes a new asynchronous getCertificate call.

deleteStoredCertificate Method
The deleteStoredCertificate method is necessary for handling cases of "invalid certificate" HTTP responses, which might result from an expired or
revoked certificate. The Logon Plugin handles these cases generically: it first orders the Certificate Provider to deleteStoredCertificate, that is, deletes the
private and public keys which are stored for the application; then it instructs the Certificate Provider to attempt to get a new signed certificate from its provider.
In cases of expired certificates, the provider should be able to assign a new valid certificate with a future expiration date. In cases of revoked certificates, the
provider should reject the new request, and the application will be unable to access the back end data.

setParameters Method
The setParameters method is optional, and necessary only if using the showUI API with an HTML or JavaScript view. A common case is getting the
username/password for authentication against a SCEP proxy server. In the sample, a case is shown where the the end user needs to provide a string with the
name of the certificate file in the application bundle. In both cases, when the end user taps 'Submit' on the screen, the dictionary of params is sent to this method
from the Logon Plugin.
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.2 Creating a Resource to Display a UI View


Create a resource to display an HTML or JavaScript view to the end user.
For iOS, the CertificateProviderDelegate contains methods that you call on the Logon plugin (delegate) from within your CustomCertificateProvider:
-(void) onGetCertificateSuccess:(SecIdentityRef) aCertObject;
-(void) onGetCertificateFailure:(NSError *)error;
-(BOOL) showUI:(id)aUIDefinition failedWithError:(NSError **)error;
For Android:
void onGetCertificateSuccess(X509KeyManager aCertObject)
void onGetCertificateFailure(int errorCode, String errorMessage)
void showUI(Object aUIDefinition) throws CertificateProviderException

onGetCertificateSuccess/onGetCertificateFailure Methods
On iOS, you call the onGetCertificateSuccess/onGetCertificateFailure methods on the delegate (the Logon Plugin) to conclude the asynchronous
getCertificate:delegate call. The reason you use a delegate pattern between the Logon Plugin and CertificateProvider is that you may need to do some

PUBLIC Page 24 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
long-running operations before the SecRefIdentity is prepared.

These operations could include:


displaying UI to the screen
making http requests to a SCEP proxy
accessing the file system
On Android, you call the onGetCertificateSuccess/onGetCertificateFailure methods, passing a CertificateProviderListener object to
getCertificate.

showUI: Method
The showUI: method is a optional method for presenting an HTML or JavaScript view to the end user. An example of one of these screens is installed in the
CredentialProvider/resource directory as x509ProviderUI.view.js.

On iOS, if you prefer to instead display a native UI during the process of getting a certificate, then instead of using showUI:, you can directly access
the rootViewController of the navigation stack, and push your views onto that navigation controller.

displaying UI to the screen


making http requests to a SCEP proxy
accessing the file system
On Android, if you prefer to instead display a native UI, you can use the context to show your own UI. To get the context, use code similar to the following:
Context context = MAFLogonCoreCDVPlugin.getInstance().getActivity();
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.3 Building and Running an iOS Project


Build and run an iOS project for an X.509 certificate provider..

Context
This task references the sample provider project. Alternately, you can use these steps to build your own certificate provider project.

Procedure
1. Create a Kapsel project with the Logon plugin, and optionally the AuthProxy plugin.
2. Add the sample provider project (or your own certificate provider project) into the Kapsel project, and update kapsel project's link library to include the
provider target from the Kapsel project settings' "Build Phases > link binary with library" section.
3. Edit the Kapsel project's info plist file, and add a string item, where the value is the provider class that implements the certificate provider interface, and
where the key is the last parameter set in the logon.init method to specify the selected certificate provider. To use the sample certificate provider project, set
both the value and the key as "X509FileCertificateProvider".
4. Export your SSO certificate from the MAC keychain, and copy it into the Kapsel project resource folder.
5. Copy the X509providerUI.view.js file from the sample certificate provider project's "resource" folder to the Kapsel project's
www\smp\logon\ui\resources folder.
6. Create a clienthub.plist and add it into the Xcode project.
7. Enable entitlement and set the keychaingroup name to "clienthubEntitlements" and $(CFBundleIdentifier). With XCode 5, you can find this setting under
Project Targets Panel > Capabilities > Keychain Sharing (you must enable Keychain Sharing). Enable Client Hub by updating the Xcode project's
keychain sharing settings.
8. If modifying the build settings for an iOS7 or iOS7.1 Deployment Target, you may get a library link error. You can manually add the libstdc++.6.0.9.dylib to
fix the issue.
9. Open MAFLogonManagerNG.bundle, and set keyMAFUseAfaria to NO to not use Afaria.
10. Copy the i18n.provider.properties from the sample certificate provider project's resource folder to the Kapsel project's www\smp\logon\i18n
folder
11. In your own application's JavaScript file where logon.init() is called, update the logon.init method to set the last parameter as
"X509FileCertificateProvider."
12. Deploy Client Hub and set the passcode.
13. Build and run the Kapsel project and it prompts for the file certificate settings. Input the certificate file name and password and verify that the registration
succeeds.
After the registration is done, verify that all Kapsel plugins can use the certificate to communicate to the server, for example, the AuthProxy plugin can
access backend OData, or the AppUpdate plugin can retrieve the new version.
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.4 Building and Running an Android Project


Build and run an Android project for an X.509 certificate provider.

Context
This task references the sample provider project. Alternately, you can use these steps to build your own certificate provider project.

Procedure

PUBLIC Page 25 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1. Create a Kapsel application with the Logon plugin, and, optionally, the authProxy plugin.
2. Import the sample certificate provider project into Eclipse.
3. The sample project depends on the Logon Core's jar file. You can find this either by looking in a Kapsel application that had Logon added to it (in the
platforms\android\libs\ directory), or wherever you have the Kapsel SDK files (<sdk folder>\plugins\logon\android\libs). In either case, grab
the maflogoncorecdvplugin-<version>.jar file and add it to the libs folder in the Eclipse project. If you are using the sample certificate from file provider, you
must also add the maflogoncore-<version>.jar file.
4. Build the project, and verify that a jar file is created in the bin folder.
5. Add the jar file from step 3 to the libs folder of the Kapsel application.
6. Add a clienthub.properties file to the platforms\android\res\raw\ directory. Use a clienthub.properties file identical to the one you
would use for registration with a certificate from Afaria. The clienthub.properties file tells the Logon core to use a certificate for registration. Since you
will register a provider, you use that that certificate rather than one from Afaria.
7. Add a line in AndroidManifest.xml:
<meta-data android:name="certFromFileProvider" android:value="com.example.certificatefromfileprovider.CustomCertificateProvide

Insert this tag inside the application tag:


<application android:debuggable="true" android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string
<meta-data android:name="certFromFileProvider" android:value="com.example.certificatefromfileprovider.CustomCertificateProvide
<other tags...>
</application>

The value in the tag you are adding must match the classpath and name of the class that implements the CertificateProvider interface. If you are using the
file provider sample, it is as above. If you are using the system provider sample, it is
"com.example.certificatefromsystemprovider.CustomCertificateProvider". If you are implementing your own provider, verify that it matches your class. Use a
short, unique descriptive name for the android:name.
If running on an Android 4.4 device or emulator, add the following permission in AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
8. Modify the call to sap.Logon.init(...) in your own Javascript file, add a string parameter at the 6th position. This string must match the
android:name from the meta-data tag you added to the AndroidManifest.xml in step 7. This allows the Javascript to specify the certificate provider to be
used, while avoiding security concerns about specifying arbitrary classes from JavaScript.
9. If you are using the file provider (or if you implement your own provider that displays a UI), then you also need to include the SAP UI5 view. In the sample
this is the x509ProviderUI.view.js file. Move this file to \platforms\android\assets\www\smp\logon\ui\resources\. Move the i18n.provider.properties to
\platforms\android\assets\www\smp\logon\i18n\.
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.5 Enabling a CertificateProvider in an Application


The basic flow for the Logon component to enable a CertificateProvider requires the end user to have the Client Hub application installed on their device, and to
enable an SSO Pincode. If the end user does not have the Client Hub application enabled, or selects "skip" on the SSO Pincode creation screen, the Logon
component ignores the registered Certificate Provider, and reverts to basic authentication for registration.

Prerequisites
Make sure Client Hub has been installed and activated by the end user.

Procedure
1. Set UserCreationPolicy=certificate.
The Logon component must find the key value UserCreationPolicy=certificate, in order to call the CertificateProvider for a certificate. A
CertificateProvider could be registered to the Logon during the Logon.init() , but would be ignored without this value. This behavior is consistent for both
Native and Kapsel SDK.
The user creation policy defines the authentication method for the user: automatic, manual or certificate. The manual and automatic methods are for the
password based authentication. The certificate method is for X.509 based authentication. If no value is set, the default is certificate.
Set the UserCreationPolicy in the clienthub.properties (Android) or clienthub.plist (iOS).
<!--Mandatory Settings-->
<!--Hostname of the server, example: xyz.sap.corp-->
Host : <string> // Hostname of the server, example: xyz.sap.corp
Port : <string> // Port of the server, example: 8080
SecurityConfiguration : <string> // Security configuration of the application, examples: "SSO",
"MySec001", "Cert02"
UserCreationPolicy : <string> // automatic/manual/certificate
2. Set the CertificateProvider for the Logon component
Pass the name of the CertificateProvider class name as a string to the Logon.init() function in the JavaScript.
sap.Logon.init(logonSuccessCallback, errorCallback, appId, context, sap.logon.IabUi, "certificateProviderClassName");

Next Steps
Create your custom certificate provider.
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.6 CertificateProvider Interface Reference


Describes the certificate provider interfaces for iOS and Android.

PUBLIC Page 26 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
In this section:
iOS
Android
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.6.1 iOS
Describes methods in the Certificate Provider and CertificateProviderDelegate. The iOS interface file, CertificateProvider.h, is available in the Kapsel
SDK's plugins/logon/ios/headers folder.
In this section:
onGetCertificateSuccess Method
onGetCertificateFailure Method
showUI Method
getCertificate Method
getStoredCertificate Method
deleteStoredCertificateWithError Method
setParameters Method
Parent topic: CertificateProvider Interface Reference

1.9.1.6.6.2.1 onGetCertificateSuccess Method


This delegate method is called by certificate provider to asynchronously report the result for the getCertificate:delegate method. The delegate method is
called after the certificate provider successfully obtains the SecIdentityRef object.

Syntax
-(void)onGetCertificateSuccess:(SecIdentityRef) aCertObject

Parameters
aCertObject
The identity object returned by the certificate provider. It can be used for the end user for registration.

Returns
None.
Parent topic: iOS

1.9.1.6.6.2.2 onGetCertificateFailure Method


This delegate method is called by certificate provider to asynchronously report the result for the getCertificate:delegate method. The delegate method is
called when the certificate provider fails to get the certificate.

Syntax
-(void)onGetCertificateFailure:(NSError *)error

Parameters
error
An NSError object contains the error information. The error code numbers and messages are specified by the certificate provider.

Returns
None.
Parent topic: iOS

1.9.1.6.6.2.3 showUI Method


This delegate method is called by the certificate provider when it needed to get user input for retrieving the certificate. For example, the certificate provider may
need to get the file path and password from the user to open a certificate file from the local file system.

Syntax
-(BOOL) showUI:(id)aUIDefinition failedWithError:(NSError **)error

Parameters
aUIDefinition
The context object specified by the certificate provider. The parameter can contain information to indicate what settings are required by the certificate provider, or

PUBLIC Page 27 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
which screen should be presented to the user for collecting user input.
error
An NSError object to report an error, if an error occurs during the showUI operation.

Returns
True or false.
Parent topic: iOS

1.9.1.6.6.2.4 getCertificate Method


The getCertificate method is the main method called by the Logon plugin to asynchronously get the client certificate from the remote server or file system. You can
use the returned certificate for mutual authentication or application registration. For iOS, the method expects the certificate provider to return a SecRefIdentity
object, which contains the private key and signed public key.

Syntax
- (void) getCertificate:(id<CertificateProviderDelegate>) delegate

Parameters
delegate
The CertificateProviderDelegate object that the certificate provider can invoke the the delegate method (onGetCertificateSuccess, onGetCertificateFailure, and
showUI) on. The certificate provider calls the delegate methods on this object to report the getCertificate result, or to collect user input for retrieving the certificate.

Returns
None.
Parent topic: iOS

1.9.1.6.6.2.5 getStoredCertificate Method


The synchronous method to return the cached certificate from the certificate store. The certificate provider can cache the certificate in the local certificate store
when the getCertificate method successfully retrieves the certificate from the remote server or file system. .

Syntax
- (BOOL) getStoredCertificate:(SecIdentityRef*)secIdentityRef error:(NSError**)anError

Parameters
secIdentityRef
Returning the previously cached identity object. If no cached identity is available, the method returns null.
anError
If an error occurs, the method returns contains an NSError object that describes the problem.

Returns
True or false.
Parent topic: iOS

1.9.1.6.6.1.6 deleteStoredCertificateWithError Method


Deletes the cached certificate from the local certificate store.

Syntax
- (BOOL) deleteStoredCertificateWithError:(NSError**)anError

Parameters
anError
If an error occurs, the method return contains an NSError object that describes the problem.

Returns
True or false.
Parent topic: iOS

1.9.1.6.6.2.7 setParameters Method


PUBLIC Page 28 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.1.6.6.2.7 setParameters Method
The setParameters method is optional, and it is only used with the showUI method. The certificate provider calls the showUI method to let the user enter
the user's information. Once the information is ready, this method is called by the Logon plugin to pass the information to the certificate provider, to let the
certificate provider continue to retrieve the certificate.

Syntax
- (BOOL) setParameters:(NSDictionary*)aDictionary error:(NSError **)error

Parameters
aDictionary
An NSDictionary object that contains the parameters for retrieving the certificate.
error
If an error occurs, the method return contains an NSError object that describes the problem.

Returns
True or false.
Parent topic: iOS

1.9.1.6.6.2 Android
Describes methods in the CertificateProvider and CertificateProviderListener.
In this section:
onGetCertificateSuccess Method
onGetCertificateFailure Method
showUI Method
getCertificate Method
getStoredCertificate Method
deleteStoredCertificate Method
setParameters Method
Parent topic: CertificateProvider Interface Reference

1.9.1.6.6.2.1 onGetCertificateSuccess Method


This method is called by certificate provider to asynchronously report the result for the getCertificate method. onGetCertificateSuccess is called
after the certificate provider successfully obtains the x509KeyManager object.

Syntax
void onGetCertificateSuccess(X509KeyManager aCertObject)

Parameters
aCertObject
The object returned by the certificate provider. It can be used for the end user for registration.

Returns
None.
Parent topic: Android

1.9.1.6.6.2.2 onGetCertificateFailure Method


This method is called by the certificate provider to asynchronously report the result for the getCertificate method. onGetCertificateFailure is
called when the certificate provider fails to get the certificate.

Syntax
void onGetCertificateFailure(int errorCode, String errorMessage)

Parameters
errorCode
An error code specified by the certificate provider.
errorMessage
An error message specified by the certificate provider.

PUBLIC Page 29 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Returns
None.
Parent topic: Android

1.9.1.6.6.2.3 showUI Method


This method is called by the certificate provider when it needs to get user input for retrieving the certificate. For example, the certificate provider may need to get
the file path and password from the user to open a certificate file from the local file system.

Syntax
void showUI(Object aUIDefinition) throws CertificateProviderException

Parameters
aUIDefinition
The context object specified by the certificate provider. The parameter can contain information to indicate what settings are required by the certificate provider, or
which screen should be presented to the user for collecting user input.

Returns
None.
Parent topic: Android

1.9.1.6.6.2.4 getCertificate Method


The getCertificate method is the main method called by the Logon plugin to asynchronously get the client certificate from the certificate provider. The
returned certificate is used to authenticate the client with the server. For Android, the method expects the certificate provider to provide an X509KeyManager
object by calling the onGetCertificateSuccess method on the provided CertificateProviderListener callback object.

Syntax
void getCertificate(CertificateProviderListener callbackObject)

Parameters
callbackObject
The CertificateProviderListener callback object. The CertificateProviderListener has the following methods: onGetCertificateSuccess ,
onGetCertificateFailure , and showUI .

Returns
None.
Parent topic: Android

1.9.1.6.6.2.5 getStoredCertificate Method


The synchronous method to return the cached certificate from the certificate provider. The certificate provider can cache the certificate when the
getCertificate method successfully retrieves a certificate. If there is no cached certificate, a CertificateProviderException can be thrown.

Syntax
X509KeyManager getStoredCertificate() throws CertificateProviderException

Parameters
None.

Returns
X509KeyManager
The cached certificate.
Parent topic: Android

1.9.1.6.6.2.6 deleteStoredCertificate Method


This function is called when the certificate provided by the provider no longer works to authenticate against the server (for example, if the certificate is expired).
This function clears the cached certificate if there is one.

PUBLIC Page 30 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Syntax
void deleteStoredCertificate() throws CertificateProviderException

Parameters
None.

Returns
None.
Parent topic: Android

1.9.1.6.6.2.7 setParameters Method


The setParameters method is optional, and it is only used with the showUI method. The certificate provider calls the showUI method to let the user enter
the user's information. Once the information is ready, this method is called by the Logon plugin to pass the information to the certificate provider, to let the
certificate provider continue to retrieve the certificate.

Syntax
void setParameters(Map params)

Parameters
params
A map of parameters to set.

Returns
None.
Parent topic: Android

1.9.1.6.7 CertificateProvider Samples


Describes samples of the certificate provider for iOS and Android..
In this section:
iOS Certificate Provider Sample
Android Certificate Provider Sample
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.6.7.1 iOS Certificate Provider Sample


This section describes a sample X.509 certificate provider for iOS.
The iOS sample includes these files:
CertificateProvider.h
X509FileCertificateProvider.h
X509FileCertificateProvider.m
The CertificateProvider.h is a required interface, and you will subclass it with your own CustomCertificateProvider.
In this section:
CertificateProvider.h
X509FileCertificateProvider Code
X509FileCertificateProvider Sample
Parent topic: CertificateProvider Samples

1.9.1.6.7.1.1 CertificateProvider.h
Examine the contents of the contents of CertificateProvider.h to see the CertificateProviderDelegate protocol, followed by the CertificateProvider interface.
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@protocol CertificateProviderDelegate <NSObject>


//onsuccess callback delegete, the certificate should be saved locally to be returned by getCachedCertificate method later
-(void) onGetCertificateSuccess:(SecIdentityRef) aCertObject;

//onerror delegate
-(void) onGetCertificateFailure:(NSError *)error;

//ui helper method to get user input


//for aUIDefintion parameter, if its type is uiviewcontroller, then it is for native app. If it is NSUrl, it represents url to get
//definition, if it is a string type, it is a html page path for kapsel app

PUBLIC Page 31 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
-(BOOL) showUI:(id)aUIDefinition failedWithError:(NSError **)error;
@end

@protocol CertificateProvider <NSObject>

//asynchronous method to get a certificate, the delegate can be called to retrieve user input and return the result.
//The method first check and return the local saved certificate if available, before requesting the certificate from remote server
//report error to caller by calling onGetCertificateFailure delegate method
//return the certificate by calling onGetCertificateSuccess method, the certificate should be saved locally before calling
//onGetCertificateSuccess method
- (void) getCertificate:(id<CertificateProviderDelegate>) delegate;

//method to synchronously get a certificate from saved local copy


//if saved certicate exists, return true and also set the identityref parameter to the certificate
//If no saved certificate exists, return true and also setting identityRef parameter to nil.
//if error happens during getting the saved certificate, return false with related error, also setting identityRef parameter to ni
- (BOOL) getStoredCertificate:(SecIdentityRef *)identityRef error:(NSError**)anError;

//method to delete the saved local copy


//if not saved certificate exists, do nothing and return true,
//if saved certificate is deleted, return true
//if saved certificate exists and fails to delete, reture false with error
- (BOOL) deleteStoredCertificateWithError:(NSError**)anError;

@optional
//method to set required parameters input by user
//report error immediately by output reference,
//this errro will not cancel the getcertificate operation
- (BOOL) setParameters:(NSDictionary*)params failedWithError:(NSError **)error;

@end

In this section:
CertificateProviderDelegate Protocol
CertificateProvider Interface
Parent topic: iOS Certificate Provider Sample

1.9.1.6.7.1.1.1 CertificateProviderDelegate Protocol


The CertificateProviderDelegate contains methods that you call on the Logon plugin (delegate) from within your CustomCertificateProvider.
-(void) onGetCertificateSuccess:(SecIdentityRef) aCertObject;
-(void) onGetCertificateFailure:(NSError *)error;
-(BOOL) showUI:(id)aUIDefinition failedWithError:(NSError **)error;

onGetCertificateSuccess/onGetCertificateFailure Methods
You call the onGetCertificateSuccess/onGetCertificateFailure methods on the delegate (the Logon Plugin) to conclude the asynchronous
getCertificate:delegate call. The reason you use a delegate pattern between the Logon Plugin and CertificateProvider is that you may need to do some
long-running operations before the SecRefIdentity is prepared. These operations could include:

displaying UI to the screen


making http requests to a SCEP proxy
accessing the file system

showUI: Method
The showUI: method is a convenience method for presenting an HTML or JavaScript view to the end user. An example of one of these screens is installed in the
CredentialProvider/resource directory: x509ProviderUI.view.js.

If you prefer to instead display a native UI during the process of getting a certificate, then instead of using showUI:, you can directly access
the rootViewController of the navigation stack, and push your views onto that navigation controller.

displaying UI to the screen


making http requests to a SCEP proxy
accessing the file system
Parent topic: CertificateProvider.h

1.9.1.6.7.1.1.2 CertificateProvider Interface


In the CertificateProvider interface, there are four methods for you to implement in your CustomCertificateProvider.
- (void) getCertificate:(id<CertificateProviderDelegate>) delegate;
- (BOOL) getStoredCertificate:(SecIdentityRef *)identityRef error:(NSError**)anError;
- (BOOL) deleteStoredCertificateWithError:(NSError**)anError;
- (BOOL) setParameters:(NSDictionary*)params failedWithError:(NSError **)error;
The first three methods are required; setParameters: is optional, and necessary only if using showUI: with an HTML or JavaScript view.

getCertificate: Method
PUBLIC Page 32 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
getCertificate: Method
The getCertificate: method is the main method called by the Logon Plugin before application registration, if the UserCreationPolicy key is set to
certificate. This method contains logic for combining the private key and signed public key, and constructing a SecRefIdentity.

When the SecRefIdentity is prepared, call [delegate onGetCertificateSuccess:mySecRefIdentity], to provide the Logon Plugin with the
identity to be used to authenticate the end user for registration.
In the case of an error, construct an NSError for the onGetCertificateFailure response. The error is logged. The specific Error Code numbers and
messages you select are flexible, but for simplicity and consistency, we recommend starting from the set defined in X509FileCertificateProvider.h.
#define Certificate_Provider_Error_Domain @"ERR_Certificate_Provider"
#define ERR_ShowUI_Delegate_Html -1
#define ERR_ShowUI_Delegate_ViewController -2
#define ERR_ShowUI_Delegate_No_UI_Settings -3
#define ERR_Set_Parameters_Failed -4
#define ERR_Certificate_File_Not_Exist -5
#define ERR_Load_Certificate_From_File_Failed -6
#define ERR_Save_Certificate_To_KeyChain_Failed -7
#define ERR_Read_KeyChain_Item_Failed -8
#define ERR_Delete_Saved_Certificate_Failed -9

getStoredCertificate: Method
The getStoredCertificate: method is different from getCertificate: in one critical way: it is synchronous, and is designed to be called by the
application many times, for HTTP requests, instead of only once, for application registration. Therefore, the implementation should return either an identity already
in memory, or return an identity from the keychain or a similar 3rd-party API. You should not show UIs or execute long-running processes within this method.
If an identity cannot be returned from the keychain, return an error. The requesting library makes a call to the Logon Plugin, requesting that
it refreshCertificate. Logon Plugin then calls the next method, deleteStoredCertificate, then makes a new
asynchronous getCertificate:delegate call.

deleteStoredCertificate: Method
The deleteStoredCertificate: method is necessary for handling cases of "invalid certificate" HTTP responses, which might result from an expired or
revoked certificate. The Logon Plugin handles these cases generically: it first orders the Certificate Provider to deleteStoredCertificate:, that is, deletes
the private and public keys which are stored for the application; then it instructs the Certificate Provider to attempt to get a new signed certificate from its provider.
In cases of expired certificates, the provider should be able to assign a new valid certificate with a future expiration date. In cases of revoked certificates, the
provider should reject the new request, and the application will be unable to access the back end data.

setParameters: Method
The setParameters: method is optional, and necessary only if using the showUI: API with an HTML or JavaScript view. A common case is getting the
username/password for authentication against a SCEP proxy server. In the sample, a case is shown where the the end user needs to provide a string with the
name of the certificate file in the application bundle. In both cases, when the end user taps 'Submit' on the screen, the dictionary of params is sent to this method
from the Logon Plugin.
Parent topic: CertificateProvider.h

1.9.1.6.7.1.2 X509FileCertificateProvider Code


The example X509FileCertificateProvider implements the <CertificateProvider> protocol, and so there are sample implementations for each of the methods
previously described.
The X509CertificateProvider.h code:
#import "CertificateProvider.h"
#import <UIKit/UIKit.h>

//define error code and error domain for error message localization
#define Certificate_Provider_Error_Domain @"ERR_Certificate_Provider"
#define ERR_ShowUI_Delegate_Html -1
#define ERR_ShowUI_Delegate_ViewController -2
#define ERR_ShowUI_Delegate_No_UI_Settings -3
#define ERR_Set_Parameters_Failed -4
#define ERR_Certificate_File_Not_Exist -5
#define ERR_Load_Certificate_From_File_Failed -6
#define ERR_Save_Certificate_To_KeyChain_Failed -7
#define ERR_Read_KeyChain_Item_Failed -8
#define ERR_Delete_Saved_Certificate_Failed -9

@interface X509FileCertificateProvider : NSObject <CertificateProvider>{


__weak id<CertificateProviderDelegate> providerDelegate;
//parameters required to get x509 certificate
NSString* filePath;
NSString* password;

//initial settings for displaying parameter screen, it contains viewID and certificate file path

PUBLIC Page 33 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
NSDictionary* _settings;
}

@end
The X509CertificateProvider.m code:
#import "X509FileCertificateProvider.h"

@interface X509FileCertificateProvider()
-(void) getClientCertificateFromFile;
-(NSError*) getErrorObject:(int)errorCode message:(NSString*)errorMessage;
@end

static NSString* const kSMPCertProviderTag = @"CERTIFICATE_PROVIDER";


static NSString* const kFileCertificateLabel = @"x509FileCertificateIdentity";

@implementation X509FileCertificateProvider {
SecIdentityRef currentIdentity;
}

#pragma mark - CertificateProvider Interface

- (void) getCertificate:(id<CertificateProviderDelegate>) delegate {


providerDelegate = delegate;
//move to mediator
NSError* error;
if (_settings){
if (![providerDelegate showUI:_settings failedWithError:&error]){
//report error
[providerDelegate onGetCertificateFailure:[self getErrorObject:ERR_ShowUI_Delegate_Html message:@"ShowUI delegate method
}
}
else{
[providerDelegate onGetCertificateFailure:[self getErrorObject:ERR_ShowUI_Delegate_No_UI_Settings message:@"ShowUI delegate
}
}

//method to synchronously get a certificate from saved local copy.


//if saved certicate exists, return true and also set the identityref parameter to the certificate
//If no saved certificate exists, return true and also setting identityRef parameter to nil.
//if error happens during getting the saved certificate, return false with related error, also setting identityRef parameter to ni
- (BOOL) getStoredCertificate:(SecIdentityRef *)pidentityRef error:(NSError**)anError{
// retrieves a SecIdentityRef from the cached object in memory. If no cached object exists, then get it from keychain for matche
// kSecAttrLabel's value, the first matched one will be returned
// Return Val : the matched identity object
*pidentityRef = nil;
NSError* error = nil;

//check current identity object if available


if (currentIdentity != nil){
*pidentityRef = currentIdentity;
}
else{
// Common name is stored in label attribute,
NSDictionary* queryIdentity = [NSDictionary dictionaryWithObjectsAndKeys:
kFileCertificateLabel, kSecAttrLabel,
(__bridge id)kSecClassIdentity, kSecClass,
kCFBooleanTrue, kSecReturnRef,
kCFBooleanTrue, kSecReturnAttributes,
kSecMatchLimitAll, kSecMatchLimit,
nil];

// Get a new identity from the keychain


// This works because the private key will automatically be associated with the certificate in the keychain
CFArrayRef result = nil;

OSStatus err = SecItemCopyMatching((__bridge CFDictionaryRef)queryIdentity, (CFTypeRef*)&result);

if (err == errSecItemNotFound)
{
*pidentityRef = nil;
}
else if (err == noErr && result != nil )
{
CFIndex resultCount = CFArrayGetCount(result);
NSLog(@"Matched identity count: %i", (int)resultCount);
// somehow two identities are returned with the same certificate, one with public key, one with private key,

PUBLIC Page 34 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
// the one with public key is invalid identity, need to return the one with the private key
for (int resultIndex = 0; resultIndex < resultCount; resultIndex++)
{
NSDictionary* thisResult = (NSDictionary*) CFArrayGetValueAtIndex(result, resultIndex);

CFTypeRef keyClass = (__bridge CFTypeRef) [thisResult objectForKey:(__bridge id)kSecAttrKeyClass];


if (keyClass != nil )
{
if ([[(__bridge id)keyClass description] isEqual:(__bridge id)kSecAttrKeyClassPrivate])
{
*pidentityRef = (__bridge SecIdentityRef)[thisResult objectForKey:(__bridge NSString*)kSecValueRef];
if (currentIdentity){
CFRelease(currentIdentity); //release previous identity object
currentIdentity = nil;
}
//get hold of the new identity object
currentIdentity = *pidentityRef;
CFRetain(currentIdentity);

}
}
}
}
else
{
error = [self getErrorObject:ERR_Read_KeyChain_Item_Failed message:@"Fail to read certificate from keychain"];
}

if (result != nil){
CFRelease(result);
}
}
if (anError != nil){
*anError = error;
}

return error == nil;


}

//method to delete the saved local copy


//if not saved certificate exists, do nothing and return true,
//if saved certificate is deleted, return true
//if saved certificate exists and fails to delete, reture false with error
- (BOOL) deleteStoredCertificateWithError:(NSError**)anError{
NSError* error = nil;
OSStatus sanityCheck = noErr;
NSDictionary *queryIdentity;

queryIdentity = [NSDictionary dictionaryWithObjectsAndKeys:


kFileCertificateLabel, kSecAttrLabel,
(__bridge id)kSecClassIdentity, kSecClass,
nil];

// Delete the private key.


sanityCheck = SecItemDelete((__bridge CFDictionaryRef)queryIdentity);
if (sanityCheck != noErr && sanityCheck != errSecItemNotFound ){
error = [self getErrorObject:ERR_Delete_Saved_Certificate_Failed message:@"Fail to delete the saved certificate"];
}

if (anError != nil){
*anError = error;
}

if (currentIdentity != nil){
CFRelease(currentIdentity);
currentIdentity = nil;
}
return error == nil;
}

- (BOOL) setParameters:(NSDictionary*) params failedWithError:(NSError **)error{


//add new params into parameter arrays, and check whether all required parameters are available, if so,
//retrieve the certificate. Otherwise, call showUI method to get the missing parameters
if (params){
[params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([key isEqualToString:@"filepath"]){
filePath = (NSString*)obj;

PUBLIC Page 35 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
}
else if ([key isEqualToString:@"password"]){
password = (NSString*)obj;
}
}];

if (filePath && password){


//get certificate from file
[self getClientCertificateFromFile];
}
else{
if (error != nil){
*error = [self getErrorObject:ERR_Set_Parameters_Failed message:@"Fail to set parameters"];
}
return FALSE;
}
return TRUE;
}

#pragma mark - Landscape-specific Interface


//initialize the settings for getting parameter UI
- (id) init{
currentIdentity = nil;
NSDictionary* certificateFileSettings = [NSDictionary dictionaryWithObjectsAndKeys:@"client.p12", @"filepath", nil];
_settings = [NSDictionary dictionaryWithObjectsAndKeys:@"x509ProviderUI", @"viewID", certificateFileSettings, @"settings", nil
return self;
}

//get client certificate from file for authentiation, and also save to a local copy to keychain for later use
-(void) getClientCertificateFromFile{

//check identity exists using the common name as application tag and application label
NSError* error = nil;

SecIdentityRef identity = nil;


CFArrayRef items = NULL;

//first try to get the saved certificate from keychain


BOOL bResult = [self getStoredCertificate:&identity error:&error];
if (bResult){
if (identity == nil ){

NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtI

NSString * fullPath = [documentsDirectory stringByAppendingPathComponent:filePath];

//check file exist


BOOL isDirectory = YES;

BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory];

if (fileExists == NO || isDirectory ){
NSLog(@"%@: File certificate not found in document directory. Trying resource folder.", kSMPCertProviderTag);
//if the file does not exist in document directory, then check the main bundle resource folder
NSString * resourceFolderPath = [[NSBundle mainBundle] resourcePath];
fullPath = [resourceFolderPath stringByAppendingPathComponent:filePath];

fileExists = [[NSFileManager defaultManager] fileExistsAtPath:fullPath isDirectory:&isDirectory];


if (fileExists == NO || isDirectory ){
NSLog(@"%@: File certificate not found.", kSMPCertProviderTag);
}
}

if ( fileExists == YES && !isDirectory ){


NSData *p12data = [NSData dataWithContentsOfFile:fullPath];
CFDataRef inP12data = (__bridge CFDataRef)p12data;

NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:


password, kSecImportExportPassphrase, nil];

OSStatus status = SecPKCS12Import(inP12data, (__bridge CFDictionaryRef)options, &items);

if (status == noErr) {
CFDictionaryRef identityAndTrust = CFArrayGetValueAtIndex(items, 0);
const void *tempIdentity = NULL;

PUBLIC Page 36 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
tempIdentity = CFDictionaryGetValue(identityAndTrust, kSecImportItemIdentity);

NSDictionary *queryCertificate = [NSDictionary dictionaryWithObjectsAndKeys:


kFileCertificateLabel, kSecAttrLabel,
(__bridge id)tempIdentity, kSecValueRef,
nil];

status = SecItemAdd((__bridge CFDictionaryRef) queryCertificate, NULL);

if (status != noErr ){
NSLog(@"%@: Fail to save certificate to keychain.", kSMPCertProviderTag);
error = [self getErrorObject:ERR_Save_Certificate_To_KeyChain_Failed message:@"Save certificate to keyc
}
}
else{
NSLog(@"%@: File certificate invalid.", kSMPCertProviderTag);
error = [self getErrorObject:ERR_Load_Certificate_From_File_Failed message:@"File certificate invalid."];
}
}
else {
NSString* errorMessage = [NSString stringWithFormat:@"Certificate file does not exist: %@", filePath];
error =[self getErrorObject:ERR_Certificate_File_Not_Exist message:errorMessage];
}
}
}
else{
error = [self getErrorObject:ERR_Read_KeyChain_Item_Failed message:@"Fail to read certificate from keychain"];
}

if (items != nil){
CFRelease(items);
}

//otherwise report the success


if (error == nil ){
[self getStoredCertificate:&identity error:&error];
}

if (identity != nil){
[providerDelegate onGetCertificateSuccess:identity];
}
else {
[providerDelegate onGetCertificateFailure:error];
}
}

-(NSError*)getErrorObject:(int)errorCode message:(NSString*)errorMessage{
NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : errorMessage };

NSError *error = [NSError errorWithDomain:Certificate_Provider_Error_Domain


code:errorCode
userInfo:userInfo];
return error;
}

@end

Parent topic: iOS Certificate Provider Sample

1.9.1.6.7.1.3 X509FileCertificateProvider Sample


Walks through the flow of the example X509FileCertificateProvider, from init, to handling getCertificate: and displaying a screen to the end user
with showUI:, to returning an identity from the keychain for getStoredCertificate requests, and clearing the keychain item in response to
deleteStoredCertificate requests.

@properties
The example does not depend on public properties, and uses a number of convenience instance properties. The most important properties are:
__weak id<CertificateProviderDelegate> providerDelegate
SecIdentityRef currentIdentity
NSDictionary* _settings;
providerDelegate
is used to reference the Logon Plugin, and is set when the Logon Plugin calls getCertificate.
currentIdentity
is used to cache the SecRefIdentity used by the application, once it is constructed from the Keychain.
_settings

PUBLIC Page 37 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
dictionary is passed as a parameter to the showUI: method, and the viewID key value instructs the Logon Plugin which sap.ui.jsview to show.

init
The example scenario involves retrieving a certificate from the application bundle, and unlocking it with the password. To get the location of the certificate, and the
password, the example displays a UI5 screen. The developer has added code to the init method, to create the reference for currentIdentity, and to
initialize the _settings dictionary.
- (id) init{
currentIdentity = nil;
NSDictionary* certificateFileSettings = @{@"filepath" : @"cert.p12"};
_settings = @{@"viewID" : @"x509ProviderUI", @"settings" : certificateFileSettings};
return self;
}
Here is an example of how the @"viewID" is mapped to the identifier of the sap.ui.jsview which is to be displayed to the user.

In x509ProviderUI.view.js:
sap.ui.jsview("x509ProviderUI", {

getControllerName: function() {
return null;
}, ...
The @"filepath" key is used to pre-populate the textfield in the UI.

getCertificate:(id<CertificateProviderDelegate>)delegate
When the Logon Plugin is registering the application connection (a one-time event which results in the creation of a persistant X-SMP-APPCID cookie), if
the UserCreationPolicy is set to "certificate", it calls getCertificate on the CertificateProvider, and passes itself as the delegate for callbacks.

In the example X509FileCertificateProvider, the procedure tries to pass the _settings dictionary to the delegate method for
showUI:(id)aUIDefinition. The _settings dictionary includes the "viewID" key to tell the Logon Plugin view controller which sap.ui.jsview to
display. If there is a failure in the display, the providerDelegate is called back with onGetCertificateFailure:(NSError *)error.
- (void) getCertificate:(id<CertificateProviderDelegate>) delegate {
providerDelegate = delegate;

NSError* error;
if (_settings){
if (![providerDelegate showUI:_settings failedWithError:&error]){
//report error
[providerDelegate onGetCertificateFailure:[self getErrorObject:ERR_ShowUI_Delegate_Html
message:@"ShowUI delegate method with html path parameter returns error"]];
}
}
else{
[providerDelegate onGetCertificateFailure:[self getErrorObject:ERR_ShowUI_Delegate_No_UI_Settings
message:@"ShowUI delegate method called without UI settings"]];
}
}

setParameters:(NSDictionary*) params failedWithError:(NSError **)error


The example of the sap.ui.jsview is included in the sample/CredentialProvider/resource folder, but the key flow to understand is that within the view,
the "Submit" button passes the JSON data from the view to an In-App Browser ("iab") event, which is captured by the Logon Plugin. The Logon Plugin then
passes the JSON data to the X509FileCertificateProvider through setParameters:.You can re-use this flow in your application that uses JavaScript or
HTML views.
In x509ProviderUI.view.js:
var button = new sap.m.Button("BTN_SUBMIT",
{
text : "Submit",
press : function(){window.iab.triggerEvent("SUBMIT", JSON.stringify(data));}
});
In X509FileCertificateProvider.m:
- (BOOL) setParameters:(NSDictionary*) params failedWithError:(NSError **)error{
//add new params into parameter arrays, and check whether all required parameters are available, if so,
//retrieve the certificate. Otherwise, call showUI method to get the missing parameters
if (params){
[params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([key isEqualToString:@"filepath"]){
filePath = (NSString*)obj;
}
else if ([key isEqualToString:@"password"]){
password = (NSString*)obj;
}
}];

PUBLIC Page 38 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
if (filePath && password){
//get certificate from file
[self getClientCertificateFromFile];
}
else{
*error = [self getErrorObject:ERR_Set_Parameters_Failed message:@"Fail to set parameters"];
return FALSE;
}
return TRUE;
}

getClientCertificateFromFile

Note
getClientCertificateFromFile is not part of the interface, but is an example of custom code for getting a signed certificate so that SecIdentityRef
can be returned.

Notice that the setParameters: implementation continues the flow by calling [self getClientCertificateFromFile]. This example shows how to
retrieve a .p12 file from the application file system, unlock it using the password obtained from the end user, and save it to the keychain. This is an appropriate
location to add the logic for getting the certificate from the landscape-specific location for instance, make an API call to an embedded library, or a HTTPS request
on the company guest-net to a proxy to sign a locally generated public key.
When it is successful unlocking the certificate and setting to the keychain, the getClientCertificateFromFile implementation should call back to the
delegate with onGetCertificateSuccess:(SecIdentityRef)identity. See how the example re-uses the interface method [self
getStoredCertificate:&identity] to retrieve the SecIdentityRef from the keychain.

On subsequent requests to getStoredCertificate:, the identity may already be in cached in memory, so it will not need to go to the keychain.

getStoredCertificate:(SecIdentityRef *)pidentityRef error:(NSError**)anError


The getCertificate:delegate method is intended for asynchronous, long-running tasks, which may require UI display. the getStoredCertificate
method is intended for synchronous, short-running tasks, which do not require UI. The expectation is that a SecRefIdentity is available in-memory, or can be
returned from the keychain or other local location.
If the CertificateProvider calls a 3rd-Party API to get the identity (for example, a component that stores the keys in an encrypted blob, instead of the keychain),
implement the API to return success or failure quickly. If it returns failure, then getStoredCertificate should return an error to the caller, and the Logon
Plugin will call the asynchronous getCertificate.

deleteStoredCertificateWithError:(NSError**)anError
Manage certificate validity on the server side — at the network edge, SAP Mobile Platform, or backend. If a certificate is expired, revoked, or otherwise invalid,
return an HTTP Request Authentication error to the device. The application should catch these invalid certificate errors, and call
the refreshCertificate method exposed by the Logon Plugin.
Parent topic: iOS Certificate Provider Sample

1.9.1.6.7.2 Android Certificate Provider Sample


This section describes a sample X.509 certificate provider for Android.
The Android sample includes these files:
CustomCertificateProvider.java
CustomKeyManager.java
In this section:
CustomCertificateProvider.java
CustomKeyManager.java
Parent topic: CertificateProvider Samples

1.9.1.6.7.2.1 CustomCertificateProvider.java
The example X.509 CustomCertificateProvider implements the <CertificateProvider> protocol, and so there are sample implementations for each of the methods
previously described.
This section provides the example code, and walks through the flow of the example, from handling getCertificate and displaying a screen to the end user
with showUI, to returning an X.509 key manager for getStoredCertificate requests, and clearing the key manager in response to
deleteStoredCertificate requests.
package com.example.certificatefromfileprovider;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.X509KeyManager;

import org.json.JSONException;
import org.json.JSONObject;

PUBLIC Page 39 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
import android.util.Log;

import com.sap.maf.html5.android.CertificateProvider;
import com.sap.maf.html5.android.CertificateProviderException;
import com.sap.maf.html5.android.CertificateProviderListener;
import com.sap.maf.html5.android.MAFLogonCoreCDVPlugin;
import com.sap.maf.tools.logon.core.LogonCore;
import com.sap.maf.tools.logon.core.LogonCoreException;

public class CustomCertificateProvider implements CertificateProvider {


private CertificateProviderListener _callback = null;
private String _alias = "smp_crt";
private String _filePath = null;
private String _certPwd = null;

@Override
public void getCertificate(CertificateProviderListener callback) {
_callback = callback;
try {
// This map contains the view ID, as well as any information the view might need
HashMap<String, Object> map = new HashMap<String, Object>();
map.put(MAFLogonCoreCDVPlugin.VIEW_ID, "x509ProviderUI");
// Now add a default value that will be displayed on the view.
// This value is used in x509ProviderUI.view.js
JSONObject settings = new JSONObject();
try {
settings.put("filepath", "certificate.p12");
} catch (JSONException e) {
// print exception to Logcat for debugging
e.printStackTrace();
}
map.put("settings", settings);
_callback.showUI(map);
} catch (CertificateProviderException e) {
// print exception to Logcat for debugging
e.printStackTrace();
}
}

@Override
public void setParameters(Map parameters) {

// Log the content of the parameters Map for debugging


Log.e("CustomCertificateProvider", "setParameters called");
Set keys = parameters.keySet();
Iterator it = keys.iterator();
while (it.hasNext()) {
Object key = it.next();
// assuming both key and value are strings
Log.e("CustomCertificateProvider", "key: " + (String) key
+ " value: " + (String) parameters.get(key));
}

_filePath = (String) parameters.get("filepath");


_certPwd = (String) parameters.get("password");

try {
CustomKeyManager keyManager = new CustomKeyManager(_filePath, _certPwd, _alias);
_callback.onGetCertificateSuccess(keyManager);
// We won't be able to save the filepath and password to the logon core's datavault
// before we are registered (since it won't exist at that point) but we can save
// the values there later.
LogonCore logonCore = LogonCore.getInstance();
logonCore.addObjectToStore("CustomFileCertificateProvider_filePath", _filePath);
logonCore.addObjectToStore("CustomFileCertificateProvider_certPwd", _certPwd);
} catch (Exception e) {
// print exception to Logcat for debugging
e.printStackTrace();
}
}

@Override
public void deleteStoredCertificate() throws CertificateProviderException {
// We're not actually going to try to delete the certificate off the filesystem.
// Just get rid of the values we got from the user.
_filePath = null;
_certPwd = null;

PUBLIC Page 40 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
}

@Override
public X509KeyManager getStoredCertificate()
throws CertificateProviderException {
X509KeyManager keyManager = null;
if (_filePath == null) {
// If we don't have a value for the filepath, check the logon core's datavault
// in case we previously saved the values there.
LogonCore logonCore = LogonCore.getInstance();
try {
_filePath = logonCore.getObjectFromStore("CustomFileCertificateProvider_filePath");
_certPwd = logonCore.getObjectFromStore("CustomFileCertificateProvider_certPwd");
} catch (LogonCoreException e) {
// print exception to logcat for debugging
e.printStackTrace();
}
}
if (_filePath != null) {
try {
keyManager = new CustomKeyManager(_filePath, _certPwd, _alias);
} catch (Exception e) {
// print exception to Logcat for debugging
e.printStackTrace();
}
}
return keyManager;
}
}

getCertificate
When the Logon plugin is registering the application connection (a one-time event which results in the creation of a persistant X-SMP-APPCID cookie), if
the UserCreationPolicy is set to "certificate", it calls getCertificate on the CertificateProvider.

setParameters
The example of the sap.ui.jsview is included in the sample/CredentialProvider/resource folder, but the key flow to understand is that within the view,
the "Submit" button passes the JSON data from the view to an In-App Browser ("iab") event, which is captured by the Logon Plugin. The Logon Plugin then
passes the JSON data to the certificate provider through setParameters.You can re-use this flow in your application that uses JavaScript or HTML views.

getStoredCertificate
The getCertificate method is intended for asynchronous, long-running tasks, which may require UI display. the getStoredCertificate method is
intended for synchronous, short-running tasks, which do not require UI.
If the CertificateProvider calls a 3rd-Party API to get the identity (for example, a component that stores the keys in an encrypted blob), implement the API to return
success or failure quickly. If it returns failure, then getStoredCertificate should return an error to the caller, and the Logon plugin will call the
asynchronous getCertificate.

deleteStoredCertificate
Manage certificate validity on the server side — at the network edge, SAP Mobile Platform, or backend. If a certificate is expired, revoked, or otherwise invalid, a
request using that certificate will get an HTTP Request Authentication error. The application should catch these invalid certificate errors, and call the
refreshCertificate method exposed by the Logon plugin. When refreshCertificate is called, it will invoke this deleteStoredCertificate
method.
Parent topic: Android Certificate Provider Sample

1.9.1.6.7.2.2 CustomKeyManager.java
CustomKeyManager.java is a helper that implements the X.509 Key Manager interface.
For more information on the X.509 Key Manager interface, see http://developer.android.com/reference/javax/net/ssl/X509KeyManager.html on the Android
Developers site.
package com.example.certificatefromfileprovider;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.CertificateException;

PUBLIC Page 41 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
import java.security.cert.X509Certificate;

import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.X509KeyManager;

import android.util.Log;

/**
* The wrapper for keystores from a file. In this class, since the certificate
* alias is specified, the class instance only represents a keystore for that
* certificate. All other certificates in the keystore are invisible.
*/
class CustomKeyManager implements X509KeyManager {

// The file key manager that contains the certificate described in


// _certSource.
private X509KeyManager _keyManager;
private String _alias;

/**
* @param keyManager
* The keystore file that contains the specified certificate.
* @param password
* The password to access the keystore file.
* @param alias
* The alias of the certificate in that should be used.
*/
CustomKeyManager(String filepath, String password, String alias)
throws Exception {
_keyManager = loadCertificates(filepath, password);

PrivateKey key = getPrivateKey(alias);


if (key == null) {
Log.w("CustomKeyManager",
"Attempted to use certificate from keystore, but " + alias
+ " is not in the keystore.");
throw new Exception(
"Attempted to use certificate from keystore, but " + alias
+ " is not in the keystore.");
}

_alias = alias;
}

/**
* Load a keystore from file into key manager.
*
* @param filepath
* path of the keystore file.
* @param password
* password of the keystore.
* @return A key manager instance for the keystore file.
* @throws AuthProxyException
*/
private X509KeyManager loadCertificates(String filepath, String password)
throws Exception {
Log.d("CustomKeyManager", "Loading certificate from file with path: "
+ filepath);
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12"); // We use only
// this key
// type. Any
// other type
// available?
char[] pwd = null;
if (password == null) {
pwd = new char[0];
} else {
pwd = password.toCharArray();
}

// Construct a keystore instance from file.


try {
keyStore.load(new FileInputStream(new File(filepath)), pwd);
} catch (FileNotFoundException fnfe) {
// It's possible the user just gave the certificate filename
// expecting us to look on the SD card,

PUBLIC Page 42 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
// so check for that.
String sDCardFilepath = "mnt/sdcard/" + filepath;
Log.d("CustomKeyManager",
"Certificate not found, trying path: " + sDCardFilepath);
try {
keyStore.load(
new FileInputStream(new File(sDCardFilepath)), pwd);
} catch (FileNotFoundException fnfe2) {
Log.e("CustomKeyManager",
"Attempted to use certificate from file, but file does not exist.");
throw fnfe2;
} catch (CertificateException ce) {
Log.e("CustomKeyManager",
"Attempted to use certificate from file, but format of file is invalid: "
+ ce.toString());
throw ce;
} catch (IOException ioe) {
Log.e("CustomKeyManager",
"Attempted to use certificate from file, but format of file is invalid: "
+ ioe.toString());
throw ioe;
}
} catch (CertificateException ce) {
Log.e("CustomKeyManager",
"Attempted to use certificate from file, but format of file is invalid: "
+ ce.toString());
throw ce;
} catch (IOException ioe) {
Log.e("CustomKeyManager",
"Attempted to use certificate from file, but format of file is invalid: "
+ ioe.toString());
throw ioe;
}

KeyManagerFactory oKMF = KeyManagerFactory


.getInstance(KeyManagerFactory.getDefaultAlgorithm());
oKMF.init(keyStore, pwd);
for (KeyManager oKM : oKMF.getKeyManagers()) {
if (oKM instanceof X509KeyManager) {
return (X509KeyManager) oKM;
}
}

return null; // Should not reach here


} catch (GeneralSecurityException gse) {
Log.e("CustomKeyManager",
"GeneralSecurityException while loading certificates: "
+ gse.toString());
throw gse;
}
}

/*
* (non-Javadoc)
*
* @see javax.net.ssl.X509KeyManager#chooseClientAlias(java.lang.String[],
* java.security.Principal[], java.net.Socket)
*
* @return Return the preselected alias.
*/
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) {
return _alias;
}

/*
* (non-Javadoc)
*
* @see javax.net.ssl.X509KeyManager#chooseServerAlias(java.lang.String,
* java.security.Principal[], java.net.Socket) This method is only required
* for server application.
*/
@Override
public String chooseServerAlias(String keyType, Principal[] issuers,
Socket socket) {
return null;
}

PUBLIC Page 43 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
/*
* (non-Javadoc)
*
* @see javax.net.ssl.X509KeyManager#getCertificateChain(java.lang.String)
*/
@Override
public X509Certificate[] getCertificateChain(String alias) {
return _keyManager.getCertificateChain(alias);
}

/*
* (non-Javadoc)
*
* @see javax.net.ssl.X509KeyManager#getClientAliases(java.lang.String,
* java.security.Principal[])
*/
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return _keyManager.getClientAliases(keyType, issuers);
}

/*
* (non-Javadoc)
*
* @see javax.net.ssl.X509KeyManager#getServerAliases(java.lang.String,
* java.security.Principal[]) This method is only required for server
* application.
*/
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return null;
}

/*
* (non-Javadoc)
*
* @see javax.net.ssl.X509KeyManager#getPrivateKey(java.lang.String)
*/
@Override
public PrivateKey getPrivateKey(String alias) {
return _keyManager.getPrivateKey(alias);
}

}
Parent topic: Android Certificate Provider Sample

1.9.1.6.8 Localizing a CertificateProvider


Add localized string values for error messages in the CertificateProvider.

Context
For iOS, Kapsel applications use NSError to construct failure response messages. To allow JavaScript to find the error resource based on NSError, the
domain and error code for NSError must match the error resource defined in the i18n.provider.properties file.

In the sample X.509 file certificate provider, the error domain and error code is defined as follows in x509FileCertificateProvider.m:
//define error code and error domain for error message localization
#define Certificate_Provider_Error_Domain @"ERR_Certificate_Provider"
#define ERR_ShowUI_Delegate_Html -1
#define ERR_ShowUI_Delegate_ViewController -2
#define ERR_ShowUI_Delegate_No_UI_Settings -3
#define ERR_Set_Parameters_Failed -4
#define ERR_Certificate_File_Not_Exist -5
#define ERR_Load_Certificate_From_File_Failed -6
#define ERR_Save_Certificate_To_KeyChain_Failed -7
#define ERR_Read_KeyChain_Item_Failed -8
#define ERR_Delete_Saved_Certificate_Failed -9
For Android, you can construct a similar list of constants, which must match the JavaScript resource file, i18n.provider.properties.

The JavaScript resource file, i18n.provider.properties, must include the matched resource for those errors in the format Domain@ErrorCode_TITLE and
Domain@ErrorCode_MSG. The resource is used for displaying the error notification alert box.
ERR_Certificate_Provider@-1_TITLE=Error
ERR_Certificate_Provider@-1_MSG=Failed to show html UI
ERR_Certificate_Provider@-2_TITLE=Error
ERR_Certificate_Provider@-2_MSG=Failed to show native UI
ERR_Certificate_Provider@-3_TITLE=Error

PUBLIC Page 44 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
ERR_Certificate_Provider@-3_MSG=Invalid UI settings
ERR_Certificate_Provider@-4_TITLE=Error
ERR_Certificate_Provider@-4_MSG=Failed to set certificate parameter
ERR_Certificate_Provider@-5_TITLE=Error
ERR_Certificate_Provider@-5_MSG=Certificate file does not exist
ERR_Certificate_Provider@-6_TITLE=Error
ERR_Certificate_Provider@-6_MSG=Failed to load certificate from file
ERR_Certificate_Provider@-7_TITLE=Error
ERR_Certificate_Provider@-7_MSG=Failed to save certificate to keychain
ERR_Certificate_Provider@-8_TITLE=Error
ERR_Certificate_Provider@-8_MSG=Failed to read certificate from keychain
ERR_Certificate_Provider@-9_TITLE=Error
ERR_Certificate_Provider@-9_MSG=Failed to delete the saved certificate

Procedure
1. In x509ProviderUI.view.js, ensure that you code for the localized strings, rather than use hard-coded default values.
2. Add a resource bundle file for the new locale and place it into the web resource folder at www/smp/logon/i18n.
3. Change the device international setting to match the locale. For example, on an iOS device, you might select General , International , and change the
language to French.
4. Restart the application, and verify that the application presents you with the localized strings in error notifications.
Parent topic: Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers

1.9.1.7 Kapsel Logon API Reference


The Kapsel Logon API Reference provides usage information for Logon API classes and methods, as well as provides sample source code.
In this section:
Logon namespace
Source code
Parent topic: Using the Logon Plugin

Related Information
Logon Plugin Overview

1.9.1.7.1 Logon namespace


The Logon plugin provides screen flows to register an app with an SAP Mobile Platform server.
The logon plugin is a component of the SAP Mobile Application Framework (MAF), exposed as a Cordova plugin. The basic idea is that it provides screen flows
where the user can enter the values needed to connect to an SAP Mobile Platform 3.0 server and stores those values in its own secure data vault. This data vault
is separate from the one provided with the encrypted storage plugin. In an OData based SAP Mobile Platform 3.0 application, a client must onboard or register
with the SAP Mobile Platform 3.0 server to receive an application connection ID for a particular app. The application connection ID must be sent along with each
request that is proxied through the SAP Mobile Platform 3.0 server to the OData producer.
Adding and Removing the Logon Plugin
The Logon plugin is added and removed using the Cordova CLI .
To add the Logon plugin to your project, use the following command:
cordova plugin add <full path to directory containing Kapsel plugins>\logon
To remove the Logon plugin from your project, use the following command:
cordova plugin rm com.sap.mp.cordova.plugins.logon

Members
Name Description

applicationId The application ID with which sap.Logon.init was called.

core Direct reference to the logon core object used by the Logon plugin.

Methods
Name Description

changePassword( onsuccess, onerror ) This method will launch the UI screen for application users to manage and update the
back-end passcode that Logon stores in the data vault that is used to authenticate the
client to the server.

deletePasscodeManager( successCallback, errorCallback ) Function to delete the datavault and all data stored therein.

get( onsuccess, onerror, key ) Get an (JSON serializable) object from the DataVault for a given key.

init( successCallback, errorCallback, applicationId, [context], [logonView] ) Initialization method to set up the Logon plugin.

initPasscodeManager( successCallback, errorCallback, applicationId, [logonView] ) Initialization method to set up the Logon plugin as a passcode and datavault manager
only.

lock( onsuccess, onerror ) Locks the Logon plugin's secure data vault.

managePasscode( onsuccess, onerror ) This method will launch the UI screen for application users to manage and update the

PUBLIC Page 45 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
data vault passcode or, if the SMP server's Client Passcode Policy allows it, enable or
disable the passcode to the data vault.

refreshCertificate( onsuccess, onerror ) Calling this method to delete the stored certificate and get a new one

set( onsuccess, onerror, key, value ) Set an (JSON serializable) object in the DataVault.

showCertificateProviderScreen( onsuccess, onerror ) Calling this method will show a screen which displays the third party certificate provider
settings screen for the application.

showRegistrationData( onsuccess, onerror ) Calling this method will show a screen which displays the current registration settings
for the application.

unlock( onsuccess, onerror ) Unlock the Logon plugin's secure data vault if it has been locked (due to being inactive,
or sap.Logon.lock being called), then the user is prompted for the passcode to unlock the
application.

Type Definitions
Name Description

errorCallback( errorObject ) Callback function that is invoked in case of an error.

getSuccessCallback( value ) Callback function that is invoked upon successfully retrieving an object from the
DataVault.

successCallback( context ) Callback function that is invoked upon successfully registering or unlocking or retrieving
the context.

successCallbackNoParameters Callback function that will be invoked with no parameters.

Source
LogonController.js, line 2002.
In this section:
applicationId member
core member
changePassword( onsuccess, onerror ) method
deletePasscodeManager( successCallback, errorCallback ) method
get( onsuccess, onerror, key ) method
init( successCallback, errorCallback, applicationId, [context], [logonView] ) method
initPasscodeManager( successCallback, errorCallback, applicationId, [logonView] ) method
lock( onsuccess, onerror ) method
managePasscode( onsuccess, onerror ) method
refreshCertificate( onsuccess, onerror ) method
set( onsuccess, onerror, key, value ) method
showCertificateProviderScreen( onsuccess, onerror ) method
showRegistrationData( onsuccess, onerror ) method
unlock( onsuccess, onerror ) method
errorCallback( errorObject ) type
getSuccessCallback( value ) type
successCallback( context ) type
successCallbackNoParameters type
Parent topic: Kapsel Logon API Reference

1.9.1.7.1.1 applicationId member


The application ID with which sap.Logon.init was called.
It is available here so it is easy to access later.

Syntax
<static> applicationId

Example
// After calling the init function
alert("The app ID for this app is: " + sap.Logon.applicationId);

Source
LogonController.js, line 2114.
Parent topic: Logon namespace

1.9.1.7.1.2 core member


Direct reference to the logon core object used by the Logon plugin.
This is needed to perform more complex operations that are not generally needed by applications.

PUBLIC Page 46 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
There are several functions that can be accessed on the core object:
getState(successCallback,errorCallback) returns the state object of the application to the success callback in the form of a JavaScript object.
getContext(successCallback,errorCallback) returns the context object of the application to the success callback in the form of a JavaScript object.
deleteRegistration(successCallback,errorCallback) deletes the application's registration from the SAP Mobile Platform server and removes
application data on device.

Syntax
<static> core

Example
var successCallback = function(result){
alert("Result: " + JSON.stringify(result));
}
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
sap.Logon.core.getState(successCallback,errorCallback);
sap.Logon.core.getContext(successCallback,errorCallback);
sap.Logon.core.deleteRegistration(successCallback,errorCallback);

Source
LogonController.js, line 2134.
Parent topic: Logon namespace

1.9.1.7.1.3 changePassword( onsuccess, onerror ) method


This method will launch the UI screen for application users to manage and update the back-end passcode that Logon stores in the data vault that is used to
authenticate the client to the server.

Syntax
<static> changePassword ( onsuccess, onerror )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The callback to call if the screen flow succeeds.onsuccess


will be called without parameters for this method.

<onerror> sap.Logon~errorCallback The function that is invoked in case of an error.

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var successCallback = function(context){
alert("Password successfully changed.");
}
sap.Logon.changePassword(successCallback,errorCallback);

Source
LogonController.js, line 2254.
Parent topic: Logon namespace

1.9.1.7.1.4 deletePasscodeManager( successCallback,


errorCallback ) method
Function to delete the datavault and all data stored therein.
This function is intended to be used when Logon has been initialized as a passcode manager via sap.Logon.initPasscodeManager. However, if it has been
initialized for server registration (via sap.Logon.init), calling this function will delete the registration and all data.

Syntax
<static> deletePasscodeManager ( successCallback, errorCallback )

PUBLIC Page 47 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Parameters
Name Type Description

<successCallback> sap.Logon~successCallbackNoParameters The function that is invoked if the deletion is successful.

<errorCallback> sap.Logon~errorCallback The function that is invoked in case of an error.

Example
var successCallback = function(){
alert("successfully deleted all data");
}

var errorCallback = function(errorInfo){


alert("error: " + JSON.stringify(errorInfo));
}
sap.Logon.deletePasscodeManager(successCallback, errorCallback);

Source
LogonController.js, line 2106.
Parent topic: Logon namespace

1.9.1.7.1.5 get( onsuccess, onerror, key ) method


Get an (JSON serializable) object from the DataVault for a given key.

Syntax
<static> get ( onsuccess, onerror, key )

Parameters
Name Type Description

<onsuccess> sap.Logon~getSuccessCallback The function that is invoked upon success.It is called with
the resulting object as a single parameter. This can be null
or undefined, if no object is defined for the given key.

<onerror> sap.Logon~errorCallback The function to invoke in case of error.

<key> string The key with which to query the DataVault.

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var getSuccess = function(value){
alert("value retrieved from the store: " + JSON.stringify(value));
}
var setSuccess = function(){
sap.Logon.get(getSuccess,errorCallback,'someKey');
}
sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');

Source
LogonController.js, line 2156.
Parent topic: Logon namespace

1.9.1.7.1.6 init( successCallback, errorCallback, applicationId,


[context], [logonView] ) method
Initialization method to set up the Logon plugin.
This will register the application with the SMP server and also authenticate the user with servers on the network. This step must be done first prior to any attempt
to communicate with the SMP server.
This function and sap.Logon.initPasscodeManager are mutually exclusive. Do not call both.

Syntax
<static> init ( successCallback, errorCallback, applicationId, [context], [logonView] )

PUBLIC Page 48 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Parameters
Name Type Argument Default Description

<successCallback> sap.Logon~successCallback The function that is invoked if


initialization is successful.The
current context is passed to this
function as the parameter.

<errorCallback> sap.Logon~errorCallback The function that is invoked in


case of an error.

<applicationId> string The unique ID of the


application.Must match the
application ID on the SAP Mobile
Platform server.

<context> object (optional) The context with default values for


application registration.See
sap.Logon~successCallback for
the structure of the context object.
Note that all properties of the
context object are optional, and
you only need to specify the
properties for which you want to
provide default values for. The
values will be presented to the
application users during the
registration process and given
them a chance to override these
values during runtime.

<logonView> string (optional) "com/sap/mp/logon/iabui" The cordova module ID of a


custom renderer for the logon,
implementing the [showScreen(),
close()] interface.Please use the
defaul module unless you are
absolutely sure that you can
provide your own custom
implementation. Please refer to
JavaScript files inside your Kapsel
project's
plugins\logon\www\common\mod
ules\ folder as example.

Example
// a custom UI can be loaded here
var logonView = sap.logon.IabUi;

// The app ID
var applicationId = "someAppID";

// You only need to specify the fields for which you want to set the default. These values are optional because they will be
// used to prefill the fields on Logon's UI screen.
var defaultContext = {
"serverHost" : "defaultServerHost.com"
\t"https" : false,
\t"serverPort" : "8080",
\t"user" : "user1",
\t"password" : "Zzzzzz123",
\t"communicatorId" : "REST",
\t"securityConfig" : "sec1",
\t"passcode" : "Aaaaaa123",
\t"unlockPasscode" : "Aaaaaa123"
};

var app_context;

var successCallback = function(context){


app_context = context;
}

var errorCallback = function(errorInfo){


alert("error: " + JSON.stringify(errorInfo));
}
sap.Logon.init(successCallback, errorCallback, applicationId, defaultContext, logonView);

Source

PUBLIC Page 49 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Source
LogonController.js, line 2054.
Parent topic: Logon namespace

1.9.1.7.1.7 initPasscodeManager( successCallback,


errorCallback, applicationId, [logonView] ) method
Initialization method to set up the Logon plugin as a passcode and datavault manager only.
When this method is called, the Logon plugin will not do anything with regards to registering with any server.
This function and sap.Logon.init are mutually exclusive. Do not call both.

Syntax
<static> initPasscodeManager ( successCallback, errorCallback, applicationId, [logonView] )

Parameters
Name Type Argument Default Description

<successCallback> sap.Logon~successCallback The function that is invoked if


initialization is successful.The
current state is passed to this
function as the parameter.

<errorCallback> sap.Logon~errorCallback The function that is invoked in


case of an error.

<applicationId> string The unique ID of the


application.This value will be used
as the datavault store ID.

<logonView> string (optional) "com/sap/mp/logon/iabui" The cordova module ID of a


custom renderer for the logon,
implementing the [showScreen(),
close()] interface.Please use the
default module unless you are
absolutely sure that you can
provide your own custom
implementation. Please refer to
JavaScript files inside your Kapsel
project's
plugins\logon\www\common\mod
ules\ folder as example.

Example
// a custom UI can be loaded here
var logonView = sap.logon.IabUi;

// The app ID
var applicationId = "someAppID";

var successCallback = function(state){


alert("successfully initialzed, resulting state: " + JSON.stringify(state));
}

var errorCallback = function(errorInfo){


alert("error: " + JSON.stringify(errorInfo));
}
sap.Logon.initPasscodeManager(successCallback, errorCallback, applicationId, logonView);

Source
LogonController.js, line 2086.
Parent topic: Logon namespace

1.9.1.7.1.8 lock( onsuccess, onerror ) method


Locks the Logon plugin's secure data vault.

Syntax
<static> lock ( onsuccess, onerror )

Parameters
PUBLIC Page 50 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The function to invoke upon success.

<onerror> sap.Logon~errorCallback The function to invoke in case of error.

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var successCallback = function(){
alert("Locked!");
}
sap.Logon.lock(successCallback,errorCallback);

Source
LogonController.js, line 2195.
Parent topic: Logon namespace

1.9.1.7.1.9 managePasscode( onsuccess, onerror ) method


This method will launch the UI screen for application users to manage and update the data vault passcode or, if the SMP server's Client Passcode Policy allows
it, enable or disable the passcode to the data vault.

Syntax
<static> managePasscode ( onsuccess, onerror )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The function to invoke upon success.

<onerror> sap.Logon~errorCallback The function to invoke in case of error.

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var successCallback = function(context){
alert("Passcode successfully managed.");
}
sap.Logon.managePasscode(successCallback,errorCallback);

Source
LogonController.js, line 2235.
Parent topic: Logon namespace

1.9.1.7.1.10 refreshCertificate( onsuccess, onerror ) method


Calling this method to delete the stored certificate and get a new one

Syntax
<static> refreshCertificate ( onsuccess, onerror )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The callback to call if the screen flow succeeds.onsuccess


will be called without parameters for this method.

<onerror> sap.Logon~errorCallback The function that is invoked in case of an error.

Example
PUBLIC Page 51 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var successCallback = function(){
alert("The certificate is refreshed.");
}
sap.Logon.refreshCertificate(successCallback,errorCallback);

Source
LogonController.js, line 2306.
Parent topic: Logon namespace

1.9.1.7.1.11 set( onsuccess, onerror, key, value ) method


Set an (JSON serializable) object in the DataVault.

Syntax
<static> set ( onsuccess, onerror, key, value )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The function to invoke upon success.onsuccess will be


called without parameters for this method.

<onerror> sap.Logon~errorCallback The function to invoke in case of error.

<key> string The key to store the provided object on.

<value> object The object to be set on the given key.Must be JSON


serializable (ie: cannot contain circular references).

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var getSuccess = function(value){
alert("value retrieved from the store: " + JSON.stringify(value));
}
var setSuccess = function(){
sap.Logon.get(getSuccess,errorCallback,'someKey');
}
sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');

Source
LogonController.js, line 2179.
Parent topic: Logon namespace

1.9.1.7.1.12 showCertificateProviderScreen( onsuccess, onerror


) method
Calling this method will show a screen which displays the third party certificate provider settings screen for the application.

Syntax
<static> showCertificateProviderScreen ( onsuccess, onerror )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The callback to call if the screen flow succeeds.onsuccess


will be called without parameters for this method.

<onerror> sap.Logon~errorCallback The function that is invoked in case of an error.

Example
PUBLIC Page 52 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var successCallback = function(context){
alert("The showRegistrationData screenflow was successful.");
}
sap.Logon.showCertificateProviderScreen(successCallback,errorCallback);

Source
LogonController.js, line 2288.
Parent topic: Logon namespace

1.9.1.7.1.13 showRegistrationData( onsuccess, onerror ) method


Calling this method will show a screen which displays the current registration settings for the application.

Syntax
<static> showRegistrationData ( onsuccess, onerror )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallbackNoParameters The callback to call if the screen flow succeeds.onsuccess


will be called without parameters for this method.

<onerror> sap.Logon~errorCallback The function that is invoked in case of an error.

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));
}
var successCallback = function(context){
alert("The showRegistrationData screenflow was successful.");
}
sap.Logon.showRegistrationData(successCallback,errorCallback);

Source
LogonController.js, line 2271.
Parent topic: Logon namespace

1.9.1.7.1.14 unlock( onsuccess, onerror ) method


Unlock the Logon plugin's secure data vault if it has been locked (due to being inactive, or sap.Logon.lock being called), then the user is prompted for the
passcode to unlock the application.
If the application is already unlocked, then nothing will be done.
If the application has passcode disabled, then passcode prompt will not be necessary. In all cases if an error does not occur, the success callback is invoked
with the current logon context as the parameter.

Syntax
<static> unlock ( onsuccess, onerror )

Parameters
Name Type Description

<onsuccess> sap.Logon~successCallback The callback to call if the screen flow succeeds.onsuccess


will be called with the current logon context as a single
parameter.

<onerror> sap.Logon~errorCallback The callback to call if the screen flow fails.

Example
var errorCallback = function(errorInfo){
alert("Error: " + JSON.stringify(errorInfo));

PUBLIC Page 53 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
}
var successCallback = function(context){
alert("Registered and unlocked. Context: " + JSON.stringify(context));
}
sap.Logon.unlock(successCallback,errorCallback);

Source
LogonController.js, line 2218.
Parent topic: Logon namespace

1.9.2.5.1.26 errorCallback( errorObject ) type


Callback function that is invoked in case of an error.

Syntax
errorCallback ( errorObject )

Parameters
Name Type Description

<errorObject> Object Depending on the origin of the error the object can take
several forms.(Unfortunately the error object structure and
content is not uniform among the platforms, this will
probably change in the future.) Errors originating from the
logon plugin have only an 'errorKey' property. The possible
values for 'errorKey':
ERR_CHANGE_TIMEOUT_FAILED
ERR_FORGOT_SSO_PIN ERR_INIT_FAILED
ERR_INVALID_ACTION ERR_INVALID_STATE
ERR_PASSCODE_REQUIRES_DIGIT
ERR_PASSCODE_REQUIRES_LOWER
ERR_PASSCODE_REQUIRES_SPECIAL
ERR_PASSCODE_REQUIRES_UPPER
ERR_PASSCODE_TOO_SHORT
ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS
ERR_REGISTRATION_CANCEL ERR_REG_FAILED
ERR_REG_FAILED_UNATHORIZED
ERR_REG_FAILED_WRONG_SERVER
ERR_SETPASSCODE_FAILED
ERR_SET_AFARIA_CREDENTIAL_FAILED
ERR_SSO_PASSCODE_SET_ERROR
ERR_UNKNOWN_SCREEN_ID
ERR_UNLOCK_FAILED ERR_USER_CANCELLED
ERR_PASSCODE_EXPIRED Errors originating in the
logon core (either iOS or Android) have the following
properties: 'errorCode', 'errorMessage', and 'errorDomain'.
The 'errorCode' is just a number uniquely identifying the
error. The 'errorMessage' property is a string with more
detailed information of what went wrong. The
'errorDomain' property specifies the domain that the error
occurred in. On iOS the 'errorDomain' property of the core
errors can take the following values:
MAFLogonCoreErrorDomain,
MAFSecureStoreManagerErrorDomain, and
MAFLogonCoreCDVPluginErrorDomain. In the
MAFLogonCoreErrorDomain the following errors are
thrown (throwing methods in paren): 3
errMAFLogonErrorCommunicationManagerError
(register, update settings, delete, change backend
password) 9
errMAFLogonErrorCouldNotDecideCommunicator
(register) 11 errMAFLogonErrorOperationNotAllowed (all)
12 errMAFLogonErrorInvalidServerHost (register) 13
errMAFLogonErrorInvalidBackendPassword
(changeBackendPassword) 15
errMAFLogonErrorUploadTraceFailed (uploadTrace) 16
errMAFLogonErrorInvalidMCIMSSOPin
(setMCIMSSOPin) 18
errMAFLogonErrorCertificateKeyError (register) 19
errMAFLogonErrorCertificateError (register) 20
errMAFLogonErrorAfariaInvalidCredentials
(setAfariaCredentialWithUser) In the
MAFSecureStoreManagerErrorDomain the following
errors are thrown (throwing methods in paren): 0
errMAFSecureStoreManagerErrorUnknown (persist,

PUBLIC Page 54 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
unlock, changePasscode, delete, getContext) 1
errMAFSecureStoreManagerErrorAlreadyExists (persist) 2
errMAFSecureStoreManagerErrorDataTypeError (unlock,
getContext) 3
errMAFSecureStoreManagerErrorDoesNotExist (unlock,
persist, getContext) 4
errMAFSecureStoreManagerErrorInvalidArg unlock,
(persist, getContext) 5
errMAFSecureStoreManagerErrorInvalidPassword
(unlock) 6 errMAFSecureStoreManagerErrorLocked
(getContext) 7
errMAFSecureStoreManagerErrorOutOfMemory (persist,
unlock, changePasscode, delete, getContext) 8
errMAFSecureStoreManagerErrorPasswordExpired
(unlock, getContext) 9
errMAFSecureStoreManagerErrorPasswordRequired
(persist, changePasscode) 10
errMAFSecureStoreManagerErrorPasswordRequiresDigit
(persist, changePasscode) 11
errMAFSecureStoreManagerErrorPasswordRequiresLowe
r (persist, changePasscode) 12
errMAFSecureStoreManagerErrorPasswordRequiresSpeci
al (persist, changePasscode) 13
errMAFSecureStoreManagerErrorPasswordRequiresUppe
r (persist, changePasscode) 14
errMAFSecureStoreManagerErrorPasswordUnderMinLen
gth (persist, changePasscode) 15
errMAFSecureStoreManagerErrorPasswordUnderMinUni
queChars (persist, changePasscode) 16
errMAFSecureStoreManagerErrorDeleted (unlock) In the
MAFLogonCoreCDVPluginErrorDomain the following
errors are thrown: 1 (init failed) 2 (plugin not initialized) 3
(no input provided) On Android the 'errorDomain' property
of the core errors can take the following values:
MAFLogonCoreErrorDomain and
MAFLogonCoreCDVPluginErrorDomain. There are no
logon specific error codes, the 'errorCode' property only
wraps the error values from the underlying libraries.

Source
LogonController.js, line 2310.
Parent topic: Logon namespace

1.9.1.7.1.16 getSuccessCallback( value ) type


Callback function that is invoked upon successfully retrieving an object from the DataVault.

Syntax
getSuccessCallback ( value )

Parameters
Name Type Description

<value> Object The object that was stored with the given key.Can be null
or undefined if no object was stored with the given key.

Source
LogonController.js, line 2316.
Parent topic: Logon namespace

1.9.1.7.1.17 successCallback( context ) type


Callback function that is invoked upon successfully registering or unlocking or retrieving the context.

Syntax
successCallback ( context )

Parameters

PUBLIC Page 55 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Name Type Description

<context> Object An object containing the current logon context.Two


properties of particular importance are
applicationEndpointURL, and applicationConnectionId.
The context object contains the following properties:
"registrationContext": {
"serverHost": Host of the server.
"domain": Domain for server. Can be used in case of SAP
Mobile Platform communication.
"resourcePath": Resource path on the server. The path is
used mainly for path based reverse proxy but can contain a
custom relay server path as well.
"https": Marks whether the server should be accessed in a
secure way.
"serverPort": Port of the server.
"user": Username in the backend.
"password": Password for the backend user.
"farmId": FarmId of the server. Can be nil. Used in case of
Relay server or SiteMinder.
"communicatorId": Id of the communicator manager that
will be used for performing the logon. Possible values:
IMO / GATEWAY / REST
"securityConfig": Security configuration. If nil, the default
configuration is used.
"mobileUser": Mobile User. Used in case of IMO manual
user creation.
"activationCode": Activation Code. Used in case of IMO
manual user creation.
"gatewayClient": The key string that identifies the client
on the gateway. Used in Gateway only registration mode.
The value will be used as adding the parameter: sap-
client=<gateway client>
"gatewayPingPath": The custom path of the ping URL on
the gateway. Used in case of Gateway only registration
mode.
}
"applicationEndpointURL": Contains the application
endpoint URL after a successful registration.
"applicationConnectionId": ID to get after a successful SUP
REST registration. Needs to be set in the download
request header with key X-SUP-APPCID
"afariaRegistration": manual / automatic / certificate
"policyContext": Contains the password policy for the
secure store {
"alwaysOn":
"alwaysOff":
"defaultOn":
"hasDigits":
"hasLowerCaseLetters":
"hasSpecialLetters":
"hasUpperCaseLetters":
"defaultAllowed":
"expirationDays":
"lockTimeout":
"minLength":
"minUniqueChars":
"retryLimit":
}
"registrationReadOnly": specifies whether context values
are coming from clientHub / afaria
"policyReadOnly": specifies whether passcode policy is
coming from afaria
"credentialsByClientHub": specifies whether credentials
are coming from clientHub

Source
LogonController.js, line 2312.
Parent topic: Logon namespace

1.9.1.7.1.18 successCallbackNoParameters type


Callback function that will be invoked with no parameters.

Syntax
successCallbackNoParameters ()

PUBLIC Page 56 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Source
LogonController.js, line 2314.
Parent topic: Logon namespace

1.9.3.3.2 Source code


In this section:
LogonController.js
Parent topic: Kapsel Logon API Reference

1.9.1.7.2.1 LogonController.js
1 var utils = sap.logon.Utils;
2 var TIMEOUT = 2000;
3
4 var _oLogonCore;
5 var _oLogonView;
6 var _hasLogonSuccessEventFired = false;
7
8 var _providedContext;
9 var _providedPasscodePolicyContext;
10
11 var flowqueue;
12
13 var _credentialProviderID;
14 var _credentialProviderCertificateAvailable = false;
15 var _registrationEventsForCredentialProvider = null;
16 var _bIsWebRegistration = false;
17
18 var passcodePolicyAttributeNames = [
19 "minUniqueChars",
20 "hasLowerCaseLetters",
21 "hasSpecialLetters",
22 "hasUpperCaseLetters",
23 "minLength",
24 "retryLimit",
25 "lockTimeout",
26 "hasDigits",
27 "defaultAllowed",
28 "expirationDays"
29 ];
30
31 var init = function (successCallback, errorCallback, applicationId, context, customView, credentialProviderID) {
32
33 normalizeResourcePath(context);
34
35 document.addEventListener("resume",
36 function(){
37 resume(
38 function() { fireEvent('onSapResumeSuccess', arguments);},
39 function() { fireEvent('onSapResumeError', arguments);}
40 );
41 },
42 false);
43
44 // The success callback used for the call to _oLogonCore.initLogon(...)
45 var initSuccess = function(certificateSetToLogonCore){
46 utils.log('LogonController: LogonCore successfully initialized.');
47
48 _credentialProviderCertificateAvailable = certificateSetToLogonCore;
49
50 // Now that Logon is initialized, registerOrUnlock is automatically called.
51 registerOrUnlock( successCallback, errorCallback );
52 }
53
54 var initError = function(error){
55 // If a parameter describing the error is given, pass it along.
56 // Otherwise, construct something to call the error callback with.
57 if( error ) {
58 errorCallback( error );
59 } else {
60 errorCallback( utils.Error('ERR_INIT_FAILED') );
61 }
62 }
63
64

PUBLIC Page 57 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
65 utils.log('LogonController.init enter');
66 utils.log(applicationId);
67 module.exports.applicationId = applicationId;
68
69 // Make note of the context given (if any)
70 if( context ){
71 _providedContext = context;
72 }
73
74 _oLogonView = customView;
75 if (!_oLogonView) {
76 _oLogonView = sap.logon.IabUi;
77 }
78
79 flowqueue = new FlowRunnerQueue();
80
81 //coLogonCore.cordova.require("com.sap.mp.cordova.plugins.logon.LogonCore");
82 _oLogonCore = sap.logon.Core;
83
84 _credentialProviderID =credentialProviderID;
85 _bIsWebRegistration = false;
86
87 _oLogonCore.initLogon(initSuccess, initError, applicationId, credentialProviderID);
88
89 //update exports definition
90 module.exports.core = _oLogonCore;
91 }
92
93 var initPasscodeManager = function (successCallback, errorCallback, applicationId, customView, passcodePolicy, context
94
95 if (verifyPasscodePolicy(passcodePolicy)) {
96 errorCallback(errorWithDomainCodeDescription("MAFLogon","7","Unrecognized attribute name: " + verifyPasscodePo
97 return;
98 }
99
100 document.addEventListener("resume",
101 function(){
102 resume(
103 function() { fireEvent('onSapResumeSuccess', arguments);},
104 function() { fireEvent('onSapResumeError', arguments);}
105 );
106 },
107 false);
108
109 // The success callback used for the call to _oLogonCore.initLogon(...)
110 var initSuccess = function(certificateSetToLogonCore){
111 utils.log('LogonController: LogonCore successfully initialized.');
112
113 _credentialProviderCertificateAvailable = certificateSetToLogonCore;
114
115 // Now that Logon is initialized, registerOrUnlock is automatically called.
116 registerOrUnlock( successCallback, errorCallback );
117 }
118
119 var initError = function(error){
120 // If a parameter describing the error is given, pass it along.
121 // Otherwise, construct something to call the error callback with.
122 if( error ) {
123 errorCallback( error );
124 } else {
125 errorCallback( utils.Error('ERR_INIT_FAILED') );
126 }
127 }
128
129
130 utils.log('LogonController.init enter');
131 utils.log(applicationId);
132 module.exports.applicationId = applicationId;
133
134 _oLogonView = customView;
135 if (!_oLogonView) {
136 _oLogonView = sap.logon.IabUi;
137 }
138
139 flowqueue = new FlowRunnerQueue();
140
141 //coLogonCore.cordova.require("com.sap.mp.cordova.plugins.logon.LogonCore");
142 _oLogonCore = sap.logon.Core;

PUBLIC Page 58 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
143
144 if (passcodePolicy){
145 _providedPasscodePolicyContext = passcodePolicy;
146 }
147
148 // Make note of the context given (if any)
149 if( context ){
150 _providedContext = context;
151 }
152
153 _bIsWebRegistration = true;
154
155 _oLogonCore.initLogon(initSuccess, initError, applicationId, null, _bIsWebRegistration );
156
157 //update exports definition
158 module.exports.core = _oLogonCore;
159 }
160
161 var fireEvent = function (eventId, args) {
162 if (typeof eventId === 'string') {
163 //var event = document.createEvent('Events');
164 //event.initEvent(eventId, false, false);
165
166 if (!window.CustomEvent) {
167 window.CustomEvent = function(type, eventInitDict) {
168 var newEvent = document.createEvent('CustomEvent');
169 newEvent.initCustomEvent(
170 type,
171 !!(eventInitDict && eventInitDict.bubbles),
172 !!(eventInitDict && eventInitDict.cancelable),
173 (eventInitDict ? eventInitDict.detail : null));
174 return newEvent;
175 };
176 }
177
178 var event = new CustomEvent(eventId, { 'detail':{ 'id': eventId, 'args': args }});
179
180 setTimeout(function() {
181 document.dispatchEvent(event);
182 }, 0);
183 } else {
184 throw 'Invalid eventId: ' + JSON.stringify(event);
185 }
186 }
187
188 var showCertificateProviderScreen = function(viewIDSettings){
189 if (!_registrationEventsForCredentialProvider) {
190 // This case will only occur if showCertificateProviderScreen has been called
191 // without refreshCertificate being called first. This should only happen during
192 // logon init on Android. Since the call did not originate in the javascript, we
193 // don't have to worry about many of the callbacks. Either we'll call
194 // setParametersForProvider with the context, or we'll call it with "cancelled".
195 _registrationEventsForCredentialProvider = {
196 onsubmit: function(context){
197 utils.logJSON(context, 'logonCore.setCertificateProviderCredential');
198 _oLogonCore.setParametersForProvider(function(){},function(){},context);
199 },
200 oncancel: function(error){
201 _oLogonView.close();
202 _credentialProviderCertificateAvailable = true;
203 _oLogonCore.setParametersForProvider(function(){},function(){},"cancelled");
204 },
205 onerror: function(error){
206 _oLogonView.showNotification(error.errorDomain + "@" + error.errorCode );
207 }
208 };
209 }
210
211 setTimeout(
212 function(){
213 var context = JSON.parse(viewIDSettings);
214 _oLogonView.showScreen("SCR_GET_CERTIFICATE_PROVIDER_PARAMETER", _registrationEventsForCredentialProvider,
215 }, 1);
216 }
217
218 var refreshCertificate = function(successCallback, errorCallback){
219
220 if(!_oLogonCore) {

PUBLIC Page 59 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
221 utils.log('FlowRunner.run MAFLogon is not initialized');
222 errorCallback(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
223 return;
224 }
225
226 if (_bIsWebRegistration){
227 utils.log('refreshCertificate is not supported for passcode manager only initialization');
228 errorCallback(errorWithDomainCodeDescription("MAFLogon","6","refreshCertificate is not supported for Passc
229 return;
230 }
231
232 if (!_credentialProviderID) {
233 utils.log('FlowRunner.run credential provider is not provided');
234 errorCallback(errorWithDomainCodeDescription("MAFLogon","4","credential provider is not provided"));
235 return;
236 }
237
238 _registrationEventsForCredentialProvider = {
239 onsubmit: function(context){
240 utils.logJSON(context, 'logonCore.setCertificateProviderCredential');
241 _oLogonCore.setParametersForProvider(
242 function(){
243 console.log("setParameterForProvider success callback");
244 },//only for debug
245 errorCallback,
246 context);
247 },
248 oncancel: function(error){
249 _oLogonView.close();
250 _credentialProviderCertificateAvailable = true;
251 },
252 onerror: function(error){
253 _oLogonView.showNotification(error.errorDomain + "@" + error.errorCode );
254 }
255 };
256
257 _oLogonCore.getCertificateFromProvider(
258 function(success){
259 _oLogonView.close();
260 _credentialProviderCertificateAvailable = true;
261 successCallback(success);
262 },
263 function(error){
264 //if the error is user cancel, then close the window, otherwise keeping the screen to allow user corrects t
265 _oLogonView.showNotification(error.errorDomain + "@" + error.errorCode );
266 //_oLogonView.close();
267 _credentialProviderCertificateAvailable = false;
268 //errorCallback(error);
269 },
270 true
271 );
272 }
273
274 var FlowRunner = function(callbacks, pLogonView, pLogonCore, flowClass) {
275
276 var onFlowSuccess;
277 var onFlowError;
278 var onFlowCancel;
279
280 var logonView;
281 var logonCore;
282 var flow;
283
284 var onsuccess = callbacks.onsuccess;
285 var onerror = callbacks.onerror;
286
287
288
289 logonView = pLogonView;
290 logonCore = pLogonCore;
291
292 onFlowSuccess = function onFlowSuccess() {
293 utils.logJSON('onFlowSuccess');
294 logonView.close();
295 onsuccess.apply(this, arguments);
296 }
297
298 onFlowError = function onFlowError() {

PUBLIC Page 60 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
299 utils.logJSON('onFlowError');
300 logonView.close();
301 onerror.apply(this, arguments);
302 }
303
304 onFlowCancel = function onFlowCancel(){
305 utils.logJSON('onFlowCancel');
306 //logonView.close();
307 onFlowError(new utils.Error('ERR_USER_CANCELLED'));
308 }
309
310 var handleCoreStateOnly = function(currentState){
311 handleCoreResult(null, currentState);
312 }
313
314 var handleCoreResult = function (currentContext, currentState) {
315 if (typeof currentContext === undefined) currentContext = null;
316
317 //workaround for defaultPasscodeAllowed
318 if (currentState) {
319 if (currentContext && currentContext.policyContext && currentContext.policyContext.defaultAllowed){
320 currentState.defaultPasscodeAllowed = true;
321 }
322 else {
323 currentState.defaultPasscodeAllowed = false;
324 if (_providedPasscodePolicyContext && _providedPasscodePolicyContext.defaultAllowed) {
325 currentState.defaultPasscodeAllowed = true;
326 }
327 }
328 }
329
330 utils.logJSON(currentContext, 'handleCoreResult currentContext');
331 utils.logJSON(currentState, 'handleCoreResult currentState');
332
333
334 utils.logJSON(flow.name);
335 var matchFound = false;
336 var rules = flow.stateTransitions;
337
338
339 ruleMatching:
340 for (key in rules){
341
342 var rule = flow.stateTransitions[key];
343 utils.logJSON(rule, 'rule-'+rules.id);
344
345 utils.logJSON(rule.condition, 'rule.condition');
346 if (typeof rule.condition === 'undefined') {
347 throw 'undefined condition in state transition rule';
348 }
349
350
351 if (rule.condition.state === null) {
352 if (currentState)
353 {
354 continue ruleMatching; // non-null state (and rule) mismatch
355 }
356 //else {
357 // // match:
358 // // rule.condition.state === null &&
359 // // (typeof currentState === 'undefined') // null or undefined
360 //}
361 }
362 else if (rule.condition.state !== 'undefined' && currentState){
363 utils.log('stateMatching');
364
365 stateMatching:
366 for (field in rule.condition.state) {
367 utils.log(field);
368 if (rule.condition.state[field] === currentState[field])
369 {
370 utils.log('field matching ' + field);
371 continue stateMatching; // state field match
372 }
373 else {
374 utils.log('field mismatching ' + field);
375 continue ruleMatching; // state field (and rule) mismatch
376 };

PUBLIC Page 61 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
377 }
378 }
379
380 if (rule.condition.context === null) {
381 if (currentContext)
382 {
383 continue ruleMatching; // non-null context (and rule) mismatch
384 }
385 //else {
386 // // match:
387 // // rule.condition.context === null &&
388 // // (typeof currentContext === 'undefined') // null or undefined
389 //}
390 }
391 else if (rule.condition.context !== 'undefined' && currentContext){
392
393 utils.log('contextMatching');
394 contextMatching:
395 for (field in rule.condition.context) {
396 utils.log(field);
397 if (rule.condition.context[field] === currentContext[field])
398 {
399 utils.log('field matching ' + field);
400 continue contextMatching; // context field match
401 }
402 else {
403 utils.log('field mismatching ' + field);
404 continue ruleMatching; // context field (and rule) mismatch
405 };
406 }
407 }
408
409 if (rule.condition.method != null ) {
410 if (!rule.condition.method())
411 {
412 continue ruleMatching; // non-null context (and rule) mismatch
413 }
414 }
415
416
417 utils.log('match found: ' + rule.id);
418 utils.logJSON(rule, 'rule');
419
420 if (typeof rule.action === 'function') {
421 rule.action(currentContext);
422 }
423 else if (typeof rule.action === 'string') {
424 // the action is a screenId
425 var screenId = rule.action;
426 utils.log('handleCoreResult: ' + screenId);
427 utils.logKeys(flow.screenEvents[screenId]);
428 if(!currentContext){
429 currentContext = {};
430 }
431
432 if( !currentContext.registrationContext && _providedContext ){
433 // The current registrationContext is null, and we have been given a context when initialized,
434 // so use the one we were given.
435 currentContext.registrationContext = _providedContext;
436 } else if (currentContext.registrationContext && _providedContext && !currentContext.registrationReadO
437 for (key in _providedContext) {
438 //if (!currentContext.registrationContext[key]){
439 currentContext.registrationContext[key] = _providedContext[key];
440 //}
441 }
442 }
443
444 logonView.showScreen(screenId, flow.screenEvents[screenId], currentContext);
445
446 }
447 else {
448 onFlowError(new utils.Error('ERR_INVALID_ACTION'));
449 }
450
451 matchFound = true;
452 break ruleMatching;
453 }
454

PUBLIC Page 62 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
455 if (!matchFound) {
456 onFlowError(new utils.Error('ERR_INVALID_STATE'));
457 }
458 }
459
460 flow = new flowClass(logonCore, logonView, handleCoreResult, onFlowSuccess, onFlowError, onFlowCancel);
461
462 this.run = function() {
463 utils.log('FlowRunner.run ' + flowClass.name);
464 utils.logKeys(flow , 'new flow ');
465 logonCore.getState(handleCoreStateOnly, onFlowError);
466 }
467 }
468
469 var FlowRunnerQueue = function() {
470 var isRunning = false;
471 var innerQueue = [];
472
473 this.add = function(flowRunner) {
474 innerQueue.push(flowRunner);
475 if (isRunning == false) {
476 isRunning = true;
477 process();
478 }
479 }
480
481 this.runNextFlow = function() {
482 innerQueue.shift();
483 if (innerQueue.length == 0) {
484 isRunning = false;
485 }
486 else {
487 process();
488 }
489 }
490
491 var process = function() {
492 if (innerQueue.length > 0) {
493 var flowRunner = innerQueue[0];
494 flowRunner.run();
495 }
496 else {
497 isRunning = false;
498 }
499 }
500 }
501
502
503 var MockFlow = function MockFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
504 //wrapped into a function to defer evaluation of the references to flow callbacks
505 //var flow = {};
506
507 this.name = 'mockFlowBuilder';
508
509 this.stateTransitions = [
510 {
511 id:"m0",
512 condition: {
513 state: {
514 secureStoreOpen: false,
515 }
516 },
517 action: 'SCR_MOCKSCREEN'
518 },
519 {
520 id:"m1",
521 condition: {
522 state: {
523 secureStoreOpen: true,
524 }
525 },
526 action: 'SCR_MOCKSCREEN'
527 },
528
529 ];
530
531 this.screenEvents = {
532 'SCR_TURN_PASSCODE_ON': {

PUBLIC Page 63 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
533 onsubmit: onFlowSuccess,
534 oncancel: onFlowCancel,
535 onerror: onFlowError,
536 }
537 };
538
539 utils.log('flow constructor return');
540 //return flow;
541 }
542
543 var RegistrationFlow = function RegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, o
544 //wrapped into a function to defer evaluation of the references to flow callbacks
545
546 this.name = 'registrationFlowBuilder';
547
548 var registrationInProgress = false;
549
550 var onCancelSSOPin = function() {
551 onFlowError(errorWithDomainCodeDescription("MAFLogon","0","SSO Passcode set screen was cancelled"));
552 }
553
554 var onCancelRegistration = function() {
555 onFlowError(errorWithDomainCodeDescription("MAFLogon","1","Registration screen was cancelled"));
556 }
557
558 // internal methods
559 var showScreen = function(screenId) {
560 return function(coreContext) {
561 logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
562 }.bind(this);
563 }.bind(this);
564
565 var onUnlockSubmit = function(context){
566 utils.logJSON(context, 'logonCore.unlockSecureStore');
567 logonCore.unlockSecureStore(onCoreResult, onUnlockError, context)
568 }
569
570 var onUnlockError = function(error) {
571 utils.logJSON("onUnlockError: " + JSON.stringify(error));
572
573 if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode && error
574 // Too many attempts --> DV deleted
575 logonView.showNotification("ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE")
576 }
577 else if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode &&
578 // passcode expired --> DV deleted
579 logonView.showNotification("ERR_PASSCODE_EXPIRED")
580 }
581 else {
582 logonView.showNotification("ERR_UNLOCK_FAILED");
583 }
584 }
585
586 var onSetAfariaCredentialError = function(error) {
587 utils.logJSON("onSetAfariaCredentialError: " + JSON.stringify(error));
588
589 logonView.showNotification("ERR_SET_AFARIA_CREDENTIAL_FAILED");
590 }
591
592 var noOp = function() { }
593
594 var onErrorAck = function(ack) {
595 if (ack.key === 'ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE') {
596 onFlowError(new utils.Error('ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE'));
597 }
598 }
599
600 var onRegistrationBackButton = function() {
601 if (registrationInProgress == true) {
602 utils.log('back button pushed, no operation is required as registration is running');
603 }
604 else {
605 onCancelRegistration();
606 }
607 }
608
609 var onUnlockVaultWithDefaultPasscode = function(){
610 utils.log('logonCore.unlockSecureStore - default passcode');

PUBLIC Page 64 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
611 var unlockContext = {"unlockPasscode":null};
612 logonCore.unlockSecureStore(onCoreResult, onFlowError, unlockContext)
613 }
614
615 var onRegSucceeded = function(context, state) {
616 onCoreResult(context, state);
617 registrationInProgress = false;
618 }
619
620 var onRegError = function(error){
621 utils.logJSON(error, 'registration failed');
622 logonView.showNotification(getRegistrationErrorText(error));
623 registrationInProgress = false;
624 _credentialProviderCertificateAvailable = false;
625 }
626
627 var onCertificateProviderError = function(error){
628 utils.logJSON(error, 'CertificateProvider reports error: ' + JSON.stringify(error));
629 logonView.showNotification(error.errorDomain + "@" + error.errorCode );
630 registrationInProgress = false;
631 _credentialProviderCertificateAvailable = false;
632 }
633
634 var onRegSubmit = function(context){
635 utils.logJSON(context, 'logonCore.startRegistration');
636 normalizeResourcePath(context);
637 registrationInProgress = true;
638 logonCore.startRegistration(onRegSucceeded, onRegError, context)
639 }
640
641 var onCreatePasscodeSubmit = function(context){
642 utils.logJSON(context, 'logonCore.persistRegistration');
643 logonCore.persistRegistration(onCoreResult, onCreatePasscodeError, context);
644 }
645
646 var onCancelRegistrationError = function(error){
647 utils.logJSON("onCancelRegistrationError: " + JSON.stringify(error));
648 logonView.showNotification(getRegistrationCancelError(error));
649 }
650
651 var onCreatePasscodeError = function(error) {
652 utils.logJSON("onCreatePasscodeError: " + JSON.stringify(error));
653 logonView.showNotification(getSecureStoreErrorText(error));
654 }
655
656 var onSSOPasscodeSetError = function(error) {
657 utils.logJSON("onSSOPasscodeSetError: " + JSON.stringify(error));
658 logonView.showNotification(getSSOPasscodeSetErrorText(error));
659 }
660
661 var callGetContext = function(){
662 utils.log('logonCore.getContext');
663 logonCore.getContext(onCoreResult, onFlowError);
664 }
665
666 var onFullRegistered = function()
667 {
668 var getContextSuccessCallback = function(result){
669
670 if(!_hasLogonSuccessEventFired) {
671 fireEvent("onSapLogonSuccess", arguments);
672 _hasLogonSuccessEventFired = true;
673 }
674
675 onFlowSuccess(result);
676 }
677 utils.log('logonCore.getContext');
678 logonCore.getContext(getContextSuccessCallback, onFlowError);
679 }
680
681 var onForgotAppPasscode = function(){
682 utils.log('logonCore.deleteRegistration');
683 logonCore.deleteRegistration(onFlowError, onFlowError);
684 }
685
686 var onForgotSsoPin = function(){
687 utils.log('forgotSSOPin');
688 logonView.showNotification("ERR_FORGOT_SSO_PIN");

PUBLIC Page 65 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
689 }
690
691 var onSkipSsoPin = function(){
692 utils.logJSON('logonCore.skipClientHub');
693 logonCore.skipClientHub(onCoreResult, onFlowError);
694 }
695
696 var callPersistWithDefaultPasscode = function(context){
697 utils.logJSON(context, 'logonCore.persistRegistration');
698 context.passcode = null;
699 logonCore.persistRegistration(
700 onCoreResult,
701 onFlowError,
702 context)
703 }
704
705 // exported properties
706 this.stateTransitions = [
707 {
708 id:"r0",
709 condition: {
710 state: {
711 secureStoreOpen: false,
712 status: 'fullRegistered',
713 defaultPasscodeUsed: true
714 }
715 },
716 action: onUnlockVaultWithDefaultPasscode
717 },
718
719 {
720 id:"r1",
721 condition: {
722 state: {
723 secureStoreOpen: false,
724 status: 'fullRegistered'
725 }
726 },
727 action: 'SCR_UNLOCK'
728 },
729
730
731 {
732 id:"r2",
733 condition: {
734 state: {
735 //secureStoreOpen: false, //TODO clarify
736 status: 'fullRegistered',
737 stateClientHub: 'availableNoSSOPin'
738 }
739 },
740 action: 'SCR_SSOPIN_SET'
741 },
742 {
743 id:"r3",
744 condition: {
745 state: {
746 status: 'new'
747 },
748 context: null
749 },
750 action: callGetContext
751 },
752
753 {
754 id:"r4",
755 condition: {
756 state: {
757 status: 'new',
758 stateClientHub: 'availableNoSSOPin'
759 }
760 },
761 action: 'SCR_SSOPIN_SET'
762 },
763
764 {
765 id:"r5",
766 condition: {

PUBLIC Page 66 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
767 state: {
768 status: 'new',
769 stateClientHub: 'availableInvalidSSOPin'
770 }
771 },
772 action: 'SCR_SSOPIN_SET'
773 },
774 {
775 id:"r6",
776 condition: {
777 state: {
778 status: 'new',
779 stateClientHub: 'availableValidSSOPin',
780 stateAfaria: 'initializationFailed',
781 },
782 context : {
783 afariaRegistration: 'certificate'
784 }
785 },
786 action: 'SCR_ENTER_AFARIA_CREDENTIAL'
787 },
788 {
789 id:"r7",
790 condition: {
791 state: {
792 status: 'new',
793 stateClientHub: 'availableValidSSOPin',
794 stateAfaria: 'credentialNeeded'
795 },
796 context : {
797 afariaRegistration: 'certificate'
798 }
799 },
800 action: 'SCR_ENTER_AFARIA_CREDENTIAL'
801 },
802 {
803 id:"r8",
804 condition: {
805 state: {
806 status: 'new',
807 stateClientHub: 'notAvailable',
808 stateAfaria: 'credentialNeeded'
809 }
810 },
811 action: 'SCR_ENTER_AFARIA_CREDENTIAL'
812 },
813 { //condition to get certificate from third party certificate provider
814 id:"r9",
815 condition: {
816 state: {
817 status: 'new'
818 },
819 context : {
820 afariaRegistration: 'certificate'
821 },
822 //the method must return true in order to match this state
823 method: function () {return _credentialProviderID != null && !_credentialProviderCertificateAvailable;}
824 },
825 action: function(context){
826 utils.logJSON(context, 'logonCore.getCertificateFromProvider');
827 _registrationEventsForCredentialProvider = {
828 onsubmit: function(context){
829 utils.logJSON(context, 'logonCore.setCertificateProviderCredential');
830 logonCore.setParametersForProvider(
831 function(){
832 console.log("setParameterForProvider success callback");},//only for debug
833 onCertificateProviderError,
834 context);
835 },
836 oncancel: onCancelRegistration,
837 onerror: onFlowError
838
839 };
840
841 //the on success callback needs to set _credentialProviderCertificateAvailable flag to continue screen
842 logonCore.getCertificateFromProvider(
843 function(){
844 console.log("getCertificateFromProvider success callback called");

PUBLIC Page 67 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
845 _credentialProviderCertificateAvailable = true;
846 onCoreResult.apply(this, arguments);
847 },
848 function(error){
849 onCertificateProviderError(error);
850 _credentialProviderCertificateAvailable = false;
851 },
852 false
853 );
854 }
855 },
856
857 //condition to indicate third party certificate is available
858 {
859 id:"r10",
860 condition: {
861 state: {
862 status: 'new',
863 },
864 context : {
865 afariaRegistration: 'certificate'
866 },
867 //the method must return true in order to match this state
868 method: function () {return _credentialProviderID != null && _credentialProviderCertificateAvailable;}
869
870 },
871 action: function(context){
872 utils.logJSON(context, 'logonCore.startRegistration');
873 logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
874 }
875
876 },
877
878 {
879 id:"r11",
880 condition: {
881 state: {
882 status: 'new',
883 isAfariaCredentialsProvided: false
884 },
885 context : {
886 afariaRegistration: 'certificate'
887 }
888 },
889 action: 'SCR_ENTER_AFARIA_CREDENTIAL'
890 },
891 {
892 id:"r12",
893 condition: {
894 state: {
895 status: 'new',
896 stateClientHub: 'availableValidSSOPin'
897 },
898 context : {
899 credentialsByClientHub : true,
900 registrationReadOnly : true
901 }
902 },
903 action: function(context){
904 utils.logJSON(context, 'logonCore.startRegistration');
905 logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
906 }
907 },
908 {
909 id:"r13",
910 condition: {
911 state: {
912 status: 'new',
913 stateClientHub: 'availableValidSSOPin',
914 stateAfaria: 'initializationSuccessful'
915 },
916 context : {
917 registrationReadOnly : true,
918 afariaRegistration: 'certificate'
919 }
920 },
921 action: function(context){
922 utils.logJSON(context, 'logonCore.startRegistration');

PUBLIC Page 68 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
923 logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
924 }
925 },
926 {
927 id:"r14",
928 condition: {
929 state: {
930 status: 'new',
931 stateClientHub: 'notAvailable',
932 stateAfaria: 'initializationSuccessful'
933 },
934 context : {
935 afariaRegistration: 'certificate'
936 }
937 },
938 action: function(context){
939 utils.logJSON(context, 'logonCore.startRegistration');
940 logonCore.startRegistration(onCoreResult, onRegError, context.registrationContext);
941 }
942 },
943 {
944 id:"r15",
945 condition: {
946 state: {
947 status: 'new',
948 stateClientHub: 'notAvailable',
949 stateAfaria: 'initializationSuccessful'
950 }
951 },
952 action: 'SCR_ENTER_CREDENTIALS'
953 },
954 {
955 id:"r16",
956 condition: {
957 state: {
958 status: 'new',
959 stateClientHub: 'availableValidSSOPin'
960 },
961 context : {
962 registrationReadOnly :true,
963 credentialsByClientHub : false
964 }
965 },
966 action: 'SCR_ENTER_CREDENTIALS'
967 },
968
969 {
970 id:"r18",
971 condition: {
972 state: {
973 status: 'new',
974 //stateClientHub: 'notAvailable' | 'availableValidSSOPin' | 'skipped' | 'error'
975 }
976 },
977 action: 'SCR_REGISTRATION'
978 },
979
980 {
981 id:"r20",
982 condition: {
983 state: {
984 secureStoreOpen: false,
985 status: 'registered',
986 defaultPasscodeUsed: true,
987 // defaultPasscodeAllowed: true,
988 }
989 },
990 action: 'SCR_SET_PASSCODE_OPT_OFF'
991 },
992 {
993 id:"r21",
994 condition: {
995 state: {
996 secureStoreOpen: false,
997 status: 'registered',
998 defaultPasscodeUsed: false,
999 defaultPasscodeAllowed: true,
1000 }

PUBLIC Page 69 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1001 },
1002 action: 'SCR_SET_PASSCODE_OPT_ON'
1003 },
1004 {
1005 id:"r22",
1006 condition: {
1007 state: {
1008 secureStoreOpen: false,
1009 status: 'registered',
1010 // defaultPasscodeAllowed: false,
1011 }
1012 },
1013 action: 'SCR_SET_PASSCODE_MANDATORY'
1014 },
1015
1016
1017 {
1018 id:"r23",
1019 condition: {
1020 state: {
1021 //secureStoreOpen: false, //TODO clarify
1022 status: 'fullRegistered',
1023 stateClientHub: 'availableInvalidSSOPin'
1024 }
1025 },
1026 action: 'SCR_SSOPIN_CHANGE'
1027 },
1028 {
1029 id:"r24",
1030 condition: {
1031 state: {
1032 secureStoreOpen: true,
1033 status: 'fullRegistered',
1034 stateClientHub: 'notAvailable'
1035 }
1036 },
1037 action: onFullRegistered
1038 },
1039 {
1040 id:"r25",
1041 condition: {
1042 state: {
1043 secureStoreOpen: true,
1044 status: 'fullRegistered',
1045 stateClientHub: 'availableValidSSOPin'
1046 }
1047 },
1048 action: onFullRegistered
1049 },
1050 {
1051 id:"r26",
1052 condition: {
1053 state: {
1054 secureStoreOpen: true,
1055 status: 'fullRegistered',
1056 stateClientHub: 'skipped'
1057 }
1058 },
1059 action: onFullRegistered
1060 },
1061
1062
1063
1064 ];
1065
1066 this.screenEvents = {
1067 'SCR_SSOPIN_SET': {
1068 onsubmit: function(context){
1069 utils.logJSON(context, 'logonCore.setSSOPasscode');
1070 logonCore.setSSOPasscode(onCoreResult, onSSOPasscodeSetError, context);
1071 },
1072 oncancel: onCancelSSOPin,
1073 onerror: onFlowError,
1074 onforgot: onForgotSsoPin,
1075 onskip: onSkipSsoPin
1076 },
1077
1078 'SCR_ENTER_AFARIA_CREDENTIAL' : {

PUBLIC Page 70 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1079 onsubmit: function(context){
1080 utils.logJSON(context, 'logonCore.setAfariaCredential');
1081 logonCore.setAfariaCredential(onCoreResult, onSetAfariaCredentialError, context);
1082 }
1083 },
1084
1085 'SCR_SSOPIN_CHANGE': {
1086 onsubmit: function(context){
1087 utils.logJSON(context, 'logonCore.setSSOPasscode');
1088 logonCore.setSSOPasscode(onCoreResult, onSSOPasscodeSetError, context);
1089 },
1090 oncancel: onSkipSsoPin,
1091 onerror: onFlowError,
1092 onforgot: onForgotSsoPin
1093 },
1094
1095 'SCR_UNLOCK': {
1096 onsubmit: onUnlockSubmit,
1097 oncancel: noOp,
1098 onerror: onFlowError,
1099 onforgot: onForgotAppPasscode,
1100 onerrorack: onErrorAck
1101 },
1102
1103 'SCR_REGISTRATION': {
1104 onsubmit: onRegSubmit,
1105 oncancel: onCancelRegistration,
1106 onerror: onFlowError,
1107 onbackbutton: onRegistrationBackButton
1108 },
1109
1110 'SCR_ENTER_CREDENTIALS' : {
1111 onsubmit: onRegSubmit,
1112 oncancel: onCancelRegistration,
1113 onerror: onFlowError
1114 },
1115 'SCR_SET_PASSCODE_OPT_ON': {
1116 onsubmit: onCreatePasscodeSubmit,
1117 oncancel: noOp,
1118 onerror: onFlowError,
1119 ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
1120 onerrorack: noOp
1121 },
1122 'SCR_SET_PASSCODE_OPT_OFF': {
1123 onsubmit: callPersistWithDefaultPasscode,
1124 oncancel: noOp,
1125 onerror: onFlowError,
1126 onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
1127 onerrorack: noOp
1128 },
1129 'SCR_SET_PASSCODE_MANDATORY': {
1130 onsubmit: onCreatePasscodeSubmit,
1131 oncancel: noOp,
1132 onerror: onFlowError,
1133 onerrorack: noOp
1134 }
1135
1136 };
1137
1138 utils.log('flow constructor return');
1139 }
1140
1141 //Web registrationFlow is used to onboard application without SMP logon
1142 var WebRegistrationFlow = function WebRegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowEr
1143 //wrapped into a function to defer evaluation of the references to flow callbacks
1144
1145 this.name = 'registrationFlowBuilder';
1146
1147 var registrationInProgress = false;
1148
1149 var onCancelRegistration = function() {
1150 onFlowError(errorWithDomainCodeDescription("MAFLogon","1","Registration screen was cancelled"));
1151 }
1152
1153 // internal methods
1154 var showScreen = function(screenId) {
1155 return function(coreContext) {
1156 logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);

PUBLIC Page 71 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1157 }.bind(this);
1158 }.bind(this);
1159
1160 var onUnlockSubmit = function(context){
1161 utils.logJSON(context, 'logonCore.unlockSecureStore');
1162 logonCore.unlockSecureStore(onCoreResult, onUnlockError, context)
1163 }
1164
1165 var noOp = function() { }
1166
1167 var onForgotAppPasscode = function(){
1168 utils.log('logonCore.deleteRegistration');
1169 logonCore.deleteRegistration(onFlowError, onFlowError);
1170 }
1171
1172 var onCreatePasscodeSubmit = function(context){
1173 utils.logJSON(context, 'logonCore.persistRegistration');
1174 if (_providedPasscodePolicyContext){
1175 context["policyContext"] = _providedPasscodePolicyContext;
1176 }
1177 logonCore.persistRegistration(onCoreResult, onCreatePasscodeError, context);
1178 }
1179
1180
1181 var onUnlockError = function(error) {
1182 utils.logJSON("onUnlockError: " + JSON.stringify(error));
1183
1184 if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode && error
1185 // Too many attempts --> DV deleted
1186 logonView.showNotification("ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE")
1187 }
1188 else if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode &&
1189 // passcode expired --> DV deleted
1190 logonView.showNotification("ERR_PASSCODE_EXPIRED")
1191 }
1192 else {
1193 logonView.showNotification("ERR_UNLOCK_FAILED");
1194 }
1195 }
1196
1197 var onUnlockVaultWithDefaultPasscode = function(){
1198 utils.log('logonCore.unlockSecureStore - default passcode');
1199 var unlockContext = {"unlockPasscode":null};
1200 logonCore.unlockSecureStore(onCoreResult, onFlowError, unlockContext)
1201 }
1202
1203 var onCreateSecureStoreSubmit = function(context){
1204 utils.logJSON(context, 'logonCore.onCreateSecureStoreSubmit');
1205 if (_providedPasscodePolicyContext){
1206 context["policyContext"] = _providedPasscodePolicyContext;
1207 }
1208 logonCore.createSecureStore(onCoreResult, onCreatePasscodeError, context);
1209
1210 }
1211
1212 var onCreateSecureStoreWithDefaultPasscodeSubmit = function(context){
1213 utils.logJSON(context, 'logonCore.onCreateSecureStoreWithDefaultPasscodeSubmit');
1214 if (_providedPasscodePolicyContext){
1215 context["policyContext"] = _providedPasscodePolicyContext;
1216 }
1217 context.passcode = null;
1218 logonCore.createSecureStore(onCoreResult, onCreatePasscodeError, context);
1219
1220 }
1221
1222 var onCancelRegistrationError = function(error){
1223 utils.logJSON("onCancelRegistrationError: " + JSON.stringify(error));
1224 logonView.showNotification(getRegistrationCancelError(error));
1225 }
1226
1227 var onCreatePasscodeError = function(error) {
1228 utils.logJSON("onCreatePasscodeError: " + JSON.stringify(error));
1229 logonView.showNotification(getSecureStoreErrorText(error));
1230 }
1231
1232 var onFullRegistered = function()
1233 {
1234 var getContextSuccessCallback = function(result){

PUBLIC Page 72 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1235
1236 onFlowSuccess(result);
1237 }
1238 utils.log('logonCore.getContext');
1239 logonCore.getState(getContextSuccessCallback, onFlowError);
1240 }
1241
1242 var callPersistWithDefaultPasscode = function(context){
1243 utils.logJSON(context, 'logonCore.persistRegistration');
1244 context.passcode = null;
1245 logonCore.persistRegistration(
1246 onCoreResult,
1247 onFlowError,
1248 context)
1249 }
1250
1251 // exported properties
1252 this.stateTransitions = [
1253 {
1254 id:"r0",
1255 condition: {
1256
1257 state: {
1258 hasSecureStore: true,
1259 secureStoreOpen: false,
1260 defaultPasscodeUsed: true
1261 }
1262 },
1263 action: onUnlockVaultWithDefaultPasscode
1264 },
1265 {
1266 id:"r1",
1267 condition: {
1268 state: {
1269 hasSecureStore: true,
1270 secureStoreOpen: false,
1271 }
1272 },
1273 action: 'SCR_UNLOCK'
1274 },
1275
1276 {
1277 id:"r20",
1278 condition: {
1279 state: {
1280 hasSecureStore: true,
1281 secureStoreOpen: false,
1282 defaultPasscodeUsed: true,
1283 // defaultPasscodeAllowed: true,
1284 }
1285 },
1286 action: 'SCR_SET_PASSCODE_OPT_OFF'
1287 },
1288 {
1289 id:"r21",
1290 condition: {
1291 state: {
1292 secureStoreOpen: false,
1293 defaultPasscodeUsed: false,
1294 defaultPasscodeAllowed: true,
1295 }
1296 },
1297 action: 'SCR_SET_PASSCODE_OPT_ON'
1298 },
1299 {
1300 id:"r22",
1301 condition: {
1302 state: {
1303 hasSecureStore: false
1304 // status: 'registered',
1305 // defaultPasscodeAllowed: false,
1306 }
1307 },
1308 action: 'SCR_SET_PASSCODE_MANDATORY'
1309 },
1310
1311 {
1312 id:"r26",

PUBLIC Page 73 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1313 condition: {
1314 state: {
1315 secureStoreOpen: true,
1316 }
1317 },
1318 action: onFullRegistered
1319 },
1320
1321
1322 ];
1323
1324 this.screenEvents = {
1325
1326 'SCR_UNLOCK': {
1327 onsubmit: onUnlockSubmit,
1328 oncancel: noOp,
1329 onerror: onFlowError,
1330 onforgot: onForgotAppPasscode,
1331 onerrorack: noOp
1332 },
1333
1334 'SCR_SET_PASSCODE_OPT_ON': {
1335 onsubmit: onCreateSecureStoreSubmit,
1336 oncancel: noOp,
1337 onerror: onFlowError,
1338 ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
1339 onerrorack: noOp
1340 },
1341 'SCR_SET_PASSCODE_OPT_OFF': {
1342 onsubmit: onCreateSecureStoreWithDefaultPasscodeSubmit,
1343 oncancel: noOp,
1344 onerror: onFlowError,
1345 onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
1346 onerrorack: noOp
1347 },
1348 'SCR_SET_PASSCODE_MANDATORY': {
1349 onsubmit: onCreateSecureStoreSubmit,
1350 oncancel: noOp,
1351 onerror: onFlowError,
1352 onerrorack: noOp
1353 }
1354
1355 };
1356
1357 utils.log('flow constructor return');
1358 }
1359
1360
1361 var ChangePasswordFlow = function ChangePasswordFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowErro
1362 //wrapped into a function to defer evaluation of the references to flow callbacks
1363
1364 this.name = 'changePasswordFlowBuilder';
1365
1366
1367 // internal methods
1368
1369 var callUnlockFlow = function(){
1370 utils.log(this.name + ' triggered unlock');
1371 registerOrUnlock(onCoreResult,onFlowError);
1372 }
1373
1374 var onChangePasswordSubmit = function(context){
1375 utils.logJSON(context, 'logonCore.changePassword');
1376 // this logonCore call does not return with context
1377 logonCore.changePassword(onPasswordChanged, onFlowError, context);
1378 }
1379
1380
1381 var onPasswordChanged = function(){
1382 utils.log('onPasswordChanged');
1383 logonCore.getContext(onFlowSuccess, onFlowError);
1384 }
1385
1386 // exported properties
1387 this.stateTransitions = [
1388 {
1389 id:"cp0",
1390 condition: {

PUBLIC Page 74 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1391 state: {
1392 secureStoreOpen: false,
1393 }
1394 },
1395 action: callUnlockFlow,
1396 },
1397 {
1398 id:"cp1",
1399 condition: {
1400 state: {
1401 secureStoreOpen: true,
1402 }
1403 },
1404 action: 'SCR_CHANGE_PASSWORD'
1405 },
1406
1407 ];
1408
1409 this.screenEvents = {
1410 'SCR_CHANGE_PASSWORD': {
1411 onsubmit: onChangePasswordSubmit,
1412 oncancel: onFlowCancel,
1413 onerror: onFlowError
1414 }
1415 };
1416
1417
1418 utils.log('flow constructor return');
1419 }
1420
1421 var ManagePasscodeFlow = function ManagePasscodeFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowErro
1422 //wrapped into a function to defer evaluation of the references to flow callbacks
1423
1424 this.name = 'managePasscodeFlowBuilder';
1425
1426 // internal methods
1427 var showScreen = function(screenId) {
1428 return function(coreContext) {
1429 logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
1430 }.bind(this);
1431 }.bind(this);
1432
1433
1434 var callChangePasscode = function(context){
1435 utils.logJSON(context, 'logonCore.changePasscode');
1436 logonCore.changePasscode(
1437 onCoreResult,
1438 onChangePasscodeError,
1439 context)
1440 }
1441
1442 var onChangePasscodeError = function(error) {
1443 utils.logJSON("onChangePasscodeError: " + JSON.stringify(error));
1444 logonView.showNotification(getSecureStoreErrorText(error));
1445 }
1446
1447 var noOp = function() { }
1448
1449 var callDisablePasscode = function(context){
1450 utils.logJSON(context, 'logonCore.disablePasscode');
1451 context.passcode = null;
1452 logonCore.changePasscode(
1453 onCoreResult,
1454 onFlowError,
1455 context)
1456 }
1457
1458 var callGetContext = function(){
1459 utils.log('logonCore.getContext');
1460 logonCore.getContext(onCoreResult, onFlowError);
1461 }
1462
1463 var onPasscodeEnable = function(context){
1464 utils.logJSON(context, this.name + ' onPasscodeEnable: ');
1465 //logonCore.changePasscode(onFlowSuccess, onFlowError, context);
1466 onFlowError();
1467 }
1468

PUBLIC Page 75 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1469 // exported properties
1470 this.stateTransitions = [
1471 {
1472 id:"mp0",
1473 condition: {
1474 state: {
1475 secureStoreOpen: true,
1476 },
1477 context: null
1478 },
1479 action: callGetContext
1480 },
1481 {
1482 id:"mp1",
1483 condition: {
1484 state: {
1485 secureStoreOpen: false,
1486 }
1487 },
1488 action: onFlowError
1489 },
1490 {
1491 id:"mp2",
1492 condition: {
1493 state: {
1494 secureStoreOpen: true,
1495 defaultPasscodeUsed: true,
1496 // defaultPasscodeAllowed: true,
1497 }
1498 },
1499 action: 'SCR_MANAGE_PASSCODE_OPT_OFF'
1500 },
1501 {
1502 id:"mp3",
1503 condition: {
1504 state: {
1505 secureStoreOpen: true,
1506 defaultPasscodeUsed: false,
1507 defaultPasscodeAllowed: true,
1508 }
1509 },
1510 action: 'SCR_MANAGE_PASSCODE_OPT_ON'
1511 },
1512 {
1513 id:"mp4",
1514 condition: {
1515 state: {
1516 secureStoreOpen: true,
1517 //defaultPasscodeUsed: [DONTCARE],
1518 defaultPasscodeAllowed: false,
1519 }
1520 },
1521 action: 'SCR_MANAGE_PASSCODE_MANDATORY'
1522 },
1523
1524
1525 ];
1526
1527 this.screenEvents = {
1528 'SCR_MANAGE_PASSCODE_OPT_ON': {
1529 onsubmit: onFlowSuccess,
1530 oncancel: onFlowCancel,
1531 onerror: onFlowError,
1532 ondisable: showScreen('SCR_CHANGE_PASSCODE_OPT_OFF'),
1533 onchange: showScreen('SCR_CHANGE_PASSCODE_OPT_ON')
1534 },
1535 'SCR_MANAGE_PASSCODE_OPT_OFF': {
1536 onsubmit: onFlowSuccess,
1537 oncancel: onFlowCancel,
1538 onerror: onFlowError,
1539 onenable: showScreen('SCR_SET_PASSCODE_OPT_ON')
1540 },
1541 'SCR_MANAGE_PASSCODE_MANDATORY': {
1542 onsubmit: onFlowSuccess,
1543 oncancel: onFlowCancel,
1544 onerror: onFlowError,
1545 onchange: showScreen('SCR_CHANGE_PASSCODE_MANDATORY')
1546 },

PUBLIC Page 76 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1547
1548
1549 'SCR_SET_PASSCODE_OPT_ON': {
1550 onsubmit: callChangePasscode,
1551 oncancel: onFlowCancel,
1552 onerror: onFlowError,
1553 ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
1554 onerrorack: noOp
1555 },
1556 'SCR_SET_PASSCODE_OPT_OFF': {
1557 onsubmit: callDisablePasscode,
1558 oncancel: onFlowCancel,
1559 onerror: onFlowError,
1560 onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
1561 onerrorack: noOp
1562 },
1563 'SCR_CHANGE_PASSCODE_OPT_ON': {
1564 onsubmit: callChangePasscode,
1565 oncancel: onFlowCancel,
1566 onerror: onFlowError,
1567 ondisable: showScreen('SCR_CHANGE_PASSCODE_OPT_OFF'),
1568 onerrorack: noOp
1569 },
1570 'SCR_CHANGE_PASSCODE_OPT_OFF': {
1571 onsubmit: callDisablePasscode,
1572 oncancel: onFlowCancel,
1573 onerror: onFlowError,
1574 onenable: showScreen('SCR_CHANGE_PASSCODE_OPT_ON'),
1575 onerrorack: noOp
1576 },
1577 'SCR_CHANGE_PASSCODE_MANDATORY': {
1578 onsubmit: callChangePasscode,
1579 oncancel: onFlowCancel,
1580 onerror: onFlowError,
1581 onerrorack: noOp
1582 },
1583
1584 };
1585
1586
1587 utils.log('flow constructor return');
1588 }
1589
1590 var ShowRegistrationFlow = function ShowRegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlow
1591 //wrapped into a function to defer evaluation of the references to flow callbacks
1592
1593 this.name = 'showRegistrationFlowBuilder';
1594
1595 var showRegistrationInfo = function(context) {
1596 logonView.showScreen('SCR_SHOW_REGISTRATION', this.screenEvents['SCR_SHOW_REGISTRATION'], context);
1597 }.bind(this);
1598
1599 var callGetContext = function(){
1600 utils.log('logonCore.getContext');
1601 logonCore.getContext(onCoreResult, onFlowError);
1602 }
1603
1604 // exported properties
1605 this.stateTransitions = [
1606 {
1607 id:"sr0",
1608 condition: {
1609 state: {
1610 secureStoreOpen: true,
1611
1612 },
1613 context: null
1614 },
1615 action: callGetContext
1616 },
1617 {
1618 id:"sr1",
1619 condition: {
1620 secureStoreOpen: true,
1621 },
1622 action: showRegistrationInfo
1623 }
1624

PUBLIC Page 77 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1625 ];
1626
1627 this.screenEvents = {
1628 'SCR_SHOW_REGISTRATION': {
1629 oncancel: onFlowSuccess,
1630 onerror: onFlowError
1631 }
1632 };
1633
1634
1635 utils.log('flow constructor return');
1636 }
1637
1638 // === flow launcher methods =====================================
1639
1640
1641 var resume = function (onsuccess, onerror) {
1642
1643 if(!_oLogonCore) {
1644 utils.log('FlowRunner.run MAFLogon is not initialized');
1645 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1646 return;
1647 }
1648
1649 var onUnlockSuccess = function(){
1650 _oLogonCore.onEvent(onsuccess, onerror, 'RESUME');
1651 }
1652
1653 var onGetStateSuccess = function(state) {
1654 //call registration flow only if the status is fullregistered in case of resume, so logon screen will not loose i
1655 if (state.status == 'fullRegistered') {
1656 registerOrUnlock(onUnlockSuccess, onerror);
1657 }
1658 }
1659
1660 getState(onGetStateSuccess, onerror);
1661 }
1662
1663
1664 var get = function (onsuccess, onerror, key) {
1665
1666 if(!_oLogonCore) {
1667 utils.log('FlowRunner.run MAFLogon is not initialized');
1668 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1669 return;
1670 }
1671
1672 var onUnlockSuccess = function(){
1673 _oLogonCore.getSecureStoreObject(onsuccess, onerror, key);
1674 }
1675
1676 registerOrUnlock(onUnlockSuccess, onerror);
1677 }
1678
1679
1680
1681 var set = function (onsuccess, onerror, key, value) {
1682
1683 if(!_oLogonCore) {
1684 utils.log('FlowRunner.run MAFLogon is not initialized');
1685 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1686 return;
1687 }
1688
1689 var onUnlockSuccess = function(){
1690 _oLogonCore.setSecureStoreObject(onsuccess, onerror, key, value);
1691 }
1692
1693 registerOrUnlock(onUnlockSuccess, onerror);
1694 }
1695
1696
1697
1698 var lock = function (onsuccess, onerror) {
1699 if(!_oLogonCore) {
1700 utils.log('FlowRunner.run MAFLogon is not initialized');
1701 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1702 return;

PUBLIC Page 78 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1703 }
1704
1705 _oLogonCore.lockSecureStore(onsuccess, onerror);
1706 }
1707
1708 var getState = function (onsuccess, onerror) {
1709 if(!_oLogonCore) {
1710 utils.log('FlowRunner.run MAFLogon is not initialized');
1711 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1712 return;
1713 }
1714
1715 _oLogonCore.getState(onsuccess, onerror);
1716 }
1717
1718 var wrapCallbackWithQueueNext = function(callback) {
1719 return function() {
1720 callback.apply(this, arguments);
1721 if (flowqueue) {
1722 flowqueue.runNextFlow();
1723 }
1724 }
1725 }
1726
1727 var registerOrUnlock = function(onsuccess, onerror) {
1728 if(!_oLogonCore) {
1729 utils.log('FlowRunner.run MAFLogon is not initialized');
1730 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1731 return;
1732 }
1733
1734 var callbacks = {
1735 "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1736 "onerror" : wrapCallbackWithQueueNext(onerror)
1737 }
1738
1739 var flow;
1740 if (_bIsWebRegistration){
1741 flow = WebRegistrationFlow;
1742 }
1743 else{
1744 flow = RegistrationFlow;
1745 }
1746 var flowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, flow);
1747
1748 if (flowqueue) {
1749 flowqueue.add(flowRunner);
1750 }
1751 else {
1752 flowRunner.run();
1753 }
1754 }
1755
1756 var changePassword = function(onsuccess, onerror) {
1757 if(!_oLogonCore) {
1758 utils.log('FlowRunner.run MAFLogon is not initialized');
1759 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1760 return;
1761 }
1762
1763 if (_bIsWebRegistration){
1764 utils.log('ChangePassword is not supported for passcode manager only initialization');
1765 onerror(errorWithDomainCodeDescription("MAFLogon","6","ChangePassword is not supported for PasscodeManager on
1766 return;
1767 }
1768
1769 var onUnlockSuccess = function(){
1770 var callbacks = {
1771 "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1772 "onerror" : wrapCallbackWithQueueNext(onerror)
1773 }
1774 var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ChangePasswordFlow);
1775
1776 if (flowqueue) {
1777 flowqueue.add(innerFlowRunner);
1778 }
1779 else {
1780 innerFlowRunner.run();

PUBLIC Page 79 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1781 }
1782 }
1783
1784 registerOrUnlock(onUnlockSuccess, onerror);
1785 }
1786
1787 var deletePasscodeManager = function(onsuccess, onerror) {
1788 if(!_oLogonCore) {
1789 utils.log('deletePasscodeManager MAFLogon is not initialized');
1790 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1791 return;
1792 }
1793
1794 var onUnlockSuccess = function(){
1795 _oLogonCore.deleteRegistration(onsuccess, onerror);
1796 }
1797
1798 registerOrUnlock(onUnlockSuccess, onerror);
1799 }
1800
1801
1802
1803 var managePasscode = function(onsuccess, onerror) {
1804 if(!_oLogonCore) {
1805 utils.log('FlowRunner.run MAFLogon is not initialized');
1806 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1807 return;
1808 }
1809
1810 var onUnlockSuccess = function(){
1811 var callbacks = {
1812 "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1813 "onerror" : wrapCallbackWithQueueNext(onerror)
1814 }
1815 var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ManagePasscodeFlow);
1816
1817 if (flowqueue) {
1818 flowqueue.add(innerFlowRunner);
1819 }
1820 else {
1821 innerFlowRunner.run();
1822 }
1823 }
1824
1825 registerOrUnlock(onUnlockSuccess, onerror);
1826 }
1827
1828 var showRegistrationData = function(onsuccess, onerror) {
1829 if(!_oLogonCore) {
1830 utils.log('FlowRunner.run MAFLogon is not initialized');
1831 onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
1832 return;
1833 }
1834
1835 if (_bIsWebRegistration){
1836 utils.log('ShowRegistrationData is not supported for passcode manager only initialization');
1837 onerror(errorWithDomainCodeDescription("MAFLogon","6","ShowRegistrationData is not supported for PasscodeMana
1838 return;
1839 }
1840
1841 var onUnlockSuccess = function(){
1842 var callbacks = {
1843 "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
1844 "onerror" : wrapCallbackWithQueueNext(onerror)
1845 }
1846 var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ShowRegistrationFlow);
1847
1848 if (flowqueue) {
1849 flowqueue.add(innerFlowRunner);
1850 }
1851 else {
1852 innerFlowRunner.run();
1853 }
1854 }
1855
1856 registerOrUnlock(onUnlockSuccess, onerror);
1857 }
1858

PUBLIC Page 80 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1859 var getSecureStoreErrorText = function(error) {
1860 utils.logJSON('LogonController.getSecureStoreErrorText: ' + JSON.stringify(error));
1861
1862 var errorText;
1863
1864 if(error.errorCode === '14' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1865 errorText = "ERR_PASSCODE_TOO_SHORT";
1866 else if(error.errorCode === '10' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1867 errorText = "ERR_PASSCODE_REQUIRES_DIGIT";
1868 else if(error.errorCode === '13' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1869 errorText = "ERR_PASSCODE_REQUIRES_UPPER";
1870 else if(error.errorCode === '11' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1871 errorText = "ERR_PASSCODE_REQUIRES_LOWER";
1872 else if(error.errorCode === '12' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1873 errorText = "ERR_PASSCODE_REQUIRES_SPECIAL";
1874 else if(error.errorCode === '15' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
1875 errorText = "ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS";
1876 else {
1877 errorText = "ERR_SETPASSCODE_FAILED";
1878 }
1879
1880 return errorText;
1881 }
1882
1883 var getSSOPasscodeSetErrorText = function(error) {
1884 utils.logJSON('LogonController.getSSOPasscodeSetErrorText: ' + JSON.stringify(error));
1885
1886 var errorText;
1887
1888 if (error.errorDomain === 'MAFLogonCoreErrorDomain') {
1889 if (error.errorCode === '16') {
1890 errorText = "ERR_SSO_PASSCODE_SET_ERROR";
1891 }
1892 }
1893
1894 return errorText;
1895 }
1896
1897 var getRegistrationErrorText = function(error) {
1898 utils.logJSON('LogonController.getRegistrationErrorText: ' + JSON.stringify(error));
1899
1900 var errorText;
1901
1902 if (error.errorDomain === 'MAFLogonCoreErrorDomain') {
1903 if (error.errorCode === '80003') {
1904 errorText = "ERR_REG_FAILED_WRONG_SERVER";
1905 }
1906 //in case of wrong application id
1907 else if (error.errorCode === '404') {
1908 errorText = "ERR_REG_FAILED";
1909 }
1910 else if (error.errorCode === '401') {
1911 errorText = "ERR_REG_FAILED_UNATHORIZED";
1912 }
1913 else if (error.errorCode === '22') {
1914 errorText = "ERR_REG_FAILED_WHITELIST_ERROR";
1915 }
1916 else {
1917 errorText = "ERR_REG_FAILED";
1918 }
1919 }
1920
1921 return errorText;
1922 }
1923
1924 var getRegistrationCancelError = function(error) {
1925 utils.logJSON('LogonController.getRegistrationCancelError: ' + JSON.stringify(error));
1926
1927 var errorText;
1928
1929 errorText = "ERR_REGISTRATION_CANCEL";
1930
1931 return errorText;
1932 }
1933
1934 var errorWithDomainCodeDescription = function(domain, code, description) {
1935 var error = {
1936 errorDomain: domain,

PUBLIC Page 81 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1937 errorCode: code,
1938 errorMessage: description
1939 };
1940
1941 return error;
1942 }
1943
1944 function normalizeResourcePath(context){
1945 //normalize resource path to absolute path (starting with '/')
1946 if (context && context.resourcePath )
1947 {
1948 context.resourcePath = context.resourcePath.trim();
1949 if (context.resourcePath.length > 0){
1950 context.resourcePath = context.resourcePath.replace("\\","/");
1951 if (context.resourcePath.charAt(0) !== '/') {
1952 context.resourcePath = "/" + context.resourcePath;
1953 }
1954
1955 //remove trailing '/' or '\'
1956 if (context.resourcePath.charAt(context.resourcePath.length-1) === '/'){
1957 context.resourcePath = context.resourcePath.substr(0, context.resourcePath.length-1);
1958 }
1959 }
1960 }
1961 }
1962
1963 //return null for succeess, otherwise, return the invalid key
1964 function verifyPasscodePolicy(policy) {
1965 for (var key in policy) {
1966 if (policy.hasOwnProperty(key)) {
1967 if (passcodePolicyAttributeNames.indexOf(key) == -1) {
1968 return key;
1969 }
1970 }
1971 }
1972 return null;
1973 }
1974
1975
1976 // =================== exported (public) members ====================
1977
1978 /**
1979 * The Logon plugin provides screen flows to register an app with an SAP Mobile Platform server.<br/>
1980 * <br/>
1981 * The logon plugin is a component of the SAP Mobile Application Framework (MAF), exposed as a Cordova plugin. The basic
1982 * idea is that it provides screen flows where the user can enter the values needed to connect to an SAP Mobile Platform
1983 * stores those values in its own secure data vault. This data vault is separate from the one provided with the
1984 * encrypted storage plugin. In an OData based SAP Mobile Platform 3.0 application, a client must onboard or register wit
1985 * server to receive an application connection ID for a particular app. The application connection ID must be sent
1986 * along with each request that is proxied through the SAP Mobile Platform 3.0 server to the OData producer.<br/>
1987 * <br/>
1988 * <b>Adding and Removing the Logon Plugin</b><br/>
1989 * The Logon plugin is added and removed using the
1990 * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a
1991 * <br/>
1992 * To add the Logon plugin to your project, use the following command:<br/>
1993 * cordova plugin add <full path to directory containing Kapsel plugins>\logon<br/>
1994 * <br/>
1995 * To remove the Logon plugin from your project, use the following command:<br/>
1996 * cordova plugin rm com.sap.mp.cordova.plugins.logon
1997 *
1998 * @namespace
1999 * @alias Logon
2000 * @memberof sap
2001 */
2002 module.exports = {
2003
2004 /**
2005 * Initialization method to set up the Logon plugin. This will register the application with the SMP server and also aut
2006 * with servers on the network. This step must be done first prior to any attempt to communicate with the SMP server.<br
2007 * <br/>
2008 * This function and {@link sap.Logon.initPasscodeManager} are mutually exclusive. Do not call both.
2009 *
2010 * @method
2011 * @param {sap.Logon~successCallback} successCallback The function that is invoked if initialization is successful. The
2012 * context is passed to this function as the parameter.
2013 * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
2014 * @param {string} applicationId The unique ID of the application. Must match the application ID on the SAP Mobile Platf

PUBLIC Page 82 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
2015 * @param {object} [context] The context with default values for application registration. See {@link sap.Logon~successC
2016 * of the context object. Note that all properties of the context object are optional, and you only need to specify the
2017 * for which you want to provide default values for. The values will be presented to the application users during the re
2018 * a chance to override these values during runtime.
2019 * @param {string} [logonView="com/sap/mp/logon/iabui"] The cordova module ID of a custom renderer for the logon,
2020 * implementing the [showScreen(), close()] interface. Please use the defaul module unless you are absolutely sure that
2021 * custom implementation. Please refer to JavaScript files inside your Kapsel project's plugins\logon\www\common\modules
2022 * @example
2023 * // a custom UI can be loaded here
2024 * var logonView = sap.logon.IabUi;
2025 *
2026 * // The app ID
2027 * var applicationId = "someAppID";
2028 *
2029 * // You only need to specify the fields for which you want to set the default. These values are optional because they
2030 * // used to prefill the fields on Logon's UI screen.
2031 * var defaultContext = {
2032 * "serverHost" : "defaultServerHost.com"
2033 * "https" : false,
2034 * "serverPort" : "8080",
2035 * "user" : "user1",
2036 * "password" : "Zzzzzz123",
2037 * "communicatorId" : "REST",
2038 * "securityConfig" : "sec1",
2039 * "passcode" : "Aaaaaa123",
2040 * "unlockPasscode" : "Aaaaaa123"
2041 * };
2042 *
2043 * var app_context;
2044 *
2045 * var successCallback = function(context){
2046 * app_context = context;
2047 * }
2048 *
2049 * var errorCallback = function(errorInfo){
2050 * alert("error: " + JSON.stringify(errorInfo));
2051 * }
2052 * sap.Logon.init(successCallback, errorCallback, applicationId, defaultContext, logonView);
2053 */
2054 init: init,
2055 /**
2056 * Initialization method to set up the Logon plugin as a passcode and datavault manager only.
2057 * When this method is called, the Logon plugin will not do anything with regards to registering
2058 * with any server.<br/>
2059 * <br/>
2060 * This function and {@link sap.Logon.init} are mutually exclusive. Do not call both.
2061 *
2062 * @method
2063 * @param {sap.Logon~successCallback} successCallback The function that is invoked if initialization is successful. The
2064 * state is passed to this function as the parameter.
2065 * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
2066 * @param {string} applicationId The unique ID of the application. This value will be used as the datavault store ID.
2067 * @param {string} [logonView="com/sap/mp/logon/iabui"] The cordova module ID of a custom renderer for the logon,
2068 * implementing the [showScreen(), close()] interface. Please use the default module unless you are absolutely sure that
2069 * custom implementation. Please refer to JavaScript files inside your Kapsel project's plugins\logon\www\common\modules
2070 * @example
2071 * // a custom UI can be loaded here
2072 * var logonView = sap.logon.IabUi;
2073 *
2074 * // The app ID
2075 * var applicationId = "someAppID";
2076 *
2077 * var successCallback = function(state){
2078 * alert("successfully initialzed, resulting state: " + JSON.stringify(state));
2079 * }
2080 *
2081 * var errorCallback = function(errorInfo){
2082 * alert("error: " + JSON.stringify(errorInfo));
2083 * }
2084 * sap.Logon.initPasscodeManager(successCallback, errorCallback, applicationId, logonView);
2085 */
2086 initPasscodeManager: initPasscodeManager,
2087 /**
2088 * Function to delete the datavault and all data stored therein.
2089 * This function is intended to be used when Logon has been initialized as a passcode manager via {@link sap.Logon.initPa
2090 * However, if it has been initialized for server registration (via {@link sap.Logon.init}), calling this function will
2091 * delete the registration and all data.
2092 *

PUBLIC Page 83 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
2093 * @method
2094 * @param {sap.Logon~successCallbackNoParameters} successCallback The function that is invoked if the deletion is success
2095 * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
2096 * @example
2097 * var successCallback = function(){
2098 * alert("successfully deleted all data");
2099 * }
2100 *
2101 * var errorCallback = function(errorInfo){
2102 * alert("error: " + JSON.stringify(errorInfo));
2103 * }
2104 * sap.Logon.deletePasscodeManager(successCallback, errorCallback);
2105 */
2106 deletePasscodeManager: deletePasscodeManager,
2107
2108 /**
2109 * The application ID with which {@link sap.Logon.init} was called. It is available here so it is easy to access l
2110 * @example
2111 * // After calling the init function
2112 * alert("The app ID for this app is: " + sap.Logon.applicationId);
2113 */
2114 applicationId: null,
2115 /**
2116 * Direct reference to the logon core object used by the Logon plugin. This is needed to perform more complex operations
2117 * are not generally needed by applications. <br/>
2118 * There are several functions that can be accessed on the core object:<br/>
2119 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getState(successCallback,errorCallback) returns the state object of t
2120 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getContext(successCallback,errorCallback) returns the context object
2121 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deleteRegistration(successCallback,errorCallback) deletes the applica
2122 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; application data on d
2123 * @example
2124 * var successCallback = function(result){
2125 * alert("Result: " + JSON.stringify(result));
2126 * }
2127 * var errorCallback = function(errorInfo){
2128 * alert("Error: " + JSON.stringify(errorInfo));
2129 * }
2130 * sap.Logon.core.getState(successCallback,errorCallback);
2131 * sap.Logon.core.getContext(successCallback,errorCallback);
2132 * sap.Logon.core.deleteRegistration(successCallback,errorCallback);
2133 */
2134 core: _oLogonCore, //Must be updated after init
2135
2136 /**
2137 * Get an (JSON serializable) object from the DataVault for a given key.
2138 * @method
2139 * @param {sap.Logon~getSuccessCallback} onsuccess The function that is invoked
2140 * upon success. It is called with the resulting object as a single parameter.
2141 * This can be null or undefined, if no object is defined for the given key.
2142 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
2143 * @param {string} key The key with which to query the DataVault.
2144 * @example
2145 * var errorCallback = function(errorInfo){
2146 * alert("Error: " + JSON.stringify(errorInfo));
2147 * }
2148 * var getSuccess = function(value){
2149 * alert("value retrieved from the store: " + JSON.stringify(value));
2150 * }
2151 * var setSuccess = function(){
2152 * sap.Logon.get(getSuccess,errorCallback,'someKey');
2153 * }
2154 * sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');
2155 */
2156 get: get,
2157
2158 /**
2159 * Set an (JSON serializable) object in the DataVault.
2160 * @method
2161 * @param {sap.Logon~successCallbackNoParameters} onsuccess The function to invoke upon success.
2162 * onsuccess will be called without parameters for this method.
2163 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
2164 * @param {string} key The key to store the provided object on.
2165 * @param {object} value The object to be set on the given key. Must be JSON serializable (ie:
2166 * cannot contain circular references).
2167 * @example
2168 * var errorCallback = function(errorInfo){
2169 * alert("Error: " + JSON.stringify(errorInfo));
2170 * }

PUBLIC Page 84 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
2171 * var getSuccess = function(value){
2172 * alert("value retrieved from the store: " + JSON.stringify(value));
2173 * }
2174 * var setSuccess = function(){
2175 * sap.Logon.get(getSuccess,errorCallback,'someKey');
2176 * }
2177 * sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');
2178 */
2179 set: set,
2180
2181 /**
2182 * Locks the Logon plugin's secure data vault.
2183 * @method
2184 * @param {sap.Logon~successCallbackNoParameters} onsuccess The function to invoke upon success.
2185 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
2186 * @example
2187 * var errorCallback = function(errorInfo){
2188 * alert("Error: " + JSON.stringify(errorInfo));
2189 * }
2190 * var successCallback = function(){
2191 * alert("Locked!");
2192 * }
2193 * sap.Logon.lock(successCallback,errorCallback);
2194 */
2195 lock: lock,
2196
2197 /**
2198 * Unlock the Logon plugin's secure data vault if it has been locked (due to being inactive, or
2199 * {@link sap.Logon.lock} being called), then the user is prompted for the passcode to unlock the
2200 * application.<br/>
2201 * If the application is already unlocked, then nothing will be done.<br/>
2202 * If the application has passcode disabled, then passcode prompt will not be necessary.
2203 * In all cases if an error does not occur, the success callback is invoked with the current logon context
2204 * as the parameter.
2205 * @method
2206 * @param {sap.Logon~successCallback} onsuccess - The callback to call if the screen flow succeeds.
2207 * onsuccess will be called with the current logon context as a single parameter.
2208 * @param {sap.Logon~errorCallback} onerror - The callback to call if the screen flow fails.
2209 * @example
2210 * var errorCallback = function(errorInfo){
2211 * alert("Error: " + JSON.stringify(errorInfo));
2212 * }
2213 * var successCallback = function(context){
2214 * alert("Registered and unlocked. Context: " + JSON.stringify(context));
2215 * }
2216 * sap.Logon.unlock(successCallback,errorCallback);
2217 */
2218 unlock: registerOrUnlock,
2219 /**
2220 * This method will launch the UI screen for application users to manage and update the data vault passcode or,
2221 * if the SMP server's Client Passcode Policy allows it, enable or disable the passcode to the data vault.
2222 *
2223 * @method
2224 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The function to invoke upon success.
2225 * @param {sap.Logon~errorCallback} onerror - The function to invoke in case of error.
2226 * @example
2227 * var errorCallback = function(errorInfo){
2228 * alert("Error: " + JSON.stringify(errorInfo));
2229 * }
2230 * var successCallback = function(context){
2231 * alert("Passcode successfully managed.");
2232 * }
2233 * sap.Logon.managePasscode(successCallback,errorCallback);
2234 */
2235 managePasscode: managePasscode,
2236
2237 /**
2238 * This method will launch the UI screen for application users to manage and update the back-end passcode that Logon stor
2239 * data vault that is used to authenticate the client to the server.
2240 *
2241 * @method
2242 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
2243 * onsuccess will be called without parameters for this method.
2244 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
2245 * @example
2246 * var errorCallback = function(errorInfo){
2247 * alert("Error: " + JSON.stringify(errorInfo));
2248 * }

PUBLIC Page 85 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
2249 * var successCallback = function(context){
2250 * alert("Password successfully changed.");
2251 * }
2252 * sap.Logon.changePassword(successCallback,errorCallback);
2253 */
2254 changePassword: changePassword,
2255
2256 /**
2257 * Calling this method will show a screen which displays the current registration settings for the application.
2258 * @method
2259 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
2260 * onsuccess will be called without parameters for this method.
2261 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
2262 * @example
2263 * var errorCallback = function(errorInfo){
2264 * alert("Error: " + JSON.stringify(errorInfo));
2265 * }
2266 * var successCallback = function(context){
2267 * alert("The showRegistrationData screenflow was successful.");
2268 * }
2269 * sap.Logon.showRegistrationData(successCallback,errorCallback);
2270 */
2271 showRegistrationData: showRegistrationData,
2272
2273 /**
2274 * Calling this method will show a screen which displays the third party certificate provider settings screen for the app
2275 * @method
2276 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
2277 * onsuccess will be called without parameters for this method.
2278 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
2279 * @example
2280 * var errorCallback = function(errorInfo){
2281 * alert("Error: " + JSON.stringify(errorInfo));
2282 * }
2283 * var successCallback = function(context){
2284 * alert("The showRegistrationData screenflow was successful.");
2285 * }
2286 * sap.Logon.showCertificateProviderScreen(successCallback,errorCallback);
2287 */
2288 showCertificateProviderScreen:showCertificateProviderScreen,
2289
2290
2291 /**
2292 * Calling this method to delete the stored certificate and get a new one
2293 * @method
2294 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
2295 * onsuccess will be called without parameters for this method.
2296 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
2297 * @example
2298 * var errorCallback = function(errorInfo){
2299 * alert("Error: " + JSON.stringify(errorInfo));
2300 * }
2301 * var successCallback = function(){
2302 * alert("The certificate is refreshed.");
2303 * }
2304 * sap.Logon.refreshCertificate(successCallback,errorCallback);
2305 */
2306 refreshCertificate: refreshCertificate
2307
2308 };
2309
2310 /**
2311 * Callback function that is invoked in case of an error.
2312 *
2313 * @callback sap.Logon~errorCallback
2314 *
2315 * @param {Object} errorObject Depending on the origin of the error the object can take several forms.
2316 * (Unfortunately the error object structure and content is not uniform among the platforms, this will
2317 * probably change in the future.)
2318 *
2319 * Errors originating from the logon plugin have only an 'errorKey' property.
2320 * The possible values for 'errorKey':
2321 *
2322 * ERR_CHANGE_TIMEOUT_FAILED
2323 * ERR_FORGOT_SSO_PIN
2324 * ERR_INIT_FAILED
2325 * ERR_INVALID_ACTION
2326 * ERR_INVALID_STATE

PUBLIC Page 86 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
2327 * ERR_PASSCODE_REQUIRES_DIGIT
2328 * ERR_PASSCODE_REQUIRES_LOWER
2329 * ERR_PASSCODE_REQUIRES_SPECIAL
2330 * ERR_PASSCODE_REQUIRES_UPPER
2331 * ERR_PASSCODE_TOO_SHORT
2332 * ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS
2333 * ERR_REGISTRATION_CANCEL
2334 * ERR_REG_FAILED
2335 * ERR_REG_FAILED_UNATHORIZED
2336 * ERR_REG_FAILED_WRONG_SERVER
2337 * ERR_SETPASSCODE_FAILED
2338 * ERR_SET_AFARIA_CREDENTIAL_FAILED
2339 * ERR_SSO_PASSCODE_SET_ERROR
2340 * ERR_UNKNOWN_SCREEN_ID
2341 * ERR_UNLOCK_FAILED
2342 * ERR_USER_CANCELLED
2343 * ERR_PASSCODE_EXPIRED
2344 *
2345 * Errors originating in the logon core (either iOS or Android) have the following properties: 'errorCode',
2346 * 'errorMessage', and 'errorDomain'.
2347 * The 'errorCode' is just a number uniquely identifying the error. The 'errorMessage'
2348 * property is a string with more detailed information of what went wrong. The 'errorDomain' property specifies
2349 * the domain that the error occurred in.
2350 *
2351 * On iOS the 'errorDomain' property of the core errors can take the following values: MAFLogonCoreErrorDomain, MAFSecureS
2352 *
2353 * In the MAFLogonCoreErrorDomain the following errors are thrown (throwing methods in paren):
2354 *
2355 * 3 errMAFLogonErrorCommunicationManagerError (register, update settings, delete, change backend password)
2356 * 9 errMAFLogonErrorCouldNotDecideCommunicator (register)
2357 * 11 errMAFLogonErrorOperationNotAllowed (all)
2358 * 12 errMAFLogonErrorInvalidServerHost (register)
2359 * 13 errMAFLogonErrorInvalidBackendPassword (changeBackendPassword)
2360 * 15 errMAFLogonErrorUploadTraceFailed (uploadTrace)
2361 * 16 errMAFLogonErrorInvalidMCIMSSOPin (setMCIMSSOPin)
2362 * 18 errMAFLogonErrorCertificateKeyError (register)
2363 * 19 errMAFLogonErrorCertificateError (register)
2364 * 20 errMAFLogonErrorAfariaInvalidCredentials (setAfariaCredentialWithUser)
2365 *
2366 * In the MAFSecureStoreManagerErrorDomain the following errors are thrown (throwing methods in paren):
2367 *
2368 * 0 errMAFSecureStoreManagerErrorUnknown (persist, unlock, changePasscode, delete, getContext)
2369 * 1 errMAFSecureStoreManagerErrorAlreadyExists (persist)
2370 * 2 errMAFSecureStoreManagerErrorDataTypeError (unlock, getContext)
2371 * 3 errMAFSecureStoreManagerErrorDoesNotExist (unlock, persist, getContext)
2372 * 4 errMAFSecureStoreManagerErrorInvalidArg unlock, (persist, getContext)
2373 * 5 errMAFSecureStoreManagerErrorInvalidPassword (unlock)
2374 * 6 errMAFSecureStoreManagerErrorLocked (getContext)
2375 * 7 errMAFSecureStoreManagerErrorOutOfMemory (persist, unlock, changePasscode, delete, getContext)
2376 * 8 errMAFSecureStoreManagerErrorPasswordExpired (unlock, getContext)
2377 * 9 errMAFSecureStoreManagerErrorPasswordRequired (persist, changePasscode)
2378 * 10 errMAFSecureStoreManagerErrorPasswordRequiresDigit (persist, changePasscode)
2379 * 11 errMAFSecureStoreManagerErrorPasswordRequiresLower (persist, changePasscode)
2380 * 12 errMAFSecureStoreManagerErrorPasswordRequiresSpecial (persist, changePasscode)
2381 * 13 errMAFSecureStoreManagerErrorPasswordRequiresUpper (persist, changePasscode)
2382 * 14 errMAFSecureStoreManagerErrorPasswordUnderMinLength (persist, changePasscode)
2383 * 15 errMAFSecureStoreManagerErrorPasswordUnderMinUniqueChars (persist, changePasscode)
2384 * 16 errMAFSecureStoreManagerErrorDeleted (unlock)
2385 *
2386 * In the MAFLogonCoreCDVPluginErrorDomain the following errors are thrown:
2387 *
2388 * 1 (init failed)
2389 * 2 (plugin not initialized)
2390 * 3 (no input provided)
2391 *
2392 * On Android the 'errorDomain' property of the core errors can take the following values: MAFLogonCoreErrorDomain and MAF
2393 * There are no logon specific error codes, the 'errorCode' property only wraps the error values from the underlying libra
2394 */
2395
2396 /**
2397 * Callback function that is invoked upon successfully registering or unlocking or retrieving the context.
2398 *
2399 * @callback sap.Logon~successCallback
2400 *
2401 * @param {Object} context An object containing the current logon context. Two properties of particular importance
2402 * are applicationEndpointURL, and applicationConnectionId.
2403 * The context object contains the following properties:<br/>
2404 * "registrationContext": {<br/>

PUBLIC Page 87 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
2405 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"serverHost": Host of the server.<br/>
2406 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"domain": Domain for server. Can be used in case of SAP Mobile Platform
2407 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"resourcePath": Resource path on the server. The path is used mainly fo
2408 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"https": Marks whether the server should be accessed in a secure way.<b
2409 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"serverPort": Port of the server.<br/>
2410 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"user": Username in the backend.<br/>
2411 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"password": Password for the backend user.<br/>
2412 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"farmId": FarmId of the server. Can be nil. Used in case of Relay serve
2413 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"communicatorId": Id of the communicator manager that will be used for
2414 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"securityConfig": Security configuration. If nil, the default configura
2415 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"mobileUser": Mobile User. Used in case of IMO manual user creation.<br
2416 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"activationCode": Activation Code. Used in case of IMO manual user crea
2417 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"gatewayClient": The key string that identifies the client on the gatew
2418 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"gatewayPingPath": The custom path of the ping URL on the gateway. Used
2419 * }<br/>
2420 * "applicationEndpointURL": Contains the application endpoint URL after a successful registration.<br/>
2421 * "applicationConnectionId": ID to get after a successful SUP REST registration. Needs to be set in the download request
2422 * "afariaRegistration": manual / automatic / certificate<br/>
2423 * "policyContext": Contains the password policy for the secure store {<br/>
2424 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"alwaysOn":<br/>
2425 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"alwaysOff":<br/>
2426 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaultOn":<br/>
2427 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasDigits":<br/>
2428 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasLowerCaseLetters":<br/>
2429 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasSpecialLetters":<br/>
2430 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasUpperCaseLetters":<br/>
2431 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaultAllowed":<br/>
2432 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"expirationDays":<br/>
2433 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"lockTimeout":<br/>
2434 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"minLength":<br/>
2435 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"minUniqueChars":<br/>
2436 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"retryLimit":<br/>
2437 * }<br/>
2438 * "registrationReadOnly": specifies whether context values are coming from clientHub / afaria<br/>
2439 * "policyReadOnly": specifies whether passcode policy is coming from afaria<br/>
2440 * "credentialsByClientHub": specifies whether credentials are coming from clientHub
2441 */
2442
2443 /**
2444 * Callback function that will be invoked with no parameters.
2445 *
2446 * @callback sap.Logon~successCallbackNoParameters
2447 */
2448
2449 /**
2450 * Callback function that is invoked upon successfully retrieving an object from the DataVault.
2451 *
2452 * @callback sap.Logon~getSuccessCallback
2453 *
2454 * @param {Object} value The object that was stored with the given key. Can be null or undefined if no object was stored
2455 * with the given key.
2456 */
2457
2458

Parent topic: Source code

1.9.2 Using the AuthProxy Plugin


The AuthProxy plugin automates the process of accepting SSL certificates returned by a call to a Web resource.

In this section:
AuthProxy Plugin Overview
Adding the AuthProxy Plugin
Adding Cookies to a Request
Using the AuthProxy Plugin to Register With SAP Mobile Platform Server
Kapsel AuthProxy API Reference
Parent topic: Kapsel Plugins

1.9.2.1 AuthProxy Plugin Overview


The AuthProxy plugin provides the ability to make HTTPS requests with mutual authentication.
The AuthProxy plugin allows you to specify a certificate to include in an HTTPS request that identifies the client to the server, which allows the server to verify the
identity of the client. An example of where you might need mutual authenticaion is in the onboarding process, when you register with an application, or, to access
an OData producer. You can make HTTPS requests with no authentication, with basic authentication, or by using certificates. Supported certificate sources
include file, system key manager, and Afaria.

Sending Requests
PUBLIC Page 88 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Sending Requests
There are two functions for sending requests:
get = function (url, header, successCB, errorCB, user, password, timeout, certSource). This is a convenience function and provides no additional
functionality compared to the sendRequest function. It just calls the sendRequest function with the method set to GET and no requestBody .
sendRequest = function (method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource).

Constructor Functions
There are three constructor functions to make objects that you can use for certificates:
CertificateFromFile = function (Path, Password, CertificateKey)
CertificateFromLogonManager = function( AppID )
CertificateFromStore = function (CertificateKey)

Note
The success callback is called upon any response from the server, so be sure to check the status on the response.

Domain Whitelisting
Kapsel plugins support Apache Cordova's domain whitelisting model. Whitelisting allows you to control access to external network resources. Apache Cordova
whitelisting allows you to whitelist individual network resources (URLs), for example, http://www.google.com.
For information about the whitelist rules, see http://docs.phonegap.com/en/3.3.0/guide_appdev_whitelist_index.md.html .
Parent topic: Using the AuthProxy Plugin

Related Information
Kapsel AuthProxy API Reference

1.9.2.2 Adding the AuthProxy Plugin


Use the Cordova command line interface to install the AuthProxy plugin.

Prerequisites
Set up the development environment.
Create your Cordova Project.
Add your OS platforms.
On Android these permissions are required:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
On iOS:
The plugin depends on afariaSLL.a
Requires the link flag of "-lstdc++," if not yet included.

Procedure
1. Add the AuthProxy plugin by entering the following at the command prompt, or terminal:
On Windows:
cordova -d plugin add <SDK_HOME>\MobileSDK3\KapselSDK\plugins\authproxy
On Mac:
cordova -d plugin add ~<SDK_HOME>/MobileSDK3/KapselSDK/plugins/authproxy

Note
The path you enter to the Kapsel plugin must be the absolute path (not relative path).

2. (Optional) To see a list of installed plugins in your Cordova project, open a command prompt or terminal window, navigate to your Cordova project folder, and
enter: cordova plugins The Cordova command line interface returns a JSON array showing installed plugins, for example:
[ 'org.apache.cordova.core.camera',
'org.apache.cordova.core.device-motion',
'org.apache.cordova.core.file' ]
In this example, the Cordova project has the Cordova core Camera, Accelerator (device-motion), and File plugins installed.
3. Modify the files in the www folder for the project as necessary, then copy them to the platform directories by running:
cordova -d prepare android
cordova -d prepare ios
4. Use the Android IDE or Xcode to deploy and run the project.
5. (Optional) For iOS, if the application uses Afaria mutual certificate authentication, or if multiple applications on the devices need to share the credentials,
you must first build and deploy Client Hub to the device, and then add the "clienthubEntitlements" and "$(CFBundleIdentifier)" items to the shared keychain
groups in the application's project settings in Xcode.
In this section:
Adding User Permissions to the Android Manifest File

PUBLIC Page 89 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Parent topic: Using the AuthProxy Plugin

Related Information
Client Hub
Provisioning Applications Using Afaria
Managing Application Registration Using Client Hub
Using the Logon Plugin
Managing iOS Application Registration Using Client Hub
Managing Android Application Registration Using Client Hub
Adding the AppUpdate Plugin
Adding the Logon Plugin
Adding the Logger Plugin
Adding the Push Notification Plugin
Adding the EncryptedStorage Plugin
Adding the Settings Plugin
Setting Up the Development Environment
Creating an Apache Cordova Project

1.9.2.2.1 Adding User Permissions to the Android Manifest File


Add user permissions to the Android project.

Procedure
1. In the Android IDE, open the AndroidManifest.xml file.
2. Add user permissions in the AndroidManifest.xml file, for example:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="smp.tutorial.android"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">
<application>

<activity>
<intent-filter>
<action />
<category />
<data />
</intent-filter>
<meta-data />
</activity>
</application>
</manifest>
3. Select File Save .
Parent topic: Adding the AuthProxy Plugin

1.9.2.3 Adding Cookies to a Request


To add cookies to a request for authentication, use the header object that is passed to the get/sendRequest functions.
Only the cookie name and value should be set this way. The other pieces of the cookie (domain, path, and so on) are set automatically based on the URL the
request is made against. The cookie is treated as a session cookie and sent on future requests as appropriate. The API examples below show an example of
how to set a cookie with the header object.
var successCallback = function( result ){
if( result.status === 200 ) {
alert("success\!
Response text: " + result.responseText );
} else {
alert("Not success, response status:
" + result.status);
}
}

var failureCallback = function( error ) {


alert("Error! Code: " + error.errorCode + "\n" + error.description + "\nNative error code: " + error.nativeErrorCode );
}

// setting a cookie with a request


var header = {cookie: "customCookieName=customCookieValue;anotherName=AnotherValue"};

PUBLIC Page 90 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
sap.AuthProxy.sendRequest("POST", "http://www.example.com/stuff/etc", header, null, successCallback, failureCallback);

Parent topic: Using the AuthProxy Plugin

1.9.2.4 Using the AuthProxy Plugin to Register With SAP Mobile


Platform Server
This example procedure demonstrates how to use the AuthProxy plugin to register with the SAP Mobile Platform Server using a client certificate.

Context
This example does not use the Logon plugin to perform the registration. You can test certificates on an Android device or emulator, or an iOS device. The server
certificate must be installed on the device's system store, so for iOS, the actual device is required.

Procedure
1. Use the keytool utility to create the server and client certificates. The SAP Mobile Platform Server stores its certificates in a file named
smp_keystore.jks.
2. Download the certificate and generate a certificate signing request (CSR).
3. Import the signed certificate into the keystore.
4. Copy the client's public key to smp_keystore.jks so that the server can authenticate the client.
5. Create a security profile in Management Cockpit
6. Import the public and private key of the client certificate to the mobile device using the PKCS12 format. Both the client certificate (stored in the keystore
client.p12 containing the public and private keys) and the certificate authority's certificate, must be added to the mobile device. You should add the
certificate authority's certificate to the device's trust store. The client certificate in this example for Android is placed in a location the application can access
it from.
adb push SAPServerCA.cer /mnt/sdcard/
adb push client.p12 /mnt/sdcard/
adb shell
cd /mnt/sdcard
ls
exit
For an iOS device, both certificates can be installed into the device's trusted store by sending them through an e-mail, opening the device browser to a
Web page that contains the links to the certificates, or by using the iPhone Configuration Utility. See http://support.apple.com/kb/DL1465 . On the iOS
device, the certificates can be viewed and uninstalled under Settings General Profiles . In addition to accessing the certificate from the file
system and the device's secure store, the client certificate can be provisioned to the device using Afaria and then accessed from Afaria using the Logon
plugin using the method sap.AuthProxy.CertificateFromLogonManager("clientKey") .
7. Create a new Cordova project to perform mutual authentication to the SAP Mobile Platform Server.
8. Add the AuthProxy plugin.
9. Create a new security provider and add an x.509 User Certificate authentication provider.
10. Copy the files to the platform directory by running the prepare command.
11. Use the Android IDE or Xcode to deploy and run the project.
In this section:
Generating Certificates and Keys
Parent topic: Using the AuthProxy Plugin

1.9.2.4.1 Generating Certificates and Keys


Use a PKI system and a trusted CA to generate production-ready certificates and keys that encrypt communication among different SAP Mobile Platform
components. You can then use the keytool utility to import and export certificate to the keystore.

Context

Note
Any changes to the keystore require the server to be restarted.

Parent topic: Using the AuthProxy Plugin to Register With SAP Mobile Platform Server

1.9.2.5 Kapsel AuthProxy API Reference


The Kapsel AuthProxy API Reference provides usage information for AuthProxy API classes and methods, as well as provides sample source code.
In this section:
AuthProxy namespace
Source code
Parent topic: Using the AuthProxy Plugin

Related Information
AuthProxy Plugin Overview

1.9.2.5.1 AuthProxy namespace


PUBLIC Page 91 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.2.5.1 AuthProxy namespace
The AuthProxy plugin provides the ability to make HTTPS requests with mutual authentication.
The regular XMLHttpRequest does not support mutual authentication. The AuthProxy plugin allows you to specify a certificate to include in an HTTPS request to
identify the client to the server. This allows the server to verify the identity of the client. An example of where you might need mutual authenticaion is the
onboarding process to register with an application, or, to access an OData producer. This occurs mostly in Business to Business (B2B) applications. This is
different from most business to consumer (B2C) web sites where it is only the server that authenticates itself to the client with a certificate.
Adding and Removing the AuthProxy Plugin
The AuthProxy plugin is added and removed using the Cordova CLI .
To add the AuthProxy plugin to your project, use the following command:
cordova plugin add <path to directory containing Kapsel plugins>\authproxy
To remove the AuthProxy plugin from your project, use the following command:
cordova plugin rm com.sap.mp.cordova.plugins.authproxy

Classes
Name Description

sap.AuthProxy.CertificateFromFile Create certificate source description object for a certificate from a keystore file.

sap.AuthProxy.CertificateFromLogonManager Create a certificate source description object for certificates from logon manager.

sap.AuthProxy.CertificateFromStore Create a certificate source description object for certificates from the system keystore.

Members
Name Description

ERR_CERTIFICATE_ALIAS_NOT_FOUND Constant indicating the certificate with the given alias could not be found.

ERR_CERTIFICATE_FILE_NOT_EXIST Constant indicating the certificate file could not be found.

ERR_CERTIFICATE_INVALID_FILE_FORMAT Constant indicating incorrect certificate file format.

ERR_CLIENT_CERTIFICATE_VALIDATION Constant indicating the provided certificate failed validation on the server side.

ERR_DOMAIN_WHITELIST_REJECTION Constant indicating cordova domain whitelist rejection error while sending request to
server.

ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED Constant indicating the certificate from file is not supported on the current platform.

ERR_GET_CERTIFICATE_FAILED Constant indicating failure in getting the certificate.

ERR_HTTP_TIMEOUT Constant indicating timeout error while connecting to the server.

ERR_INVALID_PARAMETER_VALUE Constant indicating the operation failed due to an invalid parameter (for example, a string
was passed where a number was required).

ERR_LOGON_MANAGER_CERTIFICATE_METHOD_NOT_AVAILABLE Constant indicating the logon manager certifciate method is not available.

ERR_LOGON_MANAGER_CORE_NOT_AVAILABLE Constant indicating the logon manager core library is not available.

ERR_MISSING_PARAMETER Constant indicating the operation failed because of a missing parameter.

ERR_NO_SUCH_ACTION Constant indicating there is no such Cordova action for the current service.

ERR_SERVER_CERTIFICATE_VALIDATION Constant indicating the server certificate failed validation on the client side.

ERR_SERVER_REQUEST_FAILED Constant indicating the server request failed.

ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED Constant indicating the certificate from the system keystore is not supported on the
current platform.

ERR_UNKNOWN Constant indicating the operation failed with unknown error.

Methods
Name Description

deleteCertificateFromStore( successCB, [errorCB], certificateKey ) Delete a cached certificate from the keychain.

generateODataHttpClient() Generates an OData client that uses the AuthProxy plugin to make requests.

get( url, header, successCB, errorCB, [user], [password], [timeout], [certSource] ) Send an HTTP(S) GET request to a remote server.

sendRequest( method, url, header, requestBody, successCB, errorCB, [user], Send an HTTP(S) request to a remote server.
[password], [timeout], [certSource] )

Type Definitions
Name Description

deleteCertificateSuccessCallback Callback function that is invoked upon successfully deleting a certificate from the store.

errorCallback( errorObject ) Callback function that is invoked in case of an error.

successCallback( serverResponse ) Callback function that is invoked upon a response from the server.

PUBLIC Page 92 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Source
authproxy.js, line 27.
In this section:
sap.AuthProxy.CertificateFromFile class
sap.AuthProxy.CertificateFromLogonManager class
sap.AuthProxy.CertificateFromStore class
ERR_CERTIFICATE_ALIAS_NOT_FOUND member
ERR_CERTIFICATE_FILE_NOT_EXIST member
ERR_CERTIFICATE_INVALID_FILE_FORMAT member
ERR_CLIENT_CERTIFICATE_VALIDATION member
ERR_DOMAIN_WHITELIST_REJECTION member
ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED member
ERR_GET_CERTIFICATE_FAILED member
ERR_HTTP_TIMEOUT member
ERR_INVALID_PARAMETER_VALUE member
ERR_LOGON_MANAGER_CERTIFICATE_METHOD_NOT_AVAILABLE member
ERR_LOGON_MANAGER_CORE_NOT_AVAILABLE member
ERR_MISSING_PARAMETER member
ERR_NO_SUCH_ACTION member
ERR_SERVER_CERTIFICATE_VALIDATION member
ERR_SERVER_REQUEST_FAILED member
ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED member
ERR_UNKNOWN member
deleteCertificateFromStore( successCB, [errorCB], certificateKey ) method
generateODataHttpClient() method
get( url, header, successCB, errorCB, [user], [password], [timeout], [certSource] ) method
sendRequest( method, url, header, requestBody, successCB, errorCB, [user], [password], [timeout], [certSource] ) method
deleteCertificateSuccessCallback type
errorCallback( errorObject ) type
successCallback( serverResponse ) type
Parent topic: Kapsel AuthProxy API Reference

1.9.2.5.1.1 sap.AuthProxy.CertificateFromFile class


Create certificate source description object for a certificate from a keystore file.
The keystore file must be of type PKCS12 (usually a .p12 extention) since that is the only certificate file type that can contain a private key (a private key is
needed to authenticate the client to the server). You might want to use this method if you know the desired certificate resides in a file on the filesystem.

Syntax
new CertificateFromFile ( Path, Password, CertificateKey )

Parameters
Name Type Description

<Path> string The Path of the keystore file.


For iOS clients, it first tries to load the relative file path
from the application's Documents folder. If it fails, it then
tries to load the file path from application's main bundle. In
addition, before trying to load the certificate from the file
system, the iOS client first checks whether the specified
certificate key already exists in the key store. If it does, it
loads the existing certificate from key store, instead of
loading the certificate from file system.
For Android clients, the filepath is first treated as an
absolute path. If the certificate is not found, then the
filepath is treated as relative to the root of the sdcard.

<Password> string The password of the keystore.

<CertificateKey> string A unique key (aka: alias) that is used to locate the
certificate.

Example
// Create the certificate source description object.
var fileCert = new sap.AuthProxy.CertificateFromFile("directory/certificateName.p12", "certificatePassword", "certificateKey");
// callbacks
var successCB = function(serverResponse){
alert("Status: " + JSON.stringify(serverResponse.status));
alert("Headers: " + JSON.stringify(serverResponse.headers));
alert("Response: " + JSON.stringify(serverResponse.response));
}
var errorCB = function(errorObject){

PUBLIC Page 93 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
alert("Error making request: " + JSON.stringify(errorObject));
}
// Make the request with the certificate source description object.
sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, fileCert);

Source
authproxy.js, line 225.
Parent topic: AuthProxy namespace

1.9.2.5.1.2 sap.AuthProxy.CertificateFromLogonManager class


Create a certificate source description object for certificates from logon manager.
Using the resulting certificate source description object on subsequent calls to AuthProxy.sendRequest or AuthProxy.get will cause AuthProxy to retrieve a
certificate from Logon Manager to use for client authentication. The appID parameter is used to indicate which application's certificate to use.
Note that to use a certificate from Logon Manager, the application must have already registered with the server using a certificate from Afaria.

Syntax
new CertificateFromLogonManager ( appID )

Parameters
Name Type Description

<appID> string application identifier

Example
// Create the certificate source description object.
var logonCert = new sap.AuthProxy.CertificateFromLogonManager("applicationID");
// callbacks
var successCB = function(serverResponse){
alert("Status: " + JSON.stringify(serverResponse.status));
alert("Headers: " + JSON.stringify(serverResponse.headers));
alert("Response: " + JSON.stringify(serverResponse.response));
}
var errorCB = function(errorObject){
alert("Error making request: " + JSON.stringify(errorObject));
}
// Make the request with the certificate source description object.
sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, logonCert);

Source
authproxy.js, line 282.
Parent topic: AuthProxy namespace

1.9.2.5.1.3 sap.AuthProxy.CertificateFromStore class


Create a certificate source description object for certificates from the system keystore.
You might want to use a certificate from the system keystore if you know the user's device will have the desired certificate installed on it.
On Android, sending a request with a certificate from the system store results in UI being shown for the user to pick the certificate to use (the certificate with the
alias matching the given CertificateKey is pre-selected).

Syntax
new CertificateFromStore ( CertificateKey )

Parameters
Name Type Description

<CertificateKey> string A unique key (aka: alias) that is used to locate the
certificate.

Example
// Create the certificate source description object.
var systemCert = new sap.AuthProxy.CertificateFromStore("certificatekey");

PUBLIC Page 94 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
// callbacks
var successCB = function(serverResponse){
alert("Status: " + JSON.stringify(serverResponse.status));
alert("Headers: " + JSON.stringify(serverResponse.headers));
alert("Response: " + JSON.stringify(serverResponse.response));
}
var errorCB = function(errorObject){
alert("Error making request: " + JSON.stringify(errorObject));
}
// Make the request with the certificate source description object.
sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, systemCert);

Source
authproxy.js, line 254.
Parent topic: AuthProxy namespace

1.9.2.5.1.4 ERR_CERTIFICATE_ALIAS_NOT_FOUND member


Constant indicating the certificate with the given alias could not be found.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_CERTIFICATE_ALIAS_NOT_FOUND : number

Source
authproxy.js, line 90.
Parent topic: AuthProxy namespace

1.9.2.5.1.5 ERR_CERTIFICATE_FILE_NOT_EXIST member


Constant indicating the certificate file could not be found.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_CERTIFICATE_FILE_NOT_EXIST : number

Source
authproxy.js, line 98.
Parent topic: AuthProxy namespace

1.9.2.5.1.6 ERR_CERTIFICATE_INVALID_FILE_FORMAT
member
Constant indicating incorrect certificate file format.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_CERTIFICATE_INVALID_FILE_FORMAT : number

Source
authproxy.js, line 106.
Parent topic: AuthProxy namespace

1.9.2.5.1.7 ERR_CLIENT_CERTIFICATE_VALIDATION member


Constant indicating the provided certificate failed validation on the server side.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_CLIENT_CERTIFICATE_VALIDATION : number

PUBLIC Page 95 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Source
authproxy.js, line 122.
Parent topic: AuthProxy namespace

1.9.2.5.1.8 ERR_DOMAIN_WHITELIST_REJECTION member


Constant indicating cordova domain whitelist rejection error while sending request to server.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_DOMAIN_WHITELIST_REJECTION : number

Source
authproxy.js, line 172.
Parent topic: AuthProxy namespace

1.9.2.5.1.9 ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTE
D member
Constant indicating the certificate from file is not supported on the current platform.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED : number

Source
authproxy.js, line 74.
Parent topic: AuthProxy namespace

1.9.2.5.1.10 ERR_GET_CERTIFICATE_FAILED member


Constant indicating failure in getting the certificate.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_GET_CERTIFICATE_FAILED : number

Source
authproxy.js, line 114.
Parent topic: AuthProxy namespace

1.9.2.5.1.11 ERR_HTTP_TIMEOUT member


Constant indicating timeout error while connecting to the server.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_HTTP_TIMEOUT : number

Source
authproxy.js, line 164.
Parent topic: AuthProxy namespace

1.9.2.5.1.12 ERR_INVALID_PARAMETER_VALUE member


Constant indicating the operation failed due to an invalid parameter (for example, a string was passed where a number was required).
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

PUBLIC Page 96 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Syntax
<constant> ERR_INVALID_PARAMETER_VALUE : number

Source
authproxy.js, line 48.
Parent topic: AuthProxy namespace

1.9.2.5.1.13 ERR_LOGON_MANAGER_CERTIFICATE_METHO
D_NOT_AVAILABLE member
Constant indicating the logon manager certifciate method is not available.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_LOGON_MANAGER_CERTIFICATE_METHOD_NOT_AVAILABLE : number

Source
authproxy.js, line 156.
Parent topic: AuthProxy namespace

1.9.2.5.1.14 ERR_LOGON_MANAGER_CORE_NOT_AVAILABL
E member
Constant indicating the logon manager core library is not available.
Getting this error code means you tried to use Logon plugin features (for example, a certificate from Logon) without adding the Logon plugin to the app. A possible
value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_LOGON_MANAGER_CORE_NOT_AVAILABLE : number

Source
authproxy.js, line 148.
Parent topic: AuthProxy namespace

1.9.2.5.1.15 ERR_MISSING_PARAMETER member


Constant indicating the operation failed because of a missing parameter.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_MISSING_PARAMETER : number

Source
authproxy.js, line 56.
Parent topic: AuthProxy namespace

1.9.2.5.1.16 ERR_NO_SUCH_ACTION member


Constant indicating there is no such Cordova action for the current service.
When a Cordova plugin calls into native code it specifies an action to perform. If the action provided by the JavaScript is unknown to the native code this error
occurs. This error should not occur as long as authproxy.js is unmodified. Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_NO_SUCH_ACTION : number

Source

PUBLIC Page 97 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
authproxy.js, line 66.
Parent topic: AuthProxy namespace

1.9.2.5.1.17 ERR_SERVER_CERTIFICATE_VALIDATION
member
Constant indicating the server certificate failed validation on the client side.
This is likely because the server certificate is self-signed, or not signed by a well-known certificate authority. This constant is used as a possible value for the
errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_SERVER_CERTIFICATE_VALIDATION : number

Source
authproxy.js, line 131.
Parent topic: AuthProxy namespace

1.9.2.5.1.18 ERR_SERVER_REQUEST_FAILED member


Constant indicating the server request failed.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_SERVER_REQUEST_FAILED : number

Source
authproxy.js, line 139.
Parent topic: AuthProxy namespace

1.9.2.5.1.19 ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPP
ORTED member
Constant indicating the certificate from the system keystore is not supported on the current platform.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED : number

Source
authproxy.js, line 82.
Parent topic: AuthProxy namespace

1.9.2.5.1.20 ERR_UNKNOWN member


Constant indicating the operation failed with unknown error.
Used as a possible value for the errorCode in sap.AuthProxy~ errorCallback.

Syntax
<constant> ERR_UNKNOWN : number

Source
authproxy.js, line 40.
Parent topic: AuthProxy namespace

1.9.2.5.1.21 deleteCertificateFromStore( successCB, [errorCB],


certificateKey ) method
Delete a cached certificate from the keychain.

PUBLIC Page 98 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
iOS clients always checks the cached certificate first to see if it is available before loading the certificate from the file system. If the cached certificate is no longer
valid, use this method to delete it from the keychain.
Only supported on iOS platform, NOT Android.

Syntax
deleteCertificateFromStore ( successCB, [errorCB], certificateKey )

Parameters
Name Type Argument Description

<successCB> sap.AuthProxy~deleteCertificateSuccessCa Callback method upon success.


llback

<errorCB> sap.AuthProxy~errorCallback (optional) Callback method upon failure.

<certificateKey> string The key of the certificate to be deleted.

Example
var successCB = function(){
alert("certificate successfully deleted.");
}
var errorCB = function(error){
alert("error deleting certificate: " + JSON.stringify(error));
}
sap.AuthProxy.deleteCertificateFromStore(successCB, errorCB, "certificateKeyToDelete");

Source
authproxy.js, line 643.
Parent topic: AuthProxy namespace

1.9.2.5.1.22 generateODataHttpClient() method


Generates an OData client that uses the AuthProxy plugin to make requests.
This is useful if you are using Datajs, but want to make use of the certificate features of AuthProxy. Datajs is a javascript library useful for accessing OData
services. Datajs has a concept of an HttpClient, which does the work of making the request. This function generates an HttpClient that you can specify to Datajs
so you can provide client certificates for requests. If you want to use the generated HTTP client for all future Datajs requests, you can do that by setting the
OData.defaultHttpClient property to the return value of this function. Once that is done, then doing OData stuff with Datajs is almost exactly the same, but you can
add a certificateSource to a request.

Syntax
generateODataHttpClient ()

Example
OData.defaultHttpClient = sap.AuthProxy.generateODataHttpClient();

// Using a certificate from file, for example.


fileCert = new sap.AuthProxy.CertificateFromFile("mnt/sdcard/cert.p12", "password", "certKey");

// This is the same request object you would have created if you were just using Datajs, but now
// you can add the extra 'certificateSource' property.
var createRequest = {
requestUri: "http://www.example.com/stuff/etc/example.svc",
certificateSource : fileCert,
user : "username",
password : "password",
method : "POST",
data:
{
Description: "Created Record",
CategoryName: "Created Category"
}
}

// Use Datajs to send the request.


OData.request( createRequest, successCallback, failureCallback );

Source

PUBLIC Page 99 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
authproxy.js, line 740.
Parent topic: AuthProxy namespace

1.9.2.5.1.23 get( url, header, successCB, errorCB, [user],


[password], [timeout], [certSource] ) method
Send an HTTP(S) GET request to a remote server.
This is a convenience function that simply calls sap.AuthProxy#sendRequest with "GET" as the method and null for the request body. All given parameters are
passed as-is to sap.AuthProxy.sendRequest. The success callback is invoked upon any response from the server. Even responses not generally considered to
be successful (such as 404 or 500 status codes) will result in the success callback being invoked. The error callback is reserved for problems that prevent the
AuthProxy from creating the request or contacting the server. It is, therefore, important to always check the status property on the object given to the success
callback.

Syntax
get ( url, header, successCB, errorCB, [user], [password], [timeout], [certSource] ) → {function}

Parameters
Name Type Argument Description

<url> string The URL against which to make the


request.

<header> Object HTTP header to send to the server.This is


an Object. Can be null.

<successCB> sap.AuthProxy~successCallback Callback method invoked upon a response


from the server.

<errorCB> sap.AuthProxy~errorCallback Callback method invoked in case of failure.

<user> string (optional) User ID for basic authentication.

<password> string (optional) User password for basic authentication.

<timeout> number (optional) Timeout setting in seconds.Default timeout


is 60 seconds. A value of 0 means there is
no timeout.

<certSource> Object (optional) Certificate description object.It can be one of


sap.AuthProxy#CertificateFromFile,
sap.AuthProxy#CertificateFromStore, or
sap.AuthProxy#CertificateFromLogonMana
ger.

Returns
A JavaScript function object to abort the operation. Calling the abort function results in neither the success or error callback being invoked for the original request
(excepting the case where the success or error callback was invoked before calling the abort functino). Note that the request itself cannot be unsent, and the
server will still receive the request - the JavaScript will just not know the results of that request.
Type:
function

Example
var successCB = function(serverResponse){
alert("Status: " + JSON.stringify(serverResponse.status));
alert("Headers: " + JSON.stringify(serverResponse.headers));
if (serverResponse.responseText){
alert("Response: " + JSON.stringify(serverResponse.responseText));
}
}
var errorCB = function(errorObject){
alert("Error making request: " + JSON.stringify(errorObject));
}

// To send a GET request to server, call the method


var abortFunction = sap.AuthProxy.get("http://www.example.com", null, successCB, errorCB);

// An example of aborting the request


abortFunction();

// To send a GET request to the server with headers, call the method
sap.AuthProxy.get("http://www.example.com", {HeaderName : "Header value"}, successCB, errorCB);

// To send a GET request to the server with basic authentication, call the method
sap.AuthProxy.get("https://www.example.com", headers, successCB, errorCB, "username", "password");

PUBLIC Page 100 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
// To send a GET request to the server with mutual authentication, call the method
sap.AuthProxy.get("https://www.example.com", headers, successCB, errorCB, null, null, 0,
new sap.AuthProxy.CertificateFromLogonManager("theAppId"));

Source
authproxy.js, line 623.
Parent topic: AuthProxy namespace

1.9.2.5.1.24 sendRequest( method, url, header, requestBody,


successCB, errorCB, [user], [password], [timeout], [certSource] )
method
Send an HTTP(S) request to a remote server.
This function is the centerpiece of the AuthProxy plugin. It will handle mutual authentication if a certificate source is provided. The success callback is invoked
upon any response from the server. Even responses not generally considered to be successful (such as 404 or 500 status codes) will result in the success
callback being invoked. The error callback is reserved for problems that prevent the AuthProxy from creating the request or contacting the server. It is therefore
important to always check the status property on the object given to the success callback.

Syntax
sendRequest ( method, url, header, requestBody, successCB, errorCB, [user], [password], [timeout], [certSource] ) → {function}

Parameters
Name Type Argument Description

<method> string Standard HTTP request method name.

<url> string The HTTP URL with format


http(s)://[user:password]@hostname[:port]/
path.

<header> Object HTTP header to send to the server.This is


an Object. Can be null.

<requestBody> string Data to send to the server with the


request.Can be null.

<successCB> sap.AuthProxy~successCallback Callback method invoked upon a response


from the server.

<errorCB> sap.AuthProxy~errorCallback Callback method invoked in case of failure.

<user> string (optional) User ID for basic authentication.

<password> string (optional) User password for basic authentication.

<timeout> number (optional) Timeout setting in seconds.Default timeout


is 60 seconds. A value of 0 means there is
no timeout.

<certSource> Object (optional) Certificate description object.It can be one of


sap.AuthProxy#CertificateFromFile,
sap.AuthProxy#CertificateFromStore, or
sap.AuthProxy#CertificateFromLogonMana
ger.

Returns
A JavaScript function object to abort the operation. Calling the abort function results in neither the success or error callback being invoked for the original request
(excepting the case where the success or error callback was invoked before calling the abort function). Note that the request itself cannot be unsent, and the
server will still receive the request - the JavaScript will just not know the results of that request.
Type:
function

Example
// callbacks
var successCB = function(serverResponse){
alert("Status: " + JSON.stringify(serverResponse.status));
alert("Headers: " + JSON.stringify(serverResponse.headers));
alert("Response: " + JSON.stringify(serverResponse.response));
}
var errorCB = function(errorObject){
alert("Error making request: " + JSON.stringify(errorObject));
}

PUBLIC Page 101 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
// To send a post request to the server, call the method
var abortFunction = sap.AuthProxy.sendRequest("POST", "http://www.google.com", null, "THIS IS THE BODY", successCB, errorCB);
// An example of aborting the request
abortFunction();

// To send a post request to the server with headers, call the method
sap.AuthProxy.sendRequest("POST", url, {HeaderName : "Header value"}, "THIS IS THE BODY", successCB, errorCB);

// To send a post request to the server with basic authentication, call the method
sap.AuthProxy.sendRequest("POST", url, headers, "THIS IS THE BODY", successCB, errorCB, "username", "password");

// To send a post request to the server with mutual authentication, call the method
sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null,
null, 0, new sap.AuthProxy.CertificateFromLogonManager("theAppId"));

Source
authproxy.js, line 468.
Parent topic: AuthProxy namespace

1.9.2.5.1.25 deleteCertificateSuccessCallback type


Callback function that is invoked upon successfully deleting a certificate from the store.

Syntax
deleteCertificateSuccessCallback ()

Source
authproxy.js, line 826.
Parent topic: AuthProxy namespace

1.9.2.5.1.26 errorCallback( errorObject ) type


Callback function that is invoked in case of an error.

Syntax
errorCallback ( errorObject )

Parameters
Name Type Description

<errorObject> Object An object containing two properties: 'errorCode' and


'description.' The 'errorCode' property corresponds to one
of the sap.AuthProxy constants.The 'description' property
is a string with more detailed information of what went
wrong.

Example
function errorCallback(errCode) {
//Set the default error message. Used if an invalid code is passed to the
//function (just in case) but also to cover the
//sap.AuthProxy.ERR_UNKNOWN case as well.
var msg = "Unkown Error";
switch (errCode) {
case sap.AuthProxy.ERR_INVALID_PARAMETER_VALUE:
msg = "Invalid parameter passed to method";
break;
case sap.AuthProxy.ERR_MISSING_PARAMETER:
msg = "A required parameter was missing";
break;
case sap.AuthProxy.ERR_HTTP_TIMEOUT:
msg = "The request timed out";
break;
};
//Write the error to the log
console.error(msg);

PUBLIC Page 102 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
//Let the user know what happened
navigator.notification.alert(msg, null, "AuthProxy Error", "OK");
};

Source
authproxy.js, line 822.
Parent topic: AuthProxy namespace

1.9.2.5.1.27 successCallback( serverResponse ) type


Callback function that is invoked upon a response from the server.

Syntax
successCallback ( serverResponse )

Parameters
Name Type Description

<serverResponse> Object An object containing the response from the


server.Contains a 'headers' property, a 'status' property,
and a 'responseText' property.
'headers' is an object containing all the headers in the
response.
'status' is an integer corresponding to the HTTP status
code of the response. It is important to check the status of
the response, since this success callback is invoked
upon any response from the server - including
responses that are not normally thought of as successes
(for example, the status code could be 404 or 500).
'responseText' is a string containing the body of the
response.

Source
authproxy.js, line 824.
Parent topic: AuthProxy namespace

1.9.3.3.2 Source code


In this section:
authproxy.js
Parent topic: Kapsel AuthProxy API Reference

1.9.2.5.2.1 authproxy.js
1 // 3.0.3-SNAPSHOT
2 var exec = require('cordova/exec');
3
4 /**
5 * The AuthProxy plugin provides the ability to make HTTPS requests with mutual authentication.<br/>
6 * <br/>
7 * The regular XMLHttpRequest does not
8 * support mutual authentication. The AuthProxy plugin allows you to specify a certificate to include in an HTTPS request
9 * to identify the client to the server. This allows the server to verify the identity of the client. An example of wher
10 * might need mutual authenticaion is the onboarding process to register with an application, or, to access an
11 * OData producer. This occurs mostly in Business to Business (B2B) applications. This is different from most business to
12 * consumer (B2C) web sites where it is only the server that authenticates itself to the client with a certificate.<br/>
13 * <br/>
14 * <b>Adding and Removing the AuthProxy Plugin</b><br/>
15 * The AuthProxy plugin is added and removed using the
16 * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>
17 * <br/>
18 * To add the AuthProxy plugin to your project, use the following command:<br/>
19 * cordova plugin add <path to directory containing Kapsel plugins>\authproxy<br/>
20 * <br/>
21 * To remove the AuthProxy plugin from your project, use the following command:<br/>
22 * cordova plugin rm com.sap.mp.cordova.plugins.authproxy
23 * @namespace
24 * @alias AuthProxy
25 * @memberof sap
26 */

PUBLIC Page 103 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
27 var AuthProxy = function () {};
28
29
30 /**
31 * Constant definitions for registration methods
32 */
33
34 /**
35 * Constant indicating the operation failed with unknown error. Used as a possible value for the
36 * errorCode in {@link sap.AuthProxy~errorCallback}.
37 * @constant
38 * @type number
39 */
40 AuthProxy.prototype.ERR_UNKNOWN = -1;
41
42 /**
43 * Constant indicating the operation failed due to an invalid parameter (for example, a string was passed where a number w
44 * required). Used as a possible value for the errorCode in {@link sap.AuthProxy~errorCallback}.
45 * @constant
46 * @type number
47 */
48 AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE = -2;
49
50 /**
51 * Constant indicating the operation failed because of a missing parameter. Used as a possible value for the
52 * errorCode in {@link sap.AuthProxy~errorCallback}.
53 * @constant
54 * @type number
55 */
56 AuthProxy.prototype.ERR_MISSING_PARAMETER = -3;
57
58 /**
59 * Constant indicating there is no such Cordova action for the current service. When a Cordova plugin calls into native
60 * code it specifies an action to perform. If the action provided by the JavaScript is unknown to the native code this
61 * error occurs. This error should not occur as long as authproxy.js is unmodified. Used as a possible
62 * value for the errorCode in {@link sap.AuthProxy~errorCallback}.
63 * @constant
64 * @type number
65 */
66 AuthProxy.prototype.ERR_NO_SUCH_ACTION = -100;
67
68 /**
69 * Constant indicating the certificate from file is not supported on the current platform. Used as a possible value for th
70 * errorCode in {@link sap.AuthProxy~errorCallback}.
71 * @constant
72 * @type number
73 */
74 AuthProxy.prototype.ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED = -101;
75
76 /**
77 * Constant indicating the certificate from the system keystore is not supported on the current platform. Used as a possib
78 * for the errorCode in {@link sap.AuthProxy~errorCallback}.
79 * @constant
80 * @type number
81 */
82 AuthProxy.prototype.ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED = -102;
83
84 /**
85 * Constant indicating the certificate with the given alias could not be found. Used as a possible value for the
86 * errorCode in {@link sap.AuthProxy~errorCallback}.
87 * @constant
88 * @type number
89 */
90 AuthProxy.prototype.ERR_CERTIFICATE_ALIAS_NOT_FOUND = -104;
91
92 /**
93 * Constant indicating the certificate file could not be found. Used as a possible value for the
94 * errorCode in {@link sap.AuthProxy~errorCallback}.
95 * @constant
96 * @type number
97 */
98 AuthProxy.prototype.ERR_CERTIFICATE_FILE_NOT_EXIST = -105;
99
100 /**
101 * Constant indicating incorrect certificate file format. Used as a possible value for the
102 * errorCode in {@link sap.AuthProxy~errorCallback}.
103 * @constant
104 * @type number

PUBLIC Page 104 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
105 */
106 AuthProxy.prototype.ERR_CERTIFICATE_INVALID_FILE_FORMAT = -106;
107
108 /**
109 * Constant indicating failure in getting the certificate. Used as a possible value for the
110 * errorCode in {@link sap.AuthProxy~errorCallback}.
111 * @constant
112 * @type number
113 */
114 AuthProxy.prototype.ERR_GET_CERTIFICATE_FAILED = -107;
115
116 /**
117 * Constant indicating the provided certificate failed validation on the server side. Used as a possible value for the
118 * errorCode in {@link sap.AuthProxy~errorCallback}.
119 * @constant
120 * @type number
121 */
122 AuthProxy.prototype.ERR_CLIENT_CERTIFICATE_VALIDATION = -108;
123
124 /**
125 * Constant indicating the server certificate failed validation on the client side. This is likely because the server cer
126 * is self-signed, or not signed by a well-known certificate authority. This constant is used as a possible value for the
127 * errorCode in {@link sap.AuthProxy~errorCallback}.
128 * @constant
129 * @type number
130 */
131 AuthProxy.prototype.ERR_SERVER_CERTIFICATE_VALIDATION = -109;
132
133 /**
134 * Constant indicating the server request failed. Used as a possible value for the
135 * errorCode in {@link sap.AuthProxy~errorCallback}.
136 * @constant
137 * @type number
138 */
139 AuthProxy.prototype.ERR_SERVER_REQUEST_FAILED = -110;
140
141 /**
142 * Constant indicating the logon manager core library is not available. Getting this error code means you tried
143 * to use Logon plugin features (for example, a certificate from Logon) without adding the Logon plugin to the app.
144 * A possible value for the errorCode in {@link sap.AuthProxy~errorCallback}.
145 * @constant
146 * @type number
147 */
148 AuthProxy.prototype.ERR_LOGON_MANAGER_CORE_NOT_AVAILABLE = -111;
149
150 /**
151 * Constant indicating the logon manager certifciate method is not available. Used as a possible value for the
152 * errorCode in {@link sap.AuthProxy~errorCallback}.
153 * @constant
154 * @type number
155 */
156 AuthProxy.prototype.ERR_LOGON_MANAGER_CERTIFICATE_METHOD_NOT_AVAILABLE = -112;
157
158 /**
159 * Constant indicating timeout error while connecting to the server. Used as a possible value for the
160 * errorCode in {@link sap.AuthProxy~errorCallback}.
161 * @constant
162 * @type number
163 */
164 AuthProxy.prototype.ERR_HTTP_TIMEOUT = -120;
165
166 /**
167 * Constant indicating cordova domain whitelist rejection error while sending request to server. Used as a possible value
168 * errorCode in {@link sap.AuthProxy~errorCallback}.
169 * @constant
170 * @type number
171 */
172 AuthProxy.prototype.ERR_DOMAIN_WHITELIST_REJECTION = -121;
173
174 /**
175 * Constant indicating a missing required parameter message. Used as a possible value for the description
176 * in (@link sap.AuthProxy~errorCallback}.
177 * @constant
178 * @type string
179 * @private
180 */
181 AuthProxy.prototype.MSG_MISSING_PARAMETER = "Missing a required parameter: ";
182

PUBLIC Page 105 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
183 /**
184 * Constant indicating invalid parameter value message. Used as a possible value for the description
185 * in (@link sap.AuthProxy~errorCallback}.
186 * @constant
187 * @type string
188 * @private
189 */
190 AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE = "Invalid Parameter Value for parameter: ";
191
192 /**
193 * Create certificate source description object for a certificate from a keystore file. The keystore file must be of type
194 * (usually a .p12 extention) since that is the only certificate file type that can contain a private key (a private key i
195 * to authenticate the client to the server). You might want to use this method if you know the desired certificate resid
196 * file on the filesystem.
197 * @class
198 * @param {string} Path The Path of the keystore file.<br/>For iOS clients, it first tries to load the
199 * relative file path from the application's Documents folder. If it fails, it then tries
200 * to load the file path from application's main bundle. In addition, before trying
201 * to load the certificate from the file system, the iOS client first checks whether the
202 * specified certificate key already exists in the key store. If it does, it loads
203 * the existing certificate from key store, instead of loading the certificate from
204 * file system.<br/>
205 * For Android clients, the filepath is first treated as an absolute path. If the certificate
206 * is not found, then the filepath is treated as relative to the root of the sdcard.
207 * @param {string} Password The password of the keystore.
208 * @param {string} CertificateKey A unique key (aka: alias) that is used to locate the certificate.
209 * @example
210 * // Create the certificate source description object.
211 * var fileCert = new sap.AuthProxy.CertificateFromFile("directory/certificateName.p12", "certificatePassword", "certifica
212 * // callbacks
213 * var successCB = function(serverResponse){
214 * alert("Status: " + JSON.stringify(serverResponse.status));
215 * alert("Headers: " + JSON.stringify(serverResponse.headers));
216 * alert("Response: " + JSON.stringify(serverResponse.response));
217 * }
218 * var errorCB = function(errorObject){
219 * alert("Error making request: " + JSON.stringify(errorObject));
220 * }
221 * // Make the request with the certificate source description object.
222 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, f
223 *
224 */
225 AuthProxy.prototype.CertificateFromFile = function (Path, Password, CertificateKey) {
226 this.Source = "FILE";
227 this.Path = Path;
228 this.Password = Password;
229 this.CertificateKey = CertificateKey;
230 };
231
232 /**
233 * Create a certificate source description object for certificates from the system keystore. You might want to use a cert
234 * from the system keystore if you know the user's device will have the desired certificate installed on it.<br/>
235 * On Android, sending a request with a certificate from the system store results in UI being shown for the user to pick
236 * the certificate to use (the certificate with the alias matching the given CertificateKey is pre-selected).
237 * @class
238 * @param {string} CertificateKey A unique key (aka: alias) that is used to locate the certificate.
239 * @example
240 * // Create the certificate source description object.
241 * var systemCert = new sap.AuthProxy.CertificateFromStore("certificatekey");
242 * // callbacks
243 * var successCB = function(serverResponse){
244 * alert("Status: " + JSON.stringify(serverResponse.status));
245 * alert("Headers: " + JSON.stringify(serverResponse.headers));
246 * alert("Response: " + JSON.stringify(serverResponse.response));
247 * }
248 * var errorCB = function(errorObject){
249 * alert("Error making request: " + JSON.stringify(errorObject));
250 * }
251 * // Make the request with the certificate source description object.
252 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, s
253 */
254 AuthProxy.prototype.CertificateFromStore = function (CertificateKey) {
255 this.Source = "SYSTEM";
256 this.CertificateKey = CertificateKey;
257 };
258
259
260 /**

PUBLIC Page 106 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
261 * Create a certificate source description object for certificates from logon manager. Using the resulting certificate so
262 * object on subsequent calls to AuthProxy.sendRequest or AuthProxy.get will cause AuthProxy to retrieve a certificate fro
263 * to use for client authentication. The appID parameter is used to indicate which application's certificate to use.<br/>
264 * Note that to use a certificate from Logon Manager, the application must have already registered with the server using a
265 * @class
266 * @param {string} appID application identifier
267 * @example
268 * // Create the certificate source description object.
269 * var logonCert = new sap.AuthProxy.CertificateFromLogonManager("applicationID");
270 * // callbacks
271 * var successCB = function(serverResponse){
272 * alert("Status: " + JSON.stringify(serverResponse.status));
273 * alert("Headers: " + JSON.stringify(serverResponse.headers));
274 * alert("Response: " + JSON.stringify(serverResponse.response));
275 * }
276 * var errorCB = function(errorObject){
277 * alert("Error making request: " + JSON.stringify(errorObject));
278 * }
279 * // Make the request with the certificate source description object.
280 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, l
281 */
282 AuthProxy.prototype.CertificateFromLogonManager = function (appID) {
283 this.Source = "LOGON";
284 this.AppID = appID;
285 };
286
287
288 /**
289 * Verifies that a certificate source description object (created with {@link sap.AuthProxy#CertificateFromFile},
290 * {@link sap.AuthProxy#CertificateFromStore}, or {@link sap.AuthProxy#CertificateFromLogonManager}) has all the required
291 * for those fields are the correct type. This function verifies only the certificate description object, not the certifi
292 * if the certificate source description object was created with {@link sap.AuthProxy#CertificateFromFile} and has a Strin
293 * String for the key/alias, <b>this function considers it valid even if no certificate actually exists on the filesystem<
294 * source description object is valid but the certificate itself is not, then an error occurs during the call to {@link sa
295 * {@link sap.AuthProxy#sendRequest}.
296 * @param {object} certSource The certificate source object.
297 * @param {sap.AuthProxy~errorCallback} errorCB The error callback invoked if the certificate source is not valid. Will h
298 * and 'description' properties.
299 * @example
300 * var notValidCert = {};
301 * var errorCallback = function(error){
302 * alert("certificate not valid!\nError code: " + error.errorCode + "\ndescription: " + error.description);
303 * }
304 * var isCertValid = sap.AuthProxy.validateCertSource(notValidCert, errorCallback);
305 * if( isCertValid ){
306 * // do stuff with the valid certificate source description object
307 * } else {
308 * // at this point we know the cert is not valid, and the error callback is invoked with extra information.
309 * }
310 *
311 *
312 * Developers are not expected to call this function.
313 * @private
314 */
315 AuthProxy.prototype.validateCertSource = function (certSource, errorCB) {
316 if (!certSource) {
317 // The certificate is not present, so just ignore it.
318 return true;
319 }
320
321 // errorCB required.
322 // First check this one. We may need it to return errors
323 if (errorCB && (typeof errorCB !== "function")) {
324 console.log("AuthProxy Error: errorCB is not a function");
325 return false;
326 }
327
328 try {
329 // First check whether it is an object
330 if (typeof certSource !== "object") {
331 errorCB({
332 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
333 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certSource"
334 });
335 return false;
336 }
337
338 if (certSource.Source === "FILE") {

PUBLIC Page 107 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
339 if (!certSource.Path) {
340 errorCB({
341 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
342 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "keystore path"
343 });
344 return false;
345 }
346
347 if (typeof certSource.Path !== "string") {
348 errorCB({
349 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
350 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "keystore path"
351 });
352 return false;
353 }
354
355 if (!certSource.CertificateKey) {
356 errorCB({
357 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
358 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "certificate key"
359 });
360 return false;
361 }
362
363 if (typeof certSource.CertificateKey !== "string") {
364 errorCB({
365 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
366 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certificate key"
367 });
368 return false;
369 }
370 } else if (certSource.Source === "SYSTEM") {
371 if (!certSource.CertificateKey) {
372 errorCB({
373 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
374 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "certificate key"
375 });
376 return false;
377 }
378
379 if (typeof certSource.CertificateKey !== "string") {
380 errorCB({
381 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
382 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certificate key"
383 });
384 return false;
385 }
386 } else if (certSource.Source === "LOGON") {
387 if (!certSource.AppID) {
388 errorCB({
389 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
390 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "AppID"
391 });
392 return false;
393 }
394
395 if (typeof certSource.AppID !== "string") {
396 errorCB({
397 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
398 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "AppID"
399 });
400 return false;
401 }
402 } else {
403 errorCB({
404 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
405 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certSource"
406 });
407 return false;
408 }
409
410 return true;
411 } catch (ex) {
412 errorCB({
413 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
414 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certSource"
415 });
416 }

PUBLIC Page 108 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
417 };
418
419
420 /**
421 * Send an HTTP(S) request to a remote server. This function is the centerpiece of the AuthProxy plugin. It will handle
422 * mutual authentication if a certificate source is provided.
423 * The success callback is invoked upon any response from the server. Even responses not generally considered to be
424 * successful (such as 404 or 500 status codes) will result in the success callback being invoked. The error callback
425 * is reserved for problems that prevent the AuthProxy from creating the request or contacting the server. It is therefor
426 * important to always check the status property on the object given to the success callback.
427 * @param {string} method Standard HTTP request method name.
428 * @param {string} url The HTTP URL with format http(s)://[user:password]@hostname[:port]/path.
429 * @param {Object} header HTTP header to send to the server. This is an Object. Can be null.
430 * @param {string} requestBody Data to send to the server with the request. Can be null.
431 * @param {sap.AuthProxy~successCallback} successCB Callback method invoked upon a response from the server.
432 * @param {sap.AuthProxy~errorCallback} errorCB Callback method invoked in case of failure.
433 * @param {string} [user] User ID for basic authentication.
434 * @param {string} [password] User password for basic authentication.
435 * @param {number} [timeout] Timeout setting in seconds. Default timeout is 60 seconds. A value of 0 means there is no t
436 * @param {Object} [certSource] Certificate description object. It can be one of {@link sap.AuthProxy#CertificateFromFile}
437 * {@link sap.AuthProxy#CertificateFromStore}, or {@link sap.AuthProxy#CertificateFromLogonManager}.
438 * @return {function} A JavaScript function object to abort the operation. Calling the abort function results in neither
439 * callback being invoked for the original request (excepting the case where the success or error callback was invoked bef
440 * abort function). Note that the request itself cannot be unsent, and the server will still receive the request - the Ja
441 * not know the results of that request.
442 * @example
443 * // callbacks
444 * var successCB = function(serverResponse){
445 * alert("Status: " + JSON.stringify(serverResponse.status));
446 * alert("Headers: " + JSON.stringify(serverResponse.headers));
447 * alert("Response: " + JSON.stringify(serverResponse.response));
448 * }
449 * var errorCB = function(errorObject){
450 * alert("Error making request: " + JSON.stringify(errorObject));
451 * }
452 *
453 * // To send a post request to the server, call the method
454 * var abortFunction = sap.AuthProxy.sendRequest("POST", "http://www.google.com", null, "THIS IS THE BODY", successCB, err
455 * // An example of aborting the request
456 * abortFunction();
457 *
458 * // To send a post request to the server with headers, call the method
459 * sap.AuthProxy.sendRequest("POST", url, {HeaderName : "Header value"}, "THIS IS THE BODY", successCB, errorCB);
460 *
461 * // To send a post request to the server with basic authentication, call the method
462 * sap.AuthProxy.sendRequest("POST", url, headers, "THIS IS THE BODY", successCB, errorCB, "username", "password");
463 *
464 * // To send a post request to the server with mutual authentication, call the method
465 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null,
466 * null, 0, new sap.AuthProxy.CertificateFromLogonManager("theAppId"));
467 */
468 AuthProxy.prototype.sendRequest = function (method, url, header, requestBody, successCB, errorCB, user, password, timeout,
469
470 // errorCB required.
471 // First check this one. We may need it to return errors
472 if (!errorCB || (typeof errorCB !== "function")) {
473 console.log("AuthProxy Error: errorCB is not a function");
474 // if error callback is invalid, throw an exception to notify the caller
475 throw new Error("AuthProxy Error: errorCB is not a function");
476 }
477
478 // method required
479 if (!method) {
480 console.log("AuthProxy Error: method is required");
481 errorCB({
482 errorCode: AuthProxy.prototype.ERR_MISSING_PARAMETER,
483 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "method"
484 });
485 return;
486 }
487
488
489 // We only support GET, POST, HEAD, PUT, DELETE, PATCH method
490 if (method !== "GET" && method !== "POST" && method !== "HEAD" && method !== "PUT" && method !== "DELETE" && method !=
491 console.log("Invalid Parameter Value for parameter: " + method);
492 errorCB({
493 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
494 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "method"

PUBLIC Page 109 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
495 });
496 return;
497 }
498
499
500 // url required
501 if (!url) {
502 console.log("AuthProxy Error: url is required");
503 errorCB({
504 errorCode: AuthProxy.prototype.ERR_MISSING_PARAMETER,
505 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "url"
506 });
507 return;
508 }
509
510
511 // successCB required
512 if (!successCB) {
513 console.log("AuthProxy Error: successCB is required");
514 errorCB({
515 errorCode: AuthProxy.prototype.ERR_MISSING_PARAMETER,
516 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "successCB"
517 });
518 return;
519 }
520
521
522 if (typeof successCB !== "function") {
523 console.log("AuthProxy Error: successCB is not a function");
524 errorCB({
525 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
526 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "successCB"
527 });
528 return;
529 }
530
531
532 if (user && typeof user !== "string") {
533 errorCB({
534 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
535 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "user"
536 });
537 return;
538 }
539
540
541 if (password && typeof password !== "string") {
542 errorCB({
543 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
544 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "password"
545 });
546 return;
547 }
548
549
550 if (timeout && typeof timeout !== "number") {
551 errorCB({
552 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
553 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "timeout"
554 });
555 return;
556 }
557
558 if (!this.validateCertSource(certSource, errorCB)) {
559 return;
560 }
561
562
563 try {
564 var client = new Client(method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource)
565 return client.send();
566 } catch (ex) {
567 errorCB({
568 errorCode: AuthProxy.prototype.ERR_UNKNOWN,
569 description: ex.message
570 });
571 }
572

PUBLIC Page 110 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
573 };
574
575 /**
576 * Send an HTTP(S) GET request to a remote server. This is a convenience function that simply calls {@link sap.AuthProxy#
577 * with "GET" as the method and null for the request body. All given parameters are passed as-is to sap.AuthProxy.sendReq
578 * The success callback is invoked upon any response from the server. Even responses not generally considered to be
579 * successful (such as 404 or 500 status codes) will result in the success callback being invoked. The error callback
580 * is reserved for problems that prevent the AuthProxy from creating the request or contacting the server. It is, therefo
581 * important to always check the status property on the object given to the success callback.
582 * @param {string} url The URL against which to make the request.
583 * @param {Object} header HTTP header to send to the server. This is an Object. Can be null.
584 * @param {sap.AuthProxy~successCallback} successCB Callback method invoked upon a response from the server.
585 * @param {sap.AuthProxy~errorCallback} errorCB Callback method invoked in case of failure.
586 * @param {string} [user] User ID for basic authentication.
587 * @param {string} [password] User password for basic authentication.
588 * @param {number} [timeout] Timeout setting in seconds. Default timeout is 60 seconds. A value of 0 means there is no t
589 * @param {Object} [certSource] Certificate description object. It can be one of {@link sap.AuthProxy#CertificateFromFile}
590 * {@link sap.AuthProxy#CertificateFromStore}, or {@link sap.AuthProxy#CertificateFromLogonManager}.
591 * @return {function} A JavaScript function object to abort the operation. Calling the abort function results in neither
592 * callback being invoked for the original request (excepting the case where the success or error callback was invoked bef
593 * abort functino). Note that the request itself cannot be unsent, and the server will still receive the request - the Ja
594 * not know the results of that request.
595 * @example
596 * var successCB = function(serverResponse){
597 * alert("Status: " + JSON.stringify(serverResponse.status));
598 * alert("Headers: " + JSON.stringify(serverResponse.headers));
599 * if (serverResponse.responseText){
600 * alert("Response: " + JSON.stringify(serverResponse.responseText));
601 * }
602 * }
603 * var errorCB = function(errorObject){
604 * alert("Error making request: " + JSON.stringify(errorObject));
605 * }
606 *
607 * // To send a GET request to server, call the method
608 * var abortFunction = sap.AuthProxy.get("http://www.example.com", null, successCB, errorCB);
609 *
610 * // An example of aborting the request
611 * abortFunction();
612 *
613 * // To send a GET request to the server with headers, call the method
614 * sap.AuthProxy.get("http://www.example.com", {HeaderName : "Header value"}, successCB, errorCB);
615 *
616 * // To send a GET request to the server with basic authentication, call the method
617 * sap.AuthProxy.get("https://www.example.com", headers, successCB, errorCB, "username", "password");
618 *
619 * // To send a GET request to the server with mutual authentication, call the method
620 * sap.AuthProxy.get("https://www.example.com", headers, successCB, errorCB, null, null, 0,
621 * new sap.AuthProxy.CertificateFromLogonManager("theAppId"));
622 */
623 AuthProxy.prototype.get = function (url, header, successCB, errorCB, user, password, timeout, certSource) {
624 return this.sendRequest("GET", url, header, null, successCB, errorCB, user, password, timeout, certSource);
625 };
626
627 /**
628 * Delete a cached certificate from the keychain. iOS clients always checks the cached certificate first to see if it is a
629 * loading the certificate from the file system. If the cached certificate is no longer valid, use this method to delete i
630 * <br/><b>Only supported on iOS platform, NOT Android.</b>
631 * @param {sap.AuthProxy~deleteCertificateSuccessCallback} successCB Callback method upon success.
632 * @param {sap.AuthProxy~errorCallback} [errorCB] Callback method upon failure.
633 * @param {string} certificateKey The key of the certificate to be deleted.
634 * @example
635 * var successCB = function(){
636 * alert("certificate successfully deleted.");
637 * }
638 * var errorCB = function(error){
639 * alert("error deleting certificate: " + JSON.stringify(error));
640 * }
641 * sap.AuthProxy.deleteCertificateFromStore(successCB, errorCB, "certificateKeyToDelete");
642 */
643 AuthProxy.prototype.deleteCertificateFromStore = function (successCB, errorCB, certificateKey) {
644 cordova.exec(successCB, errorCB, "AuthProxy", "deleteCertificateFromStore", [certificateKey]);
645 };
646
647 /**
648 * @private
649 */
650 var Client = function (method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource) {

PUBLIC Page 111 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
651
652 //ios plugin parameter does not support object type, convert Header and CertSource to JSON string
653 if (device.platform === "iOS" || (device.platform && device.platform.indexOf("iP") === 0)) {
654 if (header) {
655 header = JSON.stringify(header);
656 }
657 if (certSource) {
658 certSource = JSON.stringify(certSource);
659 }
660 }
661
662 this.Method = method;
663 this.Url = url;
664 this.Header = header;
665 this.RequestBody = requestBody;
666 this.SuccessCB = successCB;
667 this.ErrorCB = errorCB;
668 this.User = user;
669 this.Password = password;
670 this.Timeout = timeout;
671 this.CertSource = certSource;
672 this.IsAbort = false;
673
674 this.abort = function () {
675 this.IsAbort = true;
676 };
677
678
679 this.send = function () {
680
681 var args = [this.Method, this.Url, this.Header, this.RequestBody, this.User, this.Password, this.Timeout, this.Cer
682
683 var me = this;
684
685 var successCallBack = function (data) {
686 if (me.IsAbort === true) {
687 return;
688 }
689
690 successCB(data);
691 };
692
693 var errorCallBack = function (data) {
694 if (me.IsAbort === true) {
695 return;
696 }
697
698 errorCB(data);
699 };
700
701 exec(successCallBack, errorCallBack, "AuthProxy", "sendRequest", args);
702
703 return this.abort;
704 };
705 };
706
707 /**
708 * Generates an OData client that uses the AuthProxy plugin to make requests. This is useful if you are using Datajs, but
709 * to make use of the certificate features of AuthProxy. Datajs is a javascript library useful for accessing OData servic
710 * Datajs has a concept of an HttpClient, which does the work of making the request. This function generates an HttpClien
711 * you can specify to Datajs so you can provide client certificates for requests. If you want to use the generated HTTP c
712 * for all future Datajs requests, you can do that by setting the OData.defaultHttpClient property to the return value of
713 * function. Once that is done, then doing OData stuff with Datajs is almost exactly the same, but you can add a
714 * certificateSource to a request.
715 * @example
716 * OData.defaultHttpClient = sap.AuthProxy.generateODataHttpClient();
717 *
718 * // Using a certificate from file, for example.
719 * fileCert = new sap.AuthProxy.CertificateFromFile("mnt/sdcard/cert.p12", "password", "certKey");
720 *
721 * // This is the same request object you would have created if you were just using Datajs, but now
722 * // you can add the extra 'certificateSource' property.
723 * var createRequest = {
724 * requestUri: "http://www.example.com/stuff/etc/example.svc",
725 * certificateSource : fileCert,
726 * user : "username",
727 * password : "password",
728 * method : "POST",

PUBLIC Page 112 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
729 * data:
730 * {
731 * Description: "Created Record",
732 * CategoryName: "Created Category"
733 * }
734 * }
735 *
736 * // Use Datajs to send the request.
737 * OData.request( createRequest, successCallback, failureCallback );
738 *
739 */
740 AuthProxy.prototype.generateODataHttpClient = function () {
741 var httpClient = {
742 request: function (request, success, error) {
743 var url, requestHeaders, requestBody, statusCode, statusText, responseHeaders;
744 var responseBody, requestTimeout, requestUserName, requestPassword, requestCertificate;
745 var client, result;
746
747 url = request.requestUri;
748 requestHeaders = request.headers;
749 requestBody = request.body;
750
751 var successCB = function (data) {
752 var response = {
753 requestUri: url,
754 statusCode: data.status,
755 statusText: data.status,
756 headers: data.headers,
757 body: (data.responseText ? data.responseText : data.responseBase64)
758 };
759
760 if (response.statusCode >= 200 && response.statusCode <= 299) {
761 if (success) {
762 success(response);
763 }
764 } else {
765 if (error) {
766 error({
767 message: "HTTP request failed",
768 request: request,
769 response: response
770 });
771 }
772 }
773 };
774
775 var errorCB = function (data) {
776 if (error) {
777 error({
778 message: data
779 });
780 }
781 };
782
783 if (request.timeoutMS) {
784 requestTimeout = request.timeoutMS / 1000;
785 }
786
787 if (request.certificateSource) {
788 requestCertificate = request.certificateSource;
789 }
790
791 if (request.user) {
792 requestUserName = request.user;
793 }
794
795 if (request.password) {
796 requestPassword = request.password;
797 }
798
799 client = AuthProxy.prototype.sendRequest(request.method || "GET", url, requestHeaders, requestBody, successCB,
800
801 result = {};
802 result.abort = function () {
803 client.abort();
804
805 if (error) {
806 error({

PUBLIC Page 113 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
807 message: "Request aborted"
808 });
809 }
810 };
811 return result;
812 }
813 };
814 return httpClient;
815 };
816
817 var AuthProxyPlugin = new AuthProxy();
818
819 module.exports = AuthProxyPlugin;
820
821
822 /**
823 * Callback function that is invoked in case of an error.
824 *
825 * @callback sap.AuthProxy~errorCallback
826 *
827 * @param {Object} errorObject An object containing two properties: 'errorCode' and 'description.'
828 * The 'errorCode' property corresponds to one of the {@link sap.AuthProxy} constants. The 'description'
829 * property is a string with more detailed information of what went wrong.
830 *
831 * @example
832 * function errorCallback(errCode) {
833 * //Set the default error message. Used if an invalid code is passed to the
834 * //function (just in case) but also to cover the
835 * //sap.AuthProxy.ERR_UNKNOWN case as well.
836 * var msg = "Unkown Error";
837 * switch (errCode) {
838 * case sap.AuthProxy.ERR_INVALID_PARAMETER_VALUE:
839 * msg = "Invalid parameter passed to method";
840 * break;
841 * case sap.AuthProxy.ERR_MISSING_PARAMETER:
842 * msg = "A required parameter was missing";
843 * break;
844 * case sap.AuthProxy.ERR_HTTP_TIMEOUT:
845 * msg = "The request timed out";
846 * break;
847 * };
848 * //Write the error to the log
849 * console.error(msg);
850 * //Let the user know what happened
851 * navigator.notification.alert(msg, null, "AuthProxy Error", "OK");
852 * };
853 */
854
855 /**
856 * Callback function that is invoked upon a response from the server.
857 *
858 * @callback sap.AuthProxy~successCallback
859 *
860 * @param {Object} serverResponse An object containing the response from the server. Contains a 'headers' property,
861 * a 'status' property, and a 'responseText' property.<br/>
862 * 'headers' is an object containing all the headers in the response.<br/>
863 * 'status' is an integer corresponding to the HTTP status code of the response. It is important to check the status of
864 * the response, since <b>this success callback is invoked upon any response from the server</b> - including responses tha
865 * not normally thought of as successes (for example, the status code could be 404 or 500).<br/>
866 * 'responseText' is a string containing the body of the response.
867 */
868
869 /**
870 * Callback function that is invoked upon successfully deleting a certificate from the store.
871 *
872 * @callback sap.AuthProxy~deleteCertificateSuccessCallback
873 */

Parent topic: Source code

1.9.3 Using the AppUpdate Plugin


The AppUpdate plugin provides server-based updates to the Web application content that is running in the Kapsel application.
In this section:
AppUpdate Plugin Overview
Adding the AppUpdate Plugin
Kapsel AppUpdate API Reference
Parent topic: Kapsel Plugins

PUBLIC Page 114 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.3.1 AppUpdate Plugin Overview
The AppUpdate plugin lets an administrator remotely update the contents in the www folder and the config.xml of a deployed Kapsel application.

This means that updates to the Web application content only, which does not include application bundle contents outside the www folder, do not require
corresponding updates to the native application bundle on the end-users’ devices.

Note
When you update Web content for applications that are distributed through a public app store, you must adhere to the policies of the app store provider, even
though you do not need to go through the formal review process. Do not include updates to content that violates the terms of the app store content review
policies, or change the functionality of the application.

The AppUpdate plugin requires no developer programming, but includes a JavaScript API for customizing the way that application updates occur. The
AppUpdate plugin operates in a default mode unless you handle the provided callback APIs.

Configuration Parameters
These configuration parameters are mapped between the Management Cockpit and the Cordova CLI project folder's config.xml file. See Managing Update
Versions and Revisions for information about usage.

Management Cockpit config.xml File Example Value

Revision hybridapprevision 1

This shows an example of app-specific settings configuration for a sample app in Management Cockpit.

The settings in Management Cockpit are mapped to: Sample <AppDirectory>/www/config.xml configuration<preference name="hybridapprevision" value="1" />

Note
The revision and development versions on SAP Mobile Platform Server are independent values. The Development Version is an optional value for the
administrators’ convenience, and is not used by the AppUpdate plugin. Revisions are auto incremented upon each update of the www folder archive on the
server, regardless of whether the development version changes.

Update Flow
1. The administrator uploads a new archive of the www folder contents to SAP Mobile Platform Server, where he or she can update one or more platform
versions of the www folder in an operation. The administrator specifies the minimum version of Kapsel required for the update, and the development version
(for example, the build version). The SAP Mobile Platform Server auto increments the revision number when the administrator clicks Deploy or Deploy
All .
For details about these administrator tasks, as well as information on the underlying REST API that you can use to automate update uploads, see
administrator Guide > Application Administration > Deploying Applications > Defining Application-Specific Settings > Uploading and Deploying Hybrid
Apps.
2. The Kapsel application with the AppUpdate plugin checks with SAP Mobile Platform Server to see if there is a later revision of the www folder contents
available. If the server has a revision that is greater than the currently downloaded revision, the updated www folder is downloaded. SAP Mobile Platform
Server and the AppUpdate plugin support delta downloads between revision numbers for a development version of the www folder archive. See Managing
Update Versions and Revisions.
3. If an update to the native Kapsel application bundle is distributed, the currently downloaded revisions of the www folder contents are retained through the
update. When a newer revision is available on SAP Mobile Platform Server, the delta of the www folder contents between the on-device and server revision
numbers are downloaded to the Kapsel application. For application bundle updates with very large changes to the www folder contents, you can specify a
hybridapprevision parameter in the application bundle's config.xml matching that revision on SAP Mobile Platform Server, so that a delta download
takes place. The www folder contents in the Kapsel application bundle are then read, as if from a downloaded revision. Future revisions to the www folder
contents uploaded to the SAP Mobile Platform Server are downloaded normally by the AppUpdate plugin. See Managing Update Versions and Revisions.
4. Once an update is downloaded by the AppUpdate plugin, there are a series of configurable behaviors for handling the end-user experience, and for when
the update is applied.
The default behavior is to display a modal alert to the user with options to accept or defer updates. If the end user accepts the update, the Web application
session is restarted within the Kapsel application container, and the new version is loaded.

Example 1: User Accepts App Update


1. The AppUpdate function starts and triggers any required log on process.
2. Checking event is fired by AppUpdate.
3. AppUpdate finds that an update is available on the server, and the downloading event fires.

PUBLIC Page 115 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
4. Updates finish downloading.
5. The sap.AppUpdate.onupdateready function is triggered.
6. A prompt asks the user to reload the application.
7. The user accepts the prompt.
8. The sap.AppUpdate.reloadApp function is called and the updated application loads.

Example 2: User Defers Update Action


1. The AppUpdate function starts and triggers any required log on process.
2. Checking event is fired by AppUpdate.
3. AppUpdate finds that an update is available on the server, and the downloading event is fired.
4. Updates finish downloading.
5. The sap.AppUpdate.onupdateready function is triggered.
6. A prompt asks the user to reload the application.
7. The user cancels the prompt.
8. The sap.AppUpdate.onupdateready function is triggered the next time the application is resumed or started.

Configuring the AppUpdate User Experience


You can modify the user experience of the update event by using the onUpdateReady() function in the JavaScript application code. These modifications
include managing the UI that is shown to the user, text strings, look and feel, position of alert, and so on. You can also add behaviors such as storing a timestamp
of the last time the end user was prompted for an update, then waiting for some fixed period of time, such as a week, before again prompting the user to update.

Note
Ensure that any code written for the onUpdateReady() function that defers, or otherwise overrides, default update life cycle includes an appropriate
recovery method, and does not permanently turn off updates.

Example
Example of Overriding Default Update Behavior
You can assign a custom function to the onUpdateReady() event to override default update behavior and force an update that does not ask the user to confirm
it. It can either go immediately, or the Administrator can set a date by which it goes.
To do this, add a custom function to onUpdateReady() , for example:
sap.AppUpdate.onupdateready = myCustomAppUpdateFunction
Then, in that custom function, control the update process in whatever way you want. For example, to automatically load the update without first prompting the user
for permission, you can add something similar to this:
function myCustomAppUpdateFunction = {
// No notification just reload
console.log("Applying application update…");
sap.AppUpdate.reloadApp();
}
To use your own custom prompt to warn the user that the app is ready to update, you can do something similar to this:
function myCustomAppUpdateFunction = (e){
console.log("Confirming application update…");
navigator.notification.confirm('Do you want to install the latest application update?', doAppUpdateContinue, 'Please confirm', '
}

function doAppUpdateContinue(buttonNum){
if (buttonNum==1) {
console.log("Applying application update…");
sap.AppUpdate.reloadApp();
}
};

Managing Update Versions and Revisions


SAP Mobile Platform Server with the AppUpdate plugin supports both full updates (a complete download of the www folder archive contents on the server) and
delta updates (only changed files are downloaded to the device).
These rules govern how updates are downloaded to the device:
1. If the hybridapprevision parameter in config.xml = 0, or is omitted, the AppUpdate plugin downloads the complete www folder archive from the server
the first time the device connects. There is no delta comparison between the server revision and the initial copy on the device—the full www folder is
downloaded, and becomes hybridapprevision = <current_server_revision_number> on the device.
The initial copy from the application bundle functions normally, until the time that AppUpdate downloads the first revision from the server.
In other words, since the server's auto incremented Revision value starts at 1, a hybridapprevision value of 0, or an empty value in the config.xml tells
the AppUpdate plugin that it is working with the application bundle copy.
2. If the hybridapprevision on the device (either set in config.xml, or managed by AppUpdate plugin) is greater than 0, and there is a newer revision on
the server, then the AppUpdate plugin downloads only changed, new, or deleted resources—a delta update. The delta calculations are executed by SAP
Mobile Platform Server before a request from the AppUpdate plugin, and are maintained for updating from any available historical revision on the server to
the current revision.
This table shows an example of the update behavior. A valid update path is any distance to the right on the matrix.

Device hybridapprevision Server Revision

1.2.3/1 1.2.3/2 1.2.3/3 1.3.0/4 1.5.1/5 2.0.0/6

0 Full Full Full Full Full Full

PUBLIC Page 116 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1 Delta Delta Delta Delta Delta

2 Delta Delta Delta Delta

3 Delta Delta Delta

4 Delta Delta

5 Delta

Domain Whitelisting
Kapsel plugins support Apache Cordova's domain whitelisting model. Whitelisting allows you to control access to external network resources. Apache Cordova
whitelisting allows you to whitelist individual network resources (URLs), for example, http://www.google.com.
For information about the whitelist rules, see http://docs.phonegap.com/en/3.3.0/guide_appdev_whitelist_index.md.html .

Best Practices
For most smaller Web applications, you should simply omit the hybridapprevision parameter from the config.xml. This ensures that the revision
numbering on-device and on the server is correctly aligned. The only ‘full’ download occurs upon the Kapsel application bundle's installation and initialization
—all subsequent downloads will be deltas.
For large Web applications (tens of MBs or greater), setting the hybridapprevision parameter in the config.xml can greatly reduce the download
volume. You should ensure that the value on-device matches the correct value for the server. Since the values on the server are auto incremented, it may
be advisable when setting this parameter to complete the upload on the server before packaging and distributing the Kapsel application bundle. This
ensures that the correct value is used.
Parent topic: Using the AppUpdate Plugin

Related Information
Kapsel AppUpdate API Reference
Uploading and Deploying Hybrid Apps

Adding the AppUpdate Plugin


To install the AppUpdate plugin, use the Cordova command line interface.

Prerequisites
Set up the development environment.
Create your Cordova Project.
Add your OS platforms.

Context

Note
The AppUpdate plugin has dependencies on the Logon plugin, as well as some Cordova plugins. These are automatically added to your project when you add
the AppUpdate plugin.

Procedure
1. Add the AppUpdate plugin by entering the following at the command prompt, or terminal:
On Windows:
cordova -d plugin add <SDK_HOME>\MobileSDK3\KapselSDK\plugins\appupdate
On Mac:
cordova -d plugin add ~<SDK_HOME>/MobileSDK3/KapselSDK/plugins/appupdate

Note
The path you enter to the Kapsel plugin must be the absolute path (not relative path).

2. (Optional) To see a list of installed plugins in your Cordova project, open a command prompt or terminal window, navigate to your Cordova project folder, and
enter: cordova plugins The Cordova command line interface returns a JSON array showing installed plugins, for example:
[ 'org.apache.cordova.core.camera',
'org.apache.cordova.core.device-motion',
'org.apache.cordova.core.file' ]
In this example, the Cordova project has the Cordova core Camera, Accelerator (device-motion), and File plugins installed.
3. Modify the files in the www folder for the project as necessary, then copy them to the platform directories by running:
cordova -d prepare android
cordova -d prepare ios
4. Use the Android IDE or Xcode to deploy and run the project.

PUBLIC Page 117 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Note
If you are using an iOS device, remember to add the "clienthubEntitlements" to the Keychain Groups in the Entitlement section in Xcode.

Parent topic: Using the AppUpdate Plugin

Related Information
Adding the Logon Plugin
Adding the AuthProxy Plugin
Adding the Logger Plugin
Adding the Push Notification Plugin
Adding the EncryptedStorage Plugin
Adding the Settings Plugin
Setting Up the Development Environment
Creating an Apache Cordova Project

1.9.3.3 Kapsel AppUpdate API Reference


The Kapsel AppUpdate API Reference provides usage information for AppUpdate API classes and methods, as well as provides sample source code.
In this section:
AppUpdate namespace
Source code
Parent topic: Using the AppUpdate Plugin

Related Information
AppUpdate Plugin Overview

1.9.3.3.1 AppUpdate namespace


Used to provide server-based updates to the application content.
The AppUpdate plugin updates the contents of the www folder of deployed Kapsel applications. After an application successfully does a logon to an SAP Mobile
Platform 3 server, the AppUpdate plugin is able to download an available update. See Uploading Hybrid Apps in user documentation for information on how to
upload an update to SAP Mobile Platform 3 server.
After an update is completely downloaded, the application user is prompted to install the update and restart the application. They can decline if they wish.
Once an update is installed, the application's revision number is updated.
Adding and Removing the AppUpdate Plugin
The AppUpdate plugin is added and removed using the Cordova CLI .
To add the AppUpdate plugin to your project, use the following command:
cordova plugin add <path to directory containing Kapsel plugins>\appupdate
To remove the AppUpdate plugin from your project, use the following command:
cordova plugin rm com.sap.mp.cordova.plugins.appupdate
Hybrid App Revision Preference
This is an optional preference that tells the AppUdate plugin if the local assets are uploaded to the server, and at what number. If this preference is not provided,
the default revision is 0. In your config.xml file you can add the following preference:
<preference name="hybridapprevision" value="1" />
This means that the local assets in your www folder are uploaded to the server and the server is reporting revision 1 for them. This allows the application to receive
a delta update when revision 2 is available instead of a full update.
Caveats
It is important to test that your update has valid HTML, Javascript, and CSS. Otherwise, the update could prevent the application from functioning correctly, and
may no longer be updateable. You can test the updated application in a separate simulator or additional test device. You can also validate your Javascript with
tools like JSLint , or JSHint . You can validate CSS with CSS Lint .

Methods
Name Description

addEventListener( eventname, f ) Add a listener for an AppUpdate event.

reloadApp() Replaces the app resources with any newly downloaded resources.

removeEventListener( eventname, f ) Removes a listener for an AppUpdate event.

reset() Removes all local updates and loads the original web assets bundled with the app.

update() Force an update check.

Events
Name Description

checking Event fired when AppUpdate is checking for an update.

downloading Event fired when AppUpdate has found an update and is starting the download.

error Event fired when AppUpdate encounters an error while checking for an update or
downloading an update.

PUBLIC Page 118 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
noupdate Event fired when AppUpdate finds no available updates on server.

progress Event fired when AppUpdate has made progress downloading the update.

updateready Event fired when AppUpdate has a newly downloaded update available.

Source
appupdate.js, line 85.
In this section:
addEventListener( eventname, f ) method
reloadApp() method
removeEventListener( eventname, f ) method
reset() method
update() method
checking event
downloading event
error event
noupdate event
progress event
updateready event
Parent topic: Kapsel AppUpdate API Reference

1.9.3.3.1.1 addEventListener( eventname, f ) method


Add a listener for an AppUpdate event.
See events for available event names.

Syntax
<static> addEventListener ( eventname, f )

Parameters
Name Type Description

<eventname> string Name of the app update event.

<f> function Function to call when event is fired.

Example
sap.AppUpdate.addEventListener('checking', function(e) {
console.log("Checking for update");
});

Source
appupdate.js, line 134.
Parent topic: AppUpdate namespace

1.9.3.3.1.2 reloadApp() method


Replaces the app resources with any newly downloaded resources.

Syntax
<static> reloadApp ()

Example
sap.AppUpdate.reloadApp();

Source
appupdate.js, line 109.
Parent topic: AppUpdate namespace

1.9.3.3.1.3 removeEventListener( eventname, f ) method


Removes a listener for an AppUpdate event.
See events for available event names.

PUBLIC Page 119 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Syntax
<static> removeEventListener ( eventname, f )

Parameters
Name Type Description

<eventname> string Name of the app update event.

<f> function Function that was registered.

Example
// Adding the listener
var listener = function(e) {
console.log("Checking for update");
});
sap.AppUpdate.addEventListener('checking', listener);

// Removing the listener


sap.AppUpdate.removeEventListener('checking', listener);

Source
appupdate.js, line 154.
Parent topic: AppUpdate namespace

1.9.3.3.1.4 reset() method


Removes all local updates and loads the original web assets bundled with the app.
Call this after delete registration. Reset calls error callback if called during the update process.

Syntax
<static> reset ()

Example
sap.Logon.core.deleteRegistration(function() {
sap.AppUpdate.reset();
}, function() {});

Source
appupdate.js, line 121.
Parent topic: AppUpdate namespace

1.9.3.3.1.5 update() method


Force an update check.
By default updates are done automatically during logon and resume. See events for what will be fired during this process.

Syntax
<static> update ()

Example
sap.AppUpdate.update();

Source
appupdate.js, line 92.
Parent topic: AppUpdate namespace

1.9.3.3.1.6 checking event


Event fired when AppUpdate is checking for an update.

PUBLIC Page 120 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Properties
Name Type Description

<type> string The name of the event.Value will be checking.

Type
object

Example
sap.AppUpdate.addEventListener('checking', function(e) {
console.log("Checking for update");
});

Source
appupdate.js, line 160.
Parent topic: AppUpdate namespace

1.9.3.3.1.7 downloading event


Event fired when AppUpdate has found an update and is starting the download.

Properties
Name Type Description

<type> string The name of the event.Value will be downloading.

Type
object

Example
sap.AppUpdate.addEventListener('downloading', function(e) {
console.log("Downloading update");
});

Source
appupdate.js, line 164.
Parent topic: AppUpdate namespace

1.9.3.3.1.8 error event


Event fired when AppUpdate encounters an error while checking for an update or downloading an update.
The status code and status message are provided with this event.

Properties
Name Type Description

<type> string The name of the event.Value will be error.

<statusCode> int The http error code.

<statusMessage> string The http status message.

Type
object

Example
sap.AppUpdate.addEventListener('error', function(e) {
console.log("Error downloading update. statusCode: " + e.statusCode + " statusMessage: " + e.statusMessage);

PUBLIC Page 121 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
});

Source
appupdate.js, line 169.
Parent topic: AppUpdate namespace

1.9.3.3.1.9 noupdate event


Event fired when AppUpdate finds no available updates on server.

Properties
Name Type Description

<type> string The name of the event.Value will be noupdate.

Type
object

Example
sap.AppUpdate.addEventListener('noupdate', function(e) {
console.log("No update");
});

Source
appupdate.js, line 162.
Parent topic: AppUpdate namespace

1.9.3.3.1.10 progress event


Event fired when AppUpdate has made progress downloading the update.

Properties
Name Type Description

<type> string The name of the event.Value will be progress.

<lengthComputable> boolean Specifies whether or not the total size is known.

<loaded> int The number of bytes transferred so far.

<total> int The total number of bytes of content that will be


transferred.If total size is unknown, this value is zero.

Type
object

Example
sap.AppUpdate.addEventListener('progress', function(e) {
if (e.lengthComputable) {
var percent = Math.round(e.loaded / e.total * 100);
console.log("Progress " + percent);
}
});

Since
3.0.2

Source
appupdate.js, line 167.
Parent topic: AppUpdate namespace

1.9.3.3.1.11 updateready event


PUBLIC Page 122 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.3.3.1.11 updateready event
Event fired when AppUpdate has a newly downloaded update available.
A default handler is already added to sap.AppUpdate.onupdateready that will ask the user to reload the app. When handling this event you should call
sap.AppUpdate.reloadApp() to apply the downloaded update.

Properties
Name Type Description

<type> string The name of the event.Value will be updateready.

<revision> int The revision that was downloaded.

Type
object

Example
// This will listen for updateready event.
// Note: Use sap.AppUpdate.onupdateready if you want to override the default handler.
sap.AppUpdate.addEventListener('updateready', function(e) {
console.log("Update ready");
});

// Override default handler so that we automatically load the update


// without first prompting the user for permission,
sap.AppUpdate.onupdateready = function(e) {
// No notification just reload
console.log("Apply application update...");
sap.AppUpdate.reloadApp();
};

// Override default handler with custom prompt to warn the user that the
// application is ready to update.
sap.AppUpdate.onupdateready = function() {
console.log("Confirming application update…");
navigator.notification.confirm('Update Available',
function(buttonIndex) {
if (buttonIndex === 2) {
console.log("Applying application update…");
sap.AppUpdate.reloadApp();
}
},
"Update", ["Later", "Relaunch Now"]);
};

Source
appupdate.js, line 171.
Parent topic: AppUpdate namespace

1.9.3.3.2 Source code


In this section:
appupdate.js
Parent topic: Kapsel AppUpdate API Reference

1.9.3.3.2.1 appupdate.js
1 // 3.0.3-SNAPSHOT
2 var exec = require('cordova/exec'),
3 channel = require('cordova/channel'),
4 logonFired = false, // Flag to determine if logon manager is done
5 promptActive = false, // Flag to prevent prompt from displaying more than once
6 bundle = null; // Internationalization. Loaded with device ready
7
8
9 // Event channels for AppUpdate
10 var channels = {
11 'checking': channel.create('checking'),
12 'noupdate': channel.create('noupdate'),
13 'downloading': channel.create('downloading'),

PUBLIC Page 123 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
14 'progress': channel.create('progress'),
15 'error': channel.create('error'),
16 'updateready': channel.create('updateready')
17 };
18
19 // Holds the dom 0 handlers that are registered for the channels
20 var domZeroHandlers = {};
21
22 // Private callback that plugin calls for events
23 var _eventHandler = function (event) {
24 if (event.type) {
25 if (event.type in channels) {
26 channels[event.type].fire(event);
27 }
28 }
29 };
30
31 /** @namespace sap */
32
33 /**
34 * Used to provide server-based updates to the application content.
35 * <br/><br/>
36 * The AppUpdate plugin updates the contents of the www folder of deployed Kapsel
37 * applications. After an application successfully does a logon to an SAP Mobile Platform 3
38 * server, the AppUpdate plugin is able to download an available update. See Uploading Hybrid Apps in user documentation
39 * for information on how to upload an update to SAP Mobile Platform 3 server.
40 * <br/><br/>
41 * After an update is completely downloaded, the application user is
42 * prompted to install the update and restart the application. They can decline
43 * if they wish.
44 * <br/><br/>
45 * Once an update is installed, the application's revision number is updated.
46 * <br/><br/>
47 * <b>Adding and Removing the AppUpdate Plugin</b><br/>
48 * The AppUpdate plugin is added and removed using the
49 * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>
50 * <br/>
51 * To add the AppUpdate plugin to your project, use the following command:<br/>
52 * cordova plugin add <path to directory containing Kapsel plugins>\appupdate<br/>
53 * <br/>
54 * To remove the AppUpdate plugin from your project, use the following command:<br/>
55 * cordova plugin rm com.sap.mp.cordova.plugins.appupdate
56 * <br/><br/>
57 *
58 * <b>Hybrid App Revision Preference</b><br/>
59 * This is an optional preference that tells the AppUdate plugin if the local
60 * assets are uploaded to the server, and at what number. If this preference is
61 * not provided, the default revision is 0.
62 * In your config.xml file you can add the following preference:<br/>
63 * <preference name="hybridapprevision" value="1" />
64 <br/>
65 <br/>
66 * This means that the local assets in your www folder are uploaded to the server
67 * and the server is reporting revision 1 for them. This allows the application
68 * to receive a delta update when revision 2 is available instead of a full update.
69 * <br/><br/>
70 *
71 * <b>Caveats</b><br/>
72 * It is important to test that your update has valid HTML, Javascript, and CSS.
73 * Otherwise, the update could prevent the application from functioning correctly,
74 * and may no longer be updateable. You can test the updated application in a
75 * separate simulator or additional test device. You can also validate your
76 * Javascript with tools like <a href="http://www.jslint.com">JSLint</a>, or
77 * <a href="http://www.jshint.com">JSHint</a>.
78 * You can validate CSS with <a href="http://csslint.net">CSS Lint</a>.
79 * <br/><br/>
80 *
81 * @namespace
82 * @alias AppUpdate
83 * @memberof sap
84 */
85 module.exports = {
86 /**
87 * Force an update check. By default updates are done automatically during logon and resume.
88 * See events for what will be fired during this process.
89 * @example
90 * sap.AppUpdate.update();
91 */

PUBLIC Page 124 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
92 update: function () {
93 // Abort if logon event has not yet fired
94 if (logonFired) {
95 sap.Logon.unlock(function (connectionInfo) {
96 //Add application ID required for REST call
97 connectionInfo.applicationId = sap.Logon.applicationId;
98
99 exec(_eventHandler, null, 'AppUpdate', 'update', [connectionInfo]);
100 });
101 }
102 },
103
104 /**
105 * Replaces the app resources with any newly downloaded resources.
106 * @example
107 * sap.AppUpdate.reloadApp();
108 */
109 reloadApp: function () {
110 exec(null, null, 'AppUpdate', 'reloadApp', []);
111 },
112
113 /**
114 * Removes all local updates and loads the original web assets bundled with the app. Call this after delete registrati
115 * Reset calls error callback if called during the update process.
116 * @example
117 * sap.Logon.core.deleteRegistration(function() {
118 * sap.AppUpdate.reset();
119 * }, function() {});
120 */
121 reset: function (successCallback, errorCallback) {
122 exec(successCallback, errorCallback, 'AppUpdate', 'reset', []);
123 },
124
125 /**
126 * Add a listener for an AppUpdate event. See events for available event names.
127 * @param {string} eventname Name of the app update event.
128 * @param {function} f Function to call when event is fired.
129 * @example
130 * sap.AppUpdate.addEventListener('checking', function(e) {
131 * console.log("Checking for update");
132 * });
133 */
134 addEventListener: function (eventname, f) {
135 if (eventname in channels) {
136 channels[eventname].subscribe(f);
137 }
138 },
139
140 /**
141 * Removes a listener for an AppUpdate event. See events for available event names.
142 * @param {string} eventname Name of the app update event.
143 * @param {function} f Function that was registered.
144 * @example
145 * // Adding the listener
146 * var listener = function(e) {
147 * console.log("Checking for update");
148 * });
149 * sap.AppUpdate.addEventListener('checking', listener);
150 *
151 * // Removing the listener
152 * sap.AppUpdate.removeEventListener('checking', listener);
153 */
154 removeEventListener: function (eventname, f) {
155 if (eventname in channels) {
156 channels[eventname].unsubscribe(f);
157 }
158 }
159
160 /**
161 * Event fired when AppUpdate is checking for an update.
162 *
163 * @event sap.AppUpdate#checking
164 * @type {object}
165 * @property {string} type - The name of the event. Value will be checking.
166 * @example
167 * sap.AppUpdate.addEventListener('checking', function(e) {
168 * console.log("Checking for update");
169 * });

PUBLIC Page 125 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
170 */
171
172 /**
173 * Event fired when AppUpdate finds no available updates on server.
174 *
175 * @event sap.AppUpdate#noupdate
176 * @type {object}
177 * @property {string} type - The name of the event. Value will be noupdate.
178 * @example
179 * sap.AppUpdate.addEventListener('noupdate', function(e) {
180 * console.log("No update");
181 * });
182 */
183
184 /**
185 * Event fired when AppUpdate has found an update and is starting the download.
186 *
187 * @event sap.AppUpdate#downloading
188 * @type {object}
189 * @property {string} type - The name of the event. Value will be downloading.
190 * @example
191 * sap.AppUpdate.addEventListener('downloading', function(e) {
192 * console.log("Downloading update");
193 * });
194 */
195
196
197 /**
198 * Event fired when AppUpdate has made progress downloading the update.
199 *
200 * @since 3.0.2
201 * @event sap.AppUpdate#progress
202 * @type {object}
203 * @property {string} type - The name of the event. Value will be progress.
204 * @property {boolean} lengthComputable - Specifies whether or not the total size is known.
205 * @property {int} loaded - The number of bytes transferred so far.
206 * @property {int} total - The total number of bytes of content that will be transferred. If total size is unknown, t
207 * @example
208 * sap.AppUpdate.addEventListener('progress', function(e) {
209 * if (e.lengthComputable) {
210 * var percent = Math.round(e.loaded / e.total * 100);
211 * console.log("Progress " + percent);
212 * }
213 * });
214 */
215
216 /**
217 * Event fired when AppUpdate encounters an error while checking for an update or downloading an update.
218 * The status code and status message are provided with this event.
219 *
220 * @event sap.AppUpdate#error
221 * @type {object}
222 * @property {string} type - The name of the event. Value will be error.
223 * @property {int} statusCode - The http error code.
224 * @property {string} statusMessage - The http status message.
225 * @example
226 * sap.AppUpdate.addEventListener('error', function(e) {
227 * console.log("Error downloading update. statusCode: " + e.statusCode + " statusMessage: " + e.statusMessage);
228 * });
229 */
230
231 /**
232 * Event fired when AppUpdate has a newly downloaded update available.
233 * A default handler is already added to sap.AppUpdate.onupdateready that will ask the user to reload the app.
234 * When handling this event you should call sap.AppUpdate.reloadApp() to apply the downloaded update.
235 *
236 * @event sap.AppUpdate#updateready
237 * @type {object}
238 * @property {string} type - The name of the event. Value will be updateready.
239 * @property {int} revision - The revision that was downloaded.
240 * @example
241 *
242 * // This will listen for updateready event.
243 * // Note: Use sap.AppUpdate.onupdateready if you want to override the default handler.
244 * sap.AppUpdate.addEventListener('updateready', function(e) {
245 * console.log("Update ready");
246 * });
247 *

PUBLIC Page 126 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
248 * // Override default handler so that we automatically load the update
249 * // without first prompting the user for permission,
250 * sap.AppUpdate.onupdateready = function(e) {
251 * // No notification just reload
252 * console.log("Apply application update...");
253 * sap.AppUpdate.reloadApp();
254 * };
255 *
256 * // Override default handler with custom prompt to warn the user that the
257 * // application is ready to update.
258 * sap.AppUpdate.onupdateready = function() {
259 * console.log("Confirming application update…");
260 * navigator.notification.confirm('Update Available',
261 * function(buttonIndex) {
262 * if (buttonIndex === 2) {
263 * console.log("Applying application update…");
264 * sap.AppUpdate.reloadApp();
265 * }
266 * },
267 * "Update", ["Later", "Relaunch Now"]);
268 * };
269 */
270 };
271
272 // Add getter/setter for DOM0 style events
273 for (var type in channels) {
274 function defineSetGet(eventType) {
275 module.exports.__defineGetter__("on" + eventType, function () {
276 return domZeroHandlers[eventType];
277 });
278
279 module.exports.__defineSetter__("on" + eventType, function (val) {
280 // Remove current handler
281 if (domZeroHandlers[eventType]) {
282 module.exports.removeEventListener(eventType, domZeroHandlers[eventType]);
283 }
284
285 // Add new handler
286 if (val) {
287 domZeroHandlers[eventType] = val;
288 module.exports.addEventListener(eventType, domZeroHandlers[eventType]);
289 }
290 });
291 }
292
293 defineSetGet(type);
294 }
295
296 // Add default update ready implementation
297 module.exports.onupdateready = function () {
298 if (!promptActive) {
299 promptActive = true;
300
301 var onConfirm = function (buttonIndex) {
302 promptActive = false;
303 if (buttonIndex === 2) {
304 // Only reload if we are unlocked
305 sap.Logon.unlock(function (connectionInfo) {
306 //Add application ID required for REST call
307 connectionInfo.applicationId = sap.Logon.applicationId;
308
309 module.exports.reloadApp();
310 });
311 }
312 }
313
314 if (!bundle) {
315 // Load required translations
316 var i18n = require('com.sap.mp.cordova.plugins.i18n.i18n');
317 bundle = i18n.load({
318 path: "plugins/com.sap.mp.cordova.plugins.appupdate/www"
319 });
320 }
321
322 window.navigator.notification.confirm(
323 bundle.get("update_available"),
324 onConfirm,
325 bundle.get("update"), [bundle.get("later"), bundle.get("relaunch_now")]);

PUBLIC Page 127 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
326 }
327 }
328
329 // When logon is ready an update check is started
330 document.addEventListener("onSapLogonSuccess", function () {
331 logonFired = true;
332 module.exports.update();
333 }, false);
334
335 document.addEventListener("onSapResumeSuccess", module.exports.update, false);
336

Parent topic: Source code

1.9.4 Using the Logger Plugin


The Logger plugin includes client-side APIs that you can use for logging the activities of your application.

In this section:
Logger Plugin Overview
Adding the Logger Plugin
Viewing Client Logs
Testing Logging
Kapsel Logger API Reference
Parent topic: Kapsel Plugins

1.9.4.1 Logger Plugin Overview


The Logger plugin allows you to log information to trace bugs or other issues in your application for analysis.

Note
To upload log files successfully with the Logger plugin, these conditions must be met:
In Management Cockpit, the Log Upload check box must be selected.
The sap.Logger.upload() must be called.

With the Logger plugin, you can enable an application to write log entries that can then be automatically uploaded to SAP Mobile Platform Server for analysis by
using the sap.Logger.upload() method. If you add the Settings plugin to your project files, sap.Logger.upload() is called with a logon success
event (for example, when the application is launched or resumed and logon is successful) so the log file is uploaded automatically. If you do not use the Settings
plugin, you can upload log files only by calling the sap.Logger.upload() method manually.

Security for the log upload connection to SAP Mobile Platform Server is provided by using the security profile associated with the Application ID.
You can build in support for logging so that an administrator can remotely set the appropriate log level from SAP Mobile Platform Server. The Kapsel Logger
plugin can define each log message with specific levels, such as Debug and Error, which enables you to filter the log message by priority level. The Kapsel
Logger plugin mirrors the OData logger library so that it can collect all of the logging data produced by the OData library. The Kapsel plugins use OData libraries
in several places so that it can help see and trace the plugins' logging data.
Using the provided sap.Logger.upload() method allows you to log events that occur on the device and send them to SAP Mobile Platform Server, where an
Administrator can view them and remotely set the appropriate log level to control the amount of information that is written to the log.

Example
This shows the index.html file for a sample app, which has the appID of "com.mycompany.logger" with the server connection information. This information allows
the app to register with the appID on SAP Mobile Platform Server. This sample app logs messages with the log level and uploads a log file to SAP Mobile
Platform Server. For example, to log messages with DEBUG log level, you can call the sap.Logger.debug(...) method. You can also use other methods
for logging with other log levels (INFO, WARN and ERROR).
<html>
<head>
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script>
logonView = null;
logon = null;
applicationContext = null;
function init() {
var appId = "com.mycompany.logger"; // Change this to app id on server
// Optional initial connection context var context = {
"serverHost": "server.sap.corp", //Place your SAP Mobile Platform server 3.0 name here
"https": "false",
"serverPort": "8080",
"user": "user", //Place your user name for the OData Endpoint here
"password": "xxxxxxx", //Place your password for the OData Endpoint here
"communicatorId": "REST",
"passcode": "password",
"unlockPasscode": "password"
};
sap.Logon.init(function() { }, function() {alert("Logon Failed"); }, appId, context, sap.logon.IabUi);
sap.Logger.setLogLevel(sap.Logger.DEBUG);
}
function logMessage() {
var employee = {name: "Dan", location : "Waterloo"};

PUBLIC Page 128 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
console.log("The value of employee is " + JSON.stringify(employee));
}
function logMessage2() {
sap.Logger.debug("Debug log message");
sap.Logger.info("Info log message");
sap.Logger.warn("Warn log message");
sap.Logger.error("Error log message");
}
function uploadLog() {
sap.Logger.upload(function() {
alert("Upload Successful");
}, function(e) {
alert("Upload Failed. Status: " + e.statusCode + ", Message: " + e.statusMessage);
});
}
document.addEventListener("deviceready", init, false);
</script>
</head>
<body>
<h1>Logger Sample</h1>
<button id="log" onclick="logMessage()">Log Message with console</button><br>
<button id="log" onclick="logMessage2()">Log Message with Logging Plugin</button><br>
<button id="upload" onclick="uploadLog()">Upload Log</button>
</body>
</html>

Setting the Log Level


You can manually set the Kapsel log level in the init(…) function by adding code, for example:
sap.Logger.setLogLevel(sap.Logger.INFO,
function(logLevel) {console.log("Log level set");},
function() {console.log("Failed to set log level");});
Log levels are:
ERROR
WARN
INFO
DEBUG
By default, only error level logs are captured. Use the setLogLevel to capture other levels. If the log level is DEBUG, all log level messages are stored. If it is
WARN, the uploaded log contains WARN and ERROR messages.
On iOS, if the log level is ERROR, then only ERROR level messages are displayed in the console, even if other log level messages are generated. But if the
current log level is DEBUG, INFO, or WARN, all generated log messages, regardless of log level, are displayed in the console.On Android, all generated log
messages, regardless of log level, are shown in the Android log cat view (console).
To upload the log to the server, in the logMessageInfoToSMP(…) function, enter:
sap.Logger.setLogLevel(sap.Logger.INFO,
function(logLevel) {console.log("Log level set");},
function() {console.log("Failed to set log level");});

Domain Whitelisting
Kapsel plugins support Apache Cordova's domain whitelisting model. Whitelisting allows you to control access to external network resources. Apache Cordova
whitelisting allows you to whitelist individual network resources (URLs), for example, http://www.google.com.
For information about the whitelist rules, see http://docs.phonegap.com/en/3.3.0/guide_appdev_whitelist_index.md.html .

Limitations
On Android, the maximum for log entries is 10,000. The oldest 200 log entries are removed if the 10,000 maximum is reached. This applies to both the device
and emulator.
On iOS simulators, the Logger plugin may behave in unpredictable ways, as it is intended for use with a device. On iOS devices, there is no explicit maximum
for log entries, however, old messages are removed from the device after a time.
Parent topic: Using the Logger Plugin

Related Information
Kapsel Logger API Reference

1.9.4.2 Adding the Logger Plugin


Install the Logger plugin using the Cordova command line interface.

Prerequisites

PUBLIC Page 129 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Set up the development environment.
Create your Cordova Project.
Add your OS platforms.

Procedure
1. Add the Logger plugin by entering the following at the command prompt, or terminal:
On Windows:
cordova -d plugin add <SDK_HOME>\MobileSDK3\KapselSDK\plugins\logger
On Mac:
cordova -d plugin add ~<SDK_HOME>/MobileSDK3/KapselSDK/plugins/logger

Note
The path you enter to the Kapsel plugin must be the absolute path (not relative path).

2. (Optional) To see a list of installed plugins in your Cordova project, open a command prompt or terminal window, navigate to your Cordova project folder, and
enter: cordova plugins The Cordova command line interface returns a JSON array showing installed plugins, for example:
[ 'org.apache.cordova.core.camera',
'org.apache.cordova.core.device-motion',
'org.apache.cordova.core.file' ]
In this example, the Cordova project has the Cordova core Camera, Accelerator (device-motion), and File plugins installed.
3. Modify the files in the www folder for the project as necessary, then copy them to the platform directories by running:
cordova -d prepare android
cordova -d prepare ios
4. Use the Android IDE or Xcode to deploy and run the project.

Note
If you are using an iOS device, remember to add the "clienthubEntitlements" to the Keychain Groups in the Entitlement section in Xcode.

Parent topic: Using the Logger Plugin

Related Information
Adding the AppUpdate Plugin
Adding the Logon Plugin
Adding the AuthProxy Plugin
Adding the Push Notification Plugin
Adding the EncryptedStorage Plugin
Adding the Settings Plugin
Setting Up the Development Environment
Creating an Apache Cordova Project

1.9.4.3 Viewing Client Logs


View a client log associated with the selected application registration. The developer must have implemented REST API Logger code in the application code, and
the application must be registered and collecting data. Client requests to upload a log file to the server are authenticated based on the application security profile.
The log content varies by device type and operating system.

Context

Note
In a clustered server environment, the client log is only uploaded to the node to which the application is connected at the time of upload, and not synchronized
across the nodes in the cluster. To view these from Management Cockpit, you must connect to that node directly from Management Cockpit.

Procedure
1. From Management Cockpit, select Registrations on the Home screen to view application connections. Alternatively, in the Applications tab, click the
Registrations tab. Information for up to 200 registered applications appears.
2. Use the search, sorting, and filtering options to locate the registration in which you are interested:
3. Click the red client log icon to display the Client Logging dialog. In some cases, a list of client logs appears.
1. Click Enable Log Upload .
2. Select the log level in Log Type .
3. Click Save to save the modified setting of whether to allow uploading of client logs, and the level at which the client should log.
The red client log icon turns green.
4. Click a log file name to download the log and open it in your selected viewer.
In this section:
Client Logs
Parent topic: Using the Logger Plugin

1.9.4.3.1 Client Logs

PUBLIC Page 130 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
If client logging has been enabled for an application and log data is available, you can view the client log for the selected application registration.

Note
The log format varies by device type and operating system. Following are example log excerpts for Android and iOS.

Hybrid Client Log - Android Example


1377125811306
Debug Tag
Debug Message
null (com.sap.mp.cordova.plugins.logger.Logger:execute:54)
1893

1377125813056
Info Tag
Info Message
null (com.sap.mp.cordova.plugins.logger.Logger:execute:61)
1893

1377125814165
Warn Tag
Warn Message
null (com.sap.mp.cordova.plugins.logger.Logger:execute:68)
1893

1377125815157
Error Tag
Error Message
null (com.sap.mp.cordova.plugins.logger.Logger:execute:75)
1893

Hybrid Client Log - iOS Example


ASLMessageID = 142697
Time = Aug 20, 2013, 4:37:22 PM
TimeNanoSec = 274834000
Level = 3
PID = 4823
UID = 966313393
GID = 1824234391
ReadGID = 80
Host = PALM00545086A
Sender = KAPSEL326
Facility = com.sap.sdmlogger
Message = MAFLogon MCIM is available: NO -[MAFMCIMManager isAvailable] Line:48 thread:<NSThread: 0x9d57c10>{name = (null), num = 1

ASLMessageID = 142696
Time = Aug 20, 2013, 4:37:22 PM
TimeNanoSec = 234589000
Level = 4
PID = 4823
UID = 966313393
GID = 1824234391
ReadUID = 966313393
Host = PALM00545086A
Sender = KAPSEL326
Facility = com.sap.kapsel326
Message = Finished load of: file:///Users/i834381/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/9EC4E7F3-C156-
CFLog Local Time = 2013-08-20 16:37:22.234
CFLog Thread = c07

ASLMessageID = 142695
Time = Aug 20, 2013, 4:37:22 PM
TimeNanoSec = 194786000
Level = 4
PID = 4823
UID = 966313393
GID = 1824234391
ReadUID = 966313393
Host = PALM00545086A
Sender = KAPSEL326
Facility = com.sap.kapsel326
Message = Resetting plugins due to page load.
CFLog Local Time = 2013-08-20 16:37:22.194
CFLog Thread = c07

ASLMessageID = 142694

PUBLIC Page 131 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Time = Aug 20, 2013, 4:37:22 PM
TimeNanoSec = 152145000
Level = 4
PID = 4823
UID = 966313393
GID = 1824234391
ReadUID = 966313393
Host = PALM00545086A
Sender = KAPSEL326
Facility = com.sap.kapsel326
Message = Multi-tasking -> Device: YES, App: YES
CFLog Local Time = 2013-08-20 16:37:22.151
CFLog Thread = c07

Parent topic: Viewing Client Logs

1.9.4.4 Testing Logging


The log file is located in SMP_HOME\Server\log\clientlogs\< <application_id> >\< <application_registration_id> >\Log.txt.

Procedure
1. Run your project with the Android IDE or Xcode.
2. In Management Cockpit, enable the upload log function.

Note
For the call to sap.Logger.upload() to succeed, the Log Upload checkbox on the registration ID in the Management Cockpit must be checked.

3. View the uploaded logs in the Management Cockpit.


Parent topic: Using the Logger Plugin

1.9.4.5 Kapsel Logger API Reference


The Kapsel Logger API Reference provides usage information for Logger API classes and methods, as well as provides sample source code.
In this section:
Logger namespace
Source code
Parent topic: Using the Logger Plugin

Related Information
Logger Plugin Overview

1.9.4.5.1 Logger namespace


The Kapsel Logger plugin provides a Cordova plugin wrapper around the SAP Mobile Platform client logging API.
The Logger plugin has ERROR, WARN, INFO, and DEBUG log levels and log messages are captured based on the configured and selected log level. A Kapsel
application can be set to these log levels by programmatic control, and by the administrator changing a setting on the server. For Android and iOS, the default log
level is ERROR, so by default only ERROR level logs are captured. sap.Logger.setLogLevel() method is used to set other levels. If you want to get log messages
at all log levels, you must set the log level to DEBUG. (DEBUG < INFO < WARN < ERROR)
If the log level is set to DEBUG, the application captures all log messages.
If you set the log level to INFO, the application captures INFO, WARN, and ERROR log messages.
If you set the log level to WARN, the application captures WARN and ERROR log messages.
If you set the log level to ERROR, the application captures only Error log messages.
Using the provided sap.Logger.upload() method allows developers to upload a log file to SAP Mobile Platform Server, where an administrator can view them and
remotely set the appropriate log level to control the amount of information that is written to the log. When the sap.Logger.upload() method is triggered, a log file will
be uploaded. If the Log Upload checkbox is selected in the Management Cockpit, the client can upload a log file by calling sap.Logger.upload(). If the Log Upload
checkbox is disabled in the Management Cockpit, the client does not upload the log file to the server. The attempt to upload causes an "HTTP/1.1 403 Forbidden"
error. To support manual uploading of the log, you should implement a button or some other mechanism that calls sap.Logger.upload() when needed.
For the Logger plugin to upload a log file these conditions must be met: 1) Log Upload checkbox enabled In the Management Cockpit 2) sap.Logger.upload() is
called by developer.
The expected work flow, with the current architecture consists of the following:
1) If a user has an issue that needs to be analyzed by an administrator or developer, the user reports the issue as appropriate.
2) The administrator, or developer, enables the log collection for the user on the SAP Mobile Platform server.
3) The administrator lets the user know that he, or she, can upload log file.
4) The user uploads thelog file to the server, and the administrator gets the uploaded log file in the Management Cockpit.
5) The administrator sends the file to the developer to debug.
Currently, on iOS, if the current log level is ERROR (default level), only ERROR level messages are displayed on the console even if other log level messages
are generated. But if the current log level is DEBUG, INFO, or WARN, all generated log messages, regardless of log level, are displayed on the console.
On Android, if the current log level is ERROR, only ERROR level messages are displayed in the Android logcat view (console). if log level is INFO, then ERROR,
WARN and INFO level messages are displayed in the Android logcat view (console).
When the Kapsel Settings plugin is added to the project, Settings will: 1) Get log level from the server 2) Set it into Logger on the client 3) Call sap.Logger.upload()
after a logon success event, for example, when the app is launched or resumed and logon is successful. The Settings plugin retrieves the selected log level(type)
from the Management Cockpit on the server, sets the log level to Logger plugin, and then automatically uploads a log file to the server. If the Settings plugin is not

PUBLIC Page 132 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
added to the project, a log file can be uploaded only by the developer calling the sap.Logger.upload() method manually. To upload a log file automatically, settings
plugin is required. In the Management Cockpit, in the Client Logging dialog box, the Log Upload checkbox is able to enable or disable log file upload, and you can
choose the log type(level). You can also view a list of the uploaded log files. On the server side, there are seven log types: NONE, FATAL, ERROR, WARNING,
INFO, DEBUG and PATH. Since the Kapsel Logger plugin supports only DEBUG, INFO, WARN, and ERROR, the Logger plugin implicitly matches FATAL to
ERROR, and PATH to DEBUG. If NONE is set in the Management Cockpit, Logger sets it to default log level.
Adding and Removing the Logger Plugin
Add or remove the Logger plugin using the Cordova CLI .
To add the Logger plugin to your project, use the following command:
Cordova plugin add <path to directory containing Kapsel plugins>\logger
To remove the Logger plugin from your project, use the following command:
cordova plugin rm com.sap.mp.cordova.plugins.logger

Members
Name Description

Logger#DEBUG Constant variable for Debug log level.

Logger#ERROR Constant variable for Error log level.

Logger#INFO Constant variable for Information log level.

Logger#WARN Constant variable for Warning log level.

Methods
Name Description

debug( message, [tag], [successCallback], [errorCallback] ) Add a debug message to the log.

error( message, [tag], [successCallback], [errorCallback] ) Add an error message to the log.

getLogLevel( successCallback, [errorCallback] ) Get log level.

info( message, [tag], [successCallback], [errorCallback] ) Add an info message to the log.

setLogLevel( level, [successCallback], [errorCallback] ) Set log level.

upload( successCallback, errorCallback ) Upload a log file, with log entries, to SAP Mobile Platform server.

warn( message, [tag], [successCallback], [errorCallback] ) Add a warning message to the log.

Source
logger.js, line 70.
In this section:
Logger#DEBUG member
Logger#ERROR member
Logger#INFO member
Logger#WARN member
debug( message, [tag], [successCallback], [errorCallback] ) method
error( message, [tag], [successCallback], [errorCallback] ) method
getLogLevel( successCallback, [errorCallback] ) method
info( message, [tag], [successCallback], [errorCallback] ) method
setLogLevel( level, [successCallback], [errorCallback] ) method
upload( successCallback, errorCallback ) method
warn( message, [tag], [successCallback], [errorCallback] ) method
Parent topic: Kapsel Logger API Reference

1.9.4.5.1.1 Logger#DEBUG member


Constant variable for Debug log level.
It contains "DEBUG" string.

Syntax
<static, constant> Logger#DEBUG : String

Example
sap.Logger.setLogLevel(sap.Logger.DEBUG);

Source
logger.js, line 355.
Parent topic: Logger namespace

1.9.4.5.1.2 Logger#ERROR member


PUBLIC Page 133 of 135
© 2014 SAP SE or an SAP affiliate company. All rights reserved.
1.9.4.5.1.2 Logger#ERROR member
Constant variable for Error log level.
It contains "ERROR" string.

Syntax
<static, constant> Logger#ERROR : String

Example
sap.Logger.setLogLevel(sap.Logger.ERROR);

Source
logger.js, line 325.
Parent topic: Logger namespace

1.9.4.5.1.3 Logger#INFO member


Constant variable for Information log level.
It contains "INFO" string.

Syntax
<static, constant> Logger#INFO : String

Example
sap.Logger.setLogLevel(sap.Logger.INFO);

Source
logger.js, line 345.
Parent topic: Logger namespace

1.9.4.5.1.4 Logger#WARN member


Constant variable for Warning log level.
It contains "WARN" string.

Syntax
<static, constant> Logger#WARN : String

Example
sap.Logger.setLogLevel(sap.Logger.WARN);

Source
logger.js, line 335.
Parent topic: Logger namespace

1.9.4.5.1.5 debug( message, [tag], [successCallback],


[errorCallback] ) method
Add a debug message to the log.
This function logs messages with the 'DEBUG' log level.

Syntax
<static> debug ( message, [tag], [successCallback], [errorCallback] )

Parameters
Name Type Argument Description

PUBLIC Page 134 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.
Name Type Argument Description

<message> String Log message to be logged.

<tag> String (optional) Tag value added to the log entry used to
indicate the source of the message (for
example, SMP_LOGGER,
SMP_AUTHPROXY).

<successCallback> function (optional) Callback function called when the message


has been successfully added to the log.No
object will be passed to success callback.

<errorCallback> function (optional) Callback function called when an error


occurs while adding the message to the
log.Since Kapsel Logger native code will
always call the success callback function,
the errorCallback function will be executed
by Cordova if an error or exception occurs
while making the call to the plugin.

Example
sap.Logger.debug("debug message", "DEBUG_TAG");

Source
logger.js, line 84.
Parent topic: Logger namespace

PUBLIC Page 135 of 135


© 2014 SAP SE or an SAP affiliate company. All rights reserved.

You might also like