While replacing Citrix StoreFront (2203 CU5 LTSR) servers running Microsoft Server 2019 with servers running Server 2022, we encountered an error message during login attempts to Citrix StoreFront. Users were shown an error message stating: “Cannot complete your request.”

We were running a GSLB setup with a multi-server group (across sites), each containing several Citrix StoreFront servers (2203 CU5 LTSR). As described in “Virtual Apps and Desktops – 1912/2203 – Citrix Infrastructure / OS Upgrade” (CTX278869), we exported the configuration from an old StoreFront server running Server 2019 and imported it onto the newly created StoreFront servers running Server 2022. All servers were deployed in the same OU, received the same GPOs/settings, and apart from the different operating systems, all settings were pretty much identical.

Read More →

For my home lab environment, I use Authentik as my Identity Provider. Authentik is an open-source authentication and authorization platform that enables Single Sign-On (SSO), identity management, and multi-factor authentication (MFA) via protocols like OAuth, SAML, and LDAP. For various applications, such as the Citrix NetScaler, I use RADIUS for secondary authentication. All my Authentik users have a TOTP token in their authenticator app, which I want to use for RADIUS authentication. While configuring RADIUS in Authentik, I found the available documentation somewhat limited, and it took considerable effort to achieve a working RADIUS setup. This blog describes all the steps I followed to get RADIUS successfully running within Authentik.

For this guide, I used Authentik version 2024.10.1. I assume you already have a working Authentik setup where users already have a TOTP authenticator code available.

Read more: Setup Authentik as Radius Provider

Within the admin console, select “Stages” under “Flows and Stages” and next select “Create”. First we’ll create a “Identification Stage”. The parameters that should be configured in the stage are:

  • Type : Identification Stage
  • Name : pepperbyte-radius-identification-stage
  • User fields : Username, Email & UPN

Next, we’ll create an “Identification Stage” with the following parameters:

  • Type: Authenticator Validation Stage
  • Name : pepperbyte-radius-authenticator-validation-stage
  • Device classes : Static Tokens & TOTP Authenticators
  • Not configured action : Deny the user access
  • WebAuthn User verification: user verification should not occur.

Lastly, we’ll create a “User Login Stage” with the following parameters:

  • Type : User Login Stage
  • Name : pepperbyte-radius-user-login-stage

Now that all the required stages have been created, select “Flows” and create a new Flow with the following parameters:

  • Name : PepperByte Radius Authentication Flow
  • Title : PepperByte Radius Authentication Flow
  • Slug : pepperbyte-radius-authentication-flow
  • Designation : Authentication
  • Authentication : Require Outpost (flow can only be executed from an outpost)

Select the newly created flow “pepperbyte-radius-authentication-flow”, click on “Stage Bindings”, and then select “Bind existing stage”. Bind the previously created stages in the following order:

  • Order : 10, Stage : pepperbyte-radius-identification-stage
  • Order : 20, Stage : pepperbyte-radius-authenticator-validation-stage
  • Order : 30, Stage : pepperbyte-radius-user-login-stage

With this, the Flow is ready. Next, go to “Provider” under “Applications” and select “Create”. We’ll create a new provider with the following parameters:

  • Type : Radius Provider
  • Name : PepperByte Radius
  • Authentication flow : pepperbyte-radius-authentication-flow
  • Code-based MFA Support : Disabled
  • Shared secret : Write down the shared secret; we’ll need it later on
  • Client Networks : By preference, only specify the IP address of the RADIUS client here.

Next, go to “Applications” and select “Create”. We’ll create a new Application with the following parameters:

  • Name : PepperByte Radius
  • Slug : pepperbyte-radius
  • Provider : PepperByte Radius

Next, select “Outposts” under “Applications” and click “Create”. We’ll create a new Outpost with the following parameters:

  • Name : PepperByte Radius
  • Type : Radius
  • Application : PepperByte Radius
  • Configuration :
    • authentik_host: https://local authentik ip:port/
    • authentik_host_insecure: false
    • authentik_host_browser: “https://authentik fqdn/”

With the Radius Outpost created, last thing we have to do within the Authenik admin console is to retreive the “Authentik_Token”, which we’ll need to run the Authenik Radius Container. Select “View Deployment Info” and click “Click to copy token”. Save this token, as we’ll need it later on.

With everything set up within Authentik, we now need to add the actual RADIUS listener by adding the RADIUS Outpost to your (at least in my case) docker-compose file. Add the following configuration to your existing Authentik docker-compose file, with the following parameters:

  • {{AUTHENTIK_HOST}} : Internal Authentik FQDN/IP, in my case “https://192.168.x.x:4443”.
  • {{AUTHENTIK_RADIUS_TOKEN}} : Then, use the “Authentik_Token” saved when creating the RADIUS Outpost.
  radius_outpost:
    image: ghcr.io/goauthentik/radius:latest
    restart: unless-stopped
    ports:
      - 1812:1812/udp
    environment:
      AUTHENTIK_HOST: {{AUTHENTIK_HOST}}
      AUTHENTIK_INSECURE: "true"
      AUTHENTIK_TOKEN: {{AUTHENTIK_RADIUS_TOKEN}}
    depends_on:
      - server  

After redeploying your Authentik setup, an additional “Authentik Radius” container should be present, or you can use the automatically created “ak-outpost-pepperbyte-radius” without redeploying your whole setup. Either way, you should have an “Authentik Radius” container running.

Verify the “Health and Version” status of the RADIUS container from within the Authentik admin console, under Applications > Outpost.

With everything set up, the last step is to validate your setup by using a RADIUS test client like NTRadPing. Simply enter your Authentik server IP, the shared secret, and test a user in combination with a TOTP token code.

Ensure the RADIUS client IP is listed within the “Client Network” field in the RADIUS provider configuration.

In the screenshot below, you’ll see a RADIUS Reject response because an incorrect TOTP code was entered. A correct TOTP will, of course, generate an Access-Accept response.

A while ago, I wrote a blog about the error message ‘Application can’t be started… (Instant Passthru could not be resolved)’ that we encountered when launching a published application from our Ivanti Workspace Control managed session. Recently, we received the same message again, but this time the cause was different.

Application can’t be started… (Instant Passthru could not be resolved)

Shortly after a relatively simple task—upgrading an outdated version of Citrix Workspace App (CWA) from 1912 LTSR to the slightly newer 2203 LTSR—we encountered some inexplicable issues that made it impossible to launch Citrix Published Apps via SelfService.exe.

Read More →

Within a large environment where Ivanti Workspace Control is used in combination with a Microsoft SQL Database, the SQL Server has to handle numerous connections initiated by all the Ivanti Workspace Control Agents.To minimize the load and connections on the SQL Server, Ivanti introduced the Ivanti Relay Servers, which act as proxies for all agent connections to the SQL Server, thereby reducing the total number of SQL connections and the overall load.

While monitoring our Ivanti Relay Server, we noticed that a couple of times a day, the Ivanti Relay Servers started queuing all messages. The transactions folder filled up with transactions that weren’t forwarded to the SQL Server. The Ivanti Relay Servers have a built-in failsafe option, where they stop accepting new transactions when the queue exceeds 50,000 transactions. So, in a short period of time, all Ivanti Relay Servers went offline because they hit the 50,000 transaction threshold.

Read More →

Let’s start by stating I’m not a SQL DBA 😉 when it comes to databases, I’m just a user who needs a database for my applications 🙂 Lately, in various environments, we’ve been creating different Ivanti Workspace Control and Automation Manager databases. We simply request an empty database from the SQL department and are assigned DBO rights. Subsequently, we establish a connection to the database from Ivanti Automation Manager (for example) and handle the initial database setup within the application itself.

After initializing the SQL database, the user who performed the initialization can start Ivanti Workspace Control, for example, without encountering any issues. Another user, who has the same permissions (DBO) on the database, is unable to launch the application. The second user is able to access the SQL Database using SQL Management Studio, where they seem to have full control over the database.

Read More →

Apple OSX users sometimes experience an incorrect keyboard layout loaded within their Citrix session. As a result, special characters are often located in different places. The cause of this issue is that Apple has a different keyboard layout compared to Windows, leading to an Apple US-international keyboard being recognized as a Dutch keyboard in Windows.

How to identify your Apple keyboard layout by country or region

Some time ago, we conducted extensive research together with Citrix Support to investigate the cause of this issue and whether there are possibilities to change this behavior. Unfortunately, it has been found that this behavior cannot be changed through a central solution. This behavior can only be altered by making adjustments on a per OSX system basis. This guide provides detailed instructions on what needs to be adjusted.

Read More →

For quite some time, I’ve been using Synology PhotoStation to manage all my family photos. Since I’m not the only user—my children also use the app—I thought it might be a good idea to set some permissions on the different folders. In general, I use three different groups: full control, read-write, and read-only. This way, my kids can access all shared family photos but can’t accidentally delete them. Setting access permissions within Synology Photos is somewhat limited, so I had to reorganize my folder structure to fulfill my needs. However, in the end, it worked out very well.

Last week, I decided to move over some additional photos and reorganize parts of my original folder structure. Thinking it would be quicker than using the web GUI, I accessed my photo share through SMB. Immediately, I noticed something wasn’t right. Folders could not be renamed, data couldn’t be moved, and so on. When I looked at the Windows ACL permissions, I noticed they were different from the permissions set in Synology Photos. In my case, most permissions were inherited from the root photos folder.

Read More →

We manage a Citrix farm where users primarily launch a full desktop environment. From there, they can also connect to other applications running in Citrix Silo’s or access external Citrix farms. As an user environment manager (UEM), we utilize Ivanti Workspace Control (IWC).

When a user logs onto the primary desktop, the endpoint hostname is utilized by Ivanti Workspace Control within that session. Based on the endpoint hostname, we can set specific configurations using features like “location and devices”. In a double-hop scenario, where a user launches a Citrix published application or another Citrix desktop from within the primary session, the hostname of the primary session server is used as the hostname in the secondary session.

Read More →

Due to lifecycle management (LCM), we replaced several Citrix NetScaler appliances with new ones. Although we conducted thorough acceptance tests before putting them into production, unfortunately, we experienced an annoying issue once they were operational.

Some users complained that they saw a spinning progress bar after they successfully logged on to the Citrix NetScaler. It was only reported by a minority of users and was resolved by refreshing their web browser sessions. In the end, users stopped reporting the issue because it occurred infrequently and the solution was simple—just press F5. We initiated an investigation in the hope of completely resolving the issue.

Read More →

As a big fan of Unifi products, I manage multiple Unifi sites from a self-hosted UniFi Network Application across various locations.Sometime after migrating from my UniFi Security Gateway USG-3 to an UniFi UXG Lite and upgrading from UniFi Network Application 7.x.xx to UniFi Network Application 8.x.xx, I suddenly noticed that I could no longer modify existing firewall rules. When trying to modify a rule, I received an error message along the lines of “Unable to save rule xxx due to out of range index number 2xxx.”. I’m not sure if it was caused by switching to the UXG Lite or the software upgrade, but things changed somewhere in this process.

The only option I had was to quickly create a new one and delete the old one. Not very convenient, to say the least. Initially, I didn’t spend any more time on it since I wanted to move on and thought I would delve into it later.

Today, however, I needed to create a Firewall Rule that would be one of the first to be applied. I created a new rule in the usual way, which appeared at the bottom of the list after being created. When I tried to drag it up in the GUI, an error message appeared saying “Firewall rule reorder failed. Please ensure all firewall options have been entered correctly.”

When I took a closer look at my Firewall Rules, two things immediately stood out to me:

  • All my existing rules had an ID in the 2xxx series, while the newly created firewall rule was assigned an ID of 2xxxx.
  • All my existing rules suddenly had an extra row with a lock icon in UniFi Network Application 8.1.113.

This likely explains why I was receiving an “out of range index number” error when trying to modify existing old firewall rules. It strongly appears that UniFi has switched to a different series of index numbers for their firewall rules. Although old rules have been carried over, you can no longer modify them or give newly created firewall rules a higher priority than the old ones.

In my case, and undoubtedly for many others who have extensive firewall rules, this is quite frustrating. To make modifications, they need to be converted to a new index number, meaning you will have to create new firewall rules and then delete the old ones from the 2xxx series. Initially, I started manually replicating all the rules, but I quickly grew tired of that. There has to be a more efficient way to do this.

Although there appears to be an API for the UniFi Network Application, the documentation leaves much to be desired. I could find very little substantial documentation on it.

After some searching, I came across some API documentation on the Ubiquiti Community Wiki, which was useful. By using the URL api/s/{site}, it’s possible to interact with User-defined firewall rules via rest/firewallrule. Using the GET method, you can retrieve existing rules, and theoretically, you should be able to create some rules using the POST method. After some figuring out, I was eventually able to read all existing rules via the API.

The next step was to change the rule_index number from a 2xxx series to a 2xxxx number and then write it back using the API. To my surprise, I was able to modify the cloned firewall rule, which now had a 2xxxx ID, and successfully import the modified rule into the UniFi Network application. I ended up writing a PowerShell script that allowed me to read and modify all existing rules at once. During testing, I encountered some issues, but I was able to automate the resolution using the PowerShell script as well.

By using my script, you can convert all your old, existing Firewall Rules into new Firewall Rules in one go. I’ll share the script with you in the text below. Just make sure to create a good backup of your UniFi configuration before you run the script!!! Don’t forget to adjust the “Configuration Variables” section to suit your environment.

Backup your UniFi Network Application configuration before running the script! Better safe than sorry 😉

<#
.SYNOPSIS
This script clones firewall rules within specified index ranges and rulesets to new indices starting from a specified index.

.DESCRIPTION
The script logs into a UniFi Controller, retrieves firewall rules based on user-defined criteria, and clones them to new indices. It is configurable for different sites, ranges, and ruleset types.

.PARAMETERS
- $UnifiControllerSiteID: Site ID for which the rules are managed.
- $UnifiControllerMigrateRuleStartIndex: Start index of the rule range to clone.
- $UnifiControllerMigrateRuleEndIndex: End index of the rule range to clone.
- $UnifiControllerNewRulesStartIndex: Starting index for new cloned rules.
- $UnifiControllerRuleSet: Type of ruleset to filter (e.g., LAN_IN, LAN_OUT).

.EXAMPLE
# To execute the script, simply configure the parameters at the top of the script and run it in a PowerShell environment.

.NOTES
Ensure to test the script in a controlled environment before deploying in production.
#>

# Configuration Variables
$UnifiControllerURL = "https://xxx.xxx.xxx.xxx:8443"    #UniFi Controller IP / Hostname
$UnifiControllerUsername = "[email protected]"          #UniFi Username
$UnifiControllerPassword = "password"                   #UniFi Password
$UnifiControllerSiteID = "default"                      #UniFi SiteID   
$UnifiControllerMigrateRuleStartIndex = 2000            #Start index of the rule range to clone
$UnifiControllerMigrateRuleEndIndex = 2999              #End index of the rule range to clone.
$UnifiControllerNewRulesStartIndex = 20000              #Starting index for new cloned rules.
$UnifiControllerRuleSet = 'LAN_IN'                      #Type of ruleset to filter (e.g., LAN_IN, LAN_OUT).

# Ignore SSL errors if your controller uses a self-signed certificate
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

# Start a session and save the cookie
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$loginUri = "$UnifiControllerURL/api/login"
$body = @{ username = $UnifiControllerUsername; password = $UnifiControllerPassword } | ConvertTo-Json

$response = Invoke-RestMethod -Uri $loginUri -Method Post -Body $body -SessionVariable session -ContentType "application/json"

# Constructs the API endpoint URL and retrieves the firewall rules for the specified site ID using an authenticated GET request.
$devicesUri = "$UnifiControllerURL/api/s/$UnifiControllerSiteID/rest/firewallrule"
$devices = Invoke-RestMethod -Uri $devicesUri -WebSession $session -Method Get

# Retrieve firewall rules with rule_index between $UnifiControllerMigrateRuleStartIndex and $UnifiControllerMigrateRuleEndIndex and matching the ruleset
$filteredRules = $devices.data | Where-Object {
    $_.rule_index -ge $UnifiControllerMigrateRuleStartIndex -and $_.rule_index -le $UnifiControllerMigrateRuleEndIndex -and $_.ruleset -eq $UnifiControllerRuleSet
} | Sort-Object rule_index  # Ensure the rules are sorted by their indices

# Initialize the new index starting from $UnifiControllerNewRulesStartIndex
$newIndex = $UnifiControllerNewRulesStartIndex

foreach ($rule in $filteredRules) {
    # Clone the rule
    $newRule = $rule.PSObject.Copy()

    # Assign the new index and increment for the next rule
    $newRule.rule_index = $newIndex++
    
    # It's typical to unset the ID before submitting a new entry
    $newRule._id = $null

    # Convert the modified rule to a JSON payload
    $jsonBody = $newRule | ConvertTo-Json -Depth 5

    # Define the endpoint URI for creating the new rule
    $createRuleUri = "$UnifiControllerURL/api/s/$UnifiControllerSiteID/rest/firewallrule"

    # Send the POST request to create the new rule
    try {
        $newRuleResponse = Invoke-RestMethod -Uri $createRuleUri -WebSession $session -Method Post -Body $jsonBody -ContentType "application/json"
        Write-Host "New rule created successfully with rule_index" -NoNewline -ForegroundColor Green
        Write-Host " $newRule.rule_index" -ForegroundColor Cyan
    }
    catch {
        Write-Host "Failed to create new rule: $_" -ForegroundColor Red
    }
}

After running the script, all firewall rules will appear duplicated within the GUI, and as a final step, you will need to remove the old firewall rules from the 2xxx index series.

At the bottom of the firewall rules, select “Manage,” where you can then select the old firewall rules with a 2xxx number. Finally, click on “Remove” to delete them.