Show TOC

LogonController.jsLocate this document in the navigation structure

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 appDelegate;
19           var currentConfigIndex =0;
20      
21           var loadConfiguration = function (appDelegateObj, contextObj){
22              console.log("start loadConfiguration");
23              appDelegate = appDelegateObj;
24              var context = contextObj;
25              if (context == null){
26                 context = {};
27              }
28             if (context.operation == null){
29                 context.operation={};
30             }
31      	   if (context.operation.configSources == null){
32      		  context.operation.configSources =  ["saved", "appConfig.js", "mdm", /*"afaria", */"user"]; //mobilePlace
33      	   }
34             
35              if (!context.operation.logonView){
36                  context.operation.logonView = sap.logon.IabUi;
37              }
38      
39             if (context.appConfig == null){
40                     context.appConfig = {};
41             }
42      		//if appid is null, get the app bundle id
43      		//if logonview is null, set to default sap.logon.IabUi or the new sap.logon.Iab
44             
45             if (context.smpConfig == null){
46                     context.smpConfig = {};
47             }
48              
49             getAppConfig.call(this, context);
50          };
51          
52          var injectScript = function(url, onload, onerror) {
53              var script = document.createElement("script");
54              // onload fires even when script fails loads with an error.
55              script.onload = onload;
56              script.onerror = onerror || onload;
57              script.src = url;
58              document.head.appendChild(script);
59          };
60          
61          var injectConfigScript = function(pathPrefix, callback, context) {
62              var jsPath = 'appConfig.js';
63              if (context.operation.data && context.operation.data.length > 0){
64                  jsPath = context.operation.data;
65              }
66              var pluginPath = pathPrefix + jsPath;
67              injectScript(pluginPath,
68                  function() {
69                      callback(context);
70                  },
71                  function() {
72                      callback(context);
73                  }
74              );
75          };
76          
77          var findCordovaPath = function() {
78              var path = null;
79              var scripts = document.getElementsByTagName('script');
80              var term = 'cordova.js';
81              for (var n = scripts.length-1; n>-1; n--) {
82                  var src = scripts[n].src;
83                  if (src.indexOf(term) == (src.length - term.length)) {
84                      path = src.substring(0, src.length - term.length);
85                      break;
86                  }
87              }
88              return path;
89          };
90          
91          //get the configuration from mobile place and set it into context.operation.data,
92          //then call appdelegate.onGetAppConfig to parse the configuraiton
93          var getConfigFromMobilePlace = function(onGetConfigData, context) {
94              var email = context.operation.data;
95      				
96              var successCallback = function(result){
97                  if (result.status == 200 && result.responseText) {
98                      utils.log("got configuration from MobilePlace: " + result.responseText);
99                      try{
100                         var config = JSON.parse(result.responseText);
101                         context.operation.data = config;
102                         onGetConfigData(context);
103                     }
104                     catch(e){
105                         context.operation.logonView.showNotification("ERR_MOBILE_PLACE_CONFIG_INVALID");
106                     }
107                 } else {
108                     context.operation.logonView.showNotification("ERR_MOBILE_PLACE_CONFIG_NOT_RETRIEVED");
109                 }
110             }
111             var errorCallback = function(error){
112                 context.operation.logonView.showNotification("ERR_MOBILE_PLACE_CONFIG_NOT_RETRIEVED");
113             }
114             var appID = context.appConfig.appID;
115             
116             var mobilePlaceHost = "https://discovery.sapmobilesecure.com";
117        
118             //update mobilePlaceHost if caller sets it in provided context
119             if (context.appConfig.mobilePlaceHost != undefined){
120                 mobilePlaceHost = context.appConfig.mobilePlaceHost;
121             }
122        
123             var mobilePlaceAppID = appID;
124             if (context.appConfig.mobilePlaceAppID != undefined){
125                 mobilePlaceAppID = context.appConfig.mobilePlaceAppID;
126             }
127        
128             var getAppConfigUrl = mobilePlaceHost + "/config-api.svc/ApplicationConfigurations/getApplicationConfiguration(AppConfigID='" + mobilePlaceAppID + "',EmailAddress='" + email + "')";
129             sap.AuthProxy.sendRequest("GET",getAppConfigUrl,null,null,successCallback,errorCallback);
130     				
131         };
132                    
133     	//get the configuration from MDM. if config is available, set it into context.operation.data, and set state to run to let app
134         //delegate to handle it. Otherwise, set state to done to skip it
135         var getConfigFromMDM = function(onGetConfigData, context) {
136            
137             var successCallback = function(result){
138                 if (result != null && result.length > 0) {
139                     utils.log("got configuration from MDM: " + result);
140                     try{
141                         var config = JSON.parse(result);
142                         context.operation.data = config;
143                         onGetConfigData(context);
144                     }
145                     catch(e){
146                         //design time error
147                         alert("Invalid MDM configuration");
148                         context.operation.currentConfigState =" done";
149                         onGetConfigData(context);
150                     }
151                 } else {
152                    //MDM config not available
153                    context.operation.currentConfigState = "done";
154                    onGetConfigData(context);
155                 }
156             }
157             var errorCallback = function(error){
158                 alert("Fail to retrieve MDM configuration");
159                 context.operation.currentConfigState = "done";
160                 onGetConfigData(context);
161             }
162             sap.logon.Core.getMDMConfiguration(successCallback,errorCallback);
163         };																						 
164     																							 
165         var getAppConfig = function(context){
166             console.log("LogonController getAppConfig, currentConfigIndex=" +  context.operation.currentConfigIndex + ", currentConfigType="+ context.operation.currentConfigType +", currentConfigState="+ context.operation.currentConfigState );
167             
168             if (context.operation.currentConfigState =="complete" || context.operation.currentConfigIndex == context.operation.configSources.length && context.operation.configState == "done"){
169                     startLogonInit(context);
170             }
171             else if( context.operation.currentConfigIndex == null){
172                 if (context.operation.configSources.length > 0){
173                     context.operation.currentConfigIndex = 0;
174                     context.operation.currentConfigState = "begin";
175                 }
176                 else{
177                     startLogonInit(context);
178                 }
179             }
180             else if (context.operation.currentConfigState == "done"){
181                    ++context.operation.currentConfigIndex;
182                    //as mdm is only supported by ios, so it should be skipped for other clients
183                    if (context.operation.configSources[context.operation.currentConfigIndex] == "mdm" &&
184                       device.platform.toLowerCase() != "ios"){
185                          ++context.operation.currentConfigIndex;
186                       }
187                    context.operation.currentConfigState = "begin";
188             }
189     
190         
191            if (context.operation.currentConfigState == "begin"){
192                 if (appDelegate && appDelegate.onGetAppConfig){
193                          appDelegate.onGetAppConfig(context, getAppConfig, appDelegate.onRegistrationError);
194                          return;
195                 }
196                 else{
197                     context.operation.currentConfigState == "run";
198                 }
199            }
200            
201            if (context.operation.currentConfigState == "run"){
202                 //if configType is avilable, use it, otherwise use, context.operation.configSources[context.operation.currentConfigIndex] to get the config type
203                 var configType = context.operation.currentConfigType;
204                 if (!configType){
205                     configType = context.operation.configSources[context.operation.currentConfigIndex];
206                 }
207                 if (configType == "saved"){
208                     //try to load saved configuration first, the saved configuration will be available if application is already registered
209                     onGetConfigData(context);
210                     return;
211                 }
212                 else if (configType == "appConfig.js"){
213                     //load the js module
214                     var pathPrefix = findCordovaPath();
215                     if (pathPrefix === null) {
216                         console.log('Could not find cordova.js script tag. App initialization may fail.');
217                         pathPrefix = '';
218                     }
219                     injectConfigScript(pathPrefix, onGetConfigData, context);
220                     
221                 }
222                 else if (configType == "mdm"){
223                     getConfigFromMDM(onGetConfigData, context);
224                 }/*
225                 else if (configType == "afaria"){
226                     //TODO: read the config data from NSUserDefault MDM key. For now, just move to next config source
227                     onGetConfigData(context);
228                 }
229                */ else if (configType == "user"){
230                     //show one or more screens to get user input and set the input value to context object.
231                    
232                     //before showing the screen, the appdelegate will be called with currentScreenState of "begin", appdelegate can
233                     //choose to skip the screen by changing the state to "done".
234                    
235                     //if appdelegate does not skip it, the screen state will be changed to "show", and the jsview will be shown in
236                     //the inappbrowser, after user submit the data, the screen's onsubmit handler will set the screen state to "done"
237                     //and call the appDelegate.onSubmitScreen method.
238                    
239                     //the appdelegate will validate the input, if the validation fails, it can show the screen again by calling
240                     //showScreen and setting the state to "show". If the input is valid, it can logonController's onGetConfigData with
241                     //config state to "complete" to start the registration. If the input is valid but incomplete, it should se config
242                     //state to "done" to let onGetConfigData to move to the next config source.
243                    
244                     //The config data are passed to appdelegate at context.operation.data
245                     context.operation.currentScreenID = "enterFioriConfiguration";
246                     context.operation.currentScreenState = "begin";
247                     context.operation.currentScreenEventHander = {
248                     	onsubmit: function(data){
249                             //once user submits the screen data, change the screen state to done to let appdelegate to handle the data
250                             context.operation.currentScreenState = "done";
251                             showScreen(context, data);
252     
253                         }
254                     };
255                     showScreen(context, {});
256       
257                 }
258                 else if (configType == "mobilePlace"){
259                     getConfigFromMobilePlace(onGetConfigData, context);
260                 }
261                 else{
262                     connsole.log("unknown config type: " + configType);
263                 }
264                          
265             }
266            
267         };
268         
269         //show the screen in iab to get user input, two parameters are used as we do not want to merge data into context before validation
270         var showScreen = function(context, screenContext){
271             //screen is submitted by user when state is set to "done" by onsubmit handler, the screen data is already in context, so if appdelegate provides the onSubmitScreen method, then let it handle it.
272             //otherwise, call onGetConfigData to let logoncontroller onGetConfigData to handle it
273             if (context.operation.currentScreenState == "done"){
274                  if (appDelegate && appDelegate.onSubmitScreen){
275                     //if the configuration is valid, app delegate can call onGetConfigData to move to next config source.
276                     //if the configuration is invalid, app delegate can show the status or show an notification on iab
277                     appDelegate.onSubmitScreen(context, screenContext, onGetConfigData, showScreen, context.operation.logonView.showNotification);
278                     return;
279                 }
280                 else{
281                         context.operation.data = screenContext;
282                         onGetConfigData(context);
283                 }
284             }
285             
286             if (context.operation.currentScreenState == "begin"){
287                 if (appDelegate && appDelegate.onShowScreen){
288                     appDelegate.onShowScreen(context, screenContext, showScreen, appDelegate.onRegistrationError);
289                     return;
290                 }
291                 else{
292                     context.operation.currentScreenState = "show";
293                 }
294             }
295            
296             //if screen state is set to "show", then let logonview to display it
297             if (context.operation.currentScreenState == "show"){
298                 context.operation.logonView.showScreen(context.operation.currentScreenID, context.operation.currentScreenEventHander, screenContext);
299             }
300     
301         }
302         
303         var onGetConfigData = function(context){
304            if ( appDelegate && appDelegate.onGetAppConfig){
305                //client callback will continue the process by calling getAppConfig again
306                appDelegate.onGetAppConfig(context, getAppConfig, appDelegate.onRegistrationError);
307             }
308             else{
309                 //no client delegate, just call getAppConfig here to continue the load config process
310                setTimeout(function (){
311                     context.operation.currentConfigState == "done"; //move to next config source
312                     getAppConfig(context);
313                  }, 0);
314             }
315     
316         };
317         
318         var startLogonInit = function(context){
319          
320             //The appConfig has finished, start smp init. If context has the required property then use it, otherwise give the default value
321             if (context.appConfig.isForSMP){
322                 sap.Logon.init(appDelegate.onRegistrationSuccess, appDelegate.onRegistratioinError, context.appConfig.appID, context.smpConfig, context.operation.logonView, context.appConfig.x509CertProvider);
323             }
324             else{
325                if (context.appConfig.passcodePolicy !== undefined ) {
326                    context.smpConfig.policyContext = context.appConfig.passcodePolicy;
327                }
328                
329                sap.Logon.initPasscodeManager(appDelegate.onRegistrationSuccess, appDelegate.onRegistrationError, context.appConfig.appID, context.operation.logonView, context.appConfig.passcodePolicy, context.smpConfig);
330             }
331         };
332                    
333         var getSAMLConfig = function(inputContext){
334                    
335             if (inputContext != null && inputContext.auth != null && inputContext.auth != null && inputContext.auth.length >0 ){
336                 for (var i=0; i<inputContext.auth.length; i++){
337                    if (inputContext.auth[i]["type"] == "saml2.web.post"){
338                        //convert relative path to absolute path
339                        if (inputContext.auth[i]["config"]["saml2.web.post.finish.endpoint.uri"].substring(0, 4).toLowerCase()!="http"){
340                            var path = 'http';
341                            if (inputContext.https){
342                               path = 'https';
343                            }
344                            inputContext.auth[i]["config"]["saml2.web.post.finish.endpoint.uri"] = path+'://'+inputContext.serverHost+':'+inputContext.serverPort+inputContext.auth[i]["config"]["saml2.web.post.finish.endpoint.uri"];
345                            
346                        }
347                     return inputContext.auth[i];
348                     }
349                 }
350             }
351             return null;
352         }
353     
354                    
355     	var passcodePolicyAttributeNames = [
356     										"minUniqueChars",
357     										"hasLowerCaseLetters",
358     										"hasSpecialLetters",
359     										"hasUpperCaseLetters",
360     										"minLength",
361     										"retryLimit",
362     										"lockTimeout",
363     										"hasDigits",
364     										"defaultAllowed",
365     										"expirationDays"
366     										];
367         
368         var init = function (successCallback, errorCallback, applicationId, context, customView, credentialProviderID) {
369         
370             normalizeResourcePath(context);
371       
372             document.addEventListener("resume", 
373                 function(){
374                     resume(
375                         function() { fireEvent('onSapResumeSuccess', arguments);},
376                         function() { fireEvent('onSapResumeError', arguments);}                    
377                     );
378                 },
379                 false);
380     
381             // The success callback used for the call to _oLogonCore.initLogon(...)
382             var initSuccess = function(certificateSetToLogonCore){
383                 utils.log('LogonController: LogonCore successfully initialized.');
384     			
385                 _credentialProviderCertificateAvailable = certificateSetToLogonCore;
386     			
387                 // Now that Logon is initialized, registerOrUnlock is automatically called.
388                 registerOrUnlock(function(context) {
389                     var isDefault = function(port)
390                     {
391                         return port === 80 || port === 443;
392                     }
393                     
394                     var url = (context.registrationContext.https ? "https" : "http") + "://" 
395                         + context.registrationContext.serverHost 
396                         + (isDefault(context.registrationContext.serverPort) ? "" : (":" + context.registrationContext.serverPort))
397                         + "/";
398                     
399                     sap.AuthProxy.addLogonCookiesToWebview(function() {
400                         successCallback(context);
401                     }, errorCallback, url);
402                 },
403                 errorCallback,
404                 {forceSAMLAuth: true} );
405             }
406                    
407             var initError = function(error){
408                 // If a parameter describing the error is given, pass it along.
409                 // Otherwise, construct something to call the error callback with.
410                 if( error ) {
411                     errorCallback( error );
412                 } else {
413                     errorCallback( utils.Error('ERR_INIT_FAILED') );
414                 }
415             }
416                    
417             var getCertificateProviderConfig = function(inputContext){
418                    
419                 if (inputContext != null && inputContext.auth != null && inputContext.auth != null && inputContext.auth.length >0 ){
420                    for (var i=0; i<inputContext.auth.length; i++){
421                        if (inputContext.auth[i]["type"] == "certificate.sdkprovider"){
422                             return inputContext.auth[i];
423                        }
424                    }
425                 }
426                 return null;
427             }
428             
429     		utils.log('LogonController.init enter');
430     		utils.log(applicationId);
431     		module.exports.applicationId = applicationId;
432     			   
433     		// Make note of the context given (if any)
434     		if( context ){
435     			_providedContext = context;
436     		}
437                    
438     		_oLogonView = customView;
439     		if (!_oLogonView) {
440     			_oLogonView = sap.logon.IabUi;
441     		}
442     
443             flowqueue = new FlowRunnerQueue();
444     
445     		//coLogonCore.cordova.require("com.sap.mp.cordova.plugins.logon.LogonCore");
446             _oLogonCore = sap.logon.Core;
447           
448             _credentialProviderID =credentialProviderID;
449             _bIsWebRegistration = false;
450                 
451     		// We need to get the Mobile Place configuration BEFORE calling init.  This is
452     		// because if the configuration is set to use a client certificate, we need to
453     		// set that before calling init (because that's the only way Logon Core will
454     		// notice it properly).
455             if (_providedContext && _providedContext.mobilePlace) {
456     			function onEnterEmailSubmit(context){
457     				utils.logJSON(context, 'logon.onEnterEmailSubmit');
458     				var email = context.email;
459     				// A very basic regex that does minimal validation of the email.
460     				var emailRegex = /.+@.+/;
461     				if (emailRegex.test(email)) {
462     					var successCallback = function(result){
463     						if (result.status == 200 && result.responseText) {
464     							utils.log("got configuration from MobilePlace: " + result.responseText);
465     							var configFromMobilePlace = {};
466     							var config = JSON.parse(result.responseText);
467     							if (config.host) {
468     								configFromMobilePlace.serverHost = config.host;
469     							}
470     							if (config.port) {
471     								configFromMobilePlace.serverPort = config.port;
472     							}
473     							if (config.protocol) {
474     								if (config.protocol.toLowerCase() == "http"){
475     									configFromMobilePlace.https = false;
476     								} else {
477     									configFromMobilePlace.https = true;
478     								}
479     							}
480     							if (config.auth) {
481     								configFromMobilePlace.auth = config.auth;
482                                 }
483     							// If the host, port and protocol are set, then the config is valid.
484     							// There are other optional properties that might also be set.
485     							if (config.host && config.port && config.protocol) {
486     															
487     								var initSuccessMobilePlace = function(certificateSetToLogonCore){
488     									_oLogonCore.skipClientHub(function(){initSuccess(certificateSetToLogonCore);}, function(error){utils.logJSON(error,"")});
489     								}
490                                     // Merge the configFromMobilePlace into the _providedContext object.
491                                     // _providedContext will later be merged into the registration context
492                                     // before the registration is started.
493                                     mergeSettingsIntoRegistrationContext(configFromMobilePlace, _providedContext);
494     								
495                                    if (getCertificateProviderConfig(config) != null){
496                                         _credentialProviderID = getCertificateProviderConfig(config)['config']['certificate.sdkprovider.*'];
497     									var successOrError = function(){
498     										_oLogonCore.initLogon(initSuccessMobilePlace, initError, applicationId, _credentialProviderID);
499     									}
500     									_oLogonCore.setUserCreationPolicy(successOrError, successOrError, "certificate", applicationId, _providedContext );
501     								} else {
502     									_oLogonCore.initLogon(initSuccessMobilePlace, initError, applicationId, _credentialProviderID);
503     								}
504     				
505     							} else {
506     								_oLogonView.showNotification("ERR_MOBILE_PLACE_CONFIG_INVALID");
507     							}
508     						} else {
509     							_oLogonView.showNotification("ERR_MOBILE_PLACE_CONFIG_NOT_RETRIEVED");
510     						}
511     					}
512     					var errorCallback = function(error){
513     							_oLogonView.showNotification("ERR_MOBILE_PLACE_CONFIG_NOT_RETRIEVED");
514     					}
515     					var appID = module.exports.applicationId;
516     					
517                         var mobilePlaceHost = "https://discovery.sapmobilesecure.com";
518                    
519                         //update mobilePlaceHost if caller sets it in provided context
520                         if (_providedContext.mobilePlaceHost != undefined){
521                             mobilePlaceHost = _providedContext.mobilePlaceHost;
522                         }
523                    
524                         var mobilePlaceAppID = appID;
525                         if (_providedContext.mobilePlaceAppID != undefined){
526                             mobilePlaceAppID = _providedContext.mobilePlaceAppID;
527                         }
528                    
529                         //if mobile place app version is provided and the value is empty string,
530                         //then do not append ':' after mobilePlaceHost,
531                         //if mobile place App version is null or undefined, then set it to default value 1.0
532                         var mobilePlaceAppVersion = "";
533                         if (_providedContext.mobilePlaceAppVersion != undefined){
534                             if (_providedContext.mobilePlaceAppVersion != ""){
535                                 mobilePlaceAppVersion = ":" + _providedContext.mobilePlaceAppVersion;
536                             }
537                         }
538                         else{
539                             mobilePlaceAppVersion = ":1.0";
540                         }
541                    
542     					var getAppConfigUrl = mobilePlaceHost + "/config-api.svc/ApplicationConfigurations/getApplicationConfiguration(AppConfigID='" + mobilePlaceAppID + mobilePlaceAppVersion + "',EmailAddress='" + email + "')";
543     					sap.AuthProxy.sendRequest("GET",getAppConfigUrl,null,null,successCallback,errorCallback);
544     				} else {
545     					_oLogonView.showNotification("ERR_INVALID_EMAIL");
546     				}
547     			}
548     			
549     			// We need to check whether this app is already registered.  If it is
550     			// then we just call initLogon normally.  If not, then we have to get
551     			// the configuration from Mobile Place.
552     			var isRegisteredCallback = function(result) {
553     				if (result) {
554     					_oLogonCore.initLogon(initSuccess, initError, applicationId, credentialProviderID);
555     				} else {
556     					_oLogonView.showScreen('SCR_ENTER_EMAIL',{
557     						onsubmit: onEnterEmailSubmit,
558     						oncancel: function(error) {
559     							_oLogonView.close();
560     							initError(error);
561     						}
562     					},_providedContext);
563     				}
564     			}
565     			_oLogonCore.isRegistered(isRegisteredCallback, initError, applicationId);
566             }
567             else {
568                 if ( credentialProviderID ){
569                    var callbackMethod = function(){
570                         _oLogonCore.initLogon(initSuccess, initError, applicationId, credentialProviderID);
571                    }
572                    
573                    var isRegisteredCallback = function(result) {
574                        if (result) {
575                             _oLogonCore.initLogon(initSuccess, initError, applicationId, credentialProviderID);
576                        }
577                        else {
578                             _oLogonCore.setUserCreationPolicy(callbackMethod, callbackMethod, "certificate", applicationId, _providedContext );
579                        }
580                    }
581                    _oLogonCore.isRegistered(isRegisteredCallback, initError, applicationId);
582                    
583                 }
584                 else{
585                    _oLogonCore.initLogon(initSuccess, initError, applicationId);
586                 }
587     
588     		}
589                 
590             //update exports definition
591             module.exports.core = _oLogonCore;
592         }
593         
594         var initPasscodeManager = function (successCallback, errorCallback, applicationId, customView, passcodePolicy, context ) {
595     
596             if (verifyPasscodePolicy(passcodePolicy)) {
597                 errorCallback(errorWithDomainCodeDescription("MAFLogon","7","Unrecognized attribute name: " + verifyPasscodePolicy(passcodePolicy) + " in the given passcode policy."));
598                 return;
599             }
600     
601             document.addEventListener("resume", 
602                 function(){
603                     resume(
604                         function() { fireEvent('onSapResumeSuccess', arguments);},
605                         function() { fireEvent('onSapResumeError', arguments);}                    
606                     );
607                 },
608                 false);
609     
610             // The success callback used for the call to _oLogonCore.initLogon(...)
611             var initSuccess = function(certificateSetToLogonCore){
612                 utils.log('LogonController: LogonCore successfully initialized.');
613     			
614                 _credentialProviderCertificateAvailable = certificateSetToLogonCore;
615     			
616                 // Now that Logon is initialized, registerOrUnlock is automatically called.
617                 registerOrUnlock( successCallback, errorCallback );
618             }
619                    
620             var initError = function(error){
621                 // If a parameter describing the error is given, pass it along.
622                 // Otherwise, construct something to call the error callback with.
623                 if( error ) {
624                     errorCallback( error );
625                 } else {
626                     errorCallback( utils.Error('ERR_INIT_FAILED') );
627                 }
628             }
629             
630             
631     		utils.log('LogonController.init enter');
632     		utils.log(applicationId);
633     		module.exports.applicationId = applicationId;
634     	              
635     		_oLogonView = customView;
636     		if (!_oLogonView) {
637     			_oLogonView = sap.logon.IabUi;
638     		}
639     
640           flowqueue = new FlowRunnerQueue();
641     
642     		//coLogonCore.cordova.require("com.sap.mp.cordova.plugins.logon.LogonCore");
643           _oLogonCore = sap.logon.Core;
644           
645           if (passcodePolicy){
646               _providedPasscodePolicyContext = passcodePolicy;
647           }
648           
649           // Make note of the context given (if any)
650           if( context ){
651                 _providedContext = context;
652           }
653           
654           _bIsWebRegistration = true;
655     	  
656           _oLogonCore.initLogon(initSuccess, initError, applicationId, null, _bIsWebRegistration );
657                 
658           //update exports definition
659           module.exports.core = _oLogonCore;
660         }
661             
662         var fireEvent = function (eventId, args) {
663             if (typeof eventId === 'string') {
664                 //var event = document.createEvent('Events');
665                 //event.initEvent(eventId, false, false);
666                 
667                 if (!window.CustomEvent) {
668                     window.CustomEvent = function(type, eventInitDict) {
669                         var newEvent = document.createEvent('CustomEvent');
670                         newEvent.initCustomEvent(
671                             type,
672                             !!(eventInitDict && eventInitDict.bubbles),
673                             !!(eventInitDict && eventInitDict.cancelable),
674                             (eventInitDict ? eventInitDict.detail : null));
675                         return newEvent;
676                     };
677                 }
678                 
679                 /* Windows8 changes */
680                 if (cordova.require("cordova/platform").id.indexOf("windows") === 0) {
681                     WinJS.Application.queueEvent({
682                         type: eventId,
683                         detail: { 'id': eventId, 'args': args }
684                     });
685                 }
686                 else {
687                     var event = new CustomEvent(eventId, { 'detail': { 'id': eventId, 'args': args } });
688                     setTimeout(function () {
689                         document.dispatchEvent(event);
690                     }, 0);
691                 }
692             } else {
693                 throw 'Invalid eventId: ' + JSON.stringify(event);
694             }
695         }
696                 
697        var showCertificateProviderScreen = function(viewIDSettings){
698           if (!_registrationEventsForCredentialProvider) {
699              // This case will only occur if showCertificateProviderScreen has been called
700              // without refreshCertificate being called first.  This should only happen during
701              // logon init on Android.  Since the call did not originate in the javascript, we
702              // don't have to worry about many of the callbacks.  Either we'll call
703              // setParametersForProvider with the context, or we'll call it with "cancelled".
704              _registrationEventsForCredentialProvider = {
705                 onsubmit: function(context){
706                    utils.logJSON(context, 'logonCore.setCertificateProviderCredential');
707                       _oLogonCore.setParametersForProvider(function(){},function(){},context);
708                 },
709                 oncancel: function(error){
710                    _oLogonView.close();
711                    _credentialProviderCertificateAvailable = true;
712     			   _oLogonCore.setParametersForProvider(function(){},function(){},"cancelled");
713                 },
714                 onerror: function(error){
715                    _oLogonView.showNotification(error.errorDomain + "@" + error.errorCode );
716                 }
717              };
718           }
719     
720              setTimeout(
721                 function(){
722                    var context = JSON.parse(viewIDSettings);
723                    _oLogonView.showScreen("SCR_GET_CERTIFICATE_PROVIDER_PARAMETER", _registrationEventsForCredentialProvider, context);
724                 }, 1);
725        }
726     
727        var refreshCertificate = function(successCallback, errorCallback){
728        
729              if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
730                     utils.log('FlowRunner.run MAFLogon is not initialized');
731                 	errorCallback(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
732                 	return;
733              }
734              
735              if (_bIsWebRegistration){
736                     utils.log('refreshCertificate is not supported for passcode manager only initialization');
737                     errorCallback(errorWithDomainCodeDescription("MAFLogon","6","refreshCertificate is not supported for PasscodeManager only initialization"));
738                     return;
739              }
740              
741              if (!_credentialProviderID) {
742                     utils.log('FlowRunner.run credential provider is not provided');
743                 	errorCallback(errorWithDomainCodeDescription("MAFLogon","4","credential provider is not provided"));
744                 	return;
745              }
746     
747              _registrationEventsForCredentialProvider = {
748                       onsubmit: function(context){
749                          utils.logJSON(context, 'logonCore.setCertificateProviderCredential');
750                          _oLogonCore.setParametersForProvider(
751                              function(){
752                                  console.log("setParameterForProvider success callback");
753                              },//only for debug
754                              errorCallback,
755                              context);
756                       },
757                       oncancel: function(error){
758                             _oLogonView.close();
759                             _credentialProviderCertificateAvailable = true;
760                       },
761                       onerror: function(error){
762                             _oLogonView.showNotification(error.errorDomain + "@" + error.errorCode );
763                       }
764              };
765     
766              _oLogonCore.getCertificateFromProvider(
767                 function(success){
768                    _oLogonView.close();
769                    _credentialProviderCertificateAvailable = true;
770                    successCallback(success);
771                 },
772                 function(error){
773                    //if the error is user cancel, then close the window, otherwise keeping the screen to allow user corrects the error
774                    _oLogonView.showNotification(error.errorDomain + "@" + error.errorCode );
775                    //_oLogonView.close();
776                    _credentialProviderCertificateAvailable = false;
777                    //errorCallback(error);
778                 },
779                 true
780              );
781        }
782                    
783         //flowcontext is used to store information about a particular flow, such as whehter it is started from
784         //init method or unlock method.
785         //flowcontext is optional, but if it is passed by caller, it should have the below properties
786         //caller: id to identify the caller who start the current flow, this is only for debug purpose
787         //forceSAMLAuth: force SAML authentication even if datavault is already unlocked. Usually, the SAML
788         //               auth is only performed when data vaule is actually changed from lock to unlock state, 
789         //               however, if passcode is disablled, then  datavaule it already unlocked.
790         //               In this case, caller can set this flag to force to perform SAML auth.
791         //               logon.init sets this flag to fix the issue of. Refer to CSS Bug 1453032 2014 "No SAML challenge if passcode is disabled"
792     
793         var FlowRunner = function(callbacks, pLogonView, pLogonCore, flowClass, flowContext) {
794             
795             var onFlowSuccess;
796             var onFlowError;
797             var onFlowCancel;
798                    
799             var logonView;
800             var logonCore;
801             var flow;   
802             
803             var onsuccess = callbacks.onsuccess;
804             var onerror = callbacks.onerror;    
805                 
806             if (!flowContext){
807                 flowContext = {};
808             }
809                 
810                 
811             logonView = pLogonView;
812             logonCore = pLogonCore;
813                    
814             onFlowSuccess = function onFlowSuccess() {
815                 utils.logJSON('onFlowSuccess');
816                 logonView.close();
817                 onsuccess.apply(this, arguments);
818             }
819     
820             onFlowError = function onFlowError() {
821                 utils.logJSON('onFlowError');
822                 logonView.close();
823                 onerror.apply(this, arguments);
824             }
825                    
826             onFlowCancel = function onFlowCancel(){
827                 utils.logJSON('onFlowCancel');
828                 //logonView.close();
829                 onFlowError(new utils.Error('ERR_USER_CANCELLED'));
830             }
831                    
832             var handleCoreStateOnly = function(currentState){
833                 utils.logJSON('handleCoreStateOnly called: '+ flow.flowID);
834                 handleCoreResult(null, currentState);
835             }
836             
837             var handleCoreResult = function (currentContext, currentState) {
838                 if (typeof currentContext === undefined) currentContext = null;
839                 
840                 //workaround for defaultPasscodeAllowed. If caller provides the context, use it, otherwise using current context. 
841                 if (currentState && !currentState.hasOwnProperty("defaultPasscodeAllowed")) {
842                    if (_providedPasscodePolicyContext && _providedPasscodePolicyContext.hasOwnProperty("defaultAllowed")) {
843                        if (_providedPasscodePolicyContext.defaultAllowed === 'true'){
844                             currentState.defaultPasscodeAllowed = true;
845                        }
846                        else if (_providedPasscodePolicyContext.defaultAllowed === 'false'){
847                        currentState.defaultPasscodeAllowed = false;
848                        }
849                        else{
850                             currentState.defaultPasscodeAllowed = _providedPasscodePolicyContext.defaultAllowed;
851                        }
852                    }
853                    else if (currentContext && currentContext.policyContext && currentContext.policyContext.hasOwnProperty("defaultAllowed")){
854                         if (currentContext.policyContext.defaultAllowed === 'true'){
855                             currentState.defaultPasscodeAllowed = true;
856                         }
857                         else if (currentContext.policyContext.defaultAllowed === 'false'){
858                             currentState.defaultPasscodeAllowed = false;
859                         }
860                         else{
861                             currentState.defaultPasscodeAllowed = currentContext.policyContext.defaultAllowed;
862                         }
863                    }
864                    else {
865                         currentState.defaultPasscodeAllowed = true;
866                    }
867                 }
868     
869                 utils.logJSON(currentContext, 'handleCoreResult currentContext');
870                 utils.logJSON(currentState, 'handleCoreResult currentState');
871     
872                 
873                 utils.logJSON(flow.name);
874                 var matchFound = false;
875                 var rules = flow.stateTransitions;
876                 
877                 
878                 ruleMatching:
879                 for (key in rules){
880                 
881                     var rule = flow.stateTransitions[key];
882                     utils.logJSON(rule, rule.id);
883                    
884                     if (typeof rule.condition === 'undefined') {
885                     	throw 'undefined condition in state transition rule';
886                     }
887                     
888                     
889                     if (rule.condition.state === null) {
890                     	if (currentState)
891                     	{
892                     		continue ruleMatching; // non-null state (and rule) mismatch
893                     	}
894                     	//else {
895                     	//	// match: 
896                     	//	// rule.condition.state === null &&
897                     	//	// (typeof currentState === 'undefined') // null or undefined
898                     	//}
899                     }
900                     else if (rule.condition.state !== 'undefined' && currentState){
901                    
902                     	stateMatching:
903     		            for (field in rule.condition.state) {
904     		             
905     		                if (rule.condition.state[field] === currentState[field]) 
906     		                {
907     		                    utils.log('state field matching ' + field);
908     		                    continue stateMatching; // state field match 
909     		                }
910     		                else {
911     		                    utils.log('state field mismatching ' + field);
912     		                    continue ruleMatching; // state field (and rule) mismatch
913     		                };
914     		            }
915                     }
916                    
917                     if (rule.condition.context === null) {
918                         if (currentContext)
919                     	{
920                             continue ruleMatching; // non-null context (and rule) mismatch
921                     	}
922                     	//else {
923                     	//	// match: 
924                     	//	// rule.condition.context === null &&
925                     	//	// (typeof currentContext === 'undefined') // null or undefined
926                     	//}
927                     }
928                     else if (rule.condition.context !== 'undefined' && currentContext){
929                    
930     	                contextMatching:
931     	                for (field in rule.condition.context) {
932     	                    if (rule.condition.context[field] === currentContext[field])
933     	                    {
934     	                        utils.log('context field matching ' + field);
935     	                        continue contextMatching;  // context field match 
936     	                    }
937     	                    else {
938     	                        utils.log('context field mismatching ' + field);
939     	                        continue ruleMatching;  // context field (and rule) mismatch
940     	                    };
941     	                }
942                     }
943                    
944                    if (rule.condition.method != null ) {
945                       if (!rule.condition.method())
946                       {
947                           continue ruleMatching; // non-null context (and rule) mismatch
948                       }
949                    }
950     
951                    
952                     utils.log('match found: ' + rule.id);
953                     utils.logJSON(rule, 'rule');
954                    
955                     //handle post match action
956                     var action = rule.action;
957                     if (flow.postMatchAction) {
958                         action = flow.postMatchAction(rule);
959                         if (action== null){
960                             return;
961                         }
962                     }
963                    
964                     if (typeof action === 'function') {
965                         action(currentContext, currentState);
966                     }
967                     else if (typeof action === 'string') {
968                         // the action is a screenId
969                         var screenId = action;
970                         utils.log('handleCoreResult: ' + screenId);
971                         utils.logKeys(flow.screenEvents[screenId]);
972     					if(!currentContext){
973                             currentContext = {};
974                         }
975     					
976                         if( !currentContext.registrationContext && _providedContext ){
977     						// The current registrationContext is null, and we have been given a context when initialized,
978     						// so use the one we were given.
979     						currentContext.registrationContext = _providedContext;
980                         } else if (currentContext.registrationContext && _providedContext && !currentContext.registrationReadOnly && !(currentState.stateAfaria=='initializationSuccessful')){
981                             for (key in _providedContext) {
982                                 //if (!currentContext.registrationContext[key]){
983                                     currentContext.registrationContext[key] = _providedContext[key];
984                                 //}
985                             }
986                         }
987                    
988                         logonView.showScreen(screenId, flow.screenEvents[screenId], currentContext);
989                         
990                     }
991                     else {
992                         onFlowError(new utils.Error('ERR_INVALID_ACTION'));
993                     }
994                    
995                     matchFound = true;
996                     break ruleMatching;
997                 }
998                 
999                 if (!matchFound) {
1000                    onFlowError(new utils.Error('ERR_INVALID_STATE'));
1001                }
1002            }
1003            
1004            flow = new flowClass(logonCore, logonView, handleCoreResult, onFlowSuccess, onFlowError, onFlowCancel);
1005            
1006            flow.flowID = FlowRunner.currentID++;  //unique id
1007            flow.forceSAMLAuth = flowContext.forceSAMLAuth;
1008            this.flow = flow;
1009            
1010            console.log("create new flow with id: " + flow.flowID + ", "+  flow.caller);
1011    
1012            this.run = function() {
1013                utils.log('FlowRunner.run '  + flowClass.name);
1014                utils.logKeys(flow , 'new flow ');
1015                logonCore.getState(handleCoreStateOnly, onFlowError);
1016            }      
1017        }
1018        
1019        //static property to track flow id
1020        FlowRunner.currentID = 0;
1021            
1022        var FlowRunnerQueue = function() {
1023        	var isRunning = false;
1024        	var innerQueue = [];
1025        	
1026        	this.add = function(flowRunner) {
1027        		innerQueue.push(flowRunner);
1028        		if (isRunning == false) {
1029        			isRunning = true;
1030        			process();
1031        		}
1032        	}
1033        	
1034            this.runNextFlow = function() {
1035             	 var flowRunner = innerQueue.shift();
1036                 utils.log('FlowRunnerQueue.runNextFlow, remove flow: '+ flowRunner.flow.flowID);
1037          
1038                 if (innerQueue.length == 0) {
1039                     utils.log('FlowRunnerQueue.runNextFlow, not flow');
1040                     isRunning = false;
1041                 }
1042                 else {
1043                     process();
1044                 }
1045             }
1046        	
1047        	var process = function() {
1048        		if (innerQueue.length > 0) {
1049                    utils.log('FlowRunnerQueue.process, process flow: '+ innerQueue[0].flow.flowID);
1050        
1051        			var flowRunner = innerQueue[0];
1052        			flowRunner.run();
1053        		}
1054        		else {
1055                    utils.log('FlowRunnerQueue.process, not flow');
1056    
1057        			isRunning = false;
1058        		}
1059        	}
1060        }
1061    
1062        
1063            var MockFlow = function MockFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
1064            //wrapped into a function to defer evaluation of the references to flow callbacks
1065                //var flow = {};
1066                
1067                this.name = 'mockFlowBuilder';
1068                
1069                this.stateTransitions = [
1070                {
1071                   id:"m0",
1072                	condition: {
1073    	                state: {
1074    	                	secureStoreOpen: false,
1075    	                }
1076                    },
1077                    action: 'SCR_MOCKSCREEN'
1078                },
1079                {
1080                   id:"m1",
1081                	condition: {
1082    	                state: {
1083    	                	secureStoreOpen: true,
1084    	                }
1085                    },
1086                    action: 'SCR_MOCKSCREEN'
1087                },
1088                
1089                ];
1090            
1091                this.screenEvents = {
1092                    'SCR_TURN_PASSCODE_ON': {
1093                        onsubmit: onFlowSuccess,
1094                        oncancel: onFlowCancel,
1095                        onerror: onFlowError,
1096                    }
1097                };
1098                
1099                utils.log('flow constructor return');
1100                //return flow;
1101            }
1102            
1103            var RegistrationFlow = function RegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
1104            //wrapped into a function to defer evaluation of the references to flow callbacks
1105                
1106                this.name = 'registrationFlowBuilder';
1107                
1108                var registrationInProgress = false;
1109                var SAMLState = "notInit";
1110                var bNewRegistration = false;
1111                var bUnlockPerformed = false;
1112                var startRegistrationContext = null;
1113                var onCancelSSOPin = function() {
1114                	onFlowError(errorWithDomainCodeDescription("MAFLogon","0","SSO Passcode set screen was cancelled"));
1115                }
1116                
1117                var onCancelRegistration = function() {
1118                	onFlowError(errorWithDomainCodeDescription("MAFLogon","1","Registration screen was cancelled"));
1119                }
1120                
1121                // internal methods
1122                var showScreen = function(screenId) {
1123                    return function(coreContext) {
1124                        logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
1125                    }.bind(this);
1126                }.bind(this);
1127                
1128                var onUnlockSubmit = function(context){
1129                    utils.logJSON(context, 'logonCore.unlockSecureStore');
1130                    bUnlockPerformed = true;
1131                    logonCore.unlockSecureStore(onCoreResult, onUnlockError, context)
1132                }
1133                
1134                var onUnlockError = function(error) {
1135                    utils.logJSON("onUnlockError: " + JSON.stringify(error));
1136                    			
1137    				if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode && error.errorCode === "16") {
1138                        // Too many attempts --> DV deleted
1139                        logonView.showNotification("ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE")
1140                    }
1141    				else if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode && error.errorCode === "8") {
1142                        // passcode expired --> DV deleted
1143                        logonView.showNotification("ERR_PASSCODE_EXPIRED")
1144                    }
1145                    else {
1146                        logonView.showNotification("ERR_UNLOCK_FAILED");
1147                    }
1148                }
1149                
1150                var onSetAfariaCredentialError = function(error) {
1151                    utils.logJSON("onSetAfariaCredentialError: " + JSON.stringify(error));
1152                   
1153                   logonView.showNotification("ERR_SET_AFARIA_CREDENTIAL_FAILED");
1154                }
1155                
1156                var noOp = function() { }
1157                
1158                var onErrorAck = function(ack) {
1159                    if (ack.key === 'ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE') {
1160                            onFlowError(new utils.Error('ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE'));
1161                    }
1162                }
1163                
1164                var onRegistrationBackButton = function() {
1165                	if (registrationInProgress == true) {
1166                		utils.log('back button pushed, no operation is required as registration is running');
1167                	}
1168                	else {
1169                		onCancelRegistration();
1170                	}
1171                }
1172                
1173                var onUnlockVaultWithDefaultPasscode = function(){
1174                	utils.log('logonCore.unlockSecureStore - default passcode');
1175                	var unlockContext = {"unlockPasscode":null};
1176                	logonCore.unlockSecureStore(onCoreResult, onFlowError, unlockContext)
1177                }
1178                
1179                var onRegSucceeded = function(context, state) {
1180                	onCoreResult(context, state);
1181                	registrationInProgress = false;
1182                }
1183                
1184                var onRegError = function(error){
1185                	utils.logJSON(error, 'registration failed');
1186                	logonView.showNotification(getRegistrationErrorText(error));
1187                	registrationInProgress = false;
1188                   _credentialProviderCertificateAvailable = false;
1189                }
1190      
1191                var onCertificateProviderError = function(error){
1192                	utils.logJSON(error, 'CertificateProvider reports error: ' + JSON.stringify(error));
1193                	logonView.showNotification(error.errorDomain + "@" + error.errorCode );
1194                	registrationInProgress = false;
1195                   _credentialProviderCertificateAvailable = false;
1196                }
1197                
1198                var onRegSubmit = function(context){
1199                    utils.logJSON(context, 'startRegistration');
1200                    normalizeResourcePath(context);
1201                    registrationInProgress = true;
1202                    startRegistration(onRegSucceeded, onRegError, context);
1203                }
1204    
1205                var onCreatePasscodeSubmit = function(context){
1206                    utils.logJSON(context, 'logonCore.persistRegistration');
1207                    logonCore.persistRegistration(onCoreResult, onCreatePasscodeError, context);
1208                }
1209                
1210                var onCancelRegistrationError = function(error){
1211                	utils.logJSON("onCancelRegistrationError: " + JSON.stringify(error));            	
1212                	logonView.showNotification(getRegistrationCancelError(error));
1213                }
1214    
1215                var onCreatePasscodeError = function(error) {
1216                    utils.logJSON("onCreatePasscodeError: " + JSON.stringify(error));
1217                    logonView.showNotification(getSecureStoreErrorText(error));
1218                }
1219                
1220                var onSSOPasscodeSetError = function(error) {
1221                    utils.logJSON("onSSOPasscodeSetError: " + JSON.stringify(error));
1222                   logonView.showNotification(getSSOPasscodeSetErrorText(error));
1223                }
1224                
1225                var callGetContext = function(){
1226                    utils.log('logonCore.getContext');
1227                    logonCore.getContext(onCoreResult, onFlowError);
1228                }
1229                
1230                 var onFullRegistered = function()
1231                 {
1232                     utils.logJSON("onFullRegistered: " );
1233                
1234                 	var getContextSuccessCallback = function(result){
1235                 		
1236                 		if(!_hasLogonSuccessEventFired) {
1237                            fireEvent("onSapLogonSuccess", arguments);
1238     						_hasLogonSuccessEventFired = true;
1239                 		}
1240                 		
1241                 		onFlowSuccess(result);
1242                 	}
1243                     utils.log('logonCore.getContext');
1244                     logonCore.getContext(getContextSuccessCallback, onFlowError);
1245                 }
1246                
1247                var onForgotAppPasscode = function(){
1248                	utils.log('logonCore.deleteRegistration');
1249                    logonCore.deleteRegistration(function() { 
1250                        if (cordova.require("cordova/platform").id.indexOf("windows") === 0) {
1251                	        // Close the view on Windows. There is no webview state to be reset.
1252                	        logonView.close();
1253                            // reload the app.
1254                	        window.location.reload();
1255                	    }
1256                	    else {
1257                	        logonCore.reset();
1258                	    }
1259                    }, onFlowError);
1260                }
1261    
1262                var onForgotSsoPin = function(){
1263                	utils.log('forgotSSOPin');
1264                	logonView.showNotification("ERR_FORGOT_SSO_PIN");
1265                }
1266                
1267                var onSkipSsoPin = function(){
1268                    utils.logJSON('logonCore.skipClientHub');
1269                    logonCore.skipClientHub(onCoreResult, onFlowError);
1270                }
1271                
1272                var callPersistWithDefaultPasscode = function(context){
1273                	utils.logJSON(context, 'logonCore.persistRegistration');
1274                	context.passcode = null;
1275                	logonCore.persistRegistration(
1276                            onCoreResult,
1277                            onFlowError,
1278                            context)
1279                } 
1280    			
1281    			var onGetCertificateFromProvider = function(context){
1282    			   utils.logJSON(context, 'logonCore.getCertificateFromProvider');
1283    			   _registrationEventsForCredentialProvider =  {
1284    					onsubmit: function(context){
1285    					   utils.logJSON(context, 'logonCore.setCertificateProviderCredential');
1286    					   logonCore.setParametersForProvider(
1287    						   function(){
1288    							   console.log("setParameterForProvider success callback");},//only for debug
1289    						   onCertificateProviderError,
1290    						   context);
1291    					},
1292    					oncancel: onCancelRegistration,
1293    					onerror: onFlowError
1294    				 
1295    			   };
1296    				 
1297    			   //the on success callback needs to set _credentialProviderCertificateAvailable flag to continue screen flow
1298    			   logonCore.getCertificateFromProvider(
1299    					function(){
1300    					   console.log("getCertificateFromProvider success callback called");
1301    					   _credentialProviderCertificateAvailable = true;
1302    					   onCoreResult.apply(this, arguments);
1303    					},
1304    					function(error){
1305    					   onCertificateProviderError(error);
1306    					   _credentialProviderCertificateAvailable = false;
1307    					},
1308    					false
1309    				);
1310    			}
1311                
1312                var onReadSavedContext= function(context, state){
1313                   utils.logJSON(context, 'onReadSavedContext');
1314    			  				 
1315    			   //the on success callback needs to set _credentialProviderCertificateAvailable flag to continue screen flow
1316    			   logonCore.getSecureStoreObject(
1317                       function(savedContext){
1318                            utils.logJSON(savedContext, 'onReadSavedContext');
1319    			  
1320                            //if SAML is enabled, then show SAML screen
1321                            if (savedContext ){
1322                                _providedContext = savedContext
1323                                if ( getSAMLConfig(_providedContext) == null){
1324                                    SAMLState ="notRequired";
1325                                    onCoreResult(context, state);
1326                                }
1327                                else{
1328                                    SAMLState = "required";
1329                                    onCoreResult(context, state);
1330                                }
1331                            }
1332                            else{
1333                                SAMLState = "notRequired";
1334                                onCoreResult(context, state);
1335                            }
1336                            
1337                       },
1338                       onFlowError,
1339                       "%%providedContext");
1340                   
1341                }
1342                
1343                var startRegistration = function(onSuccess, onError, context){
1344                    utils.log('startRegistration');
1345                    bNewRegistration = true;
1346                    registrationContext = context;
1347    
1348                    if ((cordova.require("cordova/platform").id.indexOf("windows") === 0) && getSAMLConfig(_providedContext) != null) {
1349                        var errorText = 'SAML Registration is not supported on the Windows 8.1 / Windows Phone 8.1 platforms. Please use a different method of registering with the SMP server.';
1350                        utils.log(errorText);
1351                        if (typeof ("Windows" !== 'undefined')) {
1352                            (new Windows.UI.Popups.MessageDialog(errorText, "Unsupported Feature")).showAsync().done();
1353                        }
1354                        var error = { 
1355                            errorDomain : "MAFLogonCoreErrorDomain",
1356                            errorCode: -1
1357                        };
1358                        onError(error);
1359                    }
1360                    else {
1361                        if (getSAMLConfig(_providedContext) == null || SAMLState == "completed") {
1362                            _oLogonCore.startRegistration(onSuccess, onError, context);
1363                        }
1364                        else {
1365                            //start SAML authentication by launching child browser with SAML url
1366                            var samlConfigPlus = getSAMLConfig(_providedContext);
1367                            samlConfigPlus.serverHost = _providedContext.serverHost;
1368                            samlConfigPlus.applicationId = module.exports.applicationId;
1369                            samlConfigPlus.serverPort = _providedContext.serverPort;
1370                            showScreen("SCR_SAML_AUTH")(samlConfigPlus);
1371                        }
1372                    }
1373                }
1374     
1375                //save SAML configuration to data value, the %%providedContext is a reserved key in data vault
1376                var onSaveContext= function(context, state){
1377                   utils.logJSON(_providedContext, 'onSaveProvidedContext');
1378    			  				 
1379    			   //the on success callback needs to set _credentialProviderCertificateAvailable flag to continue screen flow
1380    			   logonCore.setSecureStoreObject(
1381                       function(context){
1382                            utils.logJSON(_providedContext, 'onSavedContext');
1383    			  
1384                            SAMLState ="saved";
1385                            onCoreResult(context, state);
1386                            
1387                       },
1388                       onFlowError,
1389                       "%%providedContext",
1390                       _providedContext
1391                    );
1392                   
1393                }
1394    
1395                
1396                var onSAMLAuthEvent = function(event){
1397                   
1398                    var context = _providedContext;
1399                   
1400                    utils.log('SAML callback: '+ event.url + ", context: "+  JSON.stringify(context));;
1401        
1402    
1403                    if (event.url.indexOf(getSAMLConfig(context)["config"]["saml2.web.post.finish.endpoint.redirectparam"])!= -1){
1404                         //the current screen shows SMAL html, and if any error happens during registration, the inappbrowser will need
1405                         //to show the notification in inappbrowser, since SAML html does not have javsscript context to handle the notifcation
1406                         //so we need to restore the previous logon screen to handle the notification and also allow user to resume the
1407                         //registration after dismissing the notification
1408                         SAMLState = "completed";
1409                         var screenID = _oLogonView.getPreviousScreenID();
1410                         var screenContext = _oLogonView.getPreviousContext();
1411                         utils.log('SAML previous screen id: ' + screenID);
1412                 
1413                         if (screenID != null){
1414                            // skip the clearWindow call if the platform is Android.
1415                            // Android must be handled differently.
1416                            if (!(device.platform.toLowerCase().indexOf("android") >= 0)) {
1417                               _oLogonView.clearWindow(true);
1418                            }
1419                            screenContext.busy = true;
1420                            showScreen(screenID)(screenContext);
1421                         }
1422    
1423                         var continueAfterSAML = function(){
1424                             if (bNewRegistration) {
1425                                 //A particular communicator id "idMAFLogonCommunicator_SMPHTTPREST” needs to be set for saml auth, so that MAF will skip pinging the server and gets an 401 error
1426                                 registrationContext["communicatorId"] = "REST";
1427                                 startRegistration(onCoreResult, onRegError, registrationContext);
1428                             } else {
1429                                 callGetContext();
1430                             }
1431                         }
1432    
1433                         // On Android cookies need to be extracted from the webview.
1434                         if (device.platform.toLowerCase().indexOf("android") >= 0) {
1435                             // SAML authentication was done in a webview.  On Android the webview has a different cookie jar from the java.net cookie jar
1436                             // (used by AuthProxy and the conversation library), which is also different from the cookie jar used by the request library
1437                             // (used by logoncore for registration, until they switch to the conversation library).  For requests sent via those other
1438                             // means to share the SAML authentication we need to copy the SAML cookies (ie: the session cookies associated with the SAML
1439                             // authentication) to the other cookie jars.  This must be done before registration or registration will fail.
1440                             sap.AuthProxy.getSAMLCookiesFromWebview(continueAfterSAML, continueAfterSAML, event.url);
1441                         } else {
1442                             continueAfterSAML();
1443                         }
1444                    }
1445            }
1446                
1447            //this method is used to handle post action after a match found, it can change the matched rule based on additional condition.
1448            //there are several code path will lead to action of onFullRegistered, in order to support saml authentication, we need to load the
1449            //SAML configuration, we need to load the SAML configuraton before onFullRegistered is called. so that we can trigger the SAML logon
1450            //before full registration callback is called.
1451                this.postMatchAction = function(matchedRule){
1452                   if (matchedRule.action == onFullRegistered ){
1453                       utils.log('postMatchAction onFullRegistered: ' + SAMLState + ', '+ bNewRegistration +', '+ bUnlockPerformed);
1454                   
1455                       if (bNewRegistration ){
1456                            if (SAMLState != "saved"){
1457                                return onSaveContext;
1458                            }
1459                       }
1460                       else if (bUnlockPerformed || this.forceSAMLAuth) {  //no need to do saml authentication again if data vault is already unlocked when unlock method is called, unless the call is started by logon.init
1461                   
1462                           if (SAMLState == "notInit"){
1463                                return onReadSavedContext;
1464                           }
1465                           else if (SAMLState == "required"){
1466                                var samlConfigPlus = getSAMLConfig(_providedContext);
1467                                samlConfigPlus.serverHost = _providedContext.serverHost;
1468                                samlConfigPlus.applicationId = module.exports.applicationId;
1469                                samlConfigPlus.serverPort = _providedContext.serverPort;
1470                                showScreen("SCR_SAML_AUTH")(samlConfigPlus);
1471                                return null;
1472                           }
1473                        }
1474                    }
1475                    return matchedRule.action;
1476                }
1477    
1478                // exported properties
1479                this.stateTransitions = [
1480                {
1481                   id:"r0",
1482                	condition: {
1483                		state: {
1484                			secureStoreOpen: false,
1485                			status: 'fullRegistered',
1486                			defaultPasscodeUsed: true
1487                		}
1488                	},
1489                	action: onUnlockVaultWithDefaultPasscode
1490                },
1491                
1492                {
1493                   id:"r1",
1494                	condition: {
1495    	                state: {
1496    	                	secureStoreOpen: false,
1497                        	status: 'fullRegistered'
1498    	                }
1499                    },
1500                    action: 'SCR_UNLOCK'
1501                },
1502    
1503                
1504                {
1505                   id:"r2",
1506                	condition: {
1507    	                state: {
1508    	                    //secureStoreOpen: false, //TODO clarify
1509    	                    status: 'fullRegistered',
1510    	                    stateClientHub: 'availableNoSSOPin'
1511    	                }
1512                	},
1513                    action: 'SCR_SSOPIN_SET'
1514                },
1515                {
1516                   id:"r3",
1517                	condition: {
1518    	                state: {
1519    	                	status: 'new'
1520    	                },
1521    	                context: null
1522                    },
1523                    action: callGetContext
1524                },
1525                
1526                {
1527                   id:"r4",
1528                	condition: {
1529    	                state: {
1530    	                    status: 'new',
1531    	                    stateClientHub: 'availableNoSSOPin'
1532    	                }
1533                	},
1534                    action: 'SCR_SSOPIN_SET'
1535                },
1536                
1537                {
1538                   id:"r5",
1539                	condition: {
1540    	                state: {
1541    	                    status: 'new',
1542    	                    stateClientHub: 'availableInvalidSSOPin'
1543    	                }
1544                	},
1545                    action: 'SCR_SSOPIN_SET'
1546                },
1547                {
1548                   id:"r6",
1549                	condition: {
1550    	                state: {
1551    	                    status: 'new',
1552    	                    stateClientHub: 'availableValidSSOPin',
1553                            stateAfaria: 'initializationFailed',
1554    	                },
1555                		context : {
1556                			afariaRegistration: 'certificate'
1557                		}
1558                	},
1559                    action: 'SCR_ENTER_AFARIA_CREDENTIAL'
1560                },
1561                {
1562                   id:"r7",
1563                	condition: {
1564    	                state: {
1565    	                    status: 'new',
1566    	                    stateClientHub: 'availableValidSSOPin',
1567                            stateAfaria: 'credentialNeeded'
1568    	                },
1569                		context : {
1570                			afariaRegistration: 'certificate'
1571                		}
1572                	},
1573                    action: 'SCR_ENTER_AFARIA_CREDENTIAL'
1574                },
1575                {
1576                   id:"r8",
1577                	condition: {
1578    	                state: {
1579    	                    status: 'new',
1580    	                    stateClientHub: 'notAvailable',
1581                            stateAfaria: 'credentialNeeded'
1582    	                }
1583                	},
1584                    action: 'SCR_ENTER_AFARIA_CREDENTIAL'
1585                },
1586                {  //condition to get certificate from third party certificate provider
1587                    id:"r9",
1588                    condition: {
1589                       state: {
1590                         status: 'new'
1591                        },
1592                       context : {
1593                         afariaRegistration: 'certificate'
1594                       },
1595                       //the method must return true in order to match this state
1596                       method: function () {return _credentialProviderID != null && !_credentialProviderCertificateAvailable;}
1597                    },
1598                    action: onGetCertificateFromProvider
1599                },
1600                                        
1601                 //condition to indicate third party certificate is available
1602                 {
1603                 id:"r10",
1604                 condition: {
1605                    state: {
1606                       status: 'new',
1607                    },
1608                    context : {
1609                            afariaRegistration: 'certificate'
1610                    },
1611                    //the method must return true in order to match this state
1612                    method: function () {return _credentialProviderID != null && _credentialProviderCertificateAvailable;}
1613                                         
1614                    },
1615                    action: function(context){
1616                         utils.logJSON(context, 'startRegistration');
1617                         startRegistration(onCoreResult, onRegError, context.registrationContext);
1618                    }
1619                 
1620                 },
1621    
1622                 {
1623                    id:"r11",
1624                    condition: {
1625                       state: {
1626                          status: 'new',
1627                          isAfariaCredentialsProvided: false
1628                       },
1629                       context : {
1630                          afariaRegistration: 'certificate'
1631                        }
1632                    },
1633                    action: 'SCR_ENTER_AFARIA_CREDENTIAL'
1634                },
1635                {
1636                   id:"r12",
1637                	condition: {
1638    	                state: {
1639    	                    status: 'new',
1640    	                    stateClientHub: 'availableValidSSOPin'
1641    	                },
1642                		context : {
1643                			credentialsByClientHub : true,
1644                			registrationReadOnly : true
1645                		}
1646                	},
1647                    action: function(context){
1648                        utils.logJSON(context, 'startRegistration');
1649                        startRegistration(onCoreResult, onRegError, context.registrationContext);
1650                    }
1651                },
1652                {
1653                   id:"r13",
1654                	condition: {
1655    	                state: {
1656    	                    status: 'new',
1657    	                    stateClientHub: 'availableValidSSOPin',
1658                            stateAfaria: 'initializationSuccessful'
1659    	                },
1660                		context : {
1661                			registrationReadOnly : true,
1662                            afariaRegistration: 'certificate'
1663                		}
1664                	},
1665                    action: function(context){
1666                        utils.logJSON(context, 'startRegistration');
1667                        startRegistration(onCoreResult, onRegError, context.registrationContext);
1668                    }
1669                },
1670                {
1671                   id:"r14",
1672                	condition: {
1673    	                state: {
1674    	                    status: 'new',
1675    	                    stateClientHub: 'notAvailable',
1676                            stateAfaria: 'initializationSuccessful'
1677    	                },
1678                		context : {
1679                            afariaRegistration: 'certificate'
1680                		}
1681                	},
1682                    action: function(context){
1683                        utils.logJSON(context, 'startRegistration');
1684                        startRegistration(onCoreResult, onRegError, context.registrationContext);
1685                    }
1686                },
1687                {
1688                   id:"r15",
1689                	condition: {
1690    	                state: {
1691    	                    status: 'new',
1692                            stateClientHub: 'notAvailable',
1693                            stateAfaria: 'initializationSuccessful'
1694    	                }
1695                	},
1696                    action: 'SCR_ENTER_CREDENTIALS'
1697                },
1698                {
1699                   id:"r16",
1700                	condition: {
1701    	                state: {
1702    	                    status: 'new',
1703    	                    stateClientHub: 'availableValidSSOPin'
1704    	                },
1705                		context : {
1706                			registrationReadOnly :true,
1707                			credentialsByClientHub : false
1708                		}
1709                	},
1710                    action: 'SCR_ENTER_CREDENTIALS'
1711                },
1712                                   
1713                {
1714                   id:"r18",
1715                	condition: {
1716    	                state: {
1717    	                    status: 'new',
1718    	                    //stateClientHub: 'notAvailable' | 'availableValidSSOPin' | 'skipped' | 'error'
1719    	                }
1720                	},
1721                    action: 'SCR_REGISTRATION'
1722                },
1723    
1724                {
1725                    id:"r20",
1726                    condition: {
1727    	                state: {
1728    	                	secureStoreOpen: false,
1729                            status: 'registered',
1730                            defaultPasscodeUsed: true,
1731    //                        defaultPasscodeAllowed: true,
1732    	                }
1733                    },
1734                    action: 'SCR_SET_PASSCODE_OPT_OFF'
1735                },
1736                {
1737                   id:"r21",
1738                	condition: {
1739    	                state: {
1740    	                	secureStoreOpen: false,
1741                            status: 'registered',
1742                            defaultPasscodeUsed: false,
1743                            defaultPasscodeAllowed: true,
1744    	                }
1745                    },
1746                    action: 'SCR_SET_PASSCODE_OPT_ON'
1747                },
1748                {
1749                   id:"r22",
1750                	condition: {
1751    	                state: {
1752    	                	secureStoreOpen: false,
1753                            status: 'registered',
1754    //                        defaultPasscodeAllowed: false,
1755    	                }
1756                    },
1757                    action: 'SCR_SET_PASSCODE_MANDATORY'
1758                },
1759                
1760                
1761                {
1762                   id:"r23",
1763                	condition: {
1764    	                state: {
1765    	                    //secureStoreOpen: false, //TODO clarify
1766    	                    status: 'fullRegistered',
1767    	                    stateClientHub: 'availableInvalidSSOPin'
1768    	                }
1769                	},
1770                    action: 'SCR_SSOPIN_CHANGE'
1771                },
1772                {
1773                   id:"r24",
1774                	condition: {
1775    	                state: {
1776    	                	secureStoreOpen: true,
1777    	                	status: 'fullRegistered',
1778    	                	stateClientHub: 'notAvailable'
1779    	                }
1780                    },
1781                    action: onFullRegistered
1782                },
1783                {
1784                   id:"r25",
1785                	condition: {
1786    	                state: {
1787    	                	secureStoreOpen: true,
1788    	                	status: 'fullRegistered',
1789    	                	stateClientHub: 'availableValidSSOPin'
1790    	                }
1791                    },
1792                    action: onFullRegistered
1793                },
1794                {
1795                   id:"r26",
1796                	condition: {
1797    	                state: {
1798    	                	secureStoreOpen: true,
1799    	                	status: 'fullRegistered',
1800    	                	stateClientHub: 'skipped'
1801    	                }
1802                    },
1803                    action: onFullRegistered
1804                },
1805    
1806                
1807    
1808                ];
1809                
1810                this.screenEvents = {
1811                	'SCR_SSOPIN_SET': {
1812                        onsubmit: function(context){
1813                            utils.logJSON(context, 'logonCore.setSSOPasscode');
1814                            logonCore.setSSOPasscode(onCoreResult, onSSOPasscodeSetError, context);
1815                        },
1816                        oncancel: onCancelSSOPin,
1817                        onerror: onFlowError,
1818                        onforgot: onForgotSsoPin,
1819                        onskip: onSkipSsoPin
1820                    },
1821                   
1822                   'SCR_ENTER_AFARIA_CREDENTIAL' : {
1823                        onsubmit: function(context){
1824                            utils.logJSON(context, 'logonCore.setAfariaCredential');
1825                            logonCore.setAfariaCredential(onCoreResult, onSetAfariaCredentialError, context);
1826                        }
1827                     },
1828                    
1829                	'SCR_SSOPIN_CHANGE': {
1830                        onsubmit: function(context){
1831                            utils.logJSON(context, 'logonCore.setSSOPasscode');
1832                            logonCore.setSSOPasscode(onCoreResult, onSSOPasscodeSetError, context);
1833                        },
1834                        oncancel: onSkipSsoPin,
1835                        onerror: onFlowError,
1836                        onforgot: onForgotSsoPin
1837                    },
1838                		
1839                    'SCR_UNLOCK': {
1840                        onsubmit: onUnlockSubmit,
1841                        oncancel: noOp,
1842                        onerror: onFlowError,
1843                        onforgot: onForgotAppPasscode,
1844                        onerrorack: onErrorAck 
1845                    },
1846                   
1847                    'SCR_REGISTRATION':  {
1848                        onsubmit: onRegSubmit,
1849                        oncancel: onCancelRegistration,
1850                        onerror: onFlowError,
1851                        onbackbutton: onRegistrationBackButton
1852                    },
1853                    
1854                    'SCR_ENTER_CREDENTIALS' : {
1855                    	onsubmit: onRegSubmit,
1856                        oncancel: onCancelRegistration,
1857                        onerror: onFlowError
1858                    },
1859                    'SCR_SET_PASSCODE_OPT_ON': {
1860                        onsubmit: onCreatePasscodeSubmit,
1861                        oncancel: noOp,
1862                        onerror: onFlowError,
1863                        ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
1864                        onerrorack: noOp  
1865                    },
1866                    'SCR_SET_PASSCODE_OPT_OFF': {
1867                        onsubmit: callPersistWithDefaultPasscode,
1868                        oncancel: noOp,
1869                        onerror: onFlowError,
1870                        onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
1871                        onerrorack: noOp  
1872                    },
1873                    'SCR_SET_PASSCODE_MANDATORY': {
1874                        onsubmit: onCreatePasscodeSubmit,
1875                        oncancel: noOp,
1876                        onerror: onFlowError,
1877                        onerrorack: noOp  
1878                    },
1879                    'SCR_SAML_AUTH': {
1880                        onevent: onSAMLAuthEvent,
1881                        oncancel: onFlowCancel,
1882                        onerror: onFlowError,
1883                        onerrorack: onFlowError
1884                    }
1885                   
1886                };
1887                
1888                utils.log('flow constructor return');
1889            }
1890            
1891            //Web registrationFlow is used to onboard application without SMP logon 
1892            var WebRegistrationFlow = function WebRegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
1893            //wrapped into a function to defer evaluation of the references to flow callbacks
1894                
1895                this.name = 'registrationFlowBuilder';
1896                
1897                var registrationInProgress = false;
1898                   
1899                var onCancelRegistration = function() {
1900                	onFlowError(errorWithDomainCodeDescription("MAFLogon","1","Registration screen was cancelled"));
1901                }
1902                
1903                // internal methods
1904                var showScreen = function(screenId) {
1905                    return function(coreContext) {
1906                        logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
1907                    }.bind(this);
1908                }.bind(this);
1909                
1910                var onUnlockSubmit = function(context){
1911                    utils.logJSON(context, 'logonCore.unlockSecureStore');
1912                    logonCore.unlockSecureStore(onCoreResult, onUnlockError, context)
1913                }
1914                
1915                var noOp = function() { }
1916                
1917                var onForgotAppPasscode = function(){
1918                	utils.log('logonCore.deleteRegistration');
1919                    logonCore.deleteRegistration(function() { 
1920                        if (cordova.require("cordova/platform").id.indexOf("windows") === 0) {
1921                	        // Close the view on Windows. There is no webview state to be reset.
1922                	        logonView.close();
1923                            // reload the app.
1924                	        window.location.reload();
1925                	    }
1926                	    else {
1927                	        logonCore.reset();
1928                	    }
1929                    }, onFlowError);
1930                }
1931                
1932                var onCreatePasscodeSubmit = function(context){
1933                    utils.logJSON(context, 'logonCore.persistRegistration');
1934                    if (_providedPasscodePolicyContext){
1935                        context["policyContext"] = _providedPasscodePolicyContext;
1936                    }
1937                    logonCore.persistRegistration(onCoreResult, onCreatePasscodeError, context);
1938                }
1939    
1940                
1941                var onUnlockError = function(error) {
1942                    utils.logJSON("onUnlockError: " + JSON.stringify(error));
1943                    			
1944    				if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode && error.errorCode === "16") {
1945                        // Too many attempts --> DV deleted
1946                        logonView.showNotification("ERR_TOO_MANY_ATTEMPTS_APP_PASSCODE")
1947                    }
1948    				else if (error && error.errorDomain && error.errorDomain === "MAFSecureStoreManagerErrorDomain" && error.errorCode && error.errorCode === "8") {
1949                        // passcode expired --> DV deleted
1950                        logonView.showNotification("ERR_PASSCODE_EXPIRED")
1951                    }
1952                    else {
1953                        logonView.showNotification("ERR_UNLOCK_FAILED");
1954                    }
1955                }
1956                   
1957                var onUnlockVaultWithDefaultPasscode = function(){
1958                	utils.log('logonCore.unlockSecureStore - default passcode');
1959                	var unlockContext = {"unlockPasscode":null};
1960                	logonCore.unlockSecureStore(onCoreResult, onFlowError, unlockContext)
1961                }
1962                
1963                var onCreateSecureStoreSubmit = function(context){
1964                    utils.logJSON(context, 'logonCore.onCreateSecureStoreSubmit');
1965                    if (_providedPasscodePolicyContext){
1966                        context["policyContext"] = _providedPasscodePolicyContext;
1967                    }
1968                    logonCore.createSecureStore(onCoreResult, onCreatePasscodeError, context);
1969    
1970                }
1971                
1972                var onCreateSecureStoreWithDefaultPasscodeSubmit = function(context){
1973                    utils.logJSON(context, 'logonCore.onCreateSecureStoreWithDefaultPasscodeSubmit');
1974                    if (_providedPasscodePolicyContext){
1975                        context["policyContext"] = _providedPasscodePolicyContext;
1976                    }
1977                	context.passcode = null;
1978                    logonCore.createSecureStore(onCoreResult, onCreatePasscodeError, context);
1979    
1980                }
1981                
1982                var onCancelRegistrationError = function(error){
1983                	utils.logJSON("onCancelRegistrationError: " + JSON.stringify(error));            	
1984                	logonView.showNotification(getRegistrationCancelError(error));
1985                }
1986    
1987                var onCreatePasscodeError = function(error) {
1988                    utils.logJSON("onCreatePasscodeError: " + JSON.stringify(error));
1989                    logonView.showNotification(getSecureStoreErrorText(error));
1990                }
1991                
1992                var onFullRegistered = function()
1993                {
1994                 	var getContextSuccessCallback = function(result){
1995                 		
1996                 		onFlowSuccess(result);
1997                 	}
1998                     utils.log('logonCore.getContext');
1999                     logonCore.getState(getContextSuccessCallback, onFlowError);
2000                }
2001               
2002                var callPersistWithDefaultPasscode = function(context){
2003                	utils.logJSON(context, 'logonCore.persistRegistration');
2004                	context.passcode = null;
2005                	logonCore.persistRegistration(
2006                            onCoreResult,
2007                            onFlowError,
2008                            context)
2009                }
2010                
2011                // exported properties
2012                this.stateTransitions = [
2013                {
2014                   id:"r0",
2015                	condition: {
2016                      
2017                		state: {
2018                         hasSecureStore: true,
2019                			secureStoreOpen: false,
2020                			defaultPasscodeUsed: true
2021                		}
2022                	},
2023                	action: onUnlockVaultWithDefaultPasscode
2024                },
2025                {
2026                   id:"r1",
2027                	condition: {
2028    	                state: {
2029                         hasSecureStore: true,
2030    	                	secureStoreOpen: false,
2031    	                }
2032                    },
2033                    action: 'SCR_UNLOCK'
2034                },
2035    
2036                {
2037                    id:"r20",
2038                    condition: {
2039    	                state: {
2040                         hasSecureStore:  true,
2041    	                	secureStoreOpen: false,
2042                         defaultPasscodeUsed: true,
2043    //                   defaultPasscodeAllowed: true,
2044    	                }
2045                    },
2046                    action: 'SCR_SET_PASSCODE_OPT_OFF'
2047                },
2048                {
2049                   id:"r21",
2050                	condition: {
2051    	                state: {
2052    	                	secureStoreOpen: false,
2053                            defaultPasscodeUsed: false,
2054                            defaultPasscodeAllowed: true,
2055    	                }
2056                    },
2057                    action: 'SCR_SET_PASSCODE_OPT_ON'
2058                },
2059               {
2060                   id:"r22",
2061                	condition: {
2062    	                state: {
2063                              hasSecureStore: false
2064    //                        status: 'registered',
2065    //                        defaultPasscodeAllowed: false,
2066    	                }
2067                    },
2068                    action: 'SCR_SET_PASSCODE_MANDATORY'
2069                },
2070                
2071                {
2072                   id:"r26",
2073                	condition: {
2074    	                state: {
2075    	                	secureStoreOpen: true,
2076    	                }
2077                    },
2078                    action: onFullRegistered
2079                },
2080                
2081    
2082                ];
2083                
2084                this.screenEvents = {
2085               
2086                    'SCR_UNLOCK': {
2087                        onsubmit: onUnlockSubmit,
2088                        oncancel: noOp,
2089                        onerror: onFlowError,
2090                        onforgot: onForgotAppPasscode,
2091                        onerrorack: noOp  
2092                    },
2093                   
2094                   'SCR_SET_PASSCODE_OPT_ON': {
2095                        onsubmit: onCreateSecureStoreSubmit,
2096                        oncancel: noOp,
2097                        onerror: onFlowError,
2098                        ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
2099                        onerrorack: noOp  
2100                    },
2101                    'SCR_SET_PASSCODE_OPT_OFF': {
2102                        onsubmit: onCreateSecureStoreWithDefaultPasscodeSubmit,
2103                        oncancel: noOp,
2104                        onerror: onFlowError,
2105                        onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
2106                        onerrorack: noOp  
2107                    },
2108                    'SCR_SET_PASSCODE_MANDATORY': {
2109                        onsubmit: onCreateSecureStoreSubmit,
2110                        oncancel: noOp,
2111                        onerror: onFlowError,
2112                        onerrorack: noOp  
2113                    }               
2114                   
2115                };
2116                
2117                utils.log('flow constructor return');
2118            }
2119            
2120            
2121            var ChangePasswordFlow = function ChangePasswordFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
2122            //wrapped into a function to defer evaluation of the references to flow callbacks
2123            
2124                this.name = 'changePasswordFlowBuilder';
2125                
2126                
2127                // internal methods      
2128    
2129                var callUnlockFlow = function(){
2130                        utils.log(this.name + ' triggered unlock');
2131                        registerOrUnlock(onCoreResult,onFlowError); 
2132                }
2133    
2134                var onChangePasswordSubmit = function(context){
2135                    utils.logJSON(context, 'logonCore.changePassword');
2136                    // this logonCore call does not return with context
2137                    logonCore.changePassword(onPasswordChanged, onFlowError, context);
2138                }
2139    
2140                
2141                var onPasswordChanged = function(){
2142                    utils.log('onPasswordChanged');
2143                    logonCore.getContext(onFlowSuccess, onFlowError);
2144                }
2145    
2146                // exported properties
2147                this.stateTransitions = [
2148                {
2149                   id:"cp0",
2150                	condition: {
2151    	                state: {
2152    	                	secureStoreOpen: false,
2153    	                }
2154                    },
2155                    action: callUnlockFlow,
2156                },
2157                {
2158                   id:"cp1",
2159                	condition: {
2160    	                state: {
2161    	                	secureStoreOpen: true,
2162    	                }
2163                    },
2164                    action: 'SCR_CHANGE_PASSWORD'
2165                },
2166                
2167                ];
2168                
2169                this.screenEvents = {
2170                    'SCR_CHANGE_PASSWORD': {
2171                        onsubmit: onChangePasswordSubmit,
2172                        oncancel: onFlowCancel,
2173                        onerror: onFlowError
2174                    }
2175                };
2176                
2177                
2178                utils.log('flow constructor return');
2179            }
2180            
2181            var ManagePasscodeFlow = function ManagePasscodeFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
2182            //wrapped into a function to defer evaluation of the references to flow callbacks
2183            
2184                this.name = 'managePasscodeFlowBuilder';
2185                
2186                // internal methods
2187                var showScreen = function(screenId) {
2188                    return function(coreContext) {
2189                        logonView.showScreen(screenId, this.screenEvents[screenId], coreContext);
2190                    }.bind(this);
2191                }.bind(this);
2192                
2193                
2194                var callChangePasscode = function(context){
2195                        utils.logJSON(context, 'logonCore.changePasscode');
2196                        logonCore.changePasscode(
2197                            onCoreResult,
2198                            onChangePasscodeError,
2199                            context)
2200                }
2201                
2202                var onChangePasscodeError = function(error) {
2203                    utils.logJSON("onChangePasscodeError: " + JSON.stringify(error));
2204                    logonView.showNotification(getSecureStoreErrorText(error));
2205                }           
2206    
2207                var noOp = function() { }
2208                
2209                var callDisablePasscode = function(context){
2210                	utils.logJSON(context, 'logonCore.disablePasscode');
2211                	context.passcode = null;
2212                	logonCore.changePasscode(
2213                            onCoreResult,
2214                            onFlowError,
2215                            context)
2216                }
2217                            
2218                var callGetContext = function(){
2219                    utils.log('logonCore.getContext');
2220                    logonCore.getContext(onCoreResult, onFlowError);
2221                }
2222                
2223                var onPasscodeEnable = function(context){
2224                    utils.logJSON(context, this.name + ' onPasscodeEnable: ');
2225                    //logonCore.changePasscode(onFlowSuccess, onFlowError, context);
2226                    onFlowError();
2227                }
2228        
2229                // exported properties
2230                this.stateTransitions = [
2231                {
2232                   id:"mp0",
2233                	condition: {
2234    	                state: {
2235    	                	secureStoreOpen: true,
2236    	                },
2237    	                context: null
2238                    },
2239                    action: callGetContext
2240                },
2241                {
2242                   id:"mp1",
2243                	condition: {
2244    	                state: {
2245    	                	secureStoreOpen: false,
2246    	                }
2247                    },
2248                    action: onFlowError
2249                },
2250                {
2251                   id:"mp2",
2252                	condition: {
2253    	                state: {
2254    	                	secureStoreOpen: true,
2255                            defaultPasscodeUsed: true,
2256    //                        defaultPasscodeAllowed: true,
2257    	                }
2258                    },
2259                    action: 'SCR_MANAGE_PASSCODE_OPT_OFF'
2260                },
2261                {
2262                   id:"mp3",
2263                	condition: {
2264    	                state: {
2265    	                	secureStoreOpen: true,
2266                            defaultPasscodeUsed: false,
2267                            defaultPasscodeAllowed: true,
2268    	                }
2269                    },
2270                    action: 'SCR_MANAGE_PASSCODE_OPT_ON'
2271                },
2272                {
2273                   id:"mp4",
2274                	condition: {
2275    	                state: {
2276    	                	secureStoreOpen: true,
2277                            //defaultPasscodeUsed: [DONTCARE],
2278                            defaultPasscodeAllowed: false,
2279    	                }
2280                    },
2281                    action: 'SCR_MANAGE_PASSCODE_MANDATORY'
2282                },
2283    
2284                
2285                ];
2286                
2287                this.screenEvents = {
2288                    'SCR_MANAGE_PASSCODE_OPT_ON': {
2289                        onsubmit: onFlowSuccess,
2290                        oncancel: onFlowCancel,
2291                        onerror: onFlowError,
2292                        ondisable: showScreen('SCR_CHANGE_PASSCODE_OPT_OFF'),
2293                        onchange: showScreen('SCR_CHANGE_PASSCODE_OPT_ON')
2294                    },
2295                    'SCR_MANAGE_PASSCODE_OPT_OFF': {
2296                        onsubmit: onFlowSuccess,
2297                        oncancel: onFlowCancel,
2298                        onerror: onFlowError,
2299                        onenable: showScreen('SCR_SET_PASSCODE_OPT_ON')
2300                    },
2301                    'SCR_MANAGE_PASSCODE_MANDATORY': {
2302                        onsubmit: onFlowSuccess,
2303                        oncancel: onFlowCancel,
2304                        onerror: onFlowError,
2305                        onchange: showScreen('SCR_CHANGE_PASSCODE_MANDATORY')
2306                    },
2307                   
2308                   
2309                    'SCR_SET_PASSCODE_OPT_ON': {
2310                        onsubmit: callChangePasscode,
2311                        oncancel: onFlowCancel,
2312                        onerror: onFlowError,
2313                        ondisable: showScreen('SCR_SET_PASSCODE_OPT_OFF'),
2314                        onerrorack: noOp  
2315                    },
2316                    'SCR_SET_PASSCODE_OPT_OFF': {
2317                        onsubmit: callDisablePasscode,
2318                        oncancel: onFlowCancel,
2319                        onerror: onFlowError,
2320                        onenable: showScreen('SCR_SET_PASSCODE_OPT_ON'),
2321                        onerrorack: noOp  
2322                    },
2323                    'SCR_CHANGE_PASSCODE_OPT_ON': {
2324                        onsubmit: callChangePasscode,
2325                        oncancel: onFlowCancel,
2326                        onerror: onFlowError,
2327                        ondisable: showScreen('SCR_CHANGE_PASSCODE_OPT_OFF'),
2328                        onerrorack: noOp  
2329                    },
2330                    'SCR_CHANGE_PASSCODE_OPT_OFF': {
2331                        onsubmit: callDisablePasscode,
2332                        oncancel: onFlowCancel,
2333                        onerror: onFlowError,
2334                        onenable: showScreen('SCR_CHANGE_PASSCODE_OPT_ON'),
2335                        onerrorack: noOp  
2336                    },
2337                    'SCR_CHANGE_PASSCODE_MANDATORY': {
2338                        onsubmit: callChangePasscode,
2339                        oncancel: onFlowCancel,
2340                        onerror: onFlowError,
2341                        onerrorack: noOp  
2342                    },
2343                   
2344                };
2345    
2346                
2347                utils.log('flow constructor return');
2348            }
2349            
2350            var ShowRegistrationFlow = function ShowRegistrationFlow(logonCore, logonView, onCoreResult, onFlowSuccess, onFlowError, onFlowCancel) {
2351            //wrapped into a function to defer evaluation of the references to flow callbacks
2352                
2353                this.name = 'showRegistrationFlowBuilder';
2354                
2355                var showRegistrationInfo = function(context) {
2356                	logonView.showScreen('SCR_SHOW_REGISTRATION', this.screenEvents['SCR_SHOW_REGISTRATION'], context);
2357                }.bind(this);
2358                
2359                var callGetContext = function(){
2360                    utils.log('logonCore.getContext');
2361                    logonCore.getContext(onCoreResult, onFlowError);
2362                }
2363               
2364                // exported properties
2365                this.stateTransitions = [
2366                {
2367                   id:"sr0",
2368                	condition: {
2369    	                state: {
2370    	                	secureStoreOpen: true,
2371    	                	
2372    	                },
2373    	                context: null
2374                    },
2375                    action: callGetContext
2376                },
2377                {
2378                    id:"sr1",
2379                    condition: {
2380                        secureStoreOpen: true,
2381                    },
2382                    action: showRegistrationInfo
2383                }
2384                
2385                ];
2386                
2387                this.screenEvents = {
2388                    'SCR_SHOW_REGISTRATION': {
2389                        oncancel: onFlowSuccess,
2390                        onerror: onFlowError
2391                    }
2392                };
2393    
2394    
2395                utils.log('flow constructor return');
2396            }
2397            
2398    // === flow launcher methods =====================================
2399              
2400                
2401            var resume = function (onsuccess, onerror) {
2402    
2403                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2404                    utils.log('FlowRunner.run MAFLogon is not initialized');
2405                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2406                	return;
2407                }        	
2408    
2409            	var onUnlockSuccess = function(){
2410            		_oLogonCore.onEvent(onsuccess, onerror, 'RESUME');
2411            	}
2412                
2413                var onGetStateSuccess = function(state) {
2414            	//call registration flow only if the status is fullregistered in case of resume, so logon screen will not loose its input values
2415            		if (state.status == 'fullRegistered') {
2416            			registerOrUnlock(onUnlockSuccess, onerror);
2417            		}
2418                }
2419                
2420                getState(onGetStateSuccess, onerror);
2421            }
2422            
2423    
2424            var get = function (onsuccess, onerror, key) {
2425            	
2426                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2427                    utils.log('FlowRunner.run MAFLogon is not initialized');
2428                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2429                	return;
2430                }
2431                
2432            	var onUnlockSuccess = function(){
2433            		_oLogonCore.getSecureStoreObject(onsuccess, onerror, key);
2434            	}
2435            	
2436            	registerOrUnlock(onUnlockSuccess, onerror);
2437            }
2438    
2439            var getConfiguration = function (onsuccess, onerror, type) {
2440            	
2441                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2442                    utils.log('getConfiguration MAFLogon is not initialized');
2443                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2444                	return;
2445                }
2446                
2447               
2448              	var onUnlockSuccess = function(){
2449                    var key;
2450                    if (type == "authentication" ){
2451                        var samlConfig = "";
2452                        //process the configuration data in _providedContext to get the SAML configuration and add it into the authentication configuration.
2453                        //_providedContext will be loaded when locking data vault, so we do not need to load the saved context from data vault.
2454                        if (_providedContext){
2455                            var auth = getSAMLConfig(_providedContext);
2456                            if (auth){
2457                                    var saml = auth["config"];
2458                                    if (saml){
2459                                        var samlSettings = JSON.stringify(saml);
2460                                        samlConfig = ',"saml":[{"type":"user", "data":' + samlSettings +'}]';
2461                                    }
2462                            }
2463               
2464                        }
2465                        var jsonConfig = '{"basic":[{"type":"logon"}],"clientCert":[{"type":"logon"}]' + samlConfig + '}';
2466                        onsuccess(jsonConfig);
2467                    }
2468                    else{
2469                        utils.log('getConfiguration: invalid data for "type" parameter');
2470                        onerror(errorWithDomainCodeDescription("MAFLogon","2","configType parameter is not specified"));
2471                        return;
2472                    }
2473            	}
2474            	
2475            	registerOrUnlock(onUnlockSuccess, onerror);
2476            }
2477    
2478            var set = function (onsuccess, onerror, key, value) {
2479            	
2480                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2481                    utils.log('FlowRunner.run MAFLogon is not initialized');
2482                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2483                	return;
2484                }
2485                
2486            	var onUnlockSuccess = function(){
2487            		_oLogonCore.setSecureStoreObject(onsuccess, onerror, key, value);	
2488            	}
2489    
2490            	registerOrUnlock(onUnlockSuccess, onerror);
2491            }
2492            
2493    
2494    
2495            var lock = function (onsuccess, onerror) {
2496                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2497                    utils.log('FlowRunner.run MAFLogon is not initialized');
2498                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2499                	return;
2500                }
2501                
2502                _oLogonCore.lockSecureStore(onsuccess, onerror);
2503            }
2504            
2505            var getState = function (onsuccess, onerror) {
2506                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2507                    utils.log('FlowRunner.run MAFLogon is not initialized');
2508                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2509                	return;
2510                }
2511                
2512            	_oLogonCore.getState(onsuccess, onerror);
2513            }
2514            
2515            var wrapCallbackWithQueueNext = function(callback) {
2516                return function() { 
2517    				//Need a try-cache block, so if application delegate callback function throws an exception, it will not stop the 
2518    				//logon plugin to continue processing the next flow
2519    				try{
2520    					if (callback){  
2521                        	callback.apply(this, arguments);
2522                    	}
2523    				}
2524    				catch(ex){
2525                    	alert("Appliction callback exception: " + JSON.stringify(ex));
2526    				}
2527                 	if (flowqueue) {
2528                        flowqueue.runNextFlow();
2529                    }
2530                }
2531            }
2532    
2533            var registerOrUnlock = function(onsuccess, onerror, flowContext) {
2534                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2535                    utils.log('FlowRunner.run MAFLogon is not initialized');
2536                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2537                	return;
2538                }            
2539    
2540                var callbacks = {
2541                    "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
2542                    "onerror" : wrapCallbackWithQueueNext(onerror)
2543                }
2544    
2545                var flow;
2546                if (_bIsWebRegistration){
2547                   flow = WebRegistrationFlow;
2548                }
2549                else{
2550                   flow = RegistrationFlow;
2551                }
2552                var flowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, flow, flowContext);
2553            	
2554            	if (flowqueue) {
2555            		flowqueue.add(flowRunner);
2556    			}
2557    			else {
2558    				flowRunner.run();
2559    			}
2560    		}
2561    
2562            var changePassword = function(onsuccess, onerror) {
2563            	if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2564                    utils.log('FlowRunner.run MAFLogon is not initialized');
2565                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2566                	return;
2567                }
2568                
2569                if (_bIsWebRegistration){
2570                   utils.log('ChangePassword is not supported for passcode manager only initialization');
2571                	onerror(errorWithDomainCodeDescription("MAFLogon","6","ChangePassword is not supported for PasscodeManager only initialization"));
2572                	return;
2573                }
2574                 
2575            	var onUnlockSuccess = function(){
2576                    var callbacks = {
2577                        "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
2578                        "onerror" : wrapCallbackWithQueueNext(onerror)
2579                    }
2580                    var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ChangePasswordFlow);
2581                    
2582                    // use setInterval to wait for the unlock flow to fully finish
2583                    // (if the next flow is started to soon then Android can get
2584                    // stuck with a blank screen).
2585                    var intervalID = setInterval(function(){
2586                        if (flowqueue) {
2587                            if (!flowqueue.isRunning) {
2588                                clearInterval(intervalID);
2589                                flowqueue.add(innerFlowRunner);
2590                            }
2591                        }
2592                        else {
2593                            clearInterval(intervalID);
2594                            innerFlowRunner.run();
2595                        }
2596                    }, 10);
2597            	}
2598    
2599            	registerOrUnlock(onUnlockSuccess, onerror);
2600    		}
2601          
2602          var deletePasscodeManager = function(onsuccess, onerror) {
2603            	if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2604                    utils.log('deletePasscodeManager MAFLogon is not initialized');
2605                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2606                	return;
2607                }
2608                
2609            	var onUnlockSuccess = function(){
2610                	_oLogonCore.deleteRegistration(onsuccess, onerror);
2611             }
2612    
2613            	registerOrUnlock(onUnlockSuccess, onerror);
2614    		}
2615          
2616           
2617            
2618            var managePasscode = function(onsuccess, onerror) {
2619            	if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2620                    utils.log('FlowRunner.run MAFLogon is not initialized');
2621                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2622                	return;
2623                }
2624                
2625            	var onUnlockSuccess = function(){
2626                	var callbacks = {
2627                        "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
2628                        "onerror" : wrapCallbackWithQueueNext(onerror)
2629                    }
2630                    var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ManagePasscodeFlow);
2631                        
2632                    // use setInterval to wait for the unlock flow to fully finish
2633                    // (if the next flow is started to soon then Android can get
2634                    // stuck with a blank screen).
2635                    var intervalID = setInterval(function(){
2636                        if (flowqueue) {
2637                            if (!flowqueue.isRunning) {
2638                                clearInterval(intervalID);
2639                                flowqueue.add(innerFlowRunner);
2640                            }
2641                        }
2642                        else {
2643                            clearInterval(intervalID);
2644                            innerFlowRunner.run();
2645                        }
2646                    }, 10);                
2647            	}
2648    
2649            	registerOrUnlock(onUnlockSuccess, onerror);
2650    		}
2651    
2652            var showRegistrationData = function(onsuccess, onerror) {
2653                if(!_oLogonCore || !sap.logon.Core.isInitialized()) {
2654                    utils.log('FlowRunner.run MAFLogon is not initialized');
2655                	onerror(errorWithDomainCodeDescription("MAFLogon","2","MAFLogon is not initialized"));
2656                	return;
2657                }
2658                
2659                if (_bIsWebRegistration){
2660                   utils.log('ShowRegistrationData is not supported for passcode manager only initialization');
2661                	onerror(errorWithDomainCodeDescription("MAFLogon","6","ShowRegistrationData is not supported for PasscodeManager only initialization"));
2662                	return;
2663                }
2664    
2665            	var onUnlockSuccess = function(){
2666                	var callbacks = {
2667                        "onsuccess" : wrapCallbackWithQueueNext(onsuccess),
2668                        "onerror" : wrapCallbackWithQueueNext(onerror)
2669                    }
2670                    var innerFlowRunner = new FlowRunner(callbacks, _oLogonView, _oLogonCore, ShowRegistrationFlow);
2671                        
2672                    // use setInterval to wait for the unlock flow to fully finish
2673                    // (if the next flow is started to soon then Android can get
2674                    // stuck with a blank screen).
2675                    var intervalID = setInterval(function(){
2676                        if (flowqueue) {
2677                            if (!flowqueue.isRunning) {
2678                                clearInterval(intervalID);
2679                                flowqueue.add(innerFlowRunner);
2680                            }
2681                        }
2682                        else {
2683                            clearInterval(intervalID);
2684                            innerFlowRunner.run();
2685                        }
2686                    }, 10);               
2687            	}
2688    
2689            	registerOrUnlock(onUnlockSuccess, onerror);
2690    		}
2691    
2692            var getSecureStoreErrorText = function(error) {
2693                utils.logJSON('LogonController.getSecureStoreErrorText: ' + JSON.stringify(error));
2694    
2695            	var errorText;
2696            	
2697            	if(error.errorCode === '14' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
2698            		errorText = "ERR_PASSCODE_TOO_SHORT";
2699            	else if(error.errorCode === '10' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
2700            		errorText = "ERR_PASSCODE_REQUIRES_DIGIT";
2701            	else if(error.errorCode === '13' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
2702            		errorText = "ERR_PASSCODE_REQUIRES_UPPER";
2703            	else if(error.errorCode === '11' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
2704            		errorText = "ERR_PASSCODE_REQUIRES_LOWER";
2705            	else if(error.errorCode === '12' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
2706            		errorText = "ERR_PASSCODE_REQUIRES_SPECIAL";
2707            	else if(error.errorCode === '15' && error.errorDomain === 'MAFSecureStoreManagerErrorDomain')
2708            		errorText = "ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS";
2709            	else {
2710            		errorText = "ERR_SETPASSCODE_FAILED";
2711            	}
2712            	
2713            	return errorText;
2714            }
2715            
2716            var getSSOPasscodeSetErrorText = function(error) {
2717                utils.logJSON('LogonController.getSSOPasscodeSetErrorText: ' + JSON.stringify(error));
2718                
2719                var errorText;
2720                
2721                if (error.errorDomain === 'MAFLogonCoreErrorDomain') {
2722            		if (error.errorCode === '16') {
2723            			errorText = "ERR_SSO_PASSCODE_SET_ERROR";
2724            		}
2725            	}
2726                
2727                return errorText;
2728            }
2729            
2730            var getRegistrationErrorText = function(error) {
2731            	utils.logJSON('LogonController.getRegistrationErrorText: ' + JSON.stringify(error));
2732            	
2733            	var errorText;
2734            	
2735            	if (error.errorDomain === 'MAFLogonCoreErrorDomain') {
2736            		if (error.errorCode === '80003') {
2737            			errorText = "ERR_REG_FAILED_WRONG_SERVER";
2738            		}
2739            		//in case of wrong application id
2740            		else if (error.errorCode === '404') {
2741            			errorText = "ERR_REG_FAILED";
2742            		}
2743            		else if (error.errorCode === '401') {
2744            			errorText = "ERR_REG_FAILED_UNATHORIZED";
2745            		}         
2746                    else if (error.errorCode === '22') {
2747                        errorText = "ERR_REG_FAILED_WHITELIST_ERROR";
2748                    }
2749            		else {
2750            			errorText = "ERR_REG_FAILED";
2751            		}
2752            	}
2753            	
2754            	return errorText;
2755            }
2756            
2757            var getRegistrationCancelError = function(error) {
2758            	utils.logJSON('LogonController.getRegistrationCancelError: ' + JSON.stringify(error));
2759            	
2760            	var errorText;
2761            	
2762            	errorText = "ERR_REGISTRATION_CANCEL";
2763            	
2764            	return errorText;
2765            }
2766            
2767            var errorWithDomainCodeDescription = function(domain, code, description) {
2768            	var error = {
2769            		errorDomain: domain,
2770            		errorCode: code,
2771            		errorMessage: description
2772            	};
2773            		
2774            	return error;
2775            }
2776            
2777            function normalizeResourcePath(context){
2778               //normalize resource path to absolute path (starting with '/')
2779               if (context && context.resourcePath )
2780               {
2781                   context.resourcePath = context.resourcePath.trim();
2782                   if (context.resourcePath.length > 0){
2783                      context.resourcePath = context.resourcePath.replace("\\","/");
2784                      if (context.resourcePath.charAt(0) !== '/') {
2785                         context.resourcePath = "/" + context.resourcePath;
2786                      }
2787                      
2788                      //remove trailing '/' or '\'
2789                      if (context.resourcePath.charAt(context.resourcePath.length-1) === '/'){
2790                         context.resourcePath = context.resourcePath.substr(0, context.resourcePath.length-1);
2791                      }
2792                   }
2793               }
2794            }
2795    		
2796            //return null for succeess, otherwise, return the invalid key
2797    		function verifyPasscodePolicy(policy) {
2798    			for (var key in policy) {
2799    				if (policy.hasOwnProperty(key)) {
2800    					if (passcodePolicyAttributeNames.indexOf(key) == -1) {
2801    						return key;
2802    					}
2803    				}
2804    			}
2805    			return null;
2806    		}
2807    
2808    		// This function merges specific settings into the given context.
2809    		// We can't indescriminately merge all properties because that would
2810    		// mean the default values would override the values the user enters.
2811    		function mergeSettingsIntoRegistrationContext(settings, context) {
2812    			// only properties with the following names will be merged.
2813    			var propertiesToMerge = ["serverHost","serverPort","https","auth"];
2814    			if (settings && typeof(settings) == "object") {
2815    				if (context && typeof(context) == "object") {
2816    					for (var index = 0; index < propertiesToMerge.length; index++) {
2817    						if (settings.hasOwnProperty(propertiesToMerge[index])) {
2818    							context[propertiesToMerge[index]] = settings[propertiesToMerge[index]];
2819    						}
2820    					}
2821    				}
2822    			}
2823    		}
2824                   
2825    // =================== exported (public) members ====================
2826    
2827    	/**
2828    	 * The Logon plugin provides screen flows to register an app with an SAP Mobile Platform server.<br/>
2829    	 * <br/>
2830    	 * The logon plugin is a component of the SAP Mobile Application Framework (MAF), exposed as a Cordova plugin. The basic
2831    	 * 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
2832    	 * stores those values in its own secure data vault. This data vault is separate from the one provided with the
2833    	 * 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
2834    	 * server to receive an application connection ID for a particular app. The application connection ID must be sent
2835    	 * along with each request that is proxied through the SAP Mobile Platform 3.0 server to the OData producer.<br/>
2836    	 * <br/>
2837    	 * <b>Adding and Removing the Logon Plugin</b><br/>
2838    	 * The Logon plugin is added and removed using the
2839    	 * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>.<br/>
2840    	 * <br/>
2841    	 * To add the Logon plugin to your project, use the following command:<br/>
2842    	 * cordova plugin add <full path to directory containing Kapsel plugins>\logon<br/>
2843    	 * <br/>
2844    	 * To remove the Logon plugin from your project, use the following command:<br/>
2845    	 * cordova plugin rm com.sap.mp.cordova.plugins.logon
2846    	 *
2847    	 * @namespace
2848     	 * @alias Logon
2849     	 * @memberof sap
2850     	 */
2851        module.exports = {
2852            
2853        /**
2854    	 * Initialization method to set up the Logon plugin.  This will register the application with the SMP server and also authenticate the user
2855    	 * with servers on the network.  This step must be done first prior to any attempt to communicate with the SMP server.<br/>
2856    	 * <br/>
2857    	 * This function and {@link sap.Logon.initPasscodeManager} are mutually exclusive.  Do not call both.
2858    	 *
2859    	 * @method
2860    	 * @param {sap.Logon~successCallback} successCallback The function that is invoked if initialization is successful.  The current
2861    	 * context is passed to this function as the parameter.
2862    	 * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
2863    	 * @param {string} applicationId The unique ID of the application.  Must match the application ID on the SAP Mobile Platform server.
2864    	 * @param {object} [context] The context with default values for application registration.  See {@link sap.Logon~successCallback} for the structure
2865    	 * of the context object.  Note that all properties of the context object are optional, and you only need to specify the properties
2866    	 * 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
2867    	 * a chance to override these values during runtime.  There are two additional values that can be specified in the context that are not described in
2868    	 * {@link sap.Logon~successCallback}: "mobilePlaceAppID" and "mobilePlaceAppVersion".  If left blank, the mobilePlaceAppID will default to the
2869    	 * applicationId provided to this function.  mobilePlaceAppVersion defaults to "1.0". The mobile place app ID and version are used in combination to
2870    	 * retrieve the configuration from Mobile Place.
2871    	 * @param {string} [logonView=sap.logon.IabUi] The cordova module ID of a custom renderer for the logon,
2872    	 * implementing the [showScreen(), close()] interface.  Please use the default module unless you are absolutely sure that you can provide your own
2873    	 * custom implementation.  Please refer to JavaScript files inside your Kapsel project's plugins\logon\www\common\modules\ folder as example.
2874    	 * @param {string} [certificateProviderClassName] The name identifying the custom certificate provider to use.  This parameter should only be
2875    	 * specified if the app is supposed to use a custom certificate provider.  In that case, the string specified by this parameter must match
2876    	 * the android:name of the meta-data tag in AndroidManifest.xml (the value for that tag will be the classpath and classname).
2877    	 * @example
2878    	 * // a custom UI can be loaded here
2879    	 * var logonView = sap.logon.IabUi;
2880    	 *
2881    	 * // The app ID
2882    	 * var applicationId = "someAppID";
2883    	 *
2884    	 * // You only need to specify the fields for which you want to set the default.   These values are optional because they will be 
2885    	 * // used to prefill the fields on Logon's UI screen.  
2886    	 * var defaultContext = {
2887    	 *  "serverHost" : "defaultServerHost.com"
2888    	 *  "https" : false,
2889    	 *  "serverPort" : "8080",
2890    	 *  "user" : "user1",
2891    	 *  "password" : "Zzzzzz123",
2892    	 *  "communicatorId" : "REST",
2893    	 *  "securityConfig" : "sec1",
2894    	 *  "passcode" : "Aaaaaa123",
2895    	 *  "unlockPasscode" : "Aaaaaa123"
2896    	 * };
2897    	 *
2898    	 * var app_context;
2899    	 *
2900    	 * var successCallback = function(context){
2901    	 *     app_context = context;
2902    	 * }
2903    	 *
2904    	 * var errorCallback = function(errorInfo){
2905    	 *     alert("error: " + JSON.stringify(errorInfo));
2906    	 * }
2907    	 * sap.Logon.init(successCallback, errorCallback, applicationId, defaultContext, logonView, "customCertProvider");
2908    	 */
2909    	   init: init,
2910    	/**
2911    	 * Initialization method to set up the Logon plugin as a passcode and datavault manager only.
2912    	 * When this method is called, the Logon plugin will not do anything with regards to registering
2913    	 * with any server.<br/>
2914    	 * <br/>
2915    	 * This function and {@link sap.Logon.init} are mutually exclusive.  Do not call both.
2916    	 *
2917    	 * @method
2918    	 * @param {sap.Logon~successCallback} successCallback The function that is invoked if initialization is successful.  The current
2919    	 * state is passed to this function as the parameter.
2920    	 * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
2921    	 * @param {string} applicationId The unique ID of the application.  This value will be used as the datavault store ID.
2922    	 * @param {string} [logonView="com/sap/mp/logon/iabui"] The cordova module ID of a custom renderer for the logon,
2923    	 * implementing the [showScreen(), close()] interface.  Please use the default module unless you are absolutely sure that you can provide your own
2924    	 * custom implementation.  Please refer to JavaScript files inside your Kapsel project's plugins\logon\www\common\modules\ folder as example.
2925    	 * @example
2926    	 * // a custom UI can be loaded here
2927    	 * var logonView = sap.logon.IabUi;
2928    	 *
2929    	 * // The app ID
2930    	 * var applicationId = "someAppID";
2931    	 *
2932    	 * var successCallback = function(state){
2933    	 *     alert("successfully initialzed, resulting state: " + JSON.stringify(state));
2934    	 * }
2935    	 *
2936    	 * var errorCallback = function(errorInfo){
2937    	 *     alert("error: " + JSON.stringify(errorInfo));
2938    	 * }
2939    	 * sap.Logon.initPasscodeManager(successCallback, errorCallback, applicationId, logonView);
2940    	 */
2941          initPasscodeManager: initPasscodeManager,
2942    	/**
2943    	 * Function to delete the datavault and all data stored therein.
2944    	 * This function is intended to be used when Logon has been initialized as a passcode manager via {@link sap.Logon.initPasscodeManager}.
2945    	 * However, if it has been initialized for server registration (via {@link sap.Logon.init}), calling this function will
2946    	 * delete the registration and all data.
2947    	 *
2948    	 * @method
2949    	 * @param {sap.Logon~successCallbackNoParameters} successCallback The function that is invoked if the deletion is successful.
2950    	 * @param {sap.Logon~errorCallback} errorCallback The function that is invoked in case of an error.
2951    	 * @example
2952    	 * var successCallback = function(){
2953    	 *     alert("successfully deleted all data");
2954    	 * }
2955    	 *
2956    	 * var errorCallback = function(errorInfo){
2957    	 *     alert("error: " + JSON.stringify(errorInfo));
2958    	 * }
2959    	 * sap.Logon.deletePasscodeManager(successCallback, errorCallback);
2960    	 */
2961          deletePasscodeManager: deletePasscodeManager,
2962    	 
2963           /**
2964            * The application ID with which {@link sap.Logon.init} was called.  It is available here so it is easy to access later.
2965    		* @example
2966    		* // After calling the init function
2967    		* alert("The app ID for this app is: " + sap.Logon.applicationId);
2968            */ 
2969           applicationId: null,
2970    	/**
2971    	 * Direct reference to the logon core object used by the Logon plugin.  This is needed to perform more complex operations that
2972    	 * are not generally needed by applications. <br/>
2973    	 * There are several functions that can be accessed on the core object:<br/>
2974    	 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getState(successCallback,errorCallback) returns the state object of the application to the success callback in the form of a JavaScript object.<br/>
2975    	 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getContext(successCallback,errorCallback) returns the context object of the application to the success callback in the form of a JavaScript object.<br/>
2976    	 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; deleteRegistration(successCallback,errorCallback) deletes the application's registration from the SAP Mobile Platform server and removes<br/>
2977    	 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; application data on device.<br/>
2978    	 * @example
2979    	 * var successCallback = function(result){
2980    	 *     alert("Result: " + JSON.stringify(result));
2981    	 * }
2982    	 * var errorCallback = function(errorInfo){
2983    	 *     alert("Error: " + JSON.stringify(errorInfo));
2984    	 * }
2985    	 * sap.Logon.core.getState(successCallback,errorCallback);
2986    	 * sap.Logon.core.getContext(successCallback,errorCallback);
2987    	 * sap.Logon.core.deleteRegistration(successCallback,errorCallback);
2988    	 */
2989                core: _oLogonCore, //Must be updated after init
2990    
2991    	/**
2992    	 * Get an  (JSON serializable) object from the DataVault for a given key.
2993    	 * @method
2994    	 * @param {sap.Logon~getSuccessCallback} onsuccess The function that is invoked
2995    	 * upon success.  It is called with the resulting object as a single parameter.
2996    	 * This can be null or undefined, if no object is defined for the given key.
2997    	 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
2998    	 * @param {string} key The key with which to query the DataVault.
2999    	 * @example
3000    	 * var errorCallback = function(errorInfo){
3001    	 *     alert("Error: " + JSON.stringify(errorInfo));
3002    	 * }
3003    	 * var getSuccess = function(value){
3004    	 *     alert("value retrieved from the store: " + JSON.stringify(value));
3005    	 * }
3006    	 * var setSuccess = function(){
3007    	 *     sap.Logon.get(getSuccess,errorCallback,'someKey');
3008    	 * }
3009    	 * sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');
3010    	 */           
3011                get: get,
3012         
3013    	 /**
3014    	 * Get an  (JSON serializable) configuration object from the logon based on configuration type.
3015    	 * @method
3016    	 * @param {sap.Logon~getSuccessCallback} onsuccess The function that is invoked
3017    	 * upon success.  It is called with the resulting object as a single parameter.
3018    	 * This can be null or undefined, if no object is defined for the given type.
3019    	 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
3020    	 * @param {string} key The type for the configuration. Currently only valid type is 'authentication', 
3021         * the returned configuration data can be used by authproxy plugin's sendReqeust2 method
3022    	 * @example
3023    	 * var errorCallback = function(errorInfo){
3024    	 *     alert("Error: " + JSON.stringify(errorInfo));
3025    	 * }
3026    	 * var getSuccess = function(value){
3027    	 *     alert("value retrieved from the store: " + JSON.stringify(value));
3028    	 * }
3029         *     sap.Logon.getConfiguration(getSuccess,errorCallback,'authentication');
3030         */
3031              getConfiguration: getConfiguration,
3032    
3033    	/**
3034    	 * Set an (JSON serializable) object in the DataVault.
3035    	 * @method
3036    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess The function to invoke upon success.
3037    	 * onsuccess will be called without parameters for this method. 
3038    	 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
3039    	 * @param {string} key The key to store the provided object on.
3040    	 * @param {object} value The object to be set on the given key.  Must be JSON serializable (ie:
3041    	 * cannot contain circular references).
3042    	 * @example
3043    	 * var errorCallback = function(errorInfo){
3044    	 *     alert("Error: " + JSON.stringify(errorInfo));
3045    	 * }
3046    	 * var getSuccess = function(value){
3047    	 *     alert("value retrieved from the store: " + JSON.stringify(value));
3048    	 * }
3049    	 * var setSuccess = function(){
3050    	 *     sap.Logon.get(getSuccess,errorCallback,'someKey');
3051    	 * }
3052    	 * sap.Logon.set(setSuccess,errorCallback,'someKey', 'some string (could also be an object).');
3053    	 */
3054                set: set,
3055    
3056    	/**
3057    	 * Locks the Logon plugin's secure data vault.  
3058    	 * @method
3059    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess The function to invoke upon success. 
3060    	 * @param {sap.Logon~errorCallback} onerror The function to invoke in case of error.
3061    	 * @example
3062    	 * var errorCallback = function(errorInfo){
3063    	 *     alert("Error: " + JSON.stringify(errorInfo));
3064    	 * }
3065    	 * var successCallback = function(){
3066    	 *     alert("Locked!");
3067    	 * }
3068    	 * sap.Logon.lock(successCallback,errorCallback);
3069    	 */
3070                lock: lock,
3071    
3072    	/**
3073    	 * Unlock the Logon plugin's secure data vault if it has been locked (due to being inactive, or
3074    	 * {@link sap.Logon.lock} being called), then the user is prompted for the passcode to unlock the
3075    	 * application.<br/>
3076    	 * If the application is already unlocked, then nothing will be done.<br/>
3077    	 * If the application has passcode disabled, then passcode prompt will not be necessary.
3078    	 * In all cases if an error does not occur, the success callback is invoked with the current logon context
3079    	 * as the parameter.
3080    	 * @method
3081    	 * @param {sap.Logon~successCallback} onsuccess - The callback to call if the screen flow succeeds.
3082    	 * onsuccess will be called with the current logon context as a single parameter. 
3083    	 * @param {sap.Logon~errorCallback} onerror - The callback to call if the screen flow fails.
3084    	 * @example
3085    	 * var errorCallback = function(errorInfo){
3086    	 *     alert("Error: " + JSON.stringify(errorInfo));
3087    	 * }
3088    	 * var successCallback = function(context){
3089    	 *     alert("Registered and unlocked.  Context: " + JSON.stringify(context));
3090    	 * }
3091    	 * sap.Logon.unlock(successCallback,errorCallback);
3092    	 */
3093    	    unlock: registerOrUnlock,
3094    	/**
3095    	 * This method will launch the UI screen for application users to manage and update the data vault passcode or, 
3096    	 * if the SMP server's Client Passcode Policy allows it, enable or disable the passcode to the data vault.
3097    	 * 
3098    	 * @method
3099    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The function to invoke upon success.  
3100    	 * @param {sap.Logon~errorCallback} onerror - The function to invoke in case of error.
3101    	 * @example
3102    	 * var errorCallback = function(errorInfo){
3103    	 *     alert("Error: " + JSON.stringify(errorInfo));
3104    	 * }
3105    	 * var successCallback = function(context){
3106    	 *     alert("Passcode successfully managed.");
3107    	 * }
3108    	 * sap.Logon.managePasscode(successCallback,errorCallback);
3109    	 */ 
3110    	    managePasscode: managePasscode,
3111    
3112    	/**
3113    	 * This method will launch the UI screen for application users to manage and update the back-end passcode that Logon stores in the 
3114    	 * data vault that is used to authenticate the client to the server. When this method is called, the new password will be validated 
3115    	 * on the application's backend endpoint.
3116    	 * 
3117    	 * @method
3118    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
3119    	 * onsuccess will be called without parameters for this method.
3120    	 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
3121    	 * @example
3122    	 * var errorCallback = function(errorInfo){
3123    	 *     alert("Error: " + JSON.stringify(errorInfo));
3124    	 * }
3125    	 * var successCallback = function(context){
3126    	 *     alert("Password successfully changed.");
3127    	 * }
3128    	 * sap.Logon.changePassword(successCallback,errorCallback);
3129    	 */ 
3130                changePassword: changePassword,
3131    
3132    	/**
3133    	 * Calling this method will show a screen which displays the current registration settings for the application.
3134    	 * @method
3135    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
3136    	 * onsuccess will be called without parameters for this method.
3137    	 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
3138    	 * @example
3139    	 * var errorCallback = function(errorInfo){
3140    	 *     alert("Error: " + JSON.stringify(errorInfo));
3141    	 * }
3142    	 * var successCallback = function(context){
3143    	 *     alert("The showRegistrationData screenflow was successful.");
3144    	 * }
3145    	 * sap.Logon.showRegistrationData(successCallback,errorCallback);
3146    	 */
3147                showRegistrationData: showRegistrationData,
3148    
3149    	/**
3150    	 * Calling this method will show a screen which displays the third party certificate provider settings screen for the application.
3151    	 * @method
3152    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
3153    	 * onsuccess will be called without parameters for this method.
3154    	 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
3155    	 * @example
3156    	 * var errorCallback = function(errorInfo){
3157    	 *     alert("Error: " + JSON.stringify(errorInfo));
3158    	 * }
3159    	 * var successCallback = function(context){
3160    	 *     alert("The showRegistrationData screenflow was successful.");
3161    	 * }
3162    	 * sap.Logon.showCertificateProviderScreen(successCallback,errorCallback);
3163    	 */
3164                showCertificateProviderScreen:showCertificateProviderScreen,
3165            
3166            
3167       /**
3168    	 * Calling this method to delete the stored certificate and get a new one
3169        * @method
3170    	 * @param {sap.Logon~successCallbackNoParameters} onsuccess - The callback to call if the screen flow succeeds.
3171    	 * onsuccess will be called without parameters for this method.
3172    	 * @param {sap.Logon~errorCallback} onerror The function that is invoked in case of an error.
3173    	 * @example
3174    	 * var errorCallback = function(errorInfo){
3175    	 *     alert("Error: " + JSON.stringify(errorInfo));
3176    	 * }
3177    	 * var successCallback = function(){
3178    	 *     alert("The certificate is refreshed.");
3179    	 * }
3180    	 * sap.Logon.refreshCertificate(successCallback,errorCallback);
3181        */
3182                refreshCertificate: refreshCertificate,
3183                   
3184         /**
3185    	 * Calling this method to load the configuration before starting registration
3186         * 
3187         */
3188                loadConfiguration: loadConfiguration
3189    
3190         
3191     };
3192    
3193    /**
3194     * Callback function that is invoked in case of an error.
3195     *
3196     * @callback sap.Logon~errorCallback
3197     *
3198     * @param {Object} errorObject Depending on the origin of the error the object can take several forms.
3199     * (Unfortunately the error object structure and content is not uniform among the platforms, this will
3200     * probably change in the future.)
3201     *
3202     * Errors originating from the logon plugin have only an 'errorKey' property.
3203     * The possible values for 'errorKey':
3204     *
3205     * ERR_CHANGE_TIMEOUT_FAILED
3206     * ERR_FORGOT_SSO_PIN
3207     * ERR_INIT_FAILED
3208     * ERR_INVALID_ACTION
3209     * ERR_INVALID_STATE
3210     * ERR_PASSCODE_REQUIRES_DIGIT
3211     * ERR_PASSCODE_REQUIRES_LOWER
3212     * ERR_PASSCODE_REQUIRES_SPECIAL
3213     * ERR_PASSCODE_REQUIRES_UPPER
3214     * ERR_PASSCODE_TOO_SHORT
3215     * ERR_PASSCODE_UNDER_MIN_UNIQUE_CHARS
3216     * ERR_REGISTRATION_CANCEL
3217     * ERR_REG_FAILED
3218     * ERR_REG_FAILED_UNATHORIZED
3219     * ERR_REG_FAILED_WRONG_SERVER
3220     * ERR_SETPASSCODE_FAILED
3221     * ERR_SET_AFARIA_CREDENTIAL_FAILED
3222     * ERR_SSO_PASSCODE_SET_ERROR
3223     * ERR_UNKNOWN_SCREEN_ID
3224     * ERR_UNLOCK_FAILED
3225     * ERR_USER_CANCELLED
3226     * ERR_PASSCODE_EXPIRED
3227     *
3228     * Errors originating in the logon core (either iOS or Android) have the following properties: 'errorCode', 
3229     * 'errorMessage', and 'errorDomain'.
3230     * The 'errorCode' is just a number uniquely identifying the error.  The 'errorMessage'
3231     * property is a string with more detailed information of what went wrong.  The 'errorDomain' property specifies
3232     * the domain that the error occurred in.
3233     *
3234     * On iOS the 'errorDomain' property of the core errors can take the following values: MAFLogonCoreErrorDomain, MAFSecureStoreManagerErrorDomain, and MAFLogonCoreCDVPluginErrorDomain.
3235     * 
3236     * In the MAFLogonCoreErrorDomain the following errors are thrown (throwing methods in paren):
3237     *
3238     *  3   errMAFLogonErrorCommunicationManagerError       (register, update settings, delete, change backend password)
3239     *  9   errMAFLogonErrorCouldNotDecideCommunicator      (register)
3240     *  11  errMAFLogonErrorOperationNotAllowed             (all)
3241     *  12  errMAFLogonErrorInvalidServerHost               (register)
3242     *  13  errMAFLogonErrorInvalidBackendPassword          (changeBackendPassword)
3243     *  15  errMAFLogonErrorUploadTraceFailed               (uploadTrace)
3244     *  16  errMAFLogonErrorInvalidMCIMSSOPin               (setMCIMSSOPin)
3245     *  18  errMAFLogonErrorCertificateKeyError             (register)
3246     *  19  errMAFLogonErrorCertificateError                (register)
3247     *  20  errMAFLogonErrorAfariaInvalidCredentials        (setAfariaCredentialWithUser)
3248     *
3249     * In the MAFSecureStoreManagerErrorDomain the following errors are thrown (throwing methods in paren):
3250     *
3251     *  0   errMAFSecureStoreManagerErrorUnknown    (persist, unlock, changePasscode, delete, getContext)
3252     *  1   errMAFSecureStoreManagerErrorAlreadyExists  (persist)
3253     *  2   errMAFSecureStoreManagerErrorDataTypeError  (unlock, getContext)
3254     *  3   errMAFSecureStoreManagerErrorDoesNotExist   (unlock, persist, getContext)
3255     *  4   errMAFSecureStoreManagerErrorInvalidArg unlock, (persist, getContext)
3256     *  5   errMAFSecureStoreManagerErrorInvalidPassword    (unlock)
3257     *  6   errMAFSecureStoreManagerErrorLocked     (getContext)
3258     *  7   errMAFSecureStoreManagerErrorOutOfMemory    (persist, unlock, changePasscode, delete, getContext)
3259     *  8   errMAFSecureStoreManagerErrorPasswordExpired    (unlock, getContext)
3260     *  9   errMAFSecureStoreManagerErrorPasswordRequired   (persist, changePasscode)
3261     *  10  errMAFSecureStoreManagerErrorPasswordRequiresDigit  (persist, changePasscode)
3262     *  11  errMAFSecureStoreManagerErrorPasswordRequiresLower  (persist, changePasscode)
3263     *  12  errMAFSecureStoreManagerErrorPasswordRequiresSpecial    (persist, changePasscode)
3264     *  13  errMAFSecureStoreManagerErrorPasswordRequiresUpper  (persist, changePasscode)
3265     *  14  errMAFSecureStoreManagerErrorPasswordUnderMinLength (persist, changePasscode)
3266     *  15  errMAFSecureStoreManagerErrorPasswordUnderMinUniqueChars    (persist, changePasscode)
3267     *  16  errMAFSecureStoreManagerErrorDeleted    (unlock)
3268     *
3269     * In the MAFLogonCoreCDVPluginErrorDomain the following errors are thrown:
3270     * 
3271     *  1 (init failed)
3272     *  2 (plugin not initialized)
3273     *  3 (no input provided)
3274     *
3275     * On Android the 'errorDomain' property of the core errors can take the following values: MAFLogonCoreErrorDomain and MAFLogonCoreCDVPluginErrorDomain.
3276     * There are no logon specific error codes, the 'errorCode' property only wraps the error values from the underlying libraries. 
3277     */
3278    
3279    /**
3280     * Callback function that is invoked upon successfully registering or unlocking or retrieving the context.
3281     *
3282     * @callback sap.Logon~successCallback
3283     *
3284     * @param {Object} context An object containing the current logon context.  Two properties of particular importance
3285     * are applicationEndpointURL, and applicationConnectionId.
3286     * The context object contains the following properties:<br/>
3287     * "registrationContext": {<br/>
3288     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"serverHost": Host of the server.<br/>
3289     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"domain": Domain for server. Can be used in case of SAP Mobile Platform communication.<br/>
3290     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"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.<br/>
3291     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"https": Marks whether the server should be accessed in a secure way.<br/>
3292     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"serverPort": Port of the server.<br/>
3293     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"user": Username in the backend.<br/>
3294     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"password": Password for the backend user.<br/>
3295     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"farmId": FarmId of the server. Can be nil. Used in case of Relay server or SiteMinder.<br/>
3296     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"communicatorId": Id of the communicator manager that will be used for performing the logon. Possible values: IMO / GATEWAY / REST<br/>
3297     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"securityConfig": Security configuration. If nil, the default configuration is used.<br/>
3298     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"mobileUser": Mobile User. Used in case of IMO manual user creation.<br/>
3299     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"activationCode": Activation Code. Used in case of IMO manual user creation.<br/>
3300     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"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><br/>
3301     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"gatewayPingPath": The custom path of the ping URL on the gateway. Used in case of Gateway only registration mode.<br/>
3302     * }<br/>
3303     * "applicationEndpointURL": Contains the application endpoint URL after a successful registration.<br/>
3304     * "applicationConnectionId": ID to get after a successful SUP REST registration. Needs to be set in the download request header with key X-SUP-APPCID<br/>
3305     * "afariaRegistration": manual / automatic / certificate<br/>
3306     * "policyContext": Contains the password policy for the secure store {<br/>
3307     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"alwaysOn":<br/>
3308     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"alwaysOff":<br/>
3309     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaultOn":<br/>
3310     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasDigits":<br/>
3311     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasLowerCaseLetters":<br/>
3312     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasSpecialLetters":<br/>
3313     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"hasUpperCaseLetters":<br/>
3314     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"defaultAllowed":<br/>
3315     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"expirationDays":<br/>
3316     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"lockTimeout":<br/>
3317     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"minLength":<br/>
3318     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"minUniqueChars":<br/>
3319     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"retryLimit":<br/>
3320     * }<br/>
3321     * "registrationReadOnly": specifies whether context values are coming from clientHub / afaria<br/>
3322     * "policyReadOnly": specifies whether passcode policy is coming from afaria<br/>
3323     * "credentialsByClientHub": specifies whether credentials are coming from clientHub
3324     */
3325     
3326     /**
3327      * Callback function that will be invoked with no parameters.
3328      * 
3329      * @callback sap.Logon~successCallbackNoParameters
3330      */
3331     
3332     /**
3333      * Callback function that is invoked upon successfully retrieving an object from the DataVault.
3334      * 
3335      * @callback sap.Logon~getSuccessCallback
3336      *
3337      * @param {Object} value The object that was stored with the given key.  Can be null or undefined if no object was stored
3338      * with the given key.
3339      */
3340