Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Dan_vL
Product and Topic Expert
Product and Topic Expert
0 Kudos
Previous (Mobile Services)   Home   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 or follow the tutorial Use Flows with SAP Cloud Platform SDK for Android which uses the flows library to simplify the onboarding process.

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.

    Another option is to enable the Android Studio setting Add unambiguous imports on the fly.


  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 androidx.appcompat.app.AppCompatActivity;
    import androidx.appcompat.app.AlertDialog;
    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.sap.stepbystep and choosing New, Java Class.
    Replace the code for the generated class with the code below.
    package com.sap.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 manifests/AndroidManifest.xml file, add the below entry.
    android:name=".MyApplication"


  8. The OKHTTP library requires Java 8. Set this in the Project Structure dialog.
    The Project Structure dialog can be opened via File, Project Structure.

  9. 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.

  10. 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 in MainActivity.java.

  11. 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.s...

    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/...

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


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 Mobile Services. Click on the tile.

  3. Click on the Configure Mobile Services 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 assuming the user was assigned to each of the three roles.
    {
    "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)   Home   Next (Logging)
9 Comments