SparkView integration guide

1. – Deployment

1. – Deployment

1.1 – SparkView only

sparkview-deploy-sv-only.png

Pros:

Cons:

1. – Deployment

1.2 – SparkView with reverse proxy, load balancer or VPN

sparkview-deploy-rp-vpn.png

Pros:

2. – Integration without programming

2. – Integration without programming

2.1 – Microsoft RD Web Access portal

Assume your web portal address is: https://MyRDPortal/RdWeb. You need to set up the following two entries in gateway.conf:

webfeed = https://MyRDPortal/RDWeb/feed/webfeed.aspx
directoryIndex = login.html

Checklist:

2. – Integration without programming

2.2 – Active Directory and LDAP

If all your users are domain users, please create a plain text file (encoding: UTF-8 without Byte Order Mark) with following context:

{
  "source":{
    "type": "AD",
    "properties": {
      "server": "ADServerAddress"
    }
  }
}

Save it as users.json or other name and specify the location of this file in gateway.conf:

user = C:\\workspace\\data\\users.json

You can configure servers used by all the users in servers.json and specify the location of servers.json in gateway.conf:

server = C:\\workspace\\data\\servers.json

If you are using a LDAP server, please change the type to “LDAP”. You can also configure AD/LDAP users in users.json:

{
"users": [
  {
    "name": "user1",
    "password": "user1",
    "servers": [
      "RdpServer1",
      "TEST",
      "Excel 2010"
    ],
    "isDomainUser": true,
    "transferCredential": true,
    domainServer: "serverAddr"
  }
}
2. – Integration without programming

2.3 – Radius

{
  "source": {
    "type": "RADIUS",
    "properties": {
      "server": "192.168.12.128",
      "port": "1812",
      "accountingPort": "1813",
      "sharedSecret": "test123"
      "timeout": "60000",
      "retryCount": "3"
    }
  }
}
2. – Integration without programming

2.4 – OAuth2

First, save your OAuth2 provider configuration into a JSON file, for example:

{
  "providers" : [{
    "name" : "Google",
    "client_id" : "650561938988-t2r66k1ms3hpoi3k1e2g7l2adlarau8s.apps.googleusercontent.com",
    "client_secret" : "-D-nhxWn2E97tZWWLg5IQ6Ak",
    "request_uri" : "https://accounts.google.com/o/oauth2/auth",
    "redirect_uri" : "http://localhost/oauth2callback",
    "access_token_uri": "https://oauth2.googleapis.com/token",
    "auth_uri": "/login_chrome.html",
    "scope": "openid email"
  },
  {
    "name" : "Live",
    "client_id" : "0000000040133A31",
    "client_secret" : "p9WwBr2Pyrq6mtaeZCwTSwqbIF39Br3Z",
    "request_uri" : "https://login.live.com/oauth20_authorize.srf",
    "redirect_uri" : "http://www.remotespark2.com/oauth2callback",
    "access_token_uri": "https://login.live.com/oauth20_token.srf",
    "scope": "wl.emails",
    "profile_uri": "https://apis.live.net/v5.0/me"
  }]
}

Second, specify the position of this file in gateway.conf:

oauth2 = \\user\\local\bin\\SparkViewGateway\\oauth2.json

For more information, please check the source code of login.html.

2. – Integration without programming

2.5 – SAML

You can get the integration of SAML from this document.

2. – Integration without programming

2.6 – Single Sign-On (SSO) with HTTP basic authentication

You can enable HTTP Basic Authentication on SparkView by setting authorization=Basic in gateway.conf, so all the RDP connections will use credentials from the HTTP Authorization header.

This can be used for VPN SSO integration etc

3. – Client side (browser) integration

3. – Client side (browser) integration

3.1 – Use 8 lines of code to start a remote connection from a web page

Save a JavaScript file as tutorial1.page.js with the following content:

window.onload = function() {
  var gateway = '192.168.12.111', //change this to your Spark gateway address
  server = '192.168.12.117', //change this to your RDP server address
  url = 'ws://' + gateway + '/RDP?server=' + server + '&user=vmuser&pwd=password';
  var r = new svGlobal.Rdp(url);
  r.addSurface(new svGlobal.LocalInterface());
  r.run();
};

Save a web page as tutorial1.html with the following content:

<!doctype html>
<html>
<head>
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Spark View (RDP)</title>
  <meta name="viewport" content="width = device-width, initial-scale = 1.0, user-scalable = yes, minimum-scale = 0.1, maximum-scale = 8" />
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <link rel="stylesheet" href="../hi5.css" />
  <link rel="stylesheet" href="../rdp.css" />
  <script type="text/javascript" src="../appcfg.js"></script>
  <script type="text/javascript" src="../resource.js"></script>
  <script type="text/javascript" src="../hi5core_min.js"></script>
  <script type="text/javascript" src="../hi5_min.js"></script>
  <script type="text/javascript" src="../surface_min.js"></script>
  <script type="text/javascript" src="../rdpcore_min.js"></script>
  <script type="text/javascript" src="../rdp_min.js"></script>
  <script type="text/javascript" src="tutorial1.page.js"></script>
</head>
<body>
  <div>
    <canvas id="remotectrl"></canvas>
  </div>
</body>
</html>

Double click on the html file and open it in your browser. You don’t even need a HTTP server for this demo.

Checklist:

Troubleshooting:

3. – Client side (browser) integration

3.2 – Using object or cookie for parameters

You can also use objects or cookie for parameters:

Object parameters with Rdp2:

window.onload = function() {
  var parameters = {
    gateway: '192.168.12.111',
    server: '192.168.12.117',
    user: 'vmuser',
    pwd: 'password'
  };
  var r = new svGlobal.Rdp2(parameters);
  r.addSurface(new svGlobal.LocalInterface());
  r.run();
};
window.onload = function() {
  document.cookie = 'gateway=192.168.12.111';
  document.cookie = 'server=192.168.12.117';
  document.cookie = 'user=vmuser';
  document.cookie = 'pwd=password';
  var r = new svGlobal.Rdp2();
  r.addSurface(new svGlobal.LocalInterface());
  r.run();
};

You can only set cookies if the web page is from http server.

HTTP Header parameters:

Following parameters can also be transferred within HTTP Headers:

gw_server, gw_port, gw_symlink, gw_user, gw_pwd

Best practices:

Don’t mix your web page with JavaScript code. You should always put your JavaScript code into external files because:

3. – Client side (browser) integration

3.3 – Resource redirection and parameters

SparkView has resource redirection (clipboard, drive, audio redirection etc.) disabled by default for safety reasons. You need to implicitly enable them by setting up extra parameters.

Resource redirection can be enabled on both, client side using the JavaScript library and server side using the servers.json.

Resource redirection                                                                                                  Parameter
Clipboard mapClipboard=on
Drive mapDisk=on

Also need to configure tmpdir in gateway.conf
Printer mapPrinter=on
printer=Your Printer Name

You can also configure printerDriver and printer (name) in gateway.conf

You also need to install a PostScript to PDF converter or PCL to PDF converter (depends on your printer driver) on the gateway computer (no need to install it on RDP server) and configure the location and command arguments for the converter in gateway.conf:

converter = D:\Programs\gs\gs9.16\bin\gswin32c.exe
arguments = -dBATCH -dNOPAUSE -dUseCIEColor -dPDFSETTINGS=/printer -sDEVICE=pdfwrite -q -sOutputFile=%1 %2
Audio Playback playAudio=0

soundPref=0: low audio quality, low bandwidth usage.
soundPref=1: high audio quality, high bandwidth usage.
Audio Input (Microphone) audioRecord=on
Time zone timezone= encodeURIComponent (‘(GMT-07:00) Mountain Standard Time’)

Please check the Administrator’s Manual for all parameters you can use.

Example of “enable clipboard redirection”:

var r = new svGlobal.Rdp('ws://gatewayAddr/RDP?server=192.168.12.117&mapClipboard=on');

Frequently used parameters:

Parameter                                                                                                  Value
port Integer, RDP listening port. Optional, default is 3389 for RDP, 5900 for VNC, 22 for SSH, 23 for Telnet
user String, user name (Windows User).
pwd String, password for user name.
domain String, domain name.
keyboard Integer, keyboard layout, default is 0x409 (US)
width Integer, screen width of RDP session. Default is 800
height Integer, screen height of RDP session. Default is 600
vmid Hyper-V VM GUID, For example: B3D5444C-2611-405A-9CA0-7AA8DA94DF0B, it’s for Hyper-V console connection.
minWidth Minimum width, some applications can only work on a minimum resolution
minHeight Minimum height, some applications can only work on a minimum resolution

Printer driver issue:

(Since version 5.7, Spark View can choose the best available driver automatically. It’s not recommended to set up the printer driver unless you have special needs. The followings is for reference only)

SparkView will use “MS Publisher Imagesetter” as the default printer driver, because all Windows have this driver installed by default. We found some problems with this driver: It woks good if you print only few pages, it’ll generate huge raw printing file (>1GB) if you are printing more than 50 pages. It’s better to change the printer driver in the gateway.conf:

printerDriver = HP Color LaserJet 8500 PS

You should make sure your RDP server has this printer driver installed. This is how to find a PostScript printer driver:

sv-printer-step-1.png

sv-printer-step-2.png

sv-printer-step-3.png

sv-printer-step-4.png

Copy the selected printer name then “Cancel”. You don’t need to actually install it, then you set up this printer driver in gateway.conf.

Please make sure it’s a PostScript or PCL printer. You need to set up the PostScript to PDF converter or PCL to PDF converter accordingly in gateway.conf.

  1. Download and install your desired printer driver
  2. Set up the printer driver name in gateway.conf:
    printerDriver = HP Universal Printing PS
3. – Client side (browser) integration

3.4 – Start a program on connection (as shell)

Set up the following parameters:

startProgram=shell
command=encodeURIComponent(‘C:\\apps\\notepad.exe’)
directory= encodeURIComponent(‘C:\\apps\\’)

Checklist:

3. – Client side (browser) integration

3.5 – Start RemoteApp

Add the following parameters if you want to start the RemtoeApp in current browser window:

startProgram=app
exe=||WINWORD
directory= encodeURIComponent(‘C:\\apps\\’)

Start RemtoeApp in a new window:

function startRemoteApp(remoteApp, args, dir, url){
  var r = svManager.getInstance() || new svGlobal.Rdp(url); //reuse existing session if available

  function onSurfaceReady(surface){
    r.addSurface(surface);
    if (r.running()){
      r.startApp(remoteApp, args, dir);
    }else{
      r.run();
    }
  };
  window.svOnSurfaceReady = onSurfaceReady;
  var rail = window.open('rail.html');
  rail.svOnSurfaceReady = onSurfaceReady;
}

window.onload = function() {
  var gateway = 'w-think', //change this to your SparkView address
  server = '192.168.12.132', //change this to your RDP server address
  user = 'vmuser',
  password = 'password',
  remoteApp = '||notepad',
  args = '',
  dir = '',
  url = 'ws://' + gateway + '/RDP?server=' + server + '&startProgram=app' + '&exe=' + encodeURIComponent(remoteApp) + '&user=' + user + '&pwd=' + password;
  startRemoteApp(remoteApp, args, dir, url);
};

Checklist:

3. – Client side (browser) integration

3.6 – Virtual Channel (VC) and Dynamic Virtual Channel extension

SparkView JavaScript client supports standard RDP virtual channel and dynamical virtual channel extension. You can create multiple virtual channels and dynamic virtual channels on client side using JavaScript (You can only create one VC before 4.0):

var r = new svGlobal.Rdp(protocol + gw + "/RDP?"+ s, w, h, server_bpp);
var vc = new r.VirtualChannel(); //Use r.DynamicChannel to create a dynamic virtual channel
vc.name = "CUST";
vc.process = function(buffer){
  console.log(buffer.getByte());
  console.log(buffer.getLittleEndian16());
};
vc.onopen = function(){
  var data = new Array(7);
  var rb = new RdpBuffer(data, 0, 7);
  rb.setByte(1);
  rb.setLittleEndian16(345);
  rb.setLittleEndian32(567);
  rb.markEnd();
  vc.send(rb);
};
r.addChannel(vc);

Virtual Channel is used to communicate with RDP host. You also need to write a plug-in for the RDP host.

Please check the following for more information:
http://msdn.microsoft.com/en-us/library/aa383546(v=vs.85).aspx
http://www.codeproject.com/Articles/16374/How-to-Write-a-Terminal-Services-Add-in-in-Pure-C

3. – Client side (browser) integration

3.7 – Gateway channel

You can create multiple gateway channels to create a communication layer between client browser and the gateway:

var gvc = new r.GatewayChannel();
gvc.name = "gwc";
gvc.process = function(buffer){
  console.log(buffer.getByte());
  console.log(buffer.getLittleEndian16());
};
gvc.onopen = function(){
  var data = new Array(7);
  var rb = new RdpBuffer(data, 0, 7);
  rb.setByte(3);
  rb.setLittleEndian16(45);
  rb.setLittleEndian32(678);
  rb.markEnd();
  gvc.send(rb);
};
r.addGatewayChannel(gvc);

On gateway side, your class must extend com.toremote.gateway.plugin.AbstractGatewayChannel and register it with the same name using HandlerManager.registerChannel(). Please check the plug-in example for more information.

3. – Client side (browser) integration

3.8 – Configuration file and others

You can use appcfg.js to configure some parameters for the client. Please check the source code of appcfg.js for more details.

3. – Client side (browser) integration

3.8.1 – Start up a server or application automatically after login

To start up a server or application automatically after login, you can set the following parameters in the file html/appcfg.js. Please ensure, that your content is placed inside the hi5.appcfg = {} brackets:

hi5.appcfg = {
	startup: {
		server: "", //If server is "" or not found, the first one will be opened instead.
		newWindow: false //Open in new window
	},
}

After editing, save the file and restart SparkView.

4. – Server side integration

4. – Server side integration

4.1 – HTTP API

You can use HTTP request to create a server, symlink dynamically if you don't want to write a plug-in for the gateway.

To use the HTTP server, you’ll need to configure a password in gateway.conf:

Password = yourPassword

Then you can use MD5 hash of this password with the HTTP API.

Create servers on gateway:

http://gatewayAddress/SERVER?id=serverId&displayName=Name&server=hostName&gatewayPwd=passwordInGateway.conf&...

gatewayPwd is hexadecimal MD5 hash of the password which is configured in gateway.conf.

To delete a server add "&action=delete" to the URL; to update a server, add "&action=update" to the URL.

List servers:

http://w-think/SERVER?action=list&gatewayPwd=21232f297a57a5a743894a0e4a801fc3&id=ATPlus

It returns the asked server if id is specified:

{"id":"ATPlus","displayName":"ATPlus","server":"cloud.thinrdp.net","shadowing":false,"protocols":"rdp","icon":"kbd.png","rdp":{"username":"demo","password":"demo"}}

It returns all servers if id is not specified:

{
  "display" : true,
  "type" : "NORMALLIST",
  "cols" : [
    {"name" : "id"},
    {"name" : "displayName"},
    {"name" : "server"},
    {"name" : "remoteProgram"},
    {"name" : "command"}
  ],
  "rows" : [
    ["ATPlus", "ATPlus", "192.168.12.117", "", ""],
    ["WordPad", "WordPad", "192.168.0.118", "", "wordpad.exe"]
  ]
}

http://gatewayAddress/SYMLINK?symlink=symlinkId&server=existingServerId&validTime=20m&gatewayPwd=passwordInGateway.conf&...

You can also use "validFrom", "validTo" parameters. Please check http://www.remotespark.com/view/doc/com/toremote/gateway/connection/SymLink.html for more information.

To delete a symlink, add "&action=delete" to the URL; to update a symlink, add "&action=update" to the URL.

List symlinks:

http://w-think/SYMLINK?action=list&gatewayPwd=21232f297a57a5a743894a0e4a801fc3&symlink=212a155ee951-40db-95ea-177183174fa7

It returns the asked symlink if symlink is specified:

{"id":"212a155e-e951-40db-95ea-177183174fa7","resourceId":"169.254.146.243","validFrom":"Aug 26, 2015 12:00:00 AM","parameters":""}

It returns all the symlinks if symlink is not specified:

{
  "cols":[
    {"name":"id"},
    {"name":"resourceId"},
    {"name":"password"},
    {"name":"validFrom"},
    {"name":"validTime"},
    {"name":"validTo"},
    {"name":"parameters"},
    {"name":"comment"}
  ],
  "rows":[
    ["212a155e-e951-40db-95ea-177183174fa7", "169.254.146.243", "", 1440568800000, "", 0, "", ""],
    ["c5c6bc9d-f8a7-42ca-af9c-bd28c86adab4", "169.254.146.243", "", 1452544860000, "", 0, "", ""]
  ]
}

List sessions:

http://w-think/SESSION?action=list&gatewayPwd=21232f297a57a5a743894a0e4a801fc3&id=a29575a9-08c2-4162-9bfb-4876820953db

It returns the single session information if session id is specified:

{"id":"a29575a9-08c2-4162-9bfb4876820953db","server":"192.168.12.118","clientIp":"169.254.84.132","clientAgent":"Mozilla\/5.0 (Windows NT 10.0; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/47.0.2526.111 Safari\/537.36","thumbnail":"","startTime":"Tue Jan 26 15:38:55 MST 2016","numericId":621779525,"user":"","domain":"","rdpId":1,"startTime2":1453847935826}

It returns all sessions if session id is not specified:

{
  "cols":[
    {"name":"id"},
    {"name":"server"},
    {"name":"clientIp"},
    {"name":"clientAgent"},
    {"name":"startTime"},
    {"name":"numericId"},
    {"name":"user"},
    {"name":"domain"},
    {"name":"join"},
    {"name":"protocol"},
    {"name":"symlink"},
    {"name":"thumbnail"}
  ],
  "size":1,
  "rows":[
    ["a29575a9-08c2-4162-9bfb-4876820953db","192.168.12.118","169.254.84.132","Mozilla\/5.0 (Windows NT 10.0; WOW64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/47.0.2526.111 Safari\/537.36","Tue Jan 26 15:38:55 MST 2016",621779525,"","","","RDP","",""]
  ]
}

It returns multiple session information if ids parameter is used:

http://w-think/SESSION?action=list&gatewayPwd=21232f297a57a5a743894a0e4a801fc3&id=a29575a9-08c2-4162-9bfb-4876820953db&ids=sessinId1,sessionId2

[{session1}, {session2}]

Upload license file:

http://wthink/CONTROL?licenseFile=base64encodedLicenseFile&gatewayPwd=21232f297a57a5a743894a0e4a801fc3

Please make sure you encode the value of licenseFile. For example:

encodeURIComponent(base64encodedLicenseFile)

The new license file information will be returned in JSON format if the license file was uploaded successfully.

To query the current license file information, you can use:
http://w-think/CONTROL?licenseFile=.&gatewayPwd=21232f297a57a5a743894a0e4a801fc3

Get gateway information

http://w-think/CONTROL?target=gateway

{"version":"5.8.0","buildNumber":"941","buildTime":"2020_03_04_10","startTime":1583342850085}

Password is not needed for this gateway information request.

Reset Two Factor Authentication

http://w-think/CONTROL?target=twofa&user=Username&gatewayPwd=21232f297a57a5a743894a0e4a801fc3

curl -k -G --data-urlencode "target=twofa" --data-urlencode "user=svtest\user1" https://127.0.0.1/CONTROL

Error handling:

HTTP request will return HTTP Status code 500 and {"error:": "error information"} in JSON if there is an error. For example, server or symlink with specified id was not found when you try to get a server or symlink.

HTTP request will return status code 200 if operation succeeded.

4. – Server side integration

4.2 – Plug-in

The gateway is a multi-thread application, so make sure your plug-in is:

Please refer to the related links:

4. – Server side integration

4.2.1 – Start gateway and the plug-in example project in Eclipse

Download the plug-in example:
http://remotespark.com/Plugin.zip

Extract the zip to your Eclipse workspace and run the follwing actions:

  1. File -> Import
  2. Click "Next"
  3. "Browse" to your workspace directory
  4. Select the Plugin project.
  5. Click "Finish"
  6. Right click on the Plugin project, "Run As" -> "Java Application"
  7. Make sure "SparkGateway – com.toremote.gateway" is selected.
  8. Click "OK"

Now the gateway with the plug-in is running in Eclipse. You can use the "Debug As" -> Java Application to debug your plug-in code.

Checklist:

4. – Server side integration

4.2.2 – Handshake plug-in

Handshake plug-in is invoked before establishing a RDP connection. It’s a good place to verify, modify or refuse the connection.

You can put any parameter you want when you create a connection on the client side. For example, you can put user’s session id (session on your portal) into a RDP connection:

var rdp = new svGlobal.Rdp(‘ws://myGateway/RDP?server=myServer&token=mySessionId&…’);

Then in the handshake plug-in, you can get the parameter and verify it through a web server on your portal.

class SimpleHandshakePlugin implements HandshakeInterface{
@Override
public Map<String, String> onHandshake(Map<String, String> parameters) throws ClientException{
  String token = parameters.get("token");
  if (isInvalidSession(token)){
    throw new ClientException("Invalid sessioin");
  }
  return parameters;
}

You can also encrypt the token from your portal (encrypted on server side), then decrypt it in the plug-in:

public Map<String, String> onHandshake(Map<String, String> parameters) throws ClientException{
  String token = decryptToken(token);//throw ClientException if not valid
  Map<String, String> paramsFromToken = parseToken(token);
  parameters.put(RdpParameter.server, paramsFromToken.get("server"));
  parameters.put(RdpParameter.user, paramsFromToken.get("user"));
  parameters.put(RdpParameter.pwd, paramsFromToken.get("pwd"));
  String userIp = parameters.get(RdpParameter.ARG_CLIENT_IP);
  //enable recording
  parameters.put(RdpParameter.sessionRecord, "1"); //enable session recording
  //specify the recording file name (optional)
  parameters.put(RdpParameter.RECRODING_FILE_NAME, "myFileName");
  return parameters;
}

Best practices:

4. – Server side integration

4.2.3 – Deploy your plug-in

Export the jar file:

  1. Right click on the project, "Export", select "Runable JAR file" under Java.
  2. Choose "SparkGateway - Plugin" in Launch configuration.
  3. Choose export destination.
  4. Click "Finish"

Make sure "Extract required libraries into generated JAR" selected in "Library handling"

It’s better to put your plug-in can be in a separated jar file. In this case, you should set up your plug-in file path in gateway.conf:

pluginFile=theLocationOfYourPlugin.jar

Here is how to export the plug-in into a separated jar file (without the content of SparkGateway.jar):

4. – Server side integration

4.3 – Downloading files unprompted

Users can download files through custom apps and programs. This can be archived by using the clipboard redirection:

  1. Make sure clipboard redirection is enabled, and copyFile=true in gateway.conf.
  2. Set fileUnprompted=xlsx,xls (Excel files in this case, change to your related file types)
  3. In the user's application, you need to provide a button or menu like "Download file", when the user clicks this button, their application needs to copy the file to the clipboard (remote computer's clipboard). Reference:
    https://stackoverflow.com/questions/25708895/how-to-copy-files-by-win32-api-functions-and-paste-by-ctrlv-in-my-desktop
  4. The user will then see this message in the browser:
    Unknown.png
  5. User clicks once again to download the file.

For this solution:

Appendices

Appendices

Appendix A – Integration with symlink use case

Actors:

User, User Portal, Spark Gateway

Preconditions:

User Portal:

Spark Gateway:

Basic flow:

  1. User login to User Portal.
  2. (optional) User Portal create a server on Spark Gateway with HTTP API if that server is not created yet:
    http://gatewayAddress/SERVER?id=serverId&displayName=Name&server=hostName&gatewayPwd=passwordInGateway.conf&...; Check if server exists: http://wthink/SERVER?action=list&gatewayPwd=21232f297a57a5a743894a0e4a801fc3&id=serverId;
    The gateway will return HTTP Status code 500 and {"error:": "not found"} in JSON format.
  3. User Portal create a symlink on Spark Gateway with HTTP API:
    'http://gatewayAddress/SYMLINK?symlink=symlinkId&server=existingServerId&validTime=8h&gatewayPwd=passwordInGateway.conf&parameters=' + encodeURIComponent('user=domainUser&pwd=domainPassword&domain=domain');
  4. User portal construct a connection link and display it to user:
    http://gateway/rdpdirect.html?symlink=symlinkId&displayName=nameOnBrowserTitle; or use the Spark View JS library directly to create a connection:
    var rdp = new svGlobal.Rdp(‘wss://gateway/RDP?symlink=symlinkId&..’, width, height, color);
  5. User click the link and connect.
  6. User portal delete the symlink when user exist or close the browser:
    http://gatewayAddress/SYMLINK?symlink=symlinkId&action=delete

Pros:

Cons:

Appendices

Appendix B – Integration with third party application or HTTP service

Actors:

User Portal, Spark Gateway, Third party application or HTTP server

Preconditions:

User Portal:

Spark Gateway:

Basic flow:

  1. User Portal send the token to Spark Gateway along with other parameters.
  2. Spark Gateway check if the token name is same as the value configured in authToken.name. It’s same, then.
  3. Spark Gateway execute the application or HTTP Request(GET) configured in authToken.exec, if the return code or HTTP Status code is same as the authToken.sucessCode, gateway will allow the connection, otherwise reject it.
Appendices

Appendix C – Integration with plugin use case

Actors:

User, User Portal, Spark Gateway

Preconditions:

User Portal:

SparkView:

Basic flow:

  1. User login to User Portal.
  2. User Portal encrypt the user credential and other information like User Portal session id as a token string, for example:
    'user=domainUser&pwd=domainPassword&domain=domain&session=id’.
  3. User Portal construct a connection link and display it to user:
    http://gateway/rdpdirect.html?token=myEcryptedToken&displayName=nameOnBrowserTitle&otherParameters; or use the Spark View JS library directly to create a connection:
    var rdp = new svGlobal.Rdp(‘wss://gateway/RDP?token=myEycryptedToken&..’, width, height, color);
  4. User click the link and connect.
  5. SparkView plugin decrypt the token, verify the user session (optional) and put the decrypted RDP parameters back (Please check the plugin example for details: http://www.remotespark.com/Plugin.zip)

Pros:

Cons:

Both use cases are recommended. You can also consider to use them together (symlink with plugin), so user credentials can be encrypted and don’t need to be sent to the client side.

If User Portal cannot have the user credentials in plain text, you can consider to create a temporary windows user account for every user and remove this account later.

Appendices

Appendix D – Chromium Embedded Framework (CEF), WebView and Electron

You can use CEF or Electron to make a standalone client, so SparkView client can access local resource directly (clipboard), and override some shortcuts keys reserved by the browser (Ctrl+T/W etc).

  1. Let Spark View know it can access the clipboard directly by setting directClipAccess: true in appcfg.js.
  2. For CEF, you need to enable cef_state_t javascript_access_clipboard.
  3. For WebView, please check: https://stackoverflow.com/questions/4200259/tapping-formfield-in-webview-does-not-show-soft-keyboard
  4. For Electron, you can also use mainWindow.webContents.executeJavaScript('hi5.appcfg.directClipAccess=true') to inject the code.