Skip to Content

Step by Step with the SAP Cloud Platform SDK for Android

Part 10 — OAuth

Previous (Configuration Provider and the Discovery Service)

The SDK provides multiple methods to authenticate the application with the SAP Cloud Platform Mobile Services. One of the benefits of using OAuth is that the application does not deal directly with a user name and password. The application opens a browser window to the SAP Identity service where the authentication occurs. The application receives a token that is valid for a set duration and which can be revoked. Another benefit is that the authentication can be done in Chrome which means that if one application has registered with the server, a second application authenticating to the same server can reuse the stored token. Chrome also has a feature to save credentials.

The following are some additional sources of documentation on OAuth.
OAuth 2.0
Foundation APIs

The below examples will modify the sample to use OAuth with the discovery service using OAuth2WebViewProcessor and then the OAuth2BrowserProcessor. A second app will be created demonstrating how credentials can be shared between apps using the OAuth2BrowserProcessor.
Using OAuth for Authentication
OAuth with OAuth2BrowserProcessor

Using OAuth for Authentication

  1. Modify the app to use OAuth.
  2. Unpublish and then publish the app to the Discovery Service. Add the following custom values after replacing p1743065160 with your user ID.
    {
        "serviceURL":"https://hcpms-p1743065160trial.hanatrial.ondemand.com",
        "appID":"com.sap.stepbystep",
        "connectionID":"com.sap.edm.sampleservice.v2"
    }
  3. Create a class named SAPOAuthTokenStore and replace its contents with the below code.
    package com.example.android.stepbystep;
    
    import android.net.Uri;
    
    import com.sap.cloud.mobile.foundation.authentication.OAuth2Token;
    import com.sap.cloud.mobile.foundation.authentication.OAuth2TokenStore;
    import com.sap.cloud.mobile.foundation.securestore.SecureKeyValueStore;
    
    /**
     * Singleton class which is used for store of OAuth tokens. The tokens are persisted simple
     * in the application's secure store.
     */
    public class SAPOAuthTokenStore implements OAuth2TokenStore {
        SecureKeyValueStore store;
    
        public SAPOAuthTokenStore(SecureKeyValueStore secureKeyValueStore) {
            store = secureKeyValueStore;
        }
    
        @Override
        public void storeToken(OAuth2Token oAuth2Token, String url) {
            if (store != null && store.isOpen()) {
                store.put(this.key(url), oAuth2Token);
            }
        }
    
        @Override
        public OAuth2Token getToken(String url) {
            OAuth2Token token = null;
            if (store != null && store.isOpen()) {
                token = (OAuth2Token) store.getSerializable(key(url));
            }
            return  token;
        }
    
        @Override
        public void deleteToken(String url) {
            if (store != null && store.isOpen()) {
                store.remove(key(url));
            }
        }
    
        public void deleteAllTokens() {
            if (store != null) {
                String[] keys = store.keys();
                for (String key:keys) {
                    store.remove(key);
                }
            }
        }
    
        private String key(String url) {
            return Uri.parse(url).getHost();
        }
    }
    
  4. Add the following variable definitions to MainActivity.
    private SAPOAuthTokenStore oAuthTokenStore;
    private String oAuthAuthorizationEndpoint;
    private String oAuthClientID;
    private String oAuthRedirectURL;
    private String oAuthTokenEndpoint;
    
  5. Add the below code to the getConfigurationFromDiscoveryService method below the line connectionID = config.getString(“connectionID”);.
    oAuthAuthorizationEndpoint = config.getJSONArray("auth").getJSONObject(0).getJSONObject("config").getString("oauth2.authorizationEndpoint");
    oAuthTokenEndpoint = config.getJSONArray("auth").getJSONObject(0).getJSONObject("config").getString("oauth2.tokenEndpoint");
    oAuthClientID = config.getJSONArray("auth").getJSONObject(0).getJSONObject("config").getJSONArray("oauth2.clients").getJSONObject(0).getString("clientID");
    oAuthRedirectURL = config.getJSONArray("auth").getJSONObject(0).getJSONObject("config").getJSONArray("oauth2.clients").getJSONObject(0).getString("redirectURL");
    

    The values being extracted are shown below using Fiddler which is a tool that can examine network requests.

  6. Comment or replace the below line in the onCreate method.
    //bapStore = new BasicAuthPersistentStore(myStore);
    oAuthTokenStore = new SAPOAuthTokenStore(myStore);
  7. In MainActivity.java, in the onUnregister method replace the bapStore.deleteAllCredentials() with the below lines.
    oAuthTokenStore.deleteAllTokens();
    CookieManager.getInstance().removeAllCookies(null);
  8. In MainActivity.java, in the logout method, replace the line onRegister(null) in the onResponse callback with the below line.
    System.exit(0);
  9. In the onRegister method, comment out the new OkHttpClient.Builder() line (5 lines or so) and add the below code.
    OAuth2Configuration oAuth2Configuration = new OAuth2Configuration.Builder(getApplicationContext())
            .clientId(oAuthClientID)
            .responseType("code")
            .authUrl(oAuthAuthorizationEndpoint)
            .tokenUrl(oAuthTokenEndpoint)
            .redirectUrl(oAuthRedirectURL)
            .build();
    
    myOkHttpClient = new OkHttpClient.Builder()
            .addInterceptor(new OAuth2Interceptor(new OAuth2WebViewProcessor(oAuth2Configuration), oAuthTokenStore))
            .addInterceptor(new AppHeadersInterceptor(appID, deviceID, "1.0"))
            .cookieJar(new WebkitCookieJar())
            .build();
    ClientProvider.set(myOkHttpClient);  //The OAuth flow will use this for requesting the token
    
  10. Uninstall the app and then run it. The authentication page from the SAP Identity service is shown in an HTML page being shown by the WebView component of the app.
    Notice that the SAP ID service has an option to Remember me which if checked will persist a cookie for 3 months so the credentials will not need to be entered during that time.
    The next section presents some additional options for saving credentials as the Remember me checkbox is vendor specific.
  11. It is also possible to configure the validity period for OAuth tokens in the management cockpit and if an authorization screen should be shown or not.
  12. The OAuth token can also be revoked in the SAP Cloud Platform Cockpit (not the Mobile Services cockpit). You may wish to do so if an OAuth token was compromised.

OAuth with OAuth2BrowserProcessor

This example will change the processor from the OAuth2WebViewProcessor to use OAuth2BrowserProcessor and will highlight the additional functionality this provides which includes making use of the Chrome browser’s ability to save credentials, access the System Certificate store and ability to share tokens between apps that are authenticating against the same IDP. Note, not all devices have Chrome installed on them.

  1. Edit the Security configuration.
    Change the protocol from https to the app id (com.example.android.stepbystep).
  2. Unpublish and then publish the app to the Discovery Service. Add the following custom values after replacing p1743065160 with your user ID.
    {
        "serviceURL":"https://hcpms-p1743065160trial.hanatrial.ondemand.com",
        "appID":"com.sap.stepbystep",
        "connectionID":"com.sap.edm.sampleservice.v2"
    }
  3. In the onRegister method, change the OAuth processor from OAuth2WebViewProcessor to OAuth2BrowserProcessor.
  4. Uninstall and then run the app.Authentication screen shown using the OAuth2BrowserProcessor.
    Notice the user is presented with an option to save the entered credentials.

    In the example above, the option to show the consent screen was enabled in OAuth settings of the app in the Mobile Services Management Cockpit. If this is not checked the question Do you want Google Chrome to save your password for this site is not displayed long enough for the user to click on the Save button.

    The saved passwords can be configured via the Chrome’s Settings, Save passwords menu.

    OAuth tokens can be cleared via the Unregister button in the app followed by clearing the cookies in Chrome’s Settings, Privacy, Clear browsing data menu as shown below.

  5. If the device or emulator is provisioned with an X.509 certificate, it can also be used instead of entering a user name and password for authentication.
  6. If an another app was created, perhaps using the SAP Wizard after modifying it to use the OAuth2BrowserProcessor the app can be started without the need to authenticate. It requires adding the following entry to the second app’s AndroidManifest.xml.
    <activity android:name="com.sap.cloud.mobile.foundation.authentication.OAuth2RedirectActivity">
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />
            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />
            <data android:scheme="com.example.android.someotherapp" />
        </intent-filter>
    </activity>    
    

    This can improve the user experience when a user makes uses of multiple apps using the same IDP daily.

Previous (Configuration Provider and the Discovery Service)

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply