Skip to Content
Author's profile photo Daniel Van Leeuwen

Getting Started with Kapsel – Appendix D — Security Part 2

/wp-content/uploads/2014/12/sap_logo_333927.png

Appendix D:  Security Part 2

This appendix goes over some topics that should be considered for secure Kapsel apps.

Cross-Site Request Forgery (CSRF)
Sharing Credentials between Applications
Accessing the SMP 3.0 Server From Outside a Corporate Firewall or on a Cellular Network
Using the X.509 Certificate Provider to Register using a Client Certificate
Things to Consider Before Release
SiteMinder
Additional Security Topics in Part 1

Cross-Site Request Forgery (CSRF)

CSRF is an attack which forces an end user to execute unwanted actions on a web application in which he/she is currently authenticated.  See Cross-Site Request Forgery (CSRF) for additional details.

The SAP Netweaver Gateway system protects against CSRF attacks by requiring that all modifying requests include an X-CSRF-Token in the header of the request.  The value of this is returned from a GET request.  See Cross-Site Request Forgery Protection for additional details.  The included  index.html demonstrates how to perform create, update and delete operations that make use of the CSRF header.  To use this provide the user id and password for the OData source on line 6, place a copy of datajs-1.1.2.min.js into the same folder as the HTML file and deploy the Kapsel app.  Notice below that the carrier ID AA has been deleted and the currency for AC has been changed to USD.  image3.PNG

Sharing Credentials between Applications

If multiple applications on a device connect to the same SAP Mobile Platform server and use the same user name and password or certificate, those can be shared between apps so that they only need to be entered once.  The shared credentials are managed by an application called Client Hub which integrates with the Logon plugin.  The Client Hub is provided as an Android and iOS project that can be built and installed on a mobile device or simulator.  It is part of the mobile SDK native SDK.

C:\SAP\MobileSDK3\ClientHub

  For additional details see Client Hub.

Note the applications that are sharing credentials can be either native mobile applications or Kapsel applications.

Note that the Client Hub does not work with the iOS 8 simulator.  See BCP issue 1570001617.

The Client Hub project and the Kapsel projects must be signed by the same certificate.  For more information on Android application signing see Signing Your Applications.

Perform the following steps to share credentials between two Kapsel apps.

  • Deploy the ClientHub project to a device or emulator.  When it starts provide a single sign-on password. 
    image4.PNGimage8.PNG
  • Open the LogonDemo project which was described in the section named Logon.
  • Note, if deploying to an iOS device the clienthubEntitlements keychain group must be added to the entitlements section as well as the bundle identifier.
    Note the bundle identifier can also be represented as $(CFBundleIdentifier). 
    Xcode 5
    logon8.PNG
  • On Android, add a folder and file named LogonDemo/res/raw/clienthub.properties.  The contents should include
    Host=10.7.171.208
    Port=8080
    HTTPS=false
    SecurityConfiguration=Config123
    UserCreationPolicy=automatic
    FarmID=0
    Domain=default
    URLSuffix=
    
  • Note that on Android the FarmID, Domain and URLSuffix fields must be provided even though they are not being used in this example.
  • On iOS, right click on the project and choose New File > iOS > Resource > Property List and name the file clienthub.  Right-click on the file and choose Open As > Source Code.  The contents should include
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "
    http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Host</key>
        <string>10.7.171.208</string>
        <key>Port</key>
        <string>8080</string>
        <key>HTTPS</key>
        <false/>
        <key>SecurityConfiguration</key>
        <string>Config456</string>
        <key>UserCreationPolicy</key>
        <string>automatic</string>
    </dict>
    </plist>

  • The value of SecurityConfiguration must be the same across apps that wish to share credentials on the device.
  • Remove the app from the device or simulator.  Deploy and run the app LogonDemo.  When it starts the single sign-on password for the client hub screen is requested.
    image5.PNGimage6.PNGimage7.PNG

    Notice that the registration screen is not shown.  When using the Client Hub, the connection details for the SMP 3.0 server (host, port etc.) must be statically supplied in the plist or properties file.

  • Create a second Kapsel project with a name of LogonDemo2 and an application id of com.mycompany.logon2.  Follow the steps in the section named Logon.
  • Follow the steps shown in Configuring a Kapsel App in the Management Cockpitto create an Application with the application id of
    com.mycompany.logon2
  • Create the clienthub file as described previously.
  • Deploy and run Logon2.  When it starts, the single sign-on password screen is presented.
    image5.PNGimage7.PNG

    Notice that the screen asking for a username and password was not shown as the username and password are provided from the Client Hub app.

    If Logon Demo 2 is closed and reopened, it is only the app’s passcode screen that is shown.

    image9.PNGimage10.PNG

  • Note that on iOS, it is necessary to press the reset button in the Client Hub before removing the Client Hub application.

Accessing the SMP 3.0 Server From Outside a Corporate Firewall or from a Cellular Network

Support for the Relay Server was added as part of the SMP 3.0 SP03 release.  SAP provides a publicly hosted relay server that can be used in development to enable a server such as the SMP 3.0 server to be available to devices outside of a corporate firewall or on a different network.  In a production environment it is recommended that you install the relay server into your own environment.
The relay server works by establishing a persistent connection between the rsoe.exe (outbound enabler) which typically runs on the same machine as the SMP 3.0 server and a relay server (which is publically reachable).  The publicly hosted relay server is running at http://relayserver.sybase.com and more recently at http://relayserver.sap.com.
The complete documentation is available at Relay Server.

The relay server is part of the SAP Sybase SQL Anywhere product.  If you do not already have a copy of it, a trial version can be downloaded from SAP Sybase SQL Anywhere 16 Developer Edition.  During the install, ensure the option Relay Server is checked.

The following steps demonstrate how to use the publicly hosted relay server to enable a Kapsel app to be able to connect to an SMP 3.0 server running behind a corporate firewall or on a different network.  Before following the below steps, make sure that the server connections in the SMP 3.0 server are using test data only or have sufficient security setup.

  • Create a file named C:\Kapsel_Projects\rsoeSMP.config.  Here is what my settings look like.  The farm name must be unique.
    -f dan.van.leeuwen.rsFarm
    -id rsoeSMP
    -t d5337df5a9a26141ce52bd0f5b59
    -cr "host=relayserver.sap.com;https=1;port=443;proxy_host=proxy;proxy_port=8080;url_suffix=/rs1/server/rs_server.dll"
    -cs "host=localhost;port=8080"
    -v 4
    -o c:\temp\rsoe_smp.log
    -os 10M

    The outbound enabler options are documented here.  Note the settings for proxy_host and proxy_port.  If your network does not use a proxy server, remove these values.

  • Locate the outbound enabler (rsoe.exe).  It should be located at C:\Program Files\SQL Anywhere 16\Bin64 and start it from a command window.
    rsoe @c:\Kapsel_Projects\rsoeSMP.config

    /wp-content/uploads/2014/12/image25_616896.png

  • Open a browser and verify that the SAPUI5 page can be accessed through the relay server.
    http://relayserver.sap.com/rs1/client/rs_client.dll/dan.van.leeuwen.rsFarm/sapui5/

    Note, the value dan.van.leeuwen.rsFarm will need to be replaced with your subscription ID and farm name.  At this point the relay server is allowing access to the SMP 3.0 server running on your laptop from any machine or device that can reach the public URL relayserver.sap.com.

  • Finally modify the sample from the Logon sample to use the relay server.  This will enable the Kapsel app to register against a SMP 3.0 server that is on a private network from another network.
    In register3.html, change the context to use the relay server.  The changed context is shown below.  Note, the farmId dan123.rsFarm will need to be modified to match the subscription ID provided when registering with the hosted relay server.
    var context = {
            "serverHost": "relayserver.sap.com", //Place your SMP 3.0 server name here
            "https": "false",
            "serverPort": "80",
            "user": "i82xxx",   //Place your user name for the OData Endpoint here
            "password": "xxx",  //Place your password for the OData Endpoint here
                                  //once set can be changed by calling sap.Logon.changePassword()
            "communicatorId": "REST",
            "passcode": "password",  //note hardcoding passwords and unlock passcodes are strictly for ease of use during development
                                     //once set can be changed by calling sap.Logon.managePasscode()
            "unlockPasscode": "password",
            "passcode_CONFIRM":"password",
            "farmId" : "dan.van.leeuwen.rsFarm",
            "resourcePath" : "rs1/client/rs_client.dll"
    };

Using the X.509 Certificate Provider to Register using a Client Certificate

Client certificates can be used by applications to uniquely identify a user to the SMP 3.0 server or to an OData backend.  Client certificates can be passed to the Logon Plugin either by SAP Afaria or via the X.509 Certificate Provider Interface.  The AuthProxy plugin can access a certificate directly via its CertificateFromFile or CertificateFromStore classes.  The Authproxy plugin can also access a certificate from the Logon plugin via the class CertificateFromLogonManager but the Logon plugin cannot access a certificate from the AuthProxy plugin.  If the AuthProxy setting SAPKapselHandleHttpRequests is set to true, then on Android when challenged for a certificate, the system choose certificate dialog will appear.  On iOS, only certificates that are part of the application’s key chain are displayed.  For further details see Making Certificates and Keys Available To Your App and Finding a certificate for further details.

The X.509 Certificate Provider is an interface that can be used to integrate third-party certificate providers with the Logon plugin.  For additional details see Using the X.509 Certificate Provider Interface to Integrate with Third-Party Certificate Providers and https://github.com/SAP/mobilesdk-certificateprovider.
The following steps demonstrate how to use this interface to allow the Logon plugin to access a client certificate that is stored on an Android device or emulator.  It is intended that this same technique can be used to allow the Logon plugin to work with third-party software that will provide the certificate to the device rather than simply accessing a certificate that is already on the device.  This example uses the Logonsample.

  • Add the sample implementation of the X.509 certificate provider to the project.  The source to two required Java files can be copied from CustomCertificateProvider.java and  CustomKeyManager.java
    In the file CustomCertificateProvider.java, modify the initial value of _alias to match the name of the client certificate and change the line settings.put(“filepath”, “user1.p12”); to match the name of the client certificate.
  • Add the below bolded line to the AndroidManifest.xml file to indicate the class name the logon plugin should load which implements the X.509 certificate provider API.
    <application android:hardwareAccelerated="true" android:icon="@drawable/icon" android:label="@string/app_name">
    <meta-data android:name="certFromFileProvider" android:value="com.example.certificatefromfileprovider.CustomCertificateProvider" />
  • Modify index.html to instruct the Logon plugin to use the X.509 Certificate Provider API.  Change the two occurrences of the line
    sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
    to
    sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context, null, "certFromFileProvider"); 
    //null indicates to use the default view provider, "certFromFileProvider" is the name of the class to load
    

    Modify the index.html to use

    var appId = "com.mycompany.authproxy";
    ...
    "serverHost": "ykfn00528072a.amer.global.corp.sap", //Must be the fully qualified host name
    "https": "true",
    "serverPort": "8082"  //mutual authentication port
    
  • Copy the file x509ProviderUI.view.js to C:\Kapsel_Projects\LogonDemo\plugins\com.sap.mp.cordova.plugins.logon\www\common\assets\ui\resources\x509ProviderUI.view.js
    Copy the file i18n.provider.properties to C:\Kapsel_Projects\LogonDemo\plugins\com.sap.mp.cordova.plugins.logon\www\common\assets\i18n\i18n.provider.properties
  • The following instructions enable the read request to include the client certificate.
    Add the following line to the start of the init method
    //Integrate datajs with HTTPS proxy
    OData.defaultHttpClient = sap.AuthProxy.generateODataHttpClient();
    

    Add the following two bolded lines to the read method.

    clientCert = new sap.AuthProxy.CertificateFromLogonManager("com.mycompany.logon");           
    var request = {
        headers : oHeaders,
        certificateSource : clientCert,
        requestUri : sUrl,     method : "GET" };

    Also note that the certificate alias property of the endpoint in the management cockpit can be used to specify a certificate alias.

  • This example requires that the SMP 3.0 server has been configured to use port 8082 for mutual authentication.  See the AuthProxy plugin section for additional details.
  • Ensure that the public key of the certificate authority used to sign the SMP 3.0 server’s certificate for port 8082 is installed onto the Android device or emulator and that the client certificate has been uploaded to the device.  This is covered in the AuthProxy section of the guide.
  • Copy the files to the platform directory by running
    cordova -d prepare
  • Use the Android IDE to deploy and run the project.
    image28.PNG

    Note, there seems to be a focus bug in the screen Get File Certificate Settings.  After providing the password, click on an empty space before pressing the submit button.

    image29.PNG
    image30.PNG

  • Note that the CustomCertificate Provider.java class can be debugged using Eclipse by placing a breakpoint in the method setParamaters and then clicking on Run > Debug.  After pressing the Submit button on the Get File Certificate Settings screen the breakpoint should be hit.

Things to Consider Before Release

Consider minifying or even obfuscating your code if you wish to make it harder for someone to examine your code.

Ensure that the app cannot be debugged.  See the debugging section for additional details.

Remove any hardcoded passwords.  Many of the samples have these set in the context variable so they do not need to be entered for ease of use during development.

Ensure that the log level is set appropriately and that the log commands that are left are intended to be in the production code.  Review the log output to ensure that nothing is being logged that should not.

Review the client password policy and ensure that it is set appropriately.

Consider adding a Mobile Device Management solution such as SAP Afaria to enforce a lock screen, a password policy, to enable remote wipes of a device and to prevent devices from being rooted or jail broken.

SiteMinder

SiteMinder is a commonly used access management solution that can be used with the SMP 3.0 platform.  The following links provide additional details.
CA SiteMinder
Single Sign-on Integration with SiteMinder
How-To: Set up SUP with SiteMinder

Note that comments are not easily searchable in SCN.  If you have a question that is not specific to the above content it would be best to create a new discussion on SCN.

To include a reference to this document, Right Click on the title and select ‘Copy Shortcut’.  Paste it into the new Discussion so people will know the relevance.  If you want to bring it to the attention of the author, repeat the same process with the Author’s name.

Security Part 1

Back to Getting Started With Kapsel

Assigned Tags

      25 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      Can you please elaborate more about you above comment  "Note, the read call will not succeed since the OData provider is not configured to accept an X.509 client certificate."

      Since it might be limited our work of consuming data from backend....

      It's remind me that  AuthProxy read only work and not the regular Odata read when i using client certificate.

      Thanks,

      Eli

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I went through the certificate provider section again and updated the content slightly.  The backend used by this example takes basic auth for credentials and not a client certificate.  You can however follow the instructions to make a read request against the SMP server using the mutual authentication port on 8082 or you can use the regular HTTPS port of 8081 or perhaps 443 if you add the following code to the read method.

      sUrl = sUrl.replace("8082", "443");

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi,

      Another question    in your sample you mentioned  that you need to  set clienthub.properties  for  tag SecurityConfiguration=Config123 .

      Can you tell me if is the SecurityConfiguration  need to  the same name form  application in SMP Cockpit?

      Tx,

      Eli

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      The SecurityConfiguration value needs to be the same value in each clienthub.properties file that wishes to share information between apps.

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      I've been trying the last example:

      "Using the X.509 Certificate Provider to Register using a Client Certificate"

      with no luck.

      I have setup things according to the above steps and according to this tutorial:

      http://help.sap.com/saphelp_smp306sdk/helpdata/en/cf/3151ccbd2249af9ce933c39cb6d846/content.htm

      Run ClientHub first and setup sso passcode.

      Than run LogonDemo app. when i enter the passcode and click "submit" the app closed and i get this error in LogCat:

      logClientHub.PNG

      I tried to click skip and enter the "certificate path" and "password" and clicked "submit", UI didn't changed and i got this message in LogCat:

      cancelLogCat.PNG

      Any ideas?

      First error is most important to me since i need to use clienthub for the certificate.

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      What version of the SMP SDK are you using?  I am seeing a similar error in SP06 while following the Client hub example in this guide.  I will try to find out if it is an error in the instructions or a bug.

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      I'm using the lastest  SMP SDK SP06 along with SMP SERVER SP05

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      It turns out that a few optional fields are no longer optional.  I will create a ticket for the development team to consider making them optional again.  Specifically in the Android clienthub.properties file, the following values must be present (even though they are not used by the SMP 3.0 server).

      Domain=default

      URLSuffix=

      Hope that helps,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      Your suggestion did manage to get me to the next step (with no errors), where i need to insert the "certificate path" and "certificate password".

      After inserting the two above and click "submit" i get this warning message:

      Capture.PNG

      Then it stack on the same screen, no luck on getting to the "set app passcode" screen.

      Any ideas?

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I believe that indicates that there is not a certificate with an alias of RakeveCa in the elimizCa.p12 file.

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      I'm using the same certificate file "elimizCa.P12" as i used in the AuthProxy example.

      The AuthProxy plugin did succeed on finding "RakeveCa" Alias (with mutual authenticated example) so i'm sure it's there.

      Can you check maybe there is some interruptions with the certificates extraction?

      Is there any other configurations i need to provide for this example in order to instruct the plugin about the Alias ?

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      Perhaps try listing the contents of the p12 file and check the case of the alias.

      keytool -list -keystore user1.p12 -storetype pkcs12 -storepass changeit

      It should list something like

      Keystore type: PKCS12

      Keystore provider: SunJSSE

      Your keystore contains 1 entry

      user1, Jan 13, 2015, PrivateKeyEntry,

      Certificate fingerprint (SHA1): XXXX

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      I've managed to change the Alias and register successfully.

      However, when i try to execute a read, i get an error.

      This is how the read function look like:

                  function read() {

                    if (!appCID) {

                    alert("Register or unlock before proceeding");

                    return;

                }

                      clearTable();

                      sUrl = applicationContext.applicationEndpointURL + "/Products";

                      var oHeaders = {};

        oHeaders['X-SMP-APPCID'] = appCID;               

                      var request = {

                          headers : oHeaders,

                          requestUri : sUrl,

                          method : "GET"

                      };

                      OData.read(request, readSuccessCallback, errorCallback);

                  }

      I checked that all variables have correct values (appCID, oHeaders, etc).

      This is the error i get in eclipse:

      el.PNG

      Any ideas what might be the problem?

      Thanks

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I believe you would need to pass the client certificate in the request.

      There is an example of this in the AuthProxy section of the guide.  See http://scn.sap.com/docs/DOC-49623
      and
      http://scn.sap.com/servlet/JiveServlet/download/49623-11-288633/index.html.zip

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      My question is regarding the "Using the X.509 Certificate Provider to Register using a Client Certificate" section.

      I have setup all necessary steps (including ClientHub) and managed to register and get data with the read method (thanks to your help).

      I want that the:

      sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context,null,"certFromFileProvider");

      And the hole process of setting the SSO and passcode will be automatically so the user will only see the MainDiv (after couple of seconds when all the process done).

      How can i accomplish this?

      Thanks in advanced.

      Eli

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      There is some content on how to customize the Logon plugin in the logon plugin section of the guide.  Customizing it is not very easy. 

      Getting Started with Kapsel - Part 2 -- Logon

      I believe some work is being done to make this a bit easier.  Starting in SP06 PL02 some of the screens used by the Fiori Client have been changed to be statically defined rather than dynamically generated which makes them easier to customize.  An example of this is C:\SAP\MobileSDK3\KapselSDK\SP06PL02\plugins\logon\www\common\assets\ui\resources\enterPasscode.view.js.

      At some point I hope to add more details on how to customize the statically generated screens but at this point they are only used by the Fiori Client.

      Regards,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Thanks for answering.

      Another issue, when running the app the first time (after running ClientHub) we have to go through 3 steps:

      1. Enter sso passcode

      2. Enter Certificate path and Password

      3. Enter app passcode

      After these steps i can execute Read function and get the data.

      When i run the app the second time (and invoke the init() method when deviceready event fires) i then been redirected again to step 2.

      Need to enter Enter Certificate path and Password and then back to my previous screen where i can execute the Read function again.

      Why do i need to redo Step 2?

      What condition do i need to check so i won't be needed to enter Step 2 and just start using the app with the Read function?

      Thanks

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      Perhaps you can modify the method getCertificate in the file CustomCertificateProvider.  If you have the path to the certificate and the password stored, you could perhaps call setParameters instead of _callback.showUI(map);

      The idea behind the X.509 Certificate Provider interface is to provide a way to integrate with a third part mobile device management solution that can provide a certificate to your application.  The example shown here is a very simple one where the certificate is loaded from the device's file system rather than a third party mobile device management solution.  How are you going to manage getting the client certificates onto each device?

      In general, questions that are not directly about the samples/content shown in the guide should be posted to a new discussion since the comments attached to this document are not easily searchable in SCN.

      Hope that helps,

      Dan van Leeuwen

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      Thanks for the answer, it did point me to the right direction and i have succeed to make it work.

      Thanks again

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      We would like to launch the app and spread it to our employees but the first process of the 3 steps:

      1. Enter sso passcode

      2. Enter Certificate path and Password

      3. Enter app passcode

      Is not very user friendly, i have followed your link you provided earlier regarding the customization of the logon but it is not very clear.

      Would you be able to provide more detailed instruction (maybe step by step) on how to customize the logon screen?

      This would be much appreciated since we have to deliver this app ASAP and this issue is the only thing that prevent us from delivering the app.

      Thanks

      Eli

      Author's profile photo Former Member
      Former Member

      Hi Daniel

      regarding the "Using the X.509 Certificate Provider to Register using a Client Certificate" section.


      I am able to get data using the below code:

             var oHeaders = {};

             oHeaders['X-SMP-APPCID'] = factory.appCID;

             oHeaders['content-type'] = "application/atom+xml";

             var clientCert = new sap.AuthProxy.CertificateFromLogonManager(factory.appId);

            

             var request = {

                 headers : oHeaders,

                 certificateSource : clientCert

           ,    requestUri : sUrl,

                 method : "GET"

             };

             OData.read(request, SUCCESS, FAIL, null);

      Problem is, i need to pass data with a "POST" method.

      I tried to change things up in the request object like:

             var request = {

                 headers : oHeaders,

                 certificateSource : clientCert

           ,    requestUri : sUrl,

                 method : "POST",

                data: xmlData

             };

      I get an error "no handler for data".

      What is the proper way to send a POST request using OData?

      Thank

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      The Gettting Started with Kapsel guide has a few simple examples of a create row/POST with OData that might be of some help.

      See Getting Started with Kapsel - Part 15 -- Offline OData (New in SP05)

      and

      Getting Started with Kapsel - Appendix D -- Security Part 2

      Hope that helps,

      Dan van Leeuwen

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      Updated for SP07 server and SP08 SDK.

      Note that the Certificate Provider Interface no longer requires Client Hub.

      Author's profile photo Former Member
      Former Member

      Hi Daniel,

      when trying to replicate the certificate provider scenario on SP08, SDK SP09 (

      now using SP10) and Android it gives me this error:

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(1544)] "getCertificateFromProvider success callback called", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/LogonController.js (1544)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "handleCoreResult currentContext", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"registrationContext":{"password":"","farmId":"0","resourcePath":"","communicatorId":"REST","serverPort":0,"securityConfig":"","https":true,"domain":"","activationCode":null,"serverHost":"","mobileUser":null,"user":""},"policyContext":{},"applicationConnectionId":null,"credentialsByClientHub":false,"applicationEndpointURL":null,"registrationReadOnly":false,"policyReadOnly":true,"afariaRegistration":"certificate"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "handleCoreResult currentState", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"defaultPasscodeUsed":false,"secureStoreOpen":false,"isAfariaCredentialsProvided":false,"stateClientHub":"notAvailable","stateAfaria":"initializationNotStarted","status":"new","applicationId":"flight.odata","defaultPasscodeAllowed":true}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] ""registrationFlowBuilder"", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r0", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r0","condition":{"state":{"secureStoreOpen":false,"status":"fullRegistered","defaultPasscodeUsed":true}}}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching secureStoreOpen", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r1", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r1","condition":{"state":{"secureStoreOpen":false,"status":"fullRegistered"}},"action":"SCR_UNLOCK"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching secureStoreOpen", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r2", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r2","condition":{"state":{"status":"fullRegistered","stateClientHub":"availableNoSSOPin"}},"action":"SCR_SSOPIN_SET"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.190 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r3", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r3","condition":{"state":{"status":"new"},"context":null}}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r4", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r4","condition":{"state":{"status":"new","stateClientHub":"availableNoSSOPin"}},"action":"SCR_SSOPIN_SET"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching stateClientHub", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r5", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r5","condition":{"state":{"status":"new","stateClientHub":"availableInvalidSSOPin"}},"action":"SCR_SSOPIN_SET"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching stateClientHub", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r6", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r6","condition":{"state":{"status":"new","stateClientHub":"availableValidSSOPin","stateAfaria":"initializationFailed"},"context":{"afariaRegistration":"certificate"}},"action":"SCR_ENTER_AFARIA_CREDENTIAL"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching stateClientHub", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r7", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r7","condition":{"state":{"status":"new","stateClientHub":"availableValidSSOPin","stateAfaria":"credentialNeeded"},"context":{"afariaRegistration":"certificate"}},"action":"SCR_ENTER_AFARIA_CREDENTIAL"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching stateClientHub", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r8", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r8","condition":{"state":{"status":"new","stateClientHub":"notAvailable","stateAfaria":"credentialNeeded"}},"action":"SCR_ENTER_AFARIA_CREDENTIAL"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.200 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching stateClientHub", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field mismatching stateAfaria", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r9", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r9","condition":{"state":{"status":"new"},"context":{"afariaRegistration":"certificate"}}}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "context field matching afariaRegistration", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "r10", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r10","condition":{"state":{"status":"new"},"context":{"afariaRegistration":"certificate"}}}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "state field matching status", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "context field matching afariaRegistration", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "match found: r10", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "rule", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"id":"r10","condition":{"state":{"status":"new"},"context":{"afariaRegistration":"certificate"}}}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "startRegistration", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"registrationContext":{"password":"","farmId":"0","resourcePath":"","communicatorId":"REST","serverPort":0,"securityConfig":"","https":true,"domain":"","activationCode":null,"serverHost":"","mobileUser":null,"user":""},"policyContext":{},"applicationConnectionId":null,"credentialsByClientHub":false,"applicationEndpointURL":null,"registrationReadOnly":false,"policyReadOnly":true,"afariaRegistration":"certificate"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.210 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "startRegistration", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.230 14940-15056/? I/com.sap.mobile.lib.supportability.Logger: [group: com.sap.smp.client.android] [artifact: Common] [version: 3.10.1] [buildTime: 2015-09-25 21:03] [gitCommit: 21e120ccb4a35cea7d0e54b0b21a9b8efe72252b] [gitBranch: rel-3.10]

      10-13 10:31:43.250 14940-15056/? I/com.sap.smp.request: [group: com.sap.smp.client.android] [artifact: Request] [version: 3.10.1] [buildTime: 2015-09-25 21:03] [gitCommit: 21e120ccb4a35cea7d0e54b0b21a9b8efe72252b] [gitBranch: rel-3.10]

      10-13 10:31:43.320 14940-15056/? I/com.sap.smp.request: [group: com.sap.smp.client.android] [artifact: Request] [version: 3.10.1] [buildTime: 2015-09-25 21:03] [gitCommit: 21e120ccb4a35cea7d0e54b0b21a9b8efe72252b] [gitBranch: rel-3.10]

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "registration failed", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "{"errorDomain":"MAFLogonCoreErrorDomain","errorCode":"-1","errorMessage":"java.lang.Exception: Host name may not be null"}", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(4)] ""LogonController.getRegistrationErrorText: {\"errorDomain\":\"MAFLogonCoreErrorDomain\",\"errorCode\":\"-1\",\"errorMessage\":\"java.lang.Exception: Host name may not be null\"}"", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "iabui showNotification", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(4)] ""onFlowError"", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(4)] "IAB close, NO_WINDOW, without windowRef", source: file:///android_asset/www/plugins/kapsel-plugin-logon/www/common/modules/Utils.js (4)

      10-13 10:31:43.330 14940-14940/? I/chromium: [INFO:CONSOLE(60)] "An error occurred: {"errorDomain":"MAFLogonCoreErrorDomain","errorCode":"-1","errorMessage":"java.lang.Exception: Host name may not be null"}", source: file:///android_asset/www/index.html (60)

      10-13 10:31:43.330 897-1618/? D/FocusedStackFrame: Set to : 0

      10-13 10:31:43.350 14940-15125/? W/PluginManager: THREAD WARNING: exec() call to CoreAndroid.exitApp blocked the main thread for 22ms. Plugin should use CordovaInterface.getThreadPool().

      10-13 10:31:43.350 897-911/? D/CustomFrequencyManagerService: acquireDVFSLockLocked : type : DVFS_MIN_LIMIT  frequency : 1958400  uid : 1000  pid : 897  pkgName : ACTIVITY_RESUME_BOOSTER@6

      10-13 10:31:43.360 32699-32699/? I/SQLiteSecureOpenHelper: getWritableDatabase(pwd)

      10-13 10:31:43.360 32699-32699/? I/SQLiteSecureOpenHelper: getDatabaseLocked(b,b,pwd)...

      10-13 10:31:43.360 897-911/? W/ActivityManager: mDVFSHelper.acquire()

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: com.sap.maf.tools.logon.core.LogonCoreException: No vault is present!

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: com.sap.maf.tools.logon.core.LogonCore.getSecureStorePasswordPolicy(LogonCore.java:1432)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: com.sap.maf.html5.android.MAFLogonCoreCDVPlugin.pluginResultWithReturnObject(MAFLogonCoreCDVPlugin.java:1700)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: com.sap.maf.html5.android.MAFLogonCoreCDVPlugin.onEvent(MAFLogonCoreCDVPlugin.java:1294)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: com.sap.maf.html5.android.MAFLogonCoreCDVPlugin.execute(MAFLogonCoreCDVPlugin.java:155)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: org.apache.cordova.CordovaPlugin.execute(CordovaPlugin.java:95)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: org.apache.cordova.PluginManager.exec(PluginManager.java:130)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: org.apache.cordova.CordovaBridge.jsExec(CordovaBridge.java:59)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: org.apache.cordova.engine.SystemExposedJsApi.exec(SystemExposedJsApi.java:41)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: org.chromium.base.SystemMessageHandler.nativeDoRunLoopOnce(Native Method)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: org.chromium.base.SystemMessageHandler.handleMessage(SystemMessageHandler.java:53)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: android.os.Handler.dispatchMessage(Handler.java:102)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: android.os.Looper.loop(Looper.java:145)

      10-13 10:31:43.360 14940-15125/? E/SMP_LOGON: android.os.HandlerThread.run(HandlerThread.java:61)

      10-13 10:31:43.360 14940-15125/? I/ClientHub: ClientHub application not installed on this device

      10-13 10:31:43.360 14940-15125/? E/MAFLogonCoreCDVPluginLog: CORECDVPlugin: Could not retrieve secure store policy.

      10-13 10:31:43.360 1459-1459/? D/SurfaceWidgetView: destroyHardwareResources():589638856

      The weird thing is that I set up the smpConfig and appConfig correctly on index.html, but apparently is giving an unknown hostname. PS: I am not using ClientHub.

      Debugging the application I could noticed that the getCertificate method is being called and creating an X509KeyManager correctly.

      Do you know what this might be?

      Thank you.

      Marcus

      Author's profile photo Daniel Van Leeuwen
      Daniel Van Leeuwen
      Blog Post Author

      I believe the code may have changed a bit in newer releases of the SDK.  The certificate provider sample code is now maintained on a public git server.  When using SP09 or greater of the SDK, please see this version of the Getting Started guide.

      Getting Started with Kapsel - Part 1 (SP09+)

      Regards,

      Dan van Leeuwen