• RE: DWIntegration EX_INVALID_PASS_PHRASE-1529591502

    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
  • RE: DWIntegration EX_INVALID_PASS_PHRASE-1529591502

    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
  • RE: View a document outside of DocuWare

    Seth,

    Well, someone is still going to need to log into DocuWare to use the Platform service. And, technically speaking, each user should be logging in to view the files they need, otherwise they could do an end-run around security. Licensing should be kosher because concurrent licenses will be used even if you use the same platform username from multiple workstations, and if you are on named users it does't really matter anyway because you've paid for it.

    But the permissions issue is a real one. If your Platform SDK code reveals documents that a user shouldn't have access to there is no way of knowing they are viewing a document from a file cabinet they aren't supposed to see. Logging them in with their own username via URL integration (or the Platform SDK) makes sure permissions are being honored for their specific credentials.

    To put it another way, beware "system" usernames that have access to everything, as you can introduce all sorts of problems usually taken care of by roles in DocuWare.

    Thanks,
    Joe Kaufman

     
  • RE: View a document outside of DocuWare

    Seth,

    Exactly right. You can download what you need and write as elaborate a client you want to view indexes and documents. It just takes work to write that client...

    If you really kinda sorta want to use the DocuWare viewer, why aren't you just using URL Integration?

    Thanks,
    Joe Kaufman
  • RE: View a document outside of DocuWare

    Seth,

    You would just use the API to download the file, then open it in Windows (the file extension would let Windows know what to open in). In C#, you just use Process.Start(<filename>) to open a file in its related application.

    If you also want to see the indexes, you would have to build an interface for that. As you access the Document object, that gets you the indexes, and then you can download the document itself via its download link.

    Here is the general Platform SDK documentation now:

    https://developer.docuware.com/dotNet/66b2ed1e-2aef-452a-97cd-5014bbf0242b.html

    and here is the .NET example of downloading a file:

    https://developer.docuware.com/dotNet_CodeExamples/4354370d-a0ce-42d4-ba94-6dc848ed62c0.html

    If you want to view a document without bringing DocuWare up in a browser yourself, you can use URL Integration.

    Thanks,
    Joe Kaufman
  • RE: Install DocuWare On-Premise, but in Azure Cloud

    Phil,

    Thanks for the explanation. Not sure I understand it (I thought things like Amazon VMs were almost entirely customizable and so could be configured like any local server, but you learn something new every day!

    You might want to amend the documentation to either list all the unsupported cloud VMs explicitly, just say "no cloud VMs", or provide details about why some cloud VMs don't work (e.g. "Cloud VMs that do not support protocol <whatever> are not supported by DocuWare.")

    Are VMs from Expedient and Rackspace supported, for example? What is the required IP protocol that is missing? Just curious...

    Thanks,
    Joe Kaufman
  • RE: Install DocuWare On-Premise, but in Azure Cloud

    And why are Azure VMs singled out as not supported? Does that mean AWS VMs are supported?

    A VM is a VM. We are running VM-based servers for our on-premise installation, so what is wrong with Azure VMs? Especially if DocuWare Cloud trusts Azure as its platform?

    Thanks,
    Joe Kaufman
  • RE: Delete all files in an Inbox

    Won't that leave a bunch of documents out in storage space? If you delete a file cabinet the files are still there, eating up disk space. Isn't the same true with trays/inboxes? After all, they are just file cabinets with a different internal type to them... I was always told just nuking entire entities (like file cabinets or trays) was a big no-no...

    Thanks,
    Joe Kaufman
  • RE: Any way to tell if REST services are being used on a system?

    If they have any sort of automated tasks running, then monitoring the licenses in use (the Application Type) might reveal some tasks using "Platform Service". I am not sure what Application Type the Desktop Tools use.

    But if someone has a job automated that only runs once a week in the middle of the night, monitoring is not going to be of much use.

    Thanks,
    Joe Kaufman
  • RE: Any way to tell if REST services are being used on a system?

    Craig,

    In that case, you could monitor the license types in use via the Connections Overview in the DW Admin tool (we are on 6.11 so still have access to that). I am not sure where to monitor connections in other versions.

    In the Connections Overview, you can expand connections and see the "Application Type". For example, we have a mix of "Platform Service" and "DocuWare Client". Platform Service is the API, and DocuWare Client is the web client.

    It sounds like you would like to have this sort of monitoring be more of a log that you could report on. I am not sure what facility DocuWare has for that, but hopefully someone weighs in on that sort of audit capability. There are some logs on the server, but those appear to be mostly for error logging, not a record of every single transaction.

    What version of DW are we discussing, and is it on-prem or in the cloud?

    Thanks,
    Joe Kaufman