MSI application packaging guidelines

The Cloud9 desktop app can be delivered to end users via one of these two methods:

  1. Application auto-update – commonly referred to as our “Squirrel” release which is a reference to the automation platform supporting auto-updating.  This version of the application is installed in %localappdata%, thus not requiring elevated access. 

OR

  1. Microsoft Installer (MSI) – This is an installation package that commonly requires elevated access to be installed on an end user’s machine. The MSI distribution is also often accompanied with an MSI transform overlay that can alter certain parameters of the vendor’s default installation.  

This article will guide you around the deployment of MSI packages by organizations seeking to tightly control the version of MSI that is being rolled out and to manage the user desktop software suite via common tool set. 

 

Installation

Location

The MSI default location for installation should remain the same at:

  • %ProgramFiles(x86)% \Cloud9 Technologies LLC\C9Trader

Registry settings

There are a number of registry entries added via MSI installation that are common across all MSI installed applications. The Cloud9 application installs two unique registry keys that are critical for the deployment of SSO (Single Sign On). These registry entries should not be altered in any way.

Those keys register a Custom URI handler within the user desktop so that the Cloud9 Admin Portal can return a URI of the form c9trader:\\<jwt> via the SSO SAML integration. The c9trader URI handler will pass the <jwt> to the c9shell.exe application via these registry entries to open the Cloud9 application without prompting the user to enter their credentials.

These keys are as follows:

  • Computer\HKEY_CLASSES_ROOT\c9trader\shell\open\command

  • Computer\HKEY_CURRENT_USER\Software\Classes\c9trader\shell\open\command

Text file initialization

C9TraderProps.ini – Stub file creation

Creation of stub initialization files is a common practice within application packaging process.  The Cloud9 app has an initialization file called “C9TraderProps.ini” which is located in:

  • %localappdata%\Cloud9_Technologies\C9Trader\other

This file contains certain parameters that are only retained locally within the machine and a number of items that are cached to the cloud SaaS platform.  As such, when a user logs in for the first time, any stub parameters in this file will be retained with other parameters either being defaulted or downloaded from the SaaS platform.

The text file has certain requirements to ensure proper parsing:

  • ASCII plain text
  • CRLF line terminators
  • No extra line terminators
  • No extra end of line spaces

If any of these items is not adhered to, then the Cloud9 app will be prevented from opening.

C9TraderProps.ini – Parameter options - Proxy

Here are some items that can be stubbed out in this file.

Settings – these values are not retained in the cloud SaaS platform due to the sensitivity of these parameters.

  • enableProxy=False
    • Values – True / False
    • Set to True if a web proxy is required by your firm for egress to the Internet.
  • enableAutoProxyDetection=False
    • Values – True / False
    • Set to True to see if Cloud9 can obtain the web proxy settings automatically from IE settings.  Not all methods of web proxy provisioning can be auto-detected by Cloud9.
  • enableProxyCreds=False
    • Values – True/False
    • When set to True, the fields ‘proxyUsername’ and ‘proxyPassword’ are required.
    • Please note that Cloud9 at this time does not support IWA (Integrated Windows Authentication), so the username/password either has to be a Common functional account – where all traders share the same credentials, or Individualized AD Credentials per user – in this case, then application packaging is not possible since the user own their credentials and thus cannot be pushed into an ini file.
  • proxyAddress=
    • IP Address or Hostname of the proxy
  • proxyPort=0
    • Numeric value the port used by the proxy
    • Many firms have a port that enforces ‘Proxy Authentication’ and a port where it is not required.  As per above, you may wish to push the non-proxy authentication port into the .ini file.
  • proxyUsername=
    • As mentioned above, this can really only be a functional account when performing application packaging on behalf of end users.
  • proxyPassword=
    • This would be the password of the functional account which is protected via a salt algorithm.  

C9TraderProps.ini – Parameter options – Screen placement

Screen Location parameters

The location parameters are based upon the screen resolution of the monitors used by the trader.  

  • Top=
    • Specifies number of pixels down from the top of the screen.
  • Left=
    • Specifies the number of pixels from the left side of the screen.
    • When considering multiple monitors, the “left” value will drive the window to Monitor1, Monitor2, Monitor3, etc.  
  • Height=
    • Specifies the number of pixels in height used by Cloud9.  You need to ensure that the height is not past the viewable screen when accounting for the ‘Top’.
  • Width=
    • Specifies the number of pixels in width used by Cloud9.  You need to determine if you are stretching across monitors or staying within a monitor boundary.  
  • Maximized=
    • Values = True/False
    • When True, then the values of Top, Left, Height, and Width are ignored and Cloud9 is opened in full screen mode on the default monitor.
  • AlwaysOnTop=
    • Values = True/False
    • When set to True, the Cloud9 window cannot be placed behind any other window so it will be ever present in the foreground

C9shell.exe.config – Parameter options – RTP port range

RTPStartPort to modify the default start RTP start port of 16384 you can add in the config file in the <appSettings> as shown below <add key="RtpStartPort" value="xxxxx" />.

Fortify

With Fortify (Call Recording Windows Service CRWS), the expected permissions are that the service be a local system account and the users cannot delete from the recordings folder.

There is a requirement to allow the administrator to choose the privileged location where files will be stored. The MSI installer will default to:

  • C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\

However, administrators can change this location via packaging tools. The recording location will be a subdirectory of the service executable.

Normally folders under C:\Program Files (x86)\ have a default set of permissions, for example: 

  • C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService>icacls Recordings

Cloud9 Technologies LLC NT SERVICE\TrustedInstaller:(I)(F)

NT SERVICE\TrustedInstaller:(I)(CI)(IO)(F)

NT AUTHORITY\SYSTEM:(I)(F)

NT AUTHORITY\SYSTEM:(I)(OI)(CI)(IO)(F)

BUILTIN\Administrators:(I)(F)

BUILTIN\Administrators:(I)(OI)(CI)(IO)(F)

BUILTIN\Users:(I)(RX)

BUILTIN\Users:(I)(OI)(CI)(IO)(GR,GE)

CREATOR OWNER:(I)(OI)(CI)(IO)(F)

APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(RX)

APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES:(I)(OI)(CI)(IO)(GR,GE)

APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(RX)

APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES:(I)(OI)(CI)(IO)(GR,GE)

Recommended permissions

For the purposes of this project, we remove all permissions except for the account that runs the services, Local System. The idea is that we give a default restricted set of rights to the installation. However, clients can modify the MSI to fit their needs. This can be to use a different user account or add other accounts.

Since every client's permissions need to be tailored to their security consideration, this is a recommended set of permissions in icacls. Under the assumption that the Cloud9 user is either contained in BUILTIN\Users or NT AUTHORITY\Authenticated Users

icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" 

BUILTIN\Users:(OI)(CI)(W,REA,RA)

Recommended permissions:
icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" /inheritance:d

icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" /remove *S-1-5-32-545

icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" /grant *S-1-5-32-545:(OI)(CI)(S,RD,WD,REA,WEA,RA,WA)

icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" /remove *S-1-2-0

icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" /grant *S-1-2-0:(OI)(CI)(S,RD,WD,REA,WEA,RA,WA)

icacls "C:\Program Files (x86)\Cloud9 Technologies LLC\C9CallRecordingService\Recordings" /remove *S-1-3-0

Troubleshooting 

Logging – Initialization Log – C9Zeus

Cloud9 generates an initialization log file called ‘C9Zeus.xxxxx.log’ which is located in:

  • %localappdata%\Cloud9_Technologies\C9Trader\log

Here is an example of what a parsing error would generate in that log: 

2018-09-20 10:17:53.1867|INFO|C9Shell.App|****************************  StartingC9Trader ****************************2018-09-20 10:17:53.6371|FATAL|C9Shell.App|Dispatcher Unhandled exception. , StackTrace:    at Autofac.ContainerBuilder.StartStartableComponents(IComponentContext componentContext)   at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)   at Prism.Autofac.AutofacBootstrapper.CreateContainer(ContainerBuilder containerBuilder)   at Prism.Autofac.AutofacBootstrapper.Run(Boolean runWithDefaultConfiguration)   at C9Shell.App.v7hSJNKTZLfGT4CBWmf(Object )   at C9Shell.App.OnStartup(StartupEventArgs e)   at System.Windows.Application.<.ctor>b__1_0(Object unused)   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler), InnerException: Autofac.Core.DependencyResolutionException: An exception was thrown while invoking the constructor 'Void .ctor(System.String, C9Shell.Common.Components.ApplicationConfiguration.IApplicationSettingsCacheService, C9Shell.Common.Components.Core.IConnectionProvider, C9Shell.Common.Concurrency.ITaskFactory, C9Shell.Common.ErrorHandling.IErrorManager, C9Shell.Common.Components.Core.IStatusResponseValidator)' on type 'RestCallService'. ---> Invalid URI: The hostname could not be parsed. (See inner exception for details.) ---> System.UriFormatException: Invalid URI: The hostname could not be parsed.   at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)   at System.Uri..ctor(String uriString)   at System.Net.WebProxy.CreateProxyUri(String address)   at C9Shell.Common.Components.Core.ConnectionProvider.GetHttpClient()   at C9Shell.Common.Components.RestCall.RestCallService.ie6FTW52tOgZSa4HGUX(Object 

Typically, a successful C9Zeus log will look like the following
 2019-07-02 16:29:26.6849|INFO|C9Shell.App|****************************  Starting C9Trader ****************************

2019-07-02 16:29:27.1018|INFO|C9Shell.Common.Components.Gateway.GatewayService|Starting Gateway event processing thread.

2019-07-02 16:29:31.0300|ERROR|C9Shell.Common.Components.Core.NetworkConnectivityService|No Internet Available

2019-07-02 16:29:31.0300|INFO|C9Shell.Common.Components.Core.NetworkConnectivityService|Wired Internet Available, Name: C9TEC.LOCAL (10.9.1.1)

2019-07-02 16:29:31.0300|INFO|C9Shell.Common.Components.Core.NetworkConnectivityService|Internet Available

2019-07-02 16:29:32.5025|ERROR|C9Shell.Common.Components.Core.NetworkConnectivityService|No Internet Available

2019-07-02 16:29:32.5025|INFO|C9Shell.Common.Components.Core.NetworkConnectivityService|Wired Internet Available, Name: C9TEC.LOCAL (10.9.1.1)

2019-07-02 16:29:32.5025|INFO|C9Shell.Common.Components.Core.NetworkConnectivityService|Internet Available

2019-07-02 16:29:37.2766|WARN|C9Trader.Components.ButtonBoard.Midi.MidiService|Completed _pcQueue.

2019-07-02 16:29:37.4305|INFO|C9Shell.Common.Components.ActivityRecord.ServerTimeSynchronizer|Stopping server time sychronizer 

C9TraderProps.ini file backup

Any changes to local settings such as size of the window, audio devices, and other adjustments within the ‘Settings’ section of the application will cause an update to the C9TraderProps.ini file. There will be up to 5 copies of this file contained within the system directory. The application will always write a final version of the .ini file upon closure of the application.