C
C
u
u
s
s
t
t
o
o
m
m
i
i
z
z
i
i
n
n
g
g
N
N
F
F
u
u
s
s
e
e
W
W
e
e
b
b
S
S
i
i
t
t
e
e
s
s
f
f
o
o
r
r
C
C
i
i
t
t
r
r
i
i
x
x
S
S
e
e
c
c
u
u
r
r
e
e
G
G
a
a
t
t
e
e
w
w
a
a
y
y
Notice
The information in this publication is subject to change without notice.
THIS PUBLICATION IS PROVIDED “AS IS” WITHOUT WARRANTIES OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE OR NON-INFRINGEMENT. CITRIX SYSTEMS, INC. (“CITRIX”), SHALL
NOT BE LIABLE FOR TECHNICAL OR EDITORIAL ERRORS OR OMISSIONS CONTAINED
HEREIN, NOR FOR DIRECT, INCIDENTAL, CONSEQUENTIAL OR ANY OTHER DAMAGES
RESULTING FROM THE FURNISHING, PERFORMANCE, OR USE OF THIS PUBLICATION, EVEN
IF CITRIX HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES IN ADVANCE.
This publication contains information protected by copyright. Except for internal distribution, no part of
this publication may be photocopied or reproduced in any form without prior written consent from
Citrix.
The exclusive warranty for Citrix products, if any, is stated in the product documentation
accompanying such products. Citrix does not warrant products other than its own.
Product names mentioned herein may be trademarks and/or registered trademarks of their
respective companies.
Copyright © 2001 Citrix Systems, Inc. All rights reserved.
Version History
December 15, 2001 Citrix Systems, Inc. Version 1.0
Table of Contents
OVERVIEW...1
C
OMPATIBILITY
G
UIDELINES
...2
W
HO
S
HOULD
R
EAD
T
HIS
P
APER
...2
HOW NFUSE WORKS...3
W
HAT
C
HANGES DOES
C
ITRIX
S
ECURE
G
ATEWAY
I
NTRODUCE
?...5
NFUSE CUSTOMIZATION OVERVIEW...7
C
OPY
NF
USE
E
XTENSIONS
F
ILES
R
EQUIRED
F
OR
C
ITRIX
S
ECURE
G
ATEWAY
S
UPPORT
...7
M
ODIFYING LAUNCH
.
ASP TO
S
UPPORT
T
ICKETING
...8
M
ODIFY TEMPLATE
.
ICA TO
S
UPPORT
S
ECURE
G
ATEWAY
...11
M
ODIFY
.
ASP FILE TO
S
UPPORT
D
ETECTION OF THE
ICA C
LIENT VERSION
...12
SAMPLE WEB SITE SCRIPTS INSTALLED BY NFUSE EXTENSIONS ...15
NF
USE
E
XTENSIONS
...17
csg_conf.inc ...17
ctxsta.dtd...18
rq_ticket.xml ...20
sta_error.inc ...21
sta_error16.inc ...22
sta_xml.inc...23
NF
USE
1.51 ...28
launch.asp...28
template.ica ...30
NF
USE
1.6 ...32
launch.asp...32
template.ica ...37
Overview
Citrix Secure Gateway (Secure Gateway), in conjunction with Citrix NFuse (NFuse) application portal
software, provides heightened security by securing ICA traffic between ICA Clients and either
MetaFrame XP Application Server for Windows Version 1.0 or later, or Citrix MetaFrame for UNIX
Operating Systems Version 1.1 (jointly referred to as MetaFrame) servers using SSL encryption.
NFuse forms an integral part of Secure Gateway. It provides a Web portal view of published applications,
available on MetaFrame servers, to ICA Client users. NFuse dynamically customizes content according
to a user’s profile. When users log in to the portal, NFuse accesses the MetaFrame farm and displays a
list of applications specific to the user’s group or profile.
To integrate Secure Gateway into an existing MetaFrame environment that uses NFuse to publish
applications to the Web, you need to customize the NFuse Web site. Most of the customization required
is to support “ticketing,” a core feature of Secure Gateway. Secure Gateway uses “tickets” as the means
of authentication and authorization to allow access to MetaFrame resources.
This document outlines the changes required to an existing NFuse Web site to provide support for a
Secure Gateway implementation. It includes the following sections:
Compatibility Guidelines, on page 2
How NFuse Works, on page 3
Changes Introduced by Citrix Secure Gateway, on page 5
Details of Customization Required for Citrix Secure Gateway, on page 7
Compatibility Guidelines
Secure Gateway is compatible with:
SSL-enabled ICA Clients, Version 6.20 or later
NFuse 1.51 or 1.6 running on Internet Information Server (IIS) 5.0 on a Windows 2000 Server
MetaFrame XP Application Server for Windows Version 1.0 or later
−
or
−
Citrix MetaFrame for UNIX Operating Systems Version 1.1
You also need to install NFuse Extensions on your NFuse Web server, and set up the Secure Gateway
environment as described in the Citrix Secure Gateway documentation.
Who Should Read This Paper
This document is for server administrators responsible for the planning and deployment of MetaFrame
and NFuse in the enterprise. This white paper assumes knowledge of:
Web server administration
Citrix MetaFrame XP Application Server for Windows Servers Version 1.0 or later
Citrix NFuse 1.51 or later
Citrix ICA Clients, Version 6.20 or later
Use this white paper in conjunction with the following:
Citrix Secure Gateway Administrator’s Guide
MetaFrame XP Administrator's Guide
NFuse Administrator’s Guide
How NFuse Works
This diagram describes the interaction between the Citrix server farm, an NFuse Web server, and an ICA
Client device.
Web Server
ICA Client Device Web Browser
ICA Client
Citrix Server Farm
1
3 2
4
6
5
NFuse
7
1. The user of an ICA Client device uses a Web browser to view the login page on an NFuse Web
portal. The user enters valid user credentials to log in. The credentials are sent as a standard HTTP
request over the default HTTP port 80.
2. The Web server reads the user’s information and uses the NFuse Java objects to forward that
information to the Citrix XML Service on a designated Citrix server in the server farm. This
designated server acts as a broker between the Web server and the Citrix server farm.
4. The Web server uses the NFuse Java objects to generate an HTML page containing links to the
applications in the user’s application set. Each hyperlink in the HTML page points to the template.ica
file stored on the NFuse Web server. This file serves as a template that NFuse uses to dynamically
generate customized ICA files. ICA files are text files containing parameters that configure ICA
session properties such as the application to run in the session, the address of the server that
executes the application, and the properties of the window in which to display the application. ICA
files are written in .ini file format and have an .ica extension.
5. The user initiates the next step by clicking one of the published application hyperlinks in the HTML
page. The Web browser sends a request to the Web server to retrieve an ICA file for the selected
application.
The Web server passes this request to the NFuse Java objects, which retrieve the template ICA file.
The template file contains substitution tags. The NFuse Java objects replace the substitution tags in
the template ICA file with information specific to the user and desired application.
The NFuse Java objects then send the customized ICA file to the Web browser.
6. The Web browser receives the ICA file and passes it to the client device’s ICA Client.
What Changes does Citrix Secure Gateway Introduce?
The communications described in the “
How NFuse Works
” section are the normal sequence of events
that occur when an NFuse Web server is deployed to provide access to published applications, in a Citrix
server farm, to ICA Client users.
When you introduce Secure Gateway into this environment, several changes occur in the connection
process. The illustration below shows the communications that take place between ICA Clients, NFuse,
MetaFrame servers, and Secure Gateway components before an ICA connection is established between
the ICA Client and a MetaFrame server.
Web Server
ICA Client Device Web Browser
ICA Client
Citrix Server Farm
1
3 2
4
7
8a NFuse
Secure Ticket Authority
Citrix Secure Gateway
8c
6a
5 6b
8b
A new step in the communications process is seen taking place at this point with the introduction of the
Secure Ticket Authority (STA).
6a. NFuse contacts the STA to obtain a ticket for the ICA connection that the ICA client is requesting.
6b. NFuse substitutes the value of the Address field in the template.ica file with the ticket issued by the
STA, and dynamically generates an ICA file. NFuse sends the ICA file to the Web browser on the
client device as normal.
7. The Web browser sends the ICA file received from NFuse to the ICA Client.
Again, at this point a new set of steps in the communications process is seen taking place with the
introduction of the Secure Gateway Service.
8a. The ICA Client uses the information in the ICA file to launch an SSL connection to the Secure
Gateway Service.
8b. The Secure Gateway Service extracts the ticket information from the ICA file, and requests the STA
to validate the ticket.
8c. When the STA has validated the ticket, the Secure Gateway Service establishes a connection to the
requested resource on a MetaFrame server.
NFuse Customization Overview
This section addresses in detail the changes that need to be made to a NFuse Web site to support
Secure Gateway. The changes required to NFuse are as follows:
Copy NFuse Extensions files required for Secure Gateway support
•
•
•
•
•
•
•
•
•
Modify launch.asp to support ticketing
Modify template.ica to support Secure Gateway parameters
Modify icaclient.asp or install.asp to support detection of the ICA Client version
Copy NFuse Extensions Files Required For Citrix Secure Gateway Support
When you install NFuse Extensions on your NFuse Web server, the script files that enable support for
ticketing are copied to %systemdrive%\inetpub\wwwroot\
csg
\ (where \
csg
is the directory to which you
installed NFuse Extensions). These files are listed below:
csg_conf.inc
This text file defines configuration values specific to Secure Gateway.
ctxsta.dtd
This text file is the DTD schema for the XML request packet used to request a Secure Gateway
ticket.
rq_ticket.xml
This text file defines the XML request packet used to request a Secure Gateway ticket.
sta_error.inc, sta_error16.inc
These text files define the error reporting function
staError
. This function should be customized to
suit the NFuse Web site.
sta_error.inc
is used by NFuse 1.51 and
sta_error16.inc
is used by
NFuse 1.6.
sta_xml.inc
This text file defines the STA ticket request function,
staGetTicketFromAddress
.
Copy the files listed above to the directory in which the NFuse site you are modifying resides. For
Modifying launch.asp to Support Ticketing
NFuse uses the script file, launch.asp, to launch an ICA session. You must modify this file to support
Secure Gateway ticketing.
In the code fragment shown below (extracted from a unmodified script listing), the output of the parser is
sent as is to the Web browser on the client device.
...
Response.ContentType = "application/x-ica"
Continue = True
Response.Expires = -1
While (Continue)
HtmlString = parser.getNextDataBlock()
If HtmlString = "" Then
Continue = False
Else
Response.Write(HtmlString)
To support Secure Gateway ticketing, the output of the parser must be parsed to locate the
Address
field and the
value
associated with it. This value is extracted and sent to the STA for processing through
the
staGetTicketFromAddress
function. The following script illustrates how this is done:
...
%>
<!-- #include File = "csg_conf.inc" -->
<!-- #include File = "sta_error.inc" -->
<!-- #include File = "sta_xml.inc" -->
<%
strServerAddress = ""
strConnTicket = ""
Response.ContentType = "application/x-ica"
Continue = True
Response.Expires = -1
While (Continue)
HtmlString = Parser.getNextDataBlock()
If HtmlString = "" Then
Continue = False
Else
' Check if this is the address string
strToFind = Chr(10) & "Address="
stPos = InStr(HtmlString,strToFind)
If stPos <> 0 Then
endPos = InStr(stPos+1,HtmlString,Chr(10))
cutPos = stPos + Len(strToFind)
strServerAddress = Mid(HtmlString, cutPos, _
endPos-cutPos-1)
If Len(strServerAddress) <> 0 Then
strConnTicket = _
staGetTicketFromAddress(strServerAddress)
if Len(strConnTicket) = 0 then
' invalid (empty) ticket, revert content type
' to "text/html" for error messages
Continue = False
else
str1 = Mid(HtmlString,1,cutPos-1)
str2 = Mid(HtmlString,endPos-1)
' replace Address with CSG ticket
HtmlString = str1 & strConnTicket & str2
end if
End If
End If
if (Continue) then
Response.Write(HtmlString)
end if
Modify template.ica to Support Secure Gateway
Secure Gateway requires the following parameters to be present in the template.ica file on the NFuse
Web server:
HttpBrowserAddress=!
This parameter forces the ICA Client from performing HTTP browsing. Instead, it forces the ICA
Client to connect directly to the server running the Secure Gateway Service.
BrowserProtocol=HTTPonTCP
This parameter forces the ICA Client to perform ICA browsing using the TCP/IP+HTTP network
protocol.
TransportReconnectEnabled=Off
This parameter disables Client Auto Reconnect (ACR) on the ICA Client. Secure Gateway does not
support ACR.
SSLProxyHost=CSGServer:Port
This parameter specifies the server address and port number of the server running the Secure
Gateway Service. Note that this value can be defined as an NFuse substitution tag, which is parsed
and processed by NFuse.
SSLEnable=On
This parameter forces the ICA Client to use SSL encryption for all ICA connections.
Modify .asp file to Support Detection of the ICA Client version
Standard NFuse Web sites provide a function that enables NFuse to check that the ICA Win32 Client
software is present on the client device. Secure Gateway, however, requires Citrix ICA Win32 Client,
Version 6.20 or later.
To support Secure Gateway you need NFuse to check the version of the ICA Client as well. To enable
version checking, the client detection script in your NFuse Web site needs to be. If the version number is
not 6.20 or later, then the user is prompted to download the latest version of the client software.
Note:
Ensure that the ICA Client download directory for your NFuse Web site contains download
packages for ICA Clients, Version 6.20, or later. The default path for the ICA Client download directory is
\citrix\icaweb in your Web server’s Web publishing root directory (usually
%systemdrive%\inetpub\wwwroot). Refer to the
NFuse Administrator’s Guide
for information about
deploying ICA Clients.
The code fragment shown below is an extract from the default script, icaclient.asp, on an NFuse 1.51
Web site:
...
function hasIcaObjVal()
dim obj
Err.Clear
On Error Resume Next
hasIcaObjVal = 0
set obj = CreateObject("Citrix.ICAClient")
if (Err.number = 0) then
hasIcaObjVal = 1
else
Err.Clear
set obj = CreateObject("Wfica.WficaCtl.6")
if (Err.number = 0) then
hasIcaObjVal = 1
else
Err.Clear
hasIcaObjVal = 0
end if
set obj = Nothing
end function
select case hasIcaObjVal()
case 1
...
The following script must replace the script listing shown above. This script checks that the ICA Client
software is Version 6.20 or later:
...
' Get ICA Client Object version
' returns: 0 ICA Client not installed
' 10 Pre 1.8 FR1, Wfica.WficaCtl.1
' 16 1.8 FR1, Wfica.WficaCtl.6
' 20 XP 1.0, ICO 2.0
' 21 XP 1.0 FR1, ICO 2.1,
' ICA Client version 6.20 or later
function hasIcaObjVal()
dim obj
dim badSetup
badSetup = false
Err.Clear
On Error Resume Next
hasIcaObjVal = 0
'ICO 2.x
set obj = CreateObject("Citrix.ICAClient")
if (Err.number = 0) then
clientId = obj.GetInterfaceVersion()
if (Err.number = 0) then
strPos = StrComp(clientId, "2.0", 1)
if (strPos = 0) then
'XP 1.0, ICO 2.0
hasIcaObjVal = 20
else
hasIcaObjVal = 21
end if
else
'"Citrix.ICAClient" not installed/uninstalled
'correctly
badSetup = true
end if
end if
if (badSetup = true) then
Err.Clear
set obj = Nothing
'1.8 FR1, Wfica.WficaCtl.6
set obj = CreateObject("Wfica.WficaCtl.6")
if (Err.number = 0) then
hasIcaObjVal = 16
else
Err.Clear
set obj = Nothing
'Pre 1.8 FR1, Wfica.WficaCtl.1
set obj = CreateObject("Wfica.WficaCtl.1")
if (Err.number = 0) then
hasIcaObjVal = 10
end if
end if
end if
set obj = Nothing
end function
select case hasIcaObjVal()
case 21
Sample Web site Scripts installed by NFuse
Extensions
When you install NFuse Extensions, additional system files and a sample Web site are copied to the
default installation directory %systemdrive%:\inetpub\wwwroot\csg\. The sample Web site is constructed
from a set of Web scripts and ICA specific files.
This section contains a listing of the modified Web scripts and ICA specific files that are used to construct
the sample Web site. Use these sample script listings as a reference to help you modify your existing
NFuse Web sites. The script listings in this section are organized as follows:
NFuse Extensions
The following scripts are installed for ticketing support.
csg_conf.inc
ctxsta.dtd
rq_ticket.xml
sta_error.inc
sta_error16.inc
sta_xml.inc
For NFuse 1.51 Web Sites
These files are modified on an NFuse 1.51 Web site to support Secure Gateway.
launch.asp
template.ica
For NFuse 1.6 Web Sites
These files are modified on an NFuse 1.6 Web site to support Secure Gateway.
ICA Client Version Detection Function
This section contains a listing of the
modified hasIcaObjVal() function
that performs the ICA Client
version check to determine if the client software is Version 6.20 or later.
For NFuse 1.6 Web sites, the file install.asp is modified by replacing the function,
hasIcaObjVal()
,
with the script fragment listed in this section to enable version checking of ICA Client software.
For NFuse 1.51 Web sites, the file icaclient.asp is modified by replacing the function,
hasIcaObjVal()
, with the script fragment listed in this section to enable version checking of ICA Client
software.
Note:
The ICA Client detection performed by the
hasIcaObjVal()
function on NFuse Web sites is
NFuse Extensions
csg_conf.inc
<%
' Citrix Secure Gateway Version 1.0
' csg_conf.inc
' Citrix Secure Gateway NFuse Web site configuration file
' Modify the parameters in this file to reflect the settings of your Citrix Secure Gateway ' Specify the FQDN or IP address of your MetaFrame master browser machine. Ensure that ' the value you give is surrounded with quotes as shown in the following example:
strCitrixServer = ""
' Specify XML service port number for the above Citrix MetaFrame server.
numCitrixServerPort = 80
' DO NOT MODIFY the following line Dim rg_strSTAURL(7)
' Specify the STAs in your system. '
' IMPORTANT NOTE: ' ===============
' numSTACount defines the number of active STAs in your system. ' The maximum value is 7. The value of numSTACount is 1 (ONE) ' less than the actual number of active STA, for example, if you ' have 2 (TWO) active STAs, numSTAcount should be set to 1 (ONE). Const numSTAcount = 0
' Specify the Citrix Secure Gateway Ticket Authority URLs below. Ensure that the values ' you give are surrounded with quotes as shown in the following example:
rg_strSTAURL(0) = "http://your_ticket_authority_01.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(1) = "http://your_ticket_authority_02.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(2) = "http://your_ticket_authority_03.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(3) = "http://your_ticket_authority_04.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(4) = "http://your_ticket_authority_05.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(5) = "http://your_ticket_authority_06.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(6) = "http://your_ticket_authority_07.yourdomain.com/scripts/CtxSta.dll" rg_strSTAURL(7) = "http://your_ticket_authority_08.yourdomain.com/scripts/CtxSta.dll"
' The hostnames entered above should be the same as the FQDN recorded previously, with the ' ticket authority dll path and name appended, e.g. /scripts/CtxSta.dll
ctxsta.dtd
<?xml version='1.0' encoding='UTF-8' ?>
<!-- Copyright 1999-2001 Citrix Systems Inc --> <!-- DTD for the CtxSTA protocol --> <!-- Version 1.0 21 Jun 2001 --> <!-- --> <!-- <!DOCTYPE CtxSTAProtocol [ -->
<!ELEMENT CtxSTAProtocol (
RequestTicket | ResponseTicket | RequestData | ResponseData | RequestSave | ResponseSave | ResponseError )>
<!ATTLIST CtxSTAProtocol version CDATA #REQUIRED > <!-- 1.0 -->
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- Protocol message declarations --> <!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!ELEMENT RequestTicket ( AllowedTicketType+, AllowedAuthorityIDType+, Data )>
<!ELEMENT ResponseTicket ( ( AuthorityID, Ticket, TicketVersion ) | ErrorId )>
<!ELEMENT RequestData ( Ticket, TicketVersion )>
<!ELEMENT ResponseData ( Data | ErrorId )>
<!ELEMENT RequestSave ( ( Ticket, TicketVersion, Data ) )>
<!ELEMENT ResponseSave ( Accepted | ErrorId )>
<!ELEMENT ResponseError ( ErrorId )>
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- Data type declarations --> <!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!ELEMENT ErrorId (#PCDATA)> <!-- unspecified | bad-request | out-of-memory | invalid-ticket | save-not-supported |
ticket-type-not-supported |
<!ELEMENT Accepted (#PCDATA)> <!-- ok -->
<!ELEMENT AllowedAuthorityIDType (#PCDATA)> <!-- STA-v1 -->
<!ELEMENT AllowedTicketType (#PCDATA)> <!-- STA-v1 -->
<!ELEMENT AuthorityID (#PCDATA)> <!-- A-Z or 0-9 max length of 16 -->
<!ATTLIST AuthorityID authorityType ( STA-v1 ) "STA-v1" >
<!ELEMENT Data (#PCDATA)> <!-- max length of 16k -->
<!ELEMENT Ticket (#PCDATA)> <!-- A-Z or 0-9 max length of 32 -->
<!ATTLIST Ticket ticketType ( STA-v1 ) "STA-v1" >
<!ELEMENT TicketVersion (#PCDATA)> <!-- A-Z or 0-9
max length of 2 -->
rq_ticket.xml
<?xml version="1.0"?>
<!DOCTYPE CtxSTAProtocol SYSTEM "CtxSTA.dtd">
<!-- Ticket Request Packet -->
<CtxSTAProtocol version="1"> <RequestTicket>
<AllowedTicketType>STA-v1</AllowedTicketType>
<AllowedAuthorityIDType>STA-v1</AllowedAuthorityIDType> <Data>MyTicket</Data>
sta_error.inc
<%
' Citrix Secure Gateway Version 1.0
' NFuse 1.5x specific ' ===================
' Call this function to report STA error Function staError(strError)
Response.Write strError & vbCrLf End Function
sta_error16.inc
<%
' Citrix Secure Gateway Version 1.0 '
' NFuse 1.6x specific ' ===================
' Call this function to report STA error Function staError(strError)
Response.ContentType = "text/html; charset=" & propKey.getStaticString("HTMLCharSet") Session("NFuse_errorString") = strError
Response.write "<script language='JavaScript'>" & vbCrLf Response.write "<!--" & vbCrLf
Response.write "parent.frames[0].location.href = _ 'applist.asp?NFuse_currentFolder=" & _
currentFolder & "&NFuse_lastErrorId=On" & "'" & ";" & vbCrLf Response.write "//-->" & vbCrLf
Response.write "</script>" & vbCrLf End Function
sta_xml.inc
<%
' Citrix Secure Gateway Version 1.0
Dim staGetNextErrStr
' Call this function to get the next STA, ' returns true if an STA is found,
' returns false otherwise with last error in err object
Function staGetNext(iStart, iEnd, theXmlRq, theXmlDoc, theTicket, theAuth, theVer) Dim idx
staGetNext = false staGetNextErrStr = ""
On Error Resume Next
for idx = iStart to iEnd err.Clear
' Send XML request packet to next STA
theXmlrq.open "POST", rg_strSTAURL(idx), False theXmlrq.setRequestHeader "Content-Type", "text/xml" theXmlrq.send (theXmldoc)
' Debug output:
' theXmlrq.responseXML.save(Response)
' Look for Citrix Secure Gateway Ticket information in the XML response: if err.number = 0 then
for each currNode In theXmlrq.responseXML.documentElement.childNodes if err.number <> 0 then
' error accessing childNodes staGetNextErrStr = err.description err.Clear
exit for
elseif currNode.nodeName = "ResponseTicket" then
' found an STA, NOTE that staGetNext (return code) will be ' set to "true" if at least one of "Ticket", "AuthorityID" ' and "TicketVersion" subnode is returned
for each subNode In currNode.childNodes if err.number <> 0 then
' error accessing childNodes staGetNextErrStr = err.description err.Clear
exit for
staGetNextErrStr = subNode.text exit for
elseif subNode.nodeName = "Ticket" then ' Found STA ticket!
theTicket = subNode.text staGetNext = true
elseif subNode.nodeName = "AuthorityID" then ' Found AuthorityID
theAuth = subNode.text staGetNext = true
elseif subNode.nodeName = "TicketVersion" then ' Found ticket version
theVer = subNode.text staGetNext = true end if
next ' subNode
elseif currNode.nodeName = "ResponseError" then ' set error string according to <ResponseError> for each subNode In currNode.childNodes
if subNode.nodeName = "ErrorId" then staGetNextErrStr = subNode.text exit for
end if next ' subNode exit for end if
next ' currNode
' exit loop if ticket found if staGetNext = true then
' store last known STA in Application object for next use Application.Lock
Application("LastSTA") = idx Application.Unlock
exit for end if
else
staGetNextErrStr = err.description end if
next ' rg_strSTAURL End Function
' Call this function to get a Citrix Secure Gateway Ticket for the named ' CSG Server/Service csg_addr_str
Dim xmldoc, xmlrq
Dim ticketStr, ticketVersionStr, authStr, rq_ticket_path
On Error Resume Next
staGetTicketFromAddress = "" ticketStr = ""
ticketVersionStr = "" authStr = ""
' The ProgID for Microsoft XML Parser depends on the version ' installed.
'
' For MSXML earlier than 3.0:
' Set xmlrq = Server.CreateObject("Microsoft.XMLHTTP") ' Set xmldoc = Server.CreateObject("Msxml.DOMDocument") '
' For MSXML 3.0 onwards:
' Set xmlrq = Server.CreateObject("Msxml2.XMLHTTP") ' Set xmldoc = Server.CreateObject("Msxml2.DOMDocument") '
' Try MSXML earlier than 3.0 first:
Set xmlrq = Server.CreateObject("Microsoft.XMLHTTP") if err.number <> 0 then
' now try MSXML 3.x:
Set xmlrq = Server.CreateObject("Msxml2.XMLHTTP") if err.number <> 0 then
staError("Failed to instantiate XML parser: " & err.description) Exit Function
else
Set xmldoc = Server.CreateObject("Msxml2.DOMDocument") if err.number <> 0 then
staError("Failed to instantiate XML DOMDocument: " & err.description) Exit Function
end if end if else
Set xmldoc = Server.CreateObject("Msxml.DOMDocument") if err.number <> 0 then
staError("Failed to instantiate XML DOMDocument: " & err.description) Exit Function
end if end if
' There is a known issue with MSXML earlier than 2.x where ' relative path to XML/DTD files cannot be resolved to ' physical path when running in an .ASP page on IIS server. ' The work around is to call Server.MapPath() to resolve ' the absolute path name on the server.
' Here we try to access "rq_ticket.xml" file in the
' current directoty. "rq_ticket.xml" is the <RequestTicket> ' XML packet to be sent to the STA:
rq_ticket_path = Server.MapPath("rq_ticket.xml")
' Perform synchronous load xmldoc.async = false xmldoc.load(rq_ticket_path)
if xmldoc.parseError.errorCode <> 0 then
staError("Failed to load Citrix Secure Gateway Ticket request: " & xmldoc.parseError.reason) Exit Function
end if
' Check that we have a valid <RequestTicket> packet Set currNode = xmldoc.documentElement.childNodes.item(0) If currNode.nodeName <> "RequestTicket" Then
staError("No <RequestTicket> in Citrix Secure Gateway Ticket request") Exit Function
End If
' In the rq_ticket.xml file, <Data> is the third ' child node within <RequestTicket>. <Data> specify
' the destination Citrix Secure Gateway Server/Service address. Set currSubNode = currNode.childNodes.item(2)
If currSubNode.nodeName <> "Data" Then
staError("No Data in <RequestTicket> Citrix Secure Gateway Ticket request") Exit Function
End If
' Replace the value of <Data> with the desired ' Citrix Secure Gateway Server/Service address currSubNode.text = csg_addr_str
' Debug output:
' xmldoc.save(Response) ' Exit Function
' Get the last known STA index stored in Application object Dim lastSTA
Application.Lock
lastSTA = Application("LastSTA") if lastSTA > numSTAcount then lastSTA = 0
end if
Application.Unlock
Dim idxEnd Dim hasTicket idxStart = lastSTA idxEnd = numSTAcount hasTicket = false
' get next STA starting with last known STA, ' (numSTAcount is defined in "csg_conf.inc")
hasTicket = staGetNext(idxStart, idxEnd, xmlrq, xmldoc, ticketStr, authStr, ticketVersionStr)
if (hasTicket = false) and (idxStart <> 0) then
' try again if we didn't start from first STA (ie. idx = 0) idxStart = 0
idxEnd = lastSTA ' try lastSTA as well in case it came back online
hasTicket = staGetNext(idxStart, idxEnd, xmlrq, xmldoc, ticketStr, authStr, ticketVersionStr) end if
if (hasTicket = false) then
' Report the last error (from the last STA)
staError("Request for Citrix Secure Gateway Ticket failed: " & staGetNextErrStr) Exit Function
end if
' generate ticket string as it should be passed in Address field staGetTicketFromAddress = _
";" & ticketVersionStr & ";" & authStr & ";" & ticketStr
' Debug output:
'staError("Generated ticket string: " & staGetTicketFromAddress)
NFuse 1.51
launch.asp
<% Response.Buffer=true %>
<!-- #include File = "csg_conf.inc" -->
<%
Set parser = Server.CreateObject("com.citrix.nfuse.TemplateParser") CookStr = Request.Cookies("NFuseData")
parser.setCookieSessionFields(CookStr)
UrlSessionFields = Request.ServerVariables("QUERY_STRING") parser.setUrlSessionFields(UrlSessionFields)
CurrentTransPath = Request.ServerVariables("PATH_TRANSLATED") parser.setSingleSessionField "NFuse_TemplatesDir",
Left(CurrentTransPath,InStrRev(CurrentTransPath,"\"))
parser.setSingleSessionField "NFuse_Template", "template.ica"
parser.setSingleSessionField "NFuse_CitrixServer", strCitrixServer
parser.setSingleSessionField "NFuse_CitrixServerPort", CStr(numCitrixServerPort)
if parser.Parse() = False Then
Response.Write "There was an error:<br><i>" & parser.getLastError() & "</i>" Else
%>
<!-- #include File = "sta_error.inc" --> <!-- #include File = "sta_xml.inc" -->
<%
' Perform Citrix Secure Gateway specific ticketing here. strServerAddress = ""
strConnTicket = ""
Response.ContentType = "application/x-ica" Continue = True
Response.Expires = 0 While (Continue)
HtmlString = Parser.getNextDataBlock() If HtmlString = "" Then
Continue = False Else
' Check if this is the address string strToFind = Chr(10) & "Address=" stPos = InStr(HtmlString,strToFind)
If stPos <> 0 Then
cutPos = stPos + Len(strToFind)
strServerAddress = Mid(HtmlString, cutPos, endPos-cutPos-1) If Len(strServerAddress) <> 0 Then
strConnTicket = staGetTicketFromAddress(strServerAddress) if Len(strConnTicket) = 0 then
' invalid (empty) ticket, revert content type ' to "text/html" for error messages
Response.ContentType = "text/html" Continue = False
else
str1 = Mid(HtmlString,1,cutPos-1) str2 = Mid(HtmlString,endPos-1)
HtmlString = str1 & strConnTicket & str2 end if
End If End If
if (Continue) then
Response.Write(HtmlString) end if
template.ica
; template.ica for the Citrix Secure Gateway, Version 1.0 web site ; Copyright 2001 Citrix Systems, Inc. All rights reserved.
;
<[NFuse_setSessionField NFuse_ContentType=application/x-ica]> <[NFuse_setSessionField NFuse_WindowType=seamless]>
[WFClient] Version=2
ClientName=[NFuse_ClientName] BrowserRetry=1
BrowserTimeout=20000 HttpBrowserAddress=!
TransportReconnectEnabled=Off
[ApplicationServers] [NFuse_AppName]=
[[NFuse_AppName]]
Address=[NFuse_IPV4Address]
; When using alternate address for firewall traversal purposes, replace ; the "NFuse_IPV4Address" tag above with "NFuse_IPV4AddressAlternate"
InitialProgram=#[NFuse_AppName] DesiredColor=[NFuse_WindowColors] TransportDriver=TCP/IP
WinStationDriver=ICA 3.0
AutologonAllowed=ON
; Specify the Citrix Secure Gateway Fully Qualified Domain Name (FQDN) ; and port number here, the FQDN MUST match the exact name used in ; the server certificate.
; eg. CSGServer.yourdomain.com:443 SSLProxyHost=
SSLEnable=On SSLNoCACerts=0 SSLCiphers=ALL
BrowserProtocol=HTTPonTCP
[NFuse_Ticket]
<[NFuse_IFSESSIONFIELD sessionfield="NFUSE_SOUNDTYPE" value="basic"]> ClientAudio=On
<[/NFuse_IFSESSIONFIELD]> [NFuse_IcaWindow]
SessionsharingKey=[NFuse_SessionSharingKey]
[EncRC5-0]
DriverNameWin16=pdc0w.dll DriverNameWin32=pdc0n.dll
[EncRC5-40]
DriverNameWin16=pdc40w.dll DriverNameWin32=pdc40n.dll
[EncRC5-56]
DriverNameWin16=pdc56w.dll DriverNameWin32=pdc56n.dll
[EncRC5-128]
DriverNameWin16=pdc128w.dll DriverNameWin32=pdc128n.dll
[Compress]
NFuse 1.6
launch.asp
<%
'some security - checking for valid query string 'get query string
queryStr = request.serverVariables("QUERY_STRING") 'check if query string is empty
if Len(queryStr) = 0 Then Response.End
End If
'get application name
nfuseAppName = request.queryString("NFuse_Application") 'get mime type
nfuseMimeType = request.queryString("NFuse_MIMEExtension") 'check if app name and mime type are empty
if Len(nfuseAppName) = 0 Or Len(nfuseMimeType) = 0 Then Response.End
End If
'check if mime type is valid .ica if LCase(nfuseMimeType) <> ".ica" Then Response.End
End If
'begin actual task Response.Buffer=true
Set parser = Server.CreateObject("com.citrix.nfuse.TemplateParser") Set app = Server.CreateObject("com.citrix.nfuse.App")
Set propKey = Server.CreateObject("com.citrix.nfuse.PropertiesKeys")
if app.guestLoginOnly() then anon = "On"
else
anon = Request.Cookies("NFuseLogin")("NFuse_Guest") end if
If anon = "On" Then 'Anonymous user
user = app.urlEncode("Client") domain = app.urlEncode("Anonymous") password = app.urlEncode("Anon") NFuseCookie = "NFuseModeAnon" Else
'Now we need to decrypt the password retrieved from the cookie: Dim nfuseSessionKey
nfuseSessionKey = Session("nfuseKeyString")
If Len(nfuseSessionKey) = 0 Then
Response.Redirect("logout.asp?sessionExpired=On") End If
nfuseSessionKey = mid(nfuseSessionKey,1,Len(password)) password = nfuseDecrypt(password)
NFuseCookie = "NFuseMode" End If
Function nfuseDecrypt(strEncrypted) Dim strChar, iKeyChar, iStringChar, i for i = 1 to Len(strEncrypted)
iKeyChar = Asc(mid(nfuseSessionKey,i,1)) iStringChar = Asc(mid(strEncrypted,i,1)) iDeCryptChar = iKeyChar Xor iStringChar
strDecrypted = strDecrypted & Chr(iDeCryptChar) next
nfuseDecrypt = strDecrypted End Function
CookStr = "NFuse_User=" & user & "&NFuse_Domain=" & domain & "&NFuse_Password=" & password parser.setCookieSessionFields(CookStr)
If Len(loginPage) Then If loginPage = "NDS" Then
parser.setSingleSessionField "NFuse_DomainType", loginPage End If
End If
currentFolder = Request.Cookies(NFuseCookie)("NFuse_currentFolder")
bSettings = app.allowCustomizeSettings bSize = app.allowCustomizeWindowSize bColor = app.allowCustomizeWindowColor bAudio = app.allowCustomizeAudio
bEncryption = app.allowCustomizeEncryption
If bSettings Then
DesiredColor = app.unUrlEncode(Request.Cookies(NFuseCookie)("NFuse_WindowColors")) Audio = app.unUrlEncode(Request.Cookies(NFuseCookie)("NFuse_IcaAudioType"))
Encrypt = app.unUrlEncode(Request.Cookies(NFuseCookie)("NFuse_EncryptionLevel"))
'Apply the settings. If bSize Then
If Len(DisplayMode) > 0 Then
Parser.setSingleSessionField "NFuse_WindowType", DisplayMode End If
If Len(DesiredHRES) > 0 Then
Parser.setSingleSessionField "NFuse_WindowWidth", DesiredHRES End If
If Len(DesiredVRES) > 0 Then
Parser.setSingleCookieSessionField "NFuse_WindowHeight", DesiredVRES End If
If Len(ScreenPercent) > 0 Then
Parser.setSingleCookieSessionField "NFuse_WindowScale", ScreenPercent End If
End If
If bColor Then
If Len(DesiredColor) > 0 Then
Parser.setSingleCookieSessionField "NFuse_WindowColors", DesiredColor End If
End If
If bAudio Then If Len(Audio) > 0 Then
Parser.setSingleCookieSessionField "NFuse_IcaAudioType", Audio End If
End If
If bEncryption Then
If Len(Encrypt) > 0 Then
Parser.setSingleCookieSessionField "NFuse_EncryptionLevel", Encrypt End If
End If
End If ' If bSettings
UrlSessionFields = Request.ServerVariables("QUERY_STRING") parser.setUrlSessionFields(UrlSessionFields)
CurrentTransPath = Request.ServerVariables("PATH_TRANSLATED") parser.setSingleSessionField "NFuse_TemplatesDir",
Left(CurrentTransPath,InStrRev(CurrentTransPath,"\"))
If anon = "On" or app.guestLoginOnly() Then
parser.setSingleSessionField "NFuse_Template", "guest_template.ica" Else
parser.setSingleSessionField "NFuse_Template", "template.ica" End If
'Set the client address.
If parser.Parse() = False Then
Response.ContentType = "text/html; charset=" & propKey.getStaticString("HTMLCharSet") Session("NFuse_errorString") = parser.getLastError()
Response.write "<script language='JavaScript'>" & vbCrLf Response.write "<!--" & vbCrLf
Response.write "parent.frames[0].location.href = 'applist.asp?NFuse_currentFolder=" & currentFolder & "&NFuse_lastErrorId=On" & "'" & ";" & vbCrLf
Response.write "//-->" & vbCrLf Response.write "</script>" & vbCrLf
Else %>
<!-- #include File = "csg_conf.inc" --> <!-- #include File = "sta_error16.inc" --> <!-- #include File = "sta_xml.inc" --> <%
Response.ContentType = "application/x-ica" Continue = True
Response.Expires = -1
'================================ 'Begin: NFuse16 ticket processing '--- 'While (Continue)
' HtmlString = parser.getNextDataBlock() ' If HtmlString = "" Then
' Continue = False ' Else
' Response.Write(HtmlString) ' End If
'Wend
'--- 'End: NFuse16 ticket processing '==============================
'======================================================= 'Begin: Citrix Secure Gateway specific ticket processing '--- strServerAddress = ""
strConnTicket = "" While (Continue)
HtmlString = Parser.getNextDataBlock() If HtmlString = "" Then
Else
' Check if this is the address string strToFind = Chr(10) & "Address=" stPos = InStr(HtmlString,strToFind)
If stPos <> 0 Then
endPos = InStr(stPos+1,HtmlString,Chr(10)) cutPos = stPos + Len(strToFind)
strServerAddress = Mid(HtmlString, cutPos, endPos-cutPos-1) If Len(strServerAddress) <> 0 Then
strConnTicket = staGetTicketFromAddress(strServerAddress) if Len(strConnTicket) = 0 then
' invalid (empty) ticket, revert content type ' to "text/html" for error messages
Response.ContentType = "text/html" Continue = False
else
str1 = Mid(HtmlString,1,cutPos-1) str2 = Mid(HtmlString,endPos-1)
HtmlString = str1 & strConnTicket & str2 end if
End If End If
if (Continue) then
Response.Write(HtmlString) end if
End If Wend
'--- 'End: Citrix Secure Gateway specific ticket processing '===================================================== End If
template.ica
; template.ica for the Citrix Secure Gateway, Version 1.0 web site ; Copyright 2001 Citrix Systems, Inc. All rights reserved.
;
<[NFuse_setSessionField NFuse_ContentType=application/x-ica]>
[WFClient] Version=2
ClientName=[NFuse_ClientName] HttpBrowserAddress=!
TransportReconnectEnabled=Off
[ApplicationServers] [NFuse_AppName]=
[[NFuse_AppName]]
Address=[NFuse_IPV4Address]
; When using alternate address for firewall traversal purposes, replace ; the "NFuse_IPV4Address" tag above with "NFuse_IPV4AddressAlternate" InitialProgram=#[NFuse_AppName]
DesiredColor=[NFuse_WindowColors] TransportDriver=TCP/IP
WinStationDriver=ICA 3.0
AutologonAllowed=ON
; Specify the Citrix Secure Gateway Fully Qualified Domain Name (FQDN) ; and port number here, the FQDN MUST match the exact name used in ; the server certificate.
; eg. CSGServer.yourdomain.com:443 SSLProxyHost=
SSLEnable=On SSLNoCACerts=0 SSLCiphers=ALL
[NFuse_Ticket]
[NFuse_IcaAudio] [NFuse_IcaWindow]
[NFuse_IcaEncryption]
SessionsharingKey=[NFuse_SessionSharingKey]
[EncRC5-0]
[EncRC5-40]
DriverNameWin16=pdc40w.dll DriverNameWin32=pdc40n.dll
[EncRC5-56]
DriverNameWin16=pdc56w.dll DriverNameWin32=pdc56n.dll
[EncRC5-128]
DriverNameWin16=pdc128w.dll DriverNameWin32=pdc128n.dll
[Compress]
ICA Client Version Detection Function
' Get ICA Client Object version
' returns: 0 ICA Client not installed ' 10 Pre FR1
' 16 FR1
' 20 XP 1.0, ICO 2.0
' 21 Post XP 1.0, ICO 2.1 or later function hasIcaObjVal()
dim obj dim badSetup badSetup = false Err.Clear
On Error Resume Next hasIcaObjVal = 0 'try ICO 2.x
set obj = CreateObject("Citrix.ICAClient") if (Err.number = 0) then
clientId = obj.GetInterfaceVersion() if (Err.number = 0) then
strPos = StrComp(clientId, "2.0", 1) if (strPos = 0) then
'XP 1.0 ICO 2.0 hasIcaObjVal = 20 else
'Nile ICO 2.1 or later hasIcaObjVal = 21 end if
else
'"Citrix.ICAClient" not installed/uninstalled correctly badSetup = true
end if end if
if (badSetup = true) then Err.Clear
set obj = Nothing
'try FR1 (Wfica.WficaCtl.6)
set obj = CreateObject("Wfica.WficaCtl.6") if (Err.number = 0) then
Err.Clear
set obj = Nothing
'try Pre FR1 (Wfica.WficaCtl.1)
set obj = CreateObject("Wfica.WficaCtl.1") if (Err.number = 0) then
hasIcaObjVal = 10 end if
end if end if