Skip to Content

Step by Step with the SAP Cloud Platform SDK for Android

Part 3 — Authentication

Previous (Mobile Services)   Next (Logging)

Typically, when an application is opened, a request is made to the server to retrieve application information or perhaps to validate the users credentials so that the user will not be asked for them later when using the app. After the first request is made, a session is established that persists until the application is restarted or the session timeout is reached. The requests to the server make use of a REST API.

The following are some additional sources of documentation on these topics.
Authentication
Backend Connectivity

User Information

Note there are a set of screens (welcome, passcode, etc.) provided by the
SAP Onboarding Library for Android. For an example of using these, examine the code in an SAP Wizard generated project.

Logic to save the entered credentials and reuse them will be covered in the Remembering Credentials using the Secure Store section.

In this part, logic to authenticate or register using basic authentication and to query the SAP Cloud Platform Mobile Services for user information will be added.
Authentication with Basic Auth
Access Control

Authentication with Basic Auth

The below steps will add the code to have the app authenticate with the server.

  1. Add the below variable declarations to MainActivity.
    Modify the userID (p1743065160) in the serviceURL to match your user ID.

    private OkHttpClient myOkHttpClient;
    private String deviceID;
    private final String serviceURL = "https://hcpms-p1743065160trial.hanatrial.ondemand.com";  //change p1743065160
    private final String appID = "com.sap.stepbystep";
    private final String connectionID = "com.sap.edm.sampleservice.v2";
    private String messageToToast;
    private Toast toast;
    private String currentUser;
    

    Notice that the editor indicates a problem by showing the code in red as seen below and indicates a potential way to correct the problem.

    Double tap on OkHttpClient to select it and then press Alt + Enter on Windows or Option + Enter on a Mac to use the Android Studio Quick Fix feature to add the import for OKHTTPClient. Repeat for Toast.

  2. Replace the imports section of MainActivity.java with those shown below. This will reduce the need for performing the previous step of resolving imports in future sections of this tutorial.
    
    import android.content.DialogInterface;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Looper;
    import android.provider.Settings;
    import android.support.annotation.NonNull;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AlertDialog;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.webkit.CookieManager;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    import com.sap.cloud.mobile.foundation.authentication.BasicAuthDialogAuthenticator;
    import com.sap.cloud.mobile.foundation.authentication.OAuth2BrowserProcessor;
    import com.sap.cloud.mobile.foundation.authentication.OAuth2Configuration;
    import com.sap.cloud.mobile.foundation.authentication.OAuth2Interceptor;
    import com.sap.cloud.mobile.foundation.authentication.OAuth2WebViewProcessor;
    import com.sap.cloud.mobile.foundation.common.ClientProvider;
    import com.sap.cloud.mobile.foundation.common.EncryptionError;
    import com.sap.cloud.mobile.foundation.common.EncryptionUtil;
    import com.sap.cloud.mobile.foundation.common.SettingsParameters;
    import com.sap.cloud.mobile.foundation.configurationprovider.ConfigurationLoader;
    import com.sap.cloud.mobile.foundation.configurationprovider.ConfigurationLoaderCallback;
    import com.sap.cloud.mobile.foundation.configurationprovider.ConfigurationPersistenceException;
    import com.sap.cloud.mobile.foundation.configurationprovider.ConfigurationProvider;
    import com.sap.cloud.mobile.foundation.configurationprovider.ConfigurationProviderError;
    import com.sap.cloud.mobile.foundation.configurationprovider.DefaultPersistenceMethod;
    import com.sap.cloud.mobile.foundation.configurationprovider.DiscoveryServiceConfigurationProvider;
    import com.sap.cloud.mobile.foundation.configurationprovider.FileConfigurationProvider;
    import com.sap.cloud.mobile.foundation.configurationprovider.ProviderIdentifier;
    import com.sap.cloud.mobile.foundation.configurationprovider.ProviderInputs;
    import com.sap.cloud.mobile.foundation.configurationprovider.UserInputs;
    import com.sap.cloud.mobile.foundation.logging.Logging;
    import com.sap.cloud.mobile.foundation.networking.AppHeadersInterceptor;
    import com.sap.cloud.mobile.foundation.networking.WebkitCookieJar;
    import com.sap.cloud.mobile.foundation.securestore.OpenFailureException;
    import com.sap.cloud.mobile.foundation.securestore.SecureKeyValueStore;
    import com.sap.cloud.mobile.foundation.user.UserInfo;
    import com.sap.cloud.mobile.foundation.user.UserRoles;
    import com.sap.cloud.mobile.foundation.usage.AppUsage;
    import com.sap.cloud.mobile.foundation.usage.AppUsageInfo;
    import com.sap.cloud.mobile.foundation.usage.AppUsageUploader;
    
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.slf4j.LoggerFactory;
    
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.Arrays;
    import java.util.List;
    
    import ch.qos.logback.classic.Level;
    import ch.qos.logback.classic.Logger;
    import ch.qos.logback.core.util.StatusPrinter;
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    
  3. Add the following line to the end of the onCreate. The deviceID is a unique identifier for the device or emulator and can be used to identify communications between the SAP Cloud Platform server and a particular device or emulator. An example of this can be seen in the usage section of this guide under a column named REGISTRATIONID.
    deviceID = Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID);
  4. Add the following methods.
    private void toastAMessage(String msg) {
        if (toast != null && toast.getView().isShown()) {
            msg = messageToToast + "\n" + msg;
        }
        else {  //clear any previously shown toasts that have since stopped being displayed
            messageToToast = "";
        }
        messageToToast = msg;
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
    
            @Override
            public void run() {
                if (toast != null) {
                    toast.cancel();
                }
                toast = Toast.makeText(getApplicationContext(),
                        messageToToast,
                        Toast.LENGTH_LONG);
                toast.show();
            }
        });
    }
    
    private void getUser() {
        Log.d(myTag, "In getUser");
        SettingsParameters sp = null;
        try {
            sp = new SettingsParameters(serviceURL, appID, deviceID, "1.0");
        }
        catch (MalformedURLException e) {
            e.printStackTrace();
        }
        UserRoles roles = new UserRoles(myOkHttpClient, sp);
        UserRoles.CallbackListener callbackListener = new UserRoles.CallbackListener() {
            @Override
            public void onSuccess(@NonNull UserInfo ui) {
                Log.d(myTag, "User Name: " + ui.getUserName());
                Log.d(myTag, "User Id: " + ui.getId());
                String[] roleList = ui.getRoles();
                Log.d(myTag, "User has the following Roles");
                for (int i=0; i < roleList.length; i++) {
                    Log.d(myTag, "Role Name " + roleList[i]);
                }
                currentUser = ui.getId();
                toastAMessage("Currently logged with " + ui.getId());
            }
    
            @Override
            public void onError(@NonNull Throwable throwable) {
                toastAMessage("UserRoles onFailure " + throwable.getMessage());
            }
        };
    
        roles.load(callbackListener);
    }
    
    private void enableButtonsOnRegister(final boolean enable) {
        final Button uploadLogButton = (Button) findViewById(R.id.b_uploadLog);
        final Button onlineODataButton = (Button) findViewById(R.id.b_odata);
        Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                uploadLogButton.setEnabled(enable);
                onlineODataButton.setEnabled(enable);
            }
        });
    }
    
  5. Replace the onRegister method (Ctrl F12 or Command F12 on a Mac) with the code below.
    public void onRegister(View view) {
        Log.d(myTag, "In onRegister");
        myOkHttpClient = new OkHttpClient.Builder()
                .addInterceptor(new AppHeadersInterceptor(appID, deviceID, "1.0"))
                .authenticator(new BasicAuthDialogAuthenticator())
                .cookieJar(new WebkitCookieJar())
                .build();
    
        Request request = new Request.Builder()
                .get()
                .url(serviceURL + "/" + connectionID + "/")
                .build();
    
        Callback updateUICallback = new Callback() {
            @Override
            public void onFailure(Call call, final IOException e) { //called if there is no network
                Log.d(myTag, "onFailure called during authentication " + e.getMessage());
                toastAMessage("Registration failed " + e.getMessage());
            }
            
            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (response.isSuccessful()) {
                    Log.d(myTag, "Successfully authenticated");
                    toastAMessage("Successfully authenticated");
                    enableButtonsOnRegister(true);
                    getUser();
                }
                else { //called if the credentials are incorrect
                    Log.d(myTag, "Registration failed " + response.networkResponse());
                    toastAMessage("Registration failed " + response.networkResponse());
                }
            }
        };
    
        myOkHttpClient.newCall(request).enqueue(updateUICallback);
    }
  6. Create a new class named MyApplication by right clicking on the package com.example.android.stepbystep and choosing New, Java Class.

    Replace the code for the generated class with the code below.

    package com.example.android.stepbystep;
    
    import android.app.Application;
    
    import com.sap.cloud.mobile.foundation.authentication.AppLifecycleCallbackHandler;
    
    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            registerActivityLifecycleCallbacks(AppLifecycleCallbackHandler.getInstance());
        }
    }
    

    This step enables the basic authentication dialog to have access to the top activity so it can be shown.

  7. In the AndroidManifest.xml file, add the below entry.
    android:name=".MyApplication"

  8. Run the app.
    After clicking on the registration button, a basic authentication dialog appears requesting the user’s credentials.

    Notice also that the registration appears in the management cockpit.

  9. When the application first starts, the user’s credentials can be validated so that they may not need to enter them later at a less convenient time. The following steps removes the manual step of having the user push a button to do this.

    In activity_main.xml select the xml for the button b_register and comment out or delete the selected XML.
    Add a call to onRegister(null) at the bottom of the onCreate method.

  10. The below are examples of REST API calls that can be made in a browser which shows the service document of the OData service, displays Customers, queries the role service and queries the application settings.
    Replace the user id (p1743065160) with your user id in the URL’s below.

    https://hcpms-p1743065160trial.hanatrial.ondemand.com/com.sap.edm.sampleservice.v2?X-SMP-APPID=com.sap.stepbystep

    https://hcpms-p1743065160trial.hanatrial.ondemand.com/com.sap.edm.sampleservice.v2/Customers?X-SMP-APPID=com.sap.stepbystep

    https://hcpms-p1743065160trial.hanatrial.ondemand.com/mobileservices/application/com.sap.stepbystep/roleservice/application/com.sap.stepbystep/v2/Me

    https://hcpms-p1743065160trial.hanatrial.ondemand.com/mobileservices/application/com.sap.stepbystep/Storage/v1/runtime/application/com.sap.stepbystep/global/mobileservices/settingsExchange

Access Control

The following steps demonstrate how to assign a role to a user and how to enable the access control feature which enables the application to query what roles the currently assigned user has access to.

  1. Open https://account.hanatrial.ondemand.com and log in to Neo Trial.
  2. Click on Services and search for Development & Operations. Click on the tile.
  3. Click on the Configure Development & Operations link.
  4. Click on Roles, select a role, and add your user id to that role.
  5. In the Mobile Services cockpit, enable roles and add a few Roles.
  6. A request to the role service would now return the below JSON.
    {
        "id":"P1743065160",
        "schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
        "roles":["Developer","Notification User","Administrator"],
        "userName":"P1743065160"
    }

    Note, there may be a slight delay before after making a change to the roles settings in the management cockpit.

Previous (Mobile Services)   Next (Logging)

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