Posted Thu, 21 Jun 2018 12:31:42 GMT by Casey Miller Director of Technical Services

We are receving this error when trying do a query on a field called EMPLOYEE. I convert the query data to base64 and also the login data to base 64 and then encrypt that using AES-128-CBC.  I get the error listed below.

 

The request could not be served.

Status:

500 - Internal Server Error

Message:

DocuWare.Gapi.Utils.Web.DWIntegration.EX_INVALID_PASS_PHRASE

Exception

IntegrationInvalidParameterException: DocuWare.Gapi.Utils.Web.DWIntegration.EX_INVALID_PASS_PHRASE

 

I know this passphrase is correct because I can open URL creator and use it and it works fine. Any ideas here?

Posted Thu, 21 Jun 2018 13:04:00 GMT by Casey Miller Director of Technical Services

Here is the code we are using:

 

<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

 

function encryptor($action, $string) {
    $output = false;
    
    $encrypt_method = "AES-128-CBC";
    //pls set your unique hashing key
    $secret_key = 'THEPASSPHRASE';
    $secret_iv =  'THEPASSPHRASE';
    
   
    
    // hash
    $key = hash('sha512', $secret_key);

    // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
    $key = substr(hash('sha256', $secret_key), 0, 32);
    $iv = substr(hash('sha256', $secret_key), 32, 16);

    //do the encyption given text/string/number
    if( $action == 'encrypt' ) {
 //       $output = openssl_encrypt($string, $encrypt_method, $key, $options=OPENSSL_RAW_DATA, $iv);
        $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
         $output = base64_encode($output);
    }
    else if( $action == 'decrypt' ){
        //decrypt the given text/string/number
        $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
    }
    
    return $output;
}

function base64url_encode($plainText)
{
    $base64 = base64_encode($plainText);
    $base64url = strtr($base64, '+/', '-_');
    return ($base64url);
}
?>

<script type="text/javascript">
function openit(URL,width,height)
{
    var width;
    var height;
    var newWindow, args = "";
    args += "height=" + height + ",width=" + width;
    args += " ,menubar=yes, titlebar=yes,dependent=yes,scrollbars=yes,resizable=yes";
    
    var popup = window.open("", "_blank", args) ;
    popup.location = URL;
}
</script>
<?php

 

$User = 'USER';

 

//  Setup query 
$Qry = '[EMPLOYEE__]='.trim($User);
$QrySelect = '&q='.base64url_encode($Qry);

$login = 'User=Training User\nPwd=USERPASSWORD';
$loginSelect = '&lc='.base64url_encode($login);

$ep = $loginSelect.$QrySelect;
$epencrypt = encryptor('encrypt', $ep);

 

$EditCourseLink = 'http://docuware-01/DocuWare/PlatformRO/WebClient/1/Integration?ep='.$epencrypt;

echo "<table width='100%' cellspacing='0' cellpadding='0' border='0'>";
echo "</tr>";
echo "<tr>";
echo "<TD width='15%' align='center' >
<button type='button' class='button' onclick=\"openit('$EditCourseLink',900,800)\">Certifications</button>";
echo "</td>";
echo "</tr></table>";

 

// testing only
echo $key;
ECHO '<BR><BR>';
echo $iv;
ECHO '<BR><BR>';

ECHO '<BR><BR>';
ECHO 'QRY='.$Qry;
ECHO '<BR><BR>';
ECHO 'QrySelect= '.$QrySelect;
ECHO '<BR><BR>';

ECHO 'login='.$login;
ECHO '<BR><BR>';
ECHO 'loginSelect='.$loginSelect;
ECHO '<BR><BR>';

echo $ep;
echo '<br><BR>';

echo 'epencrypt= '.$epencrypt;
echo '<br>';

echo $EditCourseLink;
echo '<br><BR>';

Posted Thu, 28 Jun 2018 11:46:48 GMT by Casey Miller Director of Technical Services

Any insight on this?

Posted Tue, 18 Jun 2019 12:58:58 GMT by Romain Amoudjayan

Hello

I've found your post during my research on the same topic. I began with another example of code, but finally, it's very similar, but my code doesn't work too.

Compared to your code, i've made differently the creation of key and iv. Also, in your function 'base64url_encode', i think you have to replace the = by 0,1 or 2 as the function HttpServerUtility.UrlTokenEncode as explained in docuware help page (http://help.docuware.com/en/#b64090t60284n89495 ) .

Here is the post i've created:
https://support.docuware.com/fr-FR/forums/help-with-technical-problems/ea9618df-c491-e911-80e7-0003ff59a7c6


Thank you

Posted Tue, 18 Jun 2019 13:05:02 GMT by Joe Kaufman Bell Laboratories Inc No longer there
Romain,

I can't be sure, but I think you might be encoding things too much, if that makes sense? Granted, I operate over an open connection, but this is how I do it (FoxPro code, hopefully it makes sense). This is what generating a URL to view a document might look like:
 
FUNCTION DWViewDocument
    LPARAMETERS pcFilecabinetGUID, puDocumentID, plDontRunURL, plUseWindowsAuth
    IF (VARTYPE(pcFilecabinetGUID) <> "C") OR EMPTY(ALLTRIM(pcFilecabinetGUID))
        * We cannot proceed without a file cabinet GUID.
        RETURN ""
    ENDIF
    * Document ID can be passed in as a numeric value or a string.
    IF (VARTYPE(puDocumentID) == "C")
        puDocumentID = VAL(puDocumentID)
    ENDIF
    IF (VARTYPE(puDocumentID) <> "N")
        * We cannot proceed without a numeric document ID.
        RETURN ""
    ENDIF        
    SET PROCEDURE TO GlobalProc ADDITIVE
    LOCAL lcURL
    * Establish a base URL with a viewer as the integration type.
    lcURL = DWGetBaseIntegrationURL(DW_INTEGRATION_TYPE_VIEWER, plUseWindowsAuth)
    * Add on file cabinet GUID.
    lcURL = lcURL + "&fc=" + pcFilecabinetGUID
    * Add on the document ID.
    lcURL = lcURL + "&did=" + ALLTRIM(STR(INT(puDocumentID)))
    IF (NOT plDontRunURL)
        * Execute the URL.
        ExecuteCommand(lcURL)
    ENDIF
    * The URL used can be returned.
    RETURN lcURL
ENDFUNC

Here is what DWGetBaseIntegrationURL() looks like:
 
FUNCTION DWGetBaseIntegrationURL
    LPARAMETERS pcIntegrationType, plUseWindowsAuth, plDontDisplayOneDoc
    IF (VARTYPE(pcIntegrationType) == "C")
        pcIntegrationType = UPPER(ALLTRIM(pcIntegrationType))
    ELSE
        * An empty integration type will make the URL be login-only.
        pcIntegrationType = ""
    ENDIF
    LOCAL lcBaseURL, lcParams
    * Start with our integration entry point.
    IF plUseWindowsAuth
        * Use NTML entry point.
        lcBaseURL = DW_INTEGRATION_ENTRY_POINT_NTLM
    ELSE
        lcBaseURL = DW_INTEGRATION_ENTRY_POINT
    ENDIF
    lcParams = ""
    * Now generate parameters, starting with login credentials (if we are not using a Windows login).
    IF (NOT plUseWindowsAuth)
        * We are NOT going use Windows authentication, so use login credentials generated here.
        lcParams = lcParams + "&lc=" + DWGetURLIntegrationCreds()
    ENDIF
    * We can set any other defaults here, too.
    IF (pcIntegrationType == DW_INTEGRATION_TYPE_RESULTLIST_VIEWER) OR (pcIntegrationType == DW_INTEGRATION_TYPE_HISTORY)
        IF (NOT plDontDisplayOneDoc)
            lcParams = lcParams + "&displayOneDoc=true"
        ENDIF
    ENDIF
    * Finally, add on the integration type parameter, if we have one.    
    IF (NOT EMPTY(pcIntegrationType))
        lcParams = lcParams + "&p=" + pcIntegrationType
    ENDIF
    IF (NOT EMPTY(lcParams))
        IF (LEFT(lcParams, 1) = "&")
            * Do not need the ampersand on the first parameter.
            lcParams = SUBSTR(lcParams, 2)
        ENDIF
        lcBaseURL = lcBaseURL + "?" + lcParams
    ENDIF
    RETURN lcBaseURL
ENDFUNC

And finally, here is what DWGetURLIntegrationCreds() looks like:
 
FUNCTION DWGetURLIntegrationCreds
    SET PROCEDURE TO GlobalProc ADDITIVE
    LOCAL lcPlainCreds, lcEncodedCreds
    * Start with a plain-text credential string. We use a literal "\n" to denote a new-line character
    * between username and password, as that is how DocuWare expect the credentials to be encoded.
    lcPlainCreds = "User=" + DW_USERNAME_URL_INTEGRATION + "\nPwd=" + DW_PASSWORD_URL_INTEGRATION
    * URL encode the plain text into a login credential string.
    lcEncodedCreds = UrlTokenEncode(lcPlainCreds)
    RETURN lcEncodedCreds
ENDFUNC

The UrlTokenEncode() function does this (looks the same as yours):
 
FUNCTION UrlTokenEncode
    * This function takes in a string and encodes it the same way System.Web.HttpServerUtility.UrlTokenEncode() 
    * would to in .NET:
    * 1. Use STRCONV to convert the input to Base64.
    * 2. Replace "+" with "-" and "/" with "_". Example: Foo+bar/=== becomes Foo-bar_===.
    * 3. Replace any number of "=" at the end of the string with an integer denoting how many they were. Example: Foo-bar_=== becomes Foo-bar_3.
    LPARAMETERS lcURL
    LOCAL lcEncoded, lnNumEqualSigns
    * 1. Convert string to Base64.
    lcEncoded = STRCONV(lcURL, 13)
    * 2. Replace certain characters with others.
    lcEncoded = CHRTRAN(lcEncoded, "+/", "-_")
    * 3. See how many "=" are at the end of the encoded string and convert to digit.
    lnNumEqualSigns = LEN(lcEncoded) - LEN(RTRIM(lcEncoded, 1, "="))
    lcEncoded = LEFT(lcEncoded, LEN(lcEncoded) - lnNumEqualSigns)
    lcEncoded = lcEncoded + ALLTRIM(STR(lnNumEqualSigns))
    RETURN lcEncoded
ENDFUNC

After all this, the URL is sent as-is -- no further encryption. User credentials and the query parameter are Url encoded, but that is it.

Maybe that won't work if you are using a secure connection, but on my system what I generate matches the URL Integrator, and the URLs work to do things like view documents. Your user credentials look correct, so it must be something with encrypting/encoding.

Good luck,
Joe Kaufman
Posted Tue, 18 Jun 2019 13:51:30 GMT by Romain Amoudjayan
Hello Joe,
Thanks for your feedback.
Indeed, if i use my parameter strings ($param) with only the request q and the login lc encrypted in base64, it works correctly.

But for security reason, i'd like to encrypt the complete parameter strings as indicated by docuware with the AES key in order to use it into the parameter "https://<url>/docuware/platform/webclient/1/Integration?ep=<parameters encrypted>" , because we will use these url on our extranet accessible directly on the web.
Thanks
Posted Tue, 18 Jun 2019 14:11:58 GMT by Joe Kaufman Bell Laboratories Inc No longer there
Romain,

Yes, your concerns are certainly valid! We are all internal, on-premise, so as long as username and password are casually hidden, that is good enough. We don't have anyone intercepting traffic and UrlDecoding to phish for passwords...

I think I tried the fully encrypted way and never got it to work either, and not just because I was using FoxPro. I believe I tried in C# and couldn't get it working until I used the DocuWare DLL that provides the underpinnings for URL integration. I don't know how to take advantage of that through PHP unless PHP has a .NET bridge you can take advantage of. Using the .NET assembly DocuWare.WebIntegration.dll lets you create a URL via code such as:
 
public static DWIntegrationUrl GetIntegrationUrl(IntegrationType integrationType = IntegrationType.Viewer)
{
    LastError = "";
    DWIntegrationUrl returnUrl = null;
    try
    {
        // Prepare DWIntegration information.
        DWIntegrationInfo integrationInfo = new DWIntegrationInfo(ServiceEntryPoint + "/WebClient", DefaultOrganizationID, false);
        integrationInfo.Scheme = DefaultIntegrationProtocol;
        integrationInfo.OrganizationId = DefaultOrganizationID;
        // Now generate a plain-text URL object with the appropriate integration type.
        returnUrl = new DWIntegrationUrl(integrationInfo, integrationType);
        // Set up default user credentials. *** NOTE *** Password goes first, then username!
        returnUrl.Parameters.UserCredentials = new UserCredentials(DefaultIntegrationPassword, DefaultIntegrationUsername);
        // Set some other reasonable defaults for the integration URL object.
        returnUrl.Parameters.DisplayOneDoc = true;
    }
    catch (Exception ex)
    {
        LastError = ex.Message;
    }
    return returnUrl;
}

(LastError is a static member field that I use for error handling/communication.)

Here are a couple deeper dives into what the DocuWare.WebIntegration assembly/namespace exposes:
 
namespace DocuWare.WebIntegration
{
    public class DWIntegrationUrl : DWWebUrl
    {
        public DWIntegrationUrl(DWIntegrationInfo integrationInfo, IntegrationType integrationType);
        public DWIntegrationUrl(DWIntegrationInfo integrationInfo, DWIntegrationUrlParameters urlParams);

        public DWIntegrationUrlParameters Parameters { get; set; }
        public DWIntegrationInfo Info { get; set; }

        public static DWIntegrationUrl Parse(string url);
        public static DWIntegrationUrl Parse(DWIntegrationInfo integrationInfo, string urlString);
        public static DWIntegrationUrl Parse(DWIntegrationInfo integrationInfo, Dictionary<string, string> parameters);
        public static DWIntegrationInfo ParseIntegrationInfo(string urlString);
    }

    public abstract class DWWebUrl
    {
        protected DWWebUrlLoginParameters parameters;

        protected DWWebUrl(DWWebLoginInfo integrationInfo, IntegrationType integrationType);
        protected DWWebUrl(DWWebLoginInfo integrationInfo, DWWebUrlLoginParameters urlParams);

        public string HttpAddress { get; }
        public string BaseUrl { get; }
        public virtual string Url { get; }
        public DWWebLoginInfo Info { get; set; }
        public DWWebUrlLoginParameters Parameters { get; set; }
        protected virtual string Page { get; }
    }

    public class DWIntegrationInfo : DWWebLoginInfo
    {
        public DWIntegrationInfo(string httpAddress, int orgID, bool useWindowsLogin);
        public DWIntegrationInfo(string httpAddress, string orgID, bool useWindowsLogin);
        protected DWIntegrationInfo(string httpAddress);

        public bool IsEncrypted { get; set; }
        protected override string LoginPage { get; }

        public static DWIntegrationInfo Parse(string urlString);
        protected override void AddQueryParams(Dictionary<string, string> par);
    }

    public class DWWebLoginInfo
    {
        protected bool isEncrypted;

        public DWWebLoginInfo(string httpAddress);
        public DWWebLoginInfo(string webClentUrl, int orgID, bool useWindowsLogin);
        protected DWWebLoginInfo(string webClentUrl, string orgID, bool useWindowsLogin);

        public bool IsEncrypted { get; }
        public string Scheme { get; set; }
        public string WebClientUrl { get; set; }
        public string OrganizationId { get; set; }
        public bool UseWindowsLogin { get; set; }
        public UrlVersion Version { get; set; }
        protected virtual string LoginPage { get; }

        public static DWWebLoginInfo Parse(string urlString);
        protected static bool ArrayContains(string[] array, string value);
        protected virtual void AddQueryParams(Dictionary<string, string> par);
        protected void ParseBaseUrl(string httpAddress);
        protected void ParseInternal(string urlString);
    }
}

I am not sure I would have gotten it to work any other way, as my URLs always looked a bit off from what the URL Creator was generating (as is the situation with you).

Thanks,
Joe Kaufman
Posted Wed, 19 Jun 2019 08:32:50 GMT by Romain Amoudjayan
Thank you Joe. Something is maybe missing in the help in the explanation of the encryption (for example in the help page of the encryption algorithm, it was not written that after encryption with AES key, we have to encrypt again a second time in base 64)

If i can't achieve the encryption in php, i will try in .net, but for the moment, i don't know how to make easily the link between my extranet, my erp, and another .net program.

Thanks

You must be signed in to post in this forum.