Aucun message portant le libellé citrix. Afficher tous les messages
Aucun message portant le libellé citrix. Afficher tous les messages

22 juillet 2016

Configuring Netscaler for Exchange ActiveSync, RPC, OWA, OAB, EWS, Autodiscover

I've been asked for my Netsclaer configuration for Exchange so I'm sharing it for everyone to (hopefully) be helpfull to many.

Unfortunately I don't have the time luxury currently to comment and explain all of it but at least the important is that the config is there. Keep in mind that the some longer command will be truncated on the blog but they should be typed on one line.


create ssl dhparam ECDH.KEY 2048 -gen 2

add ssl profile No_SSL3_profileb -dhCount 10000 -dh ENABLED -dhFile "/nsconfig/ssl/ECDH.KEY" -eRSA ENABLED -eRSACount 10000 -sessReuse ENABLED -sessTimeout 120 -sslRedirect ENABLED -redirectPortRewrite ENABLED -ssl3 DISABLED


add serviceGroup SG_EXCH_HTTPs SSL -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -cltTimeout 180 -svrTimeout 360 -CKA NO -TCPB NO -CMP NO -appflowLog DISABLED
bind serviceGroup SG_EXCH_HTTPs exchange_K1 443 -CustomServerID "\"None\""
bind serviceGroup SG_EXCH_HTTPs exchange_K2 443 -CustomServerID "\"None\""
bind serviceGroup SG_EXCH_HTTPs exchange_J1 443 -CustomServerID "\"None\""
bind serviceGroup SG_EXCH_HTTPs exchange_J2 443 -CustomServerID "\"None\""
bind serviceGroup SG_EXCH_HTTPs -monitorName https-ecv

add lb vserver LB_EXC=AutoDiscover=NoAuth SSL 0.0.0.0 0 -persistenceType NONE -Listenpolicy None -cltTimeout 360
bind lb vserver LB_EXC=AutoDiscover=NoAuth SG_EXCH_HTTPs
bind ssl vserver LB_EXC=AutoDiscover=NoAuth -cipherName claus-cipher-list-with-gcm
bind ssl vserver LB_EXC=AutoDiscover=NoAuth -certkeyName domain-wildcard
set ssl vserver LB_EXC=AutoDiscover=NoAuth -sslProfile No_SSL3_profile

add lb vserver LB_EXC=OAB_EWS=NoAuth SSL 0.0.0.0 0 -persistenceType SSLSESSION -timeout 720 -Listenpolicy None -cltTimeout 360
bind lb vserver LB_EXC=OAB_EWS=NoAuth SG_EXCH_HTTPs
bind ssl vserver LB_EXC=OAB_EWS=NoAuth -cipherName claus-cipher-list-with-gcm
bind ssl vserver LB_EXC=OAB_EWS=NoAuth -certkeyName domain-wildcard
set ssl vserver LB_EXC=OAB_EWS=NoAuth -sslProfile No_SSL3_profile

add lb vserver LB_EXC=OA-RPC=No_AUTH SSL 0.0.0.0 0 -persistenceType SOURCEIP -timeout 720 -Listenpolicy None -cltTimeout 180
bind lb vserver LB_EXC=OA-RPC=No_AUTH SG_EXCH_HTTPs
bind ssl vserver LB_EXC=OA-RPC=No_AUTH -cipherName claus-cipher-list-with-gcm
bind ssl vserver LB_EXC=OA-RPC=No_AUTH -certkeyName domain-wildcard
set ssl vserver LB_EXC=OA-RPC=No_AUTH -sslProfile No_SSL3_profile

add lb vserver LB_EXC=ActiveSync=401Auth_Corp SSL 0.0.0.0 0 -persistenceType RULE -timeout 720 -rule "HTTP.REQ.HEADER(\"Authorization\")" -Listenpolicy None -cltTimeout 180 -authn401 ON -authnVsName vs_AuthCorp.domain.com
set ssl vserver LB_EXC=ActiveSync=401Auth_Corp -sslProfile No_SSL3_profile
bind ssl vserver LB_EXC=ActiveSync=401Auth_Corp -cipherName z_metro-cipher-list-with-gcm
bind ssl vserver LB_EXC=ActiveSync=401Auth_Corp -certkeyName domain-wildcard
bind lb vserver LB_EXC=ActiveSync=401Auth_Corp SG_EXCH_HTTPs

add lb vserver LB_EXC=OWA_ECP=FullAuth_Corp SSL 0.0.0.0 0 -persistenceType COOKIEINSERT -timeout 0 -persistenceBackup SOURCEIP -backupPersistenceTimeout 720 -Listenpolicy None -cltTimeout 360 -Authentication ON -authnProfile Profile_Corp_Auth
bind lb vserver LB_EXC=OWA_ECP=FullAuth_Corp SG_EXCH_HTTPs
bind ssl vserver LB_EXC=OWA_ECP=FullAuth_Corp -cipherName claus-cipher-list-with-gcm
bind ssl vserver LB_EXC=OWA_ECP=FullAuth_Corp -certkeyName domain-wildcard
set ssl vserver LB_EXC=OWA_ECP=FullAuth_Corp -sslProfile No_SSL3_profile



add cs action ACT_SEND_EXC=AUTODISCOVER -targetLBVserver LB_EXC=AutoDiscover=NoAuth
add cs policy CSPol__EXC=AutoDiscover=No_AUTH -rule "HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).PATH.GET(1).EQ(\"AutoDiscover\") || HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).CONTAINS(\"autodiscover.domain.com\") || HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).CONTAINS(\"autodiscover3.domain.com\")" -action ACT_SEND_EXC=AUTODISCOVER

add cs action ACT_SEND_EXC=OAB_EWS -targetLBVserver LB_EXC=OAB_EWS=NoAuth
add cs policy CSPol__EXC=OAB_EWS=No_Auth -rule "HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).PATH.GET(1).EQ(\"oab\") || HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).PATH.TO_LOWER.STARTSWITH(\"/ews\")" -action ACT_SEND_EXC=OAB_EWS

add cs action ACT_SEND_EXC=OA_RPC -targetLBVserver LB_EXC=OA-RPC=No_AUTH
add cs policy CSPol__EXC=RPC=NO-AUTH -rule "HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).PATH.GET(1).EQ(\"rpc\")" -action ACT_SEND_EXC=OA_RPC

add cs action ACT_SEND_EXC=ActiveSync -targetLBVserver LB_EXC=ActiveSync=401Auth_Corp
add cs policy CSPol__EXC=ActiveSync=AUTH_401 -rule "HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).PATH.GET(1).EQ(\"Microsoft-Server-ActiveSync\")" -action ACT_SEND_EXC=ActiveSync

add cs action ACT_SEND_EXC=OWA_ECP -targetLBVserver LB_EXC=OWA_ECP=FullAuth_Corp
add cs policy CSPol_EXC=OWA_ECP=FullAuth_Corp -rule "HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).CONTAINS(\"mail.domain.com\")" -action ACT_SEND_EXC=OWA_ECP



add service Always_UP_service 1.2.3.4 HTTP 80 -gslb NONE -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -sp OFF -cltTimeout 180 -svrTimeout 360 -CustomServerID "\"None\"" -CKA NO -TCPB NO -CMP NO

add lb vserver LB_EXC_HTTP=HTTPS_EXT_redirect HTTP 24.x.x.21 80 -persistenceType NONE -Listenpolicy None -cltTimeout 180
bind lb vserver LB_EXC_HTTP=HTTPS_EXT_redirect Always_UP_service

add responder action http_to_https_actn redirect "\"https://\" + HTTP.REQ.HOSTNAME.HTTP_URL_SAFE + HTTP.REQ.URL.PATH_AND_QUERY.HTTP_URL_SAFE"
add responder policy http_to_https_pol HTTP.REQ.IS_VALID http_to_https_actn RESET

bind lb vserver LB_EXC_HTTP=HTTPS_EXT_redirect -policyName http_to_https_pol -priority 100 -gotoPriorityExpression END -type REQUEST


add cs vserver CS_Exchange SSL 24.x.x.21 443 -cltTimeout 180 -caseSensitive OFF -Listenpolicy None
bind ssl vserver CS_Exchange -cipherName claus-cipher-list-with-gcm
bind ssl vserver CS_Exchange -certkeyName domain-wildcard
set ssl vserver CS_Exchange -sslProfile No_SSL3_profile

bind cs vserver CS_Exchange -policyName CSPol__EXC=RPC=NO-AUTH -priority 80
bind cs vserver CS_Exchange -policyName CSPol__EXC=ActiveSync=AUTH_401 -priority 90
bind cs vserver CS_Exchange -policyName CSPol__EXC=OAB_EWS=No_Auth -priority 110
bind cs vserver CS_Exchange -policyName CSPol__EXC=AutoDiscover=No_AUTH -priority 120
bind cs vserver CS_Exchange -policyName CSPol_EXC=OWA_ECP=FullAuth_Corp -priority 130


17 mars 2016

Citrix Netscaler - HTTP to HTTPs sharepoint page rewrite

The contex: sharepoint is accessed directly on http internally.
We came across a problem that some of our Sharepoint page have hardcoded link instead of dynamic link so when we expose the page externally the link are static to HTTP and since the page are accessed on a secure connection the browser complain that there is unsecure data accessed in clear text instead of SSL. The work around is to rewrite the page body when they are returned to the end user so that the link contained in the page are httpS instead of http. I tried doing rewrite response body without succes and then Citrix consultant suggested to use URL Transformation feature under AppExpert -> Rewrite -> URL Transformation instead that provided a working solution for us.

First we create the profile and enter a descriptive name: TrProfile_http-httpS

Now edit this profile to add an action by clicking on insert:
Name: http2https-action
Priority: 20
Enable = Check
Response URL From: http://(.*)
Response URL Into: https://$1

Click OK.

After that we create the Policies
Name:  TrPol-http-https
Profile: TrProfile_http-httpS
Expression: HTTP.REQ.IS_VALID

Click OK.

Finally bind this transform Policy to a CS or LB Vserver:

Edit your Vserver, click the "PLUS" sign under policies, choose: transform -> Request and then bind your newly created transform policy: TrPol-http-https

Click OK, Click Done.

Now when the end users access the page, the Netscaler transform all http link in the page to https and we didn't need the developper to build a new page for external users.








03 mars 2015

Using Netscaler as ADFS proxy - Exported configuration

After my last blog article on how to replace the Microsoft ADFS Proxy, I've been asked to provide the configuration of my Netscaler for the ADFS proxy replacement so I've exported the part that are needed to achieve this, please comment with a little thanks if it was helpful to you. Note that I'm using Netscaler 10.1 with ADFS 2.0 on windows 2008r2.

I found a Citrix article about ADFS 3.0 that refer to the fact that Netscaler doesn't support the sni feature for the backend server that is used in ADFS 3.0 which is most likely causing headache to ADFS 3.0 users.
http://support.citrix.com/article/CTX125798
The citrix article refer you to this microsoft article that talk about a way to partially disable the SNI feature for ADFS 3.0... 
http://blogs.technet.com/b/applicationproxyblog/archive/2014/06/19/how-to-support-non-sni-capable-clients-with-web-application-proxy-and-ad-fs-2012-r2.aspx


Here's the code and some comments :

********* Begin Starting Notes *******
This config is for Netscaler 10.1 (Currently at Build 129.11 but it's been working with previous 10.1. build)
Your Netscaler must be licensed for "AAA - Traffic management" and it must be enable under settings -> "Configure Basic Features" (Authentication, Authorization and Auditing)
Your ADFS URL must be reachable by DNS externally (you can't authenticate using IP address, it has to be a DNS name, worst case scenario you can edit your host file temporarily for testing)
you need to have an external IP address available to Setup the Reverse Proxy

If you have multiple domain, you can easily repeat the config for the second domain and add the 2nd LDAP policy to the authentication Vserver with a different priority

Example: bind authentication Vserver vs_Auth.Company.com -policy Subdomain2.Company.com -priority 110
The domain settings in the Netscaler is not related to the AD domain but to the domain in the FQDN url (i.e.: email domain, If your internal domain is company.local and your website is company.com then the domain you set in the Netscaler is company.com)


********* End Starting Notes *******

********* Begin configuration code *******

enable ns feature AAA LB CS SSL SSLVPN REWRITE RESPONDER

add serviceGroup SG_LDAP_CORP_389 TCP -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -cltTimeout 9000 -svrTimeout 9000 -CKA NO -TCPB NO -CMP NO -appflowLog DISABLED
bind serviceGroup SG_LDAP_CORP_389 DomainControllerCorp1 389 -CustomServerID "\"None\""
bind serviceGroup SG_LDAP_CORP_389 DomainControllerCorp2 389 -CustomServerID "\"None\""

add lb vserver LB_LDAP_CORP TCP 192.168.1.79 389 -persistenceType NONE -cltTimeout 9000
bind lb vserver LB_LDAP_CORP SG_LDAP_CORP_389

add authentication ldapAction LDAP-LB_LDAP_corp -serverIP 192.168.1.79 -authTimeout 5 -ldapBase "DC=corp,DC=Company,DC=com" -ldapBindDn netscaler@corp.Company.com -ldapBindDnPassword TypeThePasswordForTheAccountHere -encrypted -ldapLoginName samAccountName -groupAttrName memberOf -subAttributeName CN -nestedGroupExtraction ON -maxNestingLevel 4 -groupNameIdentifier samAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN
add authentication ldapPolicy corp.Company.com ns_true LDAP-LB_LDAP_corp

add authentication vserver vs_Auth.Company.com SSL 192.167.233.32 443 -AuthenticationDomain Company.com
bind authentication vserver vs_Auth.Company.com -policy corp.Company.com -priority 100

set tm sessionParameter -SSO ON

add serviceGroup SG_ADFS_HTTPS SSL -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport YES -cltTimeout 180 -svrTimeout 360 -CKA NO -TCPB NO -CMP NO -appflowLog DISABLED
bind serviceGroup SG_ADFS_HTTPS ADFS_Server1 443 -CustomServerID "\"None\""
bind serviceGroup SG_ADFS_HTTPS ADFS_Server2 443 -CustomServerID "\"None\""
bind serviceGroup SG_ADFS_HTTPS -monitorName https-ecv

add lb vserver LB_ADFS_Proxy_Replacement_FullAuth_Forest SSL 192.167.233.30 443 -persistenceType COOKIEINSERT -timeout 0 -cltTimeout 180 -AuthenticationHost auth.Company.com -Authentication ON
bind lb vserver LB_ADFS_Proxy_Replacement_FullAuth_Forest SG_ADFS_HTTPS
bind ssl vserver LB_ADFS_Proxy_Replacement_FullAuth_Forest -certkeyName Company-wildcard


*************** This part is related to RSA and is optional but we require that user authenticate using their AD password AND RSA token, make sure the LDAP part works fine before adding secondary authentication ***************


add serviceGroup SG_RSA_1645 RADIUS -maxClient 0 -maxReq 0 -cip DISABLED -usip NO -useproxyport NO -cltTimeout 120 -svrTimeout 120 -CKA NO -TCPB NO -CMP NO -appflowLog DISABLED

bind serviceGroup SG_RSA_1645 RSA-AM-Server1 1645 -CustomServerID "\"None\""
bind serviceGroup SG_RSA_1645 RSA-AM-Server2 1645 -CustomServerID "\"None\""
bind serviceGroup SG_RSA_1645 -monitorName ping

add lb vserver LB_RSA-AM RADIUS 192.168.1.14 1645 -persistenceType SOURCEIP -timeout 700 -cltTimeout 120
bind lb vserver LB_RSA-AM SG_RSA_1645

add authentication radiusAction LB_RSA-AM_srv -serverIP 192.168.1.14 -serverPort 1645 -radKey YourRadiusSharedSecretHere -encrypted
add authentication radiusPolicy Radius-Company ns_true LB_RSA-AM_srv

bind authentication vserver vs_Auth.Company.com -policy Radius-Company -priority 100 -secondary


********* End configuration code *******


*************** Begin Ending Notes ***************


For LDAP authentication action, you have to create a standard user (no special right required except "password never expire") for the netscaler to use this account to log in to the LDAP server and check for the user credential. The GUI offer an option to test the LDAP credential to make sure the connection works.

The Domain you set on your ADFS_Proxy_replacement and on your Auth.company.com MUST MATCH with the domain in the URL your users are sent for the ADFS authentication. My ADFS is setup as fs.company.com, this is the name clients will connect to, and so it must be resolvable via DNS externally.

Fs.company.com must resolve to your LB_ADFS_Proxy_Replacement_FullAuth_Forest


*************** Finish Ending Notes ***************

27 février 2015

Use Citrix Netscaler as a replacement for ADFS Proxy


I did a setup last year to replace the Microsoft ADFS Proxy by using the Netscaler 10.1 as the reverse proxy for ADFS 2.0 on Windows 2008r2 (I found a Citrix article about ADFS 3.0 that refer to the fact that Netscaler doesn't support the sni feature for the backend server that is used in ADFS 3.0 which is most likely causing headache to ADFS 3.0 users. http://support.citrix.com/article/CTX125798
The citrix article refer you to this microsoft article that talk about a way to partially disable the SNI feature for ADFS 3.0... http://blogs.technet.com/b/applicationproxyblog/archive/2014/06/19/how-to-support-non-sni-capable-clients-with-web-application-proxy-and-ad-fs-2012-r2.aspx

Citrix recently published a document to accomplish this but after looking at it I realized that my setup was looking much simpler so I will publish it in this article. This blog article assume you already have your Netscaler deployed in the DMZ ready to accept external connection (we use "2 arm mode" as we do some Load balancing internally and also some reverse proxy externally)

To use the Netscaler as a reverse proxy for ADFS you need to have your Netscaler licensed for "AAA - Traffic Management" (AAA-TM) so that you can authenticate directly on the Netscaler using LDAP.

This step is optional but I strongly suggest that you Load Balance (LB) your Domain Controller (DC) to have LDAP redundancy in your Netscaler as you can't configure it to authenticate to more than 1 source so if that source is a LB then you have redundancy. 

Go into Traffic management, Load Balancing, Servers -> Add, enter the name of your domain controller (DC1.domain), the IP address and then click create. Repeat for the rest of your DC. 

Next, you need to create a service group for LDAP, go into Traffic management, Load Balancing, Service Groups-> Add, name: SG_LDAP_Domain_389 -> Protocol: TCP -> under members, click on server based, under port, type: 389, then choose the DC you created previously DC1.domain and click add, repeat for every DC in that domain, go into the monitors tab and choose TCP (note: this will only monitor if port 389 is open and listening on the DC (Citrix has some documentation on how to create a complete LDAP monitor if you really want to be bullet proof but I didn't do it so I can't comment on this part, for us, monitoring TCP port 389 was considered reliable enough to confirm if the DC is up or not). Note: Citrix documentation configure things using "Services" but I prefer to do the configuration using "Service Groups" as to me it's always simpler and safer to create a Group and put member in it instead of configuring multiple service for the same need with multiple server. 

Next we create the LB Vserver for LDAP, go into Traffic management, Load Balancing, Virtual Servers -> Add, name: LB_LDAP_Domain, IP address: x.x.x.x, Port: 389, Services Group: SG_LDAP_Domain_389, in the Method and Persistence Tab, LB Method: Least connection, Persistence: None.

Now we will create the LDAP authentication, go into Security, AAA - Application Traffic, Policies, Authentication, LDAP, in the Servers tab, click on add, Name: LDAP-LB_LDAP_Domain, Authentication type: LDAP, IP address: x.x.x.x (you need provide the IP address of the LB Vserver you created earlier) Type: AD, Port: 389, Timeout: 5, Base DN: DC=corp,DC=company,DC=com (I input the root of the domain as the search point but you can "OU=users," in front of it to restrict the search) "Administrator Bind DN" is the user you define to authenticate in AD, this user doesn't need any special permission as everyone that is authenticated has read access in AD, password and confirm password are self-explaining. Server logon Name: SamAccountName, Group Attribute: memberOf, Sub Attribute name: CN, Security: PLAINTEXT (we used port 389 above which is unencrypted). Put a check mark into "Authentication" and "User Required", under nested group extraction, I choose enable, Maximum Nesting Level: 4, GroupName: SamAccountName, Group Search: memberof, Group Search Sub-attribute: CN. Click create.

Next, still under LDAP go into the Policies tab, click Add -> Name: domain.company.com, Authentication Type: LDAP, Server: LDAP-LB_LDAP_Domain, Expression: ns_true, click create.

Next, under Security, AAA-TM, Virtual Servers, click Add, Name: vs_Auth.domain.com IP: x.x.x.x. Protocol: SSL, Port: 443 Domain: company.com (This field is very important see AuthDomainNote for more detail) Certificates: choose a valid certificate for the URL your user will be redirected to for login (Ex: auth.company.com), under authentication tab, click on "Insert Policy" in the bottom of the page and choose the policy we created earlier: domain.company.com and click on create. Note, you can configure multiple authentication profile if you want to use the dual factor authentication you can create an RSA authentication policy and insert it in the "Second..." and you will have dual authentication. http://support.citrix.com/article/CTX113640/ explain how to setup RSA with Netscaler, just do the setup under security, AAA-TM, Policies, Authentication, Radius instead of under Netscaler Gateway.

Next we need to make sure SSO is enable in AAA-TM -> go into Security, click on AAA - Application Traffic and choose "Change global settings" and put a check mark into "Single Sign-on to Web Applications" then click OK.

Finally we create the ADFS LB_Vserver and his component, go to traffic management, Load Balancing, Servers to add your ADFS servers the same way we created the DC earlier, then go into "Service Groups", create a new service group for your ADFS servers, Name: SG_ADFS_HTTPS Protocol: SSL, choose "server based", port: 443 click "add" on your ADFS server, in the monitor tab: choose: httpS-ecv

Go to Load Balancing, Virtual Servers, click Add
Name: LB_ADFS_ExternalUrl, Protocol: SSL, IP: x.x.x.x (This need to be resolvable externally as your ADFS URL, it's the IP address that was pointing to your ADFS Proxy before), Port: 443, Service Groups Tab: SG_ADFS_HTTPS, Method and Persistence tab: Least connection, Persistence: COOKIEINSERT, time-out: 0, SSL settings: Choose the certificate that match your ADFS URL. The important part is under advanced tab, scroll down to the bottom and expend "Authentication settings", check the "Authentication" box and then enter the FQDN of the url your user will be redirected to for authentication (EX: auth.company.com) See AuthDomainNote2 below.

 AuthDomainNote: The domain here is critical if you want to have everything working, it must match with the domain name that your user will be coming from to this Vserver, if user want to authenticate to application.testcompany.com and your domain name is company.com then the authentication will not work, it will only authenticate user coming from the domain company.com, this is not related to the domain name you put in AD, it can be anything as long as your domain match the domain of the url it's coming from.

AuthDomainNote2: This URL must be reachable externally and it must point to the Authentication Vserver IP address.

Now if everything works fine when you try and reach your ADFS URL you will land on the Black Netscaler login page. Type your LDAP credential and the Netscaler will then request an ADFS token on your behalf from the ADFS server and you will then be granted access to Office365 portal. This also works with any other ADFS provider that you may have configured.

Next step you will most likely want is to customize the Netscaler login page to fit your company need. I published an article in December 2014 that explain how to achieve this: http://cividan.blogspot.ca/2014/12/customize-netscaler-101-aaa-tm-login.html



22 décembre 2014

Customize netscaler 10.1 "AAA TM" login page on HA pair

I had trouble finding the right answer as to how to customize the netscaler 10.1.x AAA login page to reflect company instead of the citrix black page and to have these customization stick after a reboot.

There are many ressource out there that explain how to do the customization (mostly login.js and then the 2 digit language xml file (en.xml, fr.xml,etc )

I finally found out that things have changed in netscaler 10.1 and that using the rc.netscaler startup script to copy your file over doesn't work anymore. What you need to do is customize to your liking the various files found in /netscaler/gui folder. DO NOT REBOOT as this will get you to loose your changes. (if all is screwed then rebooting will fix the issue)

NOTE: Keep a copy of the changed files on your corporate network as you will need them again later.

When using an HA pair, do the change on the active unit.

Test untill you management are fully happy of the change you have done.

Create a directory for the customized files --> connect to the netscaler using putty and then type:  

shell 
 
mkdir /var/ns_gui_custom


Create an archive of all the files in /netscaler/ns_gui folder named customtheme.tar.gz

cd /netscaler

tar -cvzf /var/ns_gui_custom/customtheme.tar.gz ns_gui/*



Repeat on the secondary unit or copy your customtheme.tar.gz using winscp to the /var/ns_gui_custom folder on the secondary unit.

Finally, change the netscaler to use the custom theme:
From the gui, expand "Netscaler Gateway" and choose "Global Settings" in the right pane,  select: "Change Global Setting". Go to the "Client experience" tab and set the UI theme to "Custom" and click O. This will take a bit of time while the netscaler process the file and apply it as the default theme. (This will be synced with the secondary node as long as you copied the customtheme.tar.gz file)

SAVE THE CHANGE

Now you can reboot the netscaler at will and your change will "stcik".


WARNING
Before upgrading the netscaler firmware, it is strongly advised to revert to the default theme, upgrade the netscaler to the newer version, test if all is working good with the default theme, when all is good, repeat the procedure above to create a new customtheme.tar.gz and switch back to the custom theme. 

Before applying the new custom theme, you need to remove the old customtheme.tar.gz and all the files in /var/ns_gui_custom/ns_gui/

rm -r /var/ns_gui_custom/ns_gui/*
rm /var/ns_gui_custom/customtheme.tar.gz

Sometimes the old theme will works almost everywhere untill you go into a submenu and get a prompt "access denied"... this happened to me while using a different version of custom theme I went to create a new service group and got that pop-up message. This had me scratch my head for a while to figure out why as a global administrator I was denied access to a function that was working fine before.

WARNING #2
DO NOT USE NOTEPAD / WORDPAD etc to create / edit the rc.netscaler. Use the winscp editor (and cut / paste stuff from wordpad) to create / edit rc.netscaler
(it's all to do with windows / unix having different end-of-line sequences!).
If you DO wrongly use wordpad or notepad, then netscaler never gets beyond the end of the first line... and doesn't even execute that first line!

Credit goes to Paul Blitz from the netscaler forum for all these instruction.