Citrix Storefront – Adventures in customization – Dynamically configure workspace control based on group membership

Citrix Storefront – Adventures in customization – Dynamically configure workspace control based on group membership

2017-05-07
/ /
in Blog
/

I’ve been exploring the customization capabilities of Citrix Storefront and have some exciting ideas on simplifying our deployment.  What I’d really like is to reduce our store count down to a as few stores as possible.  In our Web Interface we have multiple stores based on the non-configurable settings.  They are:

  • Workspace Control Enabled with Explicit Logon
  • Workspace Control Disabled with Explicit Logon
  • Workspace Control Enabled with Domain Passthrough authentication
  • Workspace Control Disabled with Domain Passthrough authentication
  • Anonymous site

We can’t mix and match authenticated sites and anonymous sites (right?… ?) but Citrix does offer the ability to configure Authentication methods AND Workspace Control options via their ‘Receiver Extension API’s’.

These are the API’s in question:

There isn’t really a whole lot of documentation on them and how to use them.  Richard Hayton has created the Citrix Customization Cookbook which details some examples of some of the API’s.  He has several blog articles on the Citrix website that have varying degrees of applicability.  Unfortunately, he hasn’t blogged in over a year on this topic as it feels like the situation has changed a bit with the Citrix Store API’s available as well (note: these are different!).

My target is to make it so these options can be set dynamically based on the users group membership.  If you’re a member of the group ‘workspaceControlEnabled’ you get all the settings set to true, if you’re a member of ‘workspaceControlDisabled’ you get all the settings set to false.

Seems like a pretty straightforward goal?

So I thought I’d start with something pretty simple.  I have a store with Workspace Control Enabled, with show ‘Connect and Disconnect’ buttons selected:

If I log into the site:

I see everything (as I should).

So let’s start with a simple customization.  Let’s try using the API to disable these options.  I created a totally blank script.js file and added the following lines:

Now what does our menu look like?

Awesome!  Workspace Control was disabled by script!

So I said I want to disable Workspace Control if you are a member of a specific group.  Richard Hayton actually wrote a pretty good article on creating a service to facilitate grabbing your group membership with Storefront.  Unfortunately, the download link is dead.  So I wrote another PowerShell HTTP listener that takes an input and queries AD for that user and their membership, and returns a positive value if workspace control should be enabled, or a negative value if it should be disabled.  To get it to query though, it needs a value.  The best value for this, I thought, would be the user name.

Citrix provides a function to get the username and I can then pass it to my webservice, test for group membership and return whether Workspace Control (WSC) should be enabled or disabled.

I wrote my first bit of code and it crashed immediately.  I simply entered it straight into my script.js.

In order to trace the error, you simply enter “#-tr” to the end of your store URL:

and allow pop-ups.  A new tab will open allowing you to follow the ‘flow’ of Storefront as it executes its commands.  Mine crashed at:

“get username data:”

And it makes sense why it crashed there.  I haven’t even logged in yet so it has no idea who or how to get the username so it looks like Storefront just returns the login page.  We need to call our functions after logging in.

Citrix provides the following event-based functions we can hook into:

Notifications of progress

preInitialize(callback)
postInitialize(callback)
postConfigurationLoaded()
postAppListLoaded()

Note that during these calls, the UI may be hidden in native Receivers, so it is not safe to show UI
For APIs passing a callback, you MUST call the callback function, though you may delay calling it until code of your own has run.

beforeLogon(callback)

Web browsers only. Called prior to displaying any logon dialogs. You may call ‘showMessage’ here, or add your own UI.

beforeDisplayHomeScreen(callback)

All clients, called prior to displaying the main UI. This is the ideal place to add custom startup UI.
Note that for native clients, the user may not have logged in at this stage, as some clients allow offline access to the UI.

afterDisplayHomeScreen()

All clients, called once the UI is loaded and displayed. The ideal place to call APIs to adjust the initial UI, for example to start in a different tab.

So the question becomes, when does each of these get called?  We are only interested in the ones after you login.  To determine this, I hooked into each one and just did a simple trace command and then refreshed my browser to the login screen.

This is where I stopped:

And trace tab results:

These 4 stages are called before the user logs on so they are of no use to me:

preInitialize
postInitialize
postConfigurationLoaded
beforeLogon

The order of the other 3 after logon:

beforeDisplayHomeScreen
postAppListLoaded
afterDisplayHomeScreenStage

Before adding my code to the post-logon event functions I just added it back -plain jane- and rerun with a trace:

What I found is these extensions appear to have a fixed entry order point.  The workspace control extensions cannot be called after “beforeDisplayHomeScreen” stage.  If you do not call the workspace control extensions before the callback on the ‘beforeDisplayHomeScreen’ function you will be unable to control the setting.  The trace log in my screenshot for these extensions will always occur at this point in time regardless if you actually set it in ‘preInitialize, postInitialize, postConfigurationLoaded, or beforeLogon’.  And if you attempt to set it in either of the two later functions it will not log anything and your code has no effect.  So the only point in time where I can take the username and set these values are in the event function beforeDisplayHomeScreen.

<Digress>

During the course of my testing this feature I had thought about adding a button that would allow you to toggle this feature ‘enabled or disabled’ on your own whim.  But it appears once you call the Extension it’s a one and done.  I also discovered that it appears you must set the workspace control feature early in the process.  If I set it in postAppListLoaded or afterDisplayHomeScreen nothing happened.  To be fair, I do not know how to reinitialize the menu, maybe that would allow it to kick in dynamically…?  I guess that’s for further exploration on another day…

</Digress>

Ok, so we’ve found the one and only functional place we can execute our code.  So I added it.

 

The result?  Nothing.  Nothing happened.

Well, that’s not entirely true.

I’ve highlighted in yellow/orange my “getUsername” function.  We can see on line 35 we get into the function.  And on line 67 it is successfully finding and returning my name.  But the problem is that it’s getting that information after the point in time that we can set the WSC features (highlighted in blue — line 60-62).

I found that using ajax for this command and attempting to use async was causing my failure.  I understand it’s bad practice to do synchronous commands, especially in javascript as they will lock the UI while executing, but, thus far it’s the only way I know to ensure it gets completed in the proper order.  I am really not a web developer so I don’t know what’s the proper technique here to send a couple ajax requests that only blocks at the specific point in time that WSC kicks in…  Or find a way to redraw the menu?  But for the purposes of getting this working, this is the solution I’ve chosen to go with.  I’m wide open to better suggestions.  The real big extension that would be an issue is the ‘webReconnectAtStartup’.  This feature will reconnect any existing sessions you have and the way that Citrix currently implements it, they want it run as soon as the UI is displayed.  This makes some sense as that’s the whole point.  You don’t want to wait around after logging in some indeterminate or random amount of seconds for your session to reconnect…  But, this issue can be alleviated.  Citrix actually offers a way to implement this feature yourself via the Store API so we could implement our own custom version of this function that would get all your sessions and reconnect them…

Which could just leave building the menu as something that could be moved back to async if I can figure out how to rebuild it or build it dynamically…

Anyway, that maybe for another day.  For today, the following works for my purpose.

This is my custom/script.js file that I finished from this blog post:

 

Here is the LDAP_HttpListener.psm1

Lastly, the scheduled task to call the listener:

 

 

 

 

3 Comments

  1. Pingback: Detailed Change Log – Carl Stalhood

  2. Pingback: EUC Weekly Digest – May 13, 2017 – Carl Stalhood

  3. Pingback: Site Updates – May 2017 – Carl Stalhood

Post a Comment

Your email address will not be published. Required fields are marked *

*