Introduction

K2 blackpearl utilizes the concept of a primary identity and a secondary identity. The primary identity provides the logged on user with authenticated access to the K2 Host Server. The secondary identity is used to authenticate the current user against a security label.

The user logs onto the K2 Host Server using their primary identity. When the user needs to execute a BAPI this is performed using the K2 blackpearl security provider system, which may prompt the user to cache a secondary credentials set, if a valid set is not available.

The Primary sets of credentials are cached in the Credentials Cache table against the K2 security label. The secondary sets of credentials are associated with the primary set along with the relevant security labels. If the credentials for the user are changed by the administrator, then the process described here will be repeated, overwriting the existing secondary set of credentials
Note: A full discussion of the K2 blackpearl security model and architecture is beyond the scope of this document.

User Authentication

K2 blackpearl utilizes Active Directory to authenticate the user and K2 connect passes a set of credentials to the SAP instance as a serial connection string. These two systems operate differently, but since authentication must take place before a BAPI will respond, they need to work together to authenticate the user and allow them access.

First Time Login

When the user logs in for the first time, the following takes place:
  1. User logs on to the Server with primary credential set using a K2 label. This will use SSPI to authenticate the logged in user in the client OS.
  2. Once authenticated on the server, the primary identity of the user will be logged and persisted in the credential cache.

SAP Access

The process of accessing SAP to run the SAP BAPI involves a number of steps. These steps require interaction and authentication between K2 blackpearl, the selected user manager (in this scenario, Active Directory) and SAP. From the onset, using K2 connect for SAP to authenticate a user is the same in principle as using the SAP GUI. The steps are provided in point form to simplify and help in explaining how it works. If a further and deeper discussion of this is required, please consult the K2 blackpearl documentation.
The discussion makes the following assumptions:
  • A custom ASPX form is in play
  • The designer wants to streamline authentication by adding custom code to their custom form

K2 connect User Authentication Process

Note: The step is performed before SAP credentials are cached.


[Figure 1. First SAP Logging Attempt – No secondary credentials cached]
  1. The User, from the custom form attempts to execute a SmartObject that uses a K2 connect Service instance object that consumes a particular BAPI.
  2. The SmartObject Server will receive the method request, and first establish the primary identity of the user logged on to the server.
  3. Once this is established, the SmartObject server will inspect the request and determine which services needs to be executed for this request.
  4. For each service, it will then determine if the service instance requires credentials. If a service requires credentials, the SmartObject server will use the security label mapped to the service instance and request credentials from the K2 server for the label for the current primary identity.
  5. The K2 server will attempt to retrieve credentials for the primary identity for the specified label. In this case, none will exist, so the K2 Server will throw an AuthenticationException back to the client.

Cache User Credentials Options

There are two methods that can be used to cache a secondary set of credentials:
  • Manual method : The manual method requires that the end user proceeds to the User Settings > Single Sign On Page in K2 Workspace and manually caches a set of credentials against a security label for a SAP Instance. Since this method may require interaction between the administrator and the end user it is not ideal for an environment where there is a high volume of non technical users.
  • Automatic Procedure : The automatic method requires that a portion of code be added to your custom form. This enables the form to handle the exception when it is recieved from the K2 Server. The user can be prompted to supply a valid set of secondary credentials then.
    This method is better suited for streamlining the process of cacheing credentials since it can be performed from the form, without the need to go into K2 Workspace.

Manual Cache Credentials Procedure

When a User logs in to a K2 application (e.g., K2 Workspace, K2 Designer for Visual Studio) this establishes a primary login or primary identity with the K2 Server.

To be able to login to SAP and execute a task (task: query, execute a transaction, etc) against a BAPI, a secondary credentials set must be cached against the SAP security label for the BAPIs. The security label, in most cases has the same name as the name of the SAP destination and this is entered in the field labelled Extra Data. When this is not the case, the name of the SAP destination takes preference, and is entered into the field labelled Extra Data.

The manual cache credentials process is described in point form below:

  1. Open up K2 Workspace and select User Settings > Single Sign On
  2. Select the correct SAP Instance label, e.g. SAP R3
  3. Select Cache credentials
  4. Enter the following details



    • User Name
    • Password
    • In the Extra Data field, enter the name of the SAP destination,eg SAP R3. This may be the same security label. If the name of the SAP Destination is not entered authentication errors will occur!
  5. Click Ok

If the user does not enter the name of the SAP Destination, or leaves the Extra Data field blank, the following error will result:

Note: The primary login is also the Active Directory account. Secondary login credentials are then cached and passed to the secondary or backend systems. The secondary credentials are linked to the primary credentials and are used to authenticate the user on the secondary or backend systems.

Automated Cache Procedure

The Automated Procedure requires the developer to add custom code to the project; specifically the custom user form, which enables the user to cache credentials without having to go to the K2 Workspace > User Preferences Page.
The process that takes place in the background is described below in the diagram and the following numbered steps.

[Figure 2. Cache Secondary User Credentials]
  1. The client then needs to handle the exception and retrieve the SecurityProviderFriendlyName from the exception
  2. The client then needs to prompt the user for username and password for the SecurityProviderFriendlyName which is the label the service instance is mapped to
  3. The user then needs to specify user name, password and extra data (if applicable). In the case of the K2 connect Service, extra data will be the label name the service instance is mapped to
  4. Next, the client needs to call Authenticate to the server, while logged in with its primary credential set. Authenticate takes the same connection string as Open, the values in the connection string will be different:
    • SecurityLabel=MySAP (label name)
    • IsPrimary=false
    • IsIntegrated=false
    • UserID=SUPER
    • Password=IDES
    • Host=server name
    • Port=5555
  5. Once the server receives the Authenticate request, it will use the label and get the mapped security provider instance. It will call the Authenticate method on the security provider, passing the user name, password and extra data. The security provider, in this case SAP, will attempt to connect to SAP using the credentials. If the connection succeeded, true will be returned (if false is returned an exception will be returned to the client.);
  6. Once true is returned, the server will cache this secondary credential set against the primary identity currently logged onto the K2 Server
  7. The client now needs to resubmit the SmartObject execution request. Step 1 to 4 will be repeated. They are represented by steps a – d in the diagram above
  8. K2 server will now be able to retrieve the secondary credential set for the primary identity and give them to the SmartObject Server
  9. The SmartObject server will pass the credential set to the K2 connect Service and the service will use the credentials to log onto SAP and execute the BAPI
  10. At his point, if the user specified for the secondary credential set does not have rights to access the specific BAPI, the user that executed the request needs to take it up with the (in this case) SAP Administrator.

Catching the Exception

The service object, before it can be used from within K2 Designer for Visual Studio is published as a SmartObject utilizing the service methods available from the BAPI. When the call is made to use the service methods the SmartObject passes the credentials of the logged on user for authentication purposes.

When a set of credentials are not available, the exception that is thrown must be trapped. The code sample shown below illustrates how to catch the exception.

private string ReturnSmartObjectException(SmartObjectException smartObjectException)
  {     StringBuilder errorMessage = new StringBuilder();

    foreach (SmartObjectExceptionData smartobjectExceptionData in smartObjectException.BrokerData)
      {
      string message = smartobjectExceptionData.Message;
      string service = smartobjectExceptionData.ServiceName;
      string serviceGuid = smartobjectExceptionData.ServiceGuid;
      string severity = smartobjectExceptionData.Severity.ToString();
      string innermessage = smartobjectExceptionData.InnerExceptionMessage;

      errorMessage.AppendLine("Service: " + service);
      errorMessage.AppendLine("Service Guid: " + serviceGuid);
      errorMessage.AppendLine("Severity: " + severity);b
      errorMessage.AppendLine("Error Message: " + message);
      errorMessage.AppendLine("InnerException Message: " + innermessage);
      }
  return errorMessage.ToString();
  }




Console Application

Shown below is a code sample for an example console application that performs the authentication check and then will prompt the user for a set of credentials if required. Once the set of credentials have been entered, an API call is made and a set of credentials are cached against a security label.

using System;
using System.Collections.Generic;
using System.Text;

namespace TestAuthentication
 {
  class Program
   {
   static void Main(string[] args)
    {
      try
      {
      ExecuteListSmartObject("Account", "GetList");
      }
      catch (Exception ex)
      {
      Console.WriteLine("ERROR: {0}", ex.Message);
      }
      finally
   {
    Console.WriteLine("Press any key to continue ...");
    Console.ReadKey();
   }
 }

 static void ExecuteListSmartObject(string smartObjectName, string methodToExecute)
  {
   SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder scConnectionStringBuilder =
   new SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder();
    scConnectionStringBuilder.Host = "localhost";
   scConnectionStringBuilder.Port = 5555;
   scConnectionStringBuilder.IsPrimaryLogin = true;
   scConnectionStringBuilder.Integrated = true;

   SourceCode.SmartObjects.Client.SmartObjectClientServer clientServer =
   new SourceCode.SmartObjects.Client.SmartObjectClientServer();
   clientServer.CreateConnection();
   clientServer.Connection.Open(scConnectionStringBuilder.ConnectionString);

   SourceCode.SmartObjects.Client.SmartObject smartObject = clientServer.GetSmartObject(smartObjectName);
   smartObject.MethodToExecute = methodToExecute;

   bool tryAgain = true;

   while (tryAgain)
     {
     tryAgain = false;
     try
     {
     SourceCode.SmartObjects.Client.SmartObjectList listResult = clientServer.ExecuteList(smartObject);
     Console.WriteLine("Successful");
     tryAgain = false;
     }
     catch (SourceCode.Hosting.Exceptions.AuthenticationException authEx)
     {
     // User to supply Authentication details
     if (AddProvideAuthentication(authEx, clientServer))
     {
     tryAgain = true;
     }
     }
  }
 }

 static bool AddProvideAuthentication(SourceCode.Hosting.Exceptions.AuthenticationException authEx,
  SourceCode.SmartObjects.Client.SmartObjectClientServer clientServer)
   {
   // Get UserName
   Console.WriteLine(string.Format("Provide UserName for {0}", authEx.ProviderFriendlyName));
   string userName = Console.ReadLine();

   if (string.IsNullOrEmpty(userName))
   {
    return false;
   }

   // Get Password
   Console.WriteLine(string.Format("Provide Password for {0}", authEx.ProviderFriendlyName));

   string password = Console.ReadLine();

   if (string.IsNullOrEmpty(password))
    {
     return false;
    }

   // Apply Authentication to current SmartObjectClientServer
   SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder conn =
   new SourceCode.Hosting.Client.BaseAPI.SCConnectionStringBuilder();
   conn.Host = clientServer.Connection.Host;
   conn.Port = clientServer.Connection.Port;
   conn.IsPrimaryLogin = false;
   conn.Integrated = false;
   conn.SecurityLabelName = authEx.ProviderFriendlyName;
   conn.UserID = userName;
   conn.Password = password;
   conn.AuthData = authEx.ProviderFriendlyName;

    clientServer.Connection.Authenticate(conn.ConnectionString);
   return true;
  }
 }
}




Conclusion

The reason for including this code segment into your application is to make things easier for the end user. The manual method requires navigating to K2 Workspace, where as the automatic method enables the end user to cache a set of credentials from the user form.