ProjectWise SDK - Bentley IMS Login

I need to use the ProjectWise SDK (not the pwps_dab module) to login using Bentley IMS authentication. The documentation indicates 'aaApi_LoginWithSecurityToken' is the function but I'm not sure how to acquire the 'security token'. Does anyone have a working example they can share? 

  • I mean to post some code for this, but here's a snippet that may help you, but it is in C#, so you man need to use MostOfDavesClasses.

    You can get that code with the link in this post:  https://communities.bentley.com/products/programming/projectwise_programming/m/mediagallery/273950 

    However that link doesn't demonstrate using IMS authenication.

    So here's the snippet:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Runtime.InteropServices;
    
    namespace SampleIMSConsole
    {
        class Program
        {
            [DllImport("c:\\program files\\bentley\\projectwise\\bin\\dmscli.dll", CharSet = CharSet.Unicode)]
            private static extern bool aaApi_LoginWithSecurityToken(string dataSource, string securityToken, bool asAdmin, string hostname, long[] productIds);
    
            // BOOL aaApi_GetRelyingPartyIdentifier(LPCWSTR pServerName, LPWSTR* ppRelyingPartyIdentifier )
            [DllImport("c:\\program files\\bentley\\projectwise\\bin\\dmscli.dll", CharSet = CharSet.Unicode)]
            private static extern bool aaApi_GetRelyingPartyIdentifier(string serverName, ref string relyingPartyIdentifier);
    
            static void Main(string[] args)
            {
                if (args.Length > 0)
                {
                    string _loginToken = ""; // MyLoginCommands.GetLoginToken(DatasourceName);
    
                    string relyingParty = "";
                    string serverName = args[0].Split(':')[0];
                    bool relyingPartySuccess = aaApi_GetRelyingPartyIdentifier(serverName, ref relyingParty);
    
                    // Contact the Connection Client and ask for the login token.
                    try
                    {
                        Bentley.Connect.Client.API.V1.ConnectClientAPI conn = new Bentley.Connect.Client.API.V1.ConnectClientAPI();
    
                        _loginToken = conn.GetSerializedDelegateSecurityToken(relyingParty);
                    }
                    catch (Exception ex)
                    {
                    }
    
                    if (aaApi_LoginWithSecurityToken(args[0], _loginToken, true, null, null))
                    {
                        Console.WriteLine(string.Format("Logged in OK to '{0}' with BentleyIMS.", args[0]));
                    }
                    else
                    {
                        Console.WriteLine(string.Format("Error logging in to '{0}'", args[0]));
                    }
    
                }
            }
        }
    }
    

    HTHs

  • Thanks Dan, really appreciate the quick reply.

    I've used your approach and can successfully return the secure token but it fails to login. The error detail returned by aaApi_GetLastErrorDetail is 'Invalid user name and password combination.'

    The CONECTION client is signed in and my account is federated on the test datasource. Here's the current code with additional output for testing purposes.

    public static bool LoginBentleyIMS(string dataSource, bool asAdmin, string hostname, bool verbose=false)
            {
                string _loginToken;
    
                string relyingParty = "";
                string serverName = dataSource.Split(':')[0];
    
                if (!dmscli.aaApi_GetRelyingPartyIdentifier(serverName, ref relyingParty))
                {
                    Console.WriteLine(dmsgen.aaApi_GetLastErrorMessage());
                }
    
                // Contact the Connection Client and ask for the login token.
                try
                {
                    Bentley.Connect.Client.API.V1.ConnectClientAPI conn = new Bentley.Connect.Client.API.V1.ConnectClientAPI();
    
                    _loginToken = conn.GetSerializedDelegateSecurityToken(relyingParty);
    
                    if (verbose)
                    {
                        Console.WriteLine(relyingParty);
                        Console.WriteLine(_loginToken);
                    }           
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    return false;
                }
    
                var successfull=dmscli.aaApi_LoginWithSecurityToken(dataSource, _loginToken, asAdmin, hostname, null);
    
                if (successfull)
                {
                    Console.WriteLine(string.Format("Logged in OK to '{0}' with BentleyIMS.", dataSource));
                }
                else
                {
                    Console.WriteLine(dmsgen.aaApi_GetLastErrorMessage());
                    Console.WriteLine(dmsgen.aaApi_GetLastErrorDetail());
                    Console.WriteLine(string.Format("Error logging in to '{0}'", dataSource));
                }
    
                return successfull;
            }

    Added a reference to "C:\Program Files\Common Files\Bentley Shared\CONNECTION Client\Bentley.Connect.Client.API.dll" to access the "Bentley.Connect.Client.API.V1.ConnectClientAPI" class.

    Example call: LoginBentleyIMS("servername:datasource",true,null);

  • Matthew,

    I've got a working sample IMS login that I will be posting soon, but it is a bit different from what I posted for you.  I'm wondering if the fact that you have a federated account that may be the "problem", in that the code I provided to you doesn't account for that situation?  I don't have a federated account to test with, so I'm not sure at this point if that may be the issue.

    If you have time, can you please try using PowerShell (PWPS_DAB) to connect to your datasource using your federated account?  If that works, then I can look at the code behind the Cmdlet (New-PWLogin) and see if there are additional steps being taken to generate a token that works. 

    And if you get the PowerShell login to work, please post or send me an email on the details of how you used it (parameters and values) so that I can explore the path taken through the code behind the Cmdlet as then I should be able to determine what needs to be changed in the sample I provided.

    A private message in communities will work or you can directly email me at Dan.Williams@Bentley.com.

    FWIW, my understanding of how federation works is that the "user" gets a token from their Identify Provider and then that token is passed onto the Federation Provider which generates another token that is passed onto the application (or perhaps the other way around?).  So I wondering if the token you are getting with the sample code I provided is just the one of the steps?

    I'll do my best to try to get this sorted out, but feel free to see if you can generate the "right" token that needs to be passed onto the ProjectWise login function.

    And if you find a way to get a token that works, please post your solution, or at least the approach you took!

  • Matthew,

    "Good news", I can reproduce your problem.

    Using a federated account, I get a valid token with the same code as you did, but when I try to log into my datasource with a federated account, it fails with the same error message as you received.  However, for my test case, the error message was correct.  My target datasource doesn't have an account matching what I used for the CONNECTION Client!  If I use the same CONNECTION Client session for a datasource where that federated account has a matching user account (and enabled, etc.), it works!  

    So, can you please verify that the user credentials you are using for your CONNECTION Client are the same as the federated account in your target datasource?  

  • Hi Dan, again thank you for all your help. Fingers crossed I'll get sometime today to test and get back to you