Hey all!

A long time ago, in the early days of Jamf Connect, I blogged about configuring Jamf Connect with ADFS. This without the use of Azure: https://travellingtechguy.blog/jamf-connect-against-adfs-without-azure/

While it kind of worked, there was one big problem: the local accounts being created with a syntax of domain\username. This was far from ideal as username syntax on macOS and not officially supported by Jamf.

Important: before continuing, just for the record, I’m still convinced the recommended way to configure Jamf Connect is via Azure (Entra) only (or any other Cloud iDP for that matter), followed by hybrid setup with AllowCloudPassword Validation if ADFS can not be fully taken out of the mix. What is discussed in this post is only as last resort and proof of technical possibility, especially in view of Microsoft’s cloud focused stand on things as well.

That said, today I faced some challenge in troubleshooting Jamf Connect and ROPG with environments where the short names in AD, aka samaccountname or windowsaccountname have a space in the user name. For instance: firstname.lastname@domain.com as UPN with short name (samaccountname) “first last” (instead of fLast or firstlast, etc…).

As the specific setup I had to look at included a federated Azure tenant, with ADFS, I ended up with reviewing Jamf Connect and ADFS setups again. This initially in view of testing Kerberos with short names including a space. Sidetracking in my testing, I ended up reviewing the pure ADFS setup again, as I realised, while creating additional claims for ADFS to pass into the OIDC ID token, that it IS possible to use Jamf Connect with pure ADFS and no Azure! And this without the users being created like “domain\username”.

Disclaimer: this is at the moment of writing this not officially supported or documented by Jamf. Use it for testing only, or at own risk.

Let’s have a look at it, as well as doing the required setup for situations where you need Kerberos with usernames including a space.

The key is to add additional claims to the ADFS app and the way we create the app to start with.

Create the ADFS app:

  • Open the AD FS Management application.
  • Right-click Application Groups, and then select the Add Application Group option from the menu.
  • On the Add Application Group Wizard screen, provide Name and Description for the OpenID Connect Client, and then click Native application accessing a web API. Click Next.
  • On the Native Application screen, a Client Identifier will be automatically generated. Copy it as you will need it in next step. Add the redirect URI: https://127.0.0.1/jamfconnect
  • On the Configure Web API screen, copy the Client Identifier generated in the previous step and add it as the Identifier.
  • On the Access Control Policy screen, select Permit Everyone (or fine tune to select users as needed)
  • On the Configure Application Permissions screen, select allatclaims, profile and openid in Permitted scopes.
  • Complete the wizard.

This should allow Jamf Connect to work with OIDC and ROPG against this app, but in view of this exercise, we need to add some custom claims.

For this we need to go on the WEB API of our ADFS app and go to the tab “Issuance Transform Rules“:

As you can see I create 2 custom rules already, one to define a custom shortname for OIDC and one for ROPG. Why?

Well, the first problem I wanted to tackle here is the syntax of the username being creating by Jamf Connect Login. As said, when setting up JC with pure ADFS, it would create the local user as “domain\username”. This is where this oidcShortName claim comes into play:

With the below regex translation I’m basically taking the windowsaccountname (reported as domain\username) and dropping the “domain\”, as well as dropping any spaces which the username may include:

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
 => issue(Type = "oidcShortName", Value = regexreplace(c.Value, ".*\\|\s+", ""));

However, in order not to break Kerberos, which via Jamf Connect Menu Bar by my surprise works with usernames including spaces, I created another claim for the ropgShortName:

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
 => issue(Type = "ropgShortName", Value = regexreplace(c.Value, ".*\\", ""));

This one just drops the “domain\” but leaves the rest of the windowsaccountname intact.

With those 2 claims in place, I can now make Jamf Connect Login and Jamf Connect Menu Bar work just fine with pure ADFS! However, there is one more catch! Well a small one. Or two.

Let’s look at my plist as that wil make things easier to explain I think. I highlighted the important keys:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CreateJamfConnectPassword</key>
	<false/>
	<key>OIDCClientID</key>
	<string>ff201424-xxxx-xxxx-xxxx-60eb09355c3c</string>
	<key>OIDCDiscoveryURL</key>
	<string>https://adfsttg.travellingtechguy.dev/adfs/.well-known/openid-configuration</string>
	<key>OIDCNewPassword</key>
	<false/>
	<key>OIDCProvider</key>
	<string>Custom</string>
	<key>OIDCROPGID</key>
	<string>ff201424-xxxx-xxxx-xxxx-60eb09355c3c</string>
        <key>OIDCShortName</key>
        <string>oidcShortName</string>
        <key>OIDCROPGShortName</key>
        <string>upn</string> 
        <key>OIDCUsePassthroughAuth</key>
        <true/>
</dict>
</plist>

To tell Jamf Connect Login to NOT create the username by default with the “domain\user” syntax, we need to set the OIDCShortName to the claim we created for this: oidcShortName

However, as Jamf Connect would then try to use that username, which even may have spaces in the username removed (see above) ROPG and password validation (OIDCNewPassword set to false) would FAIL. To fix this I tell Jamf Connect to use the upn as OIDCROPGShortName and all works fine.

Without this, you would hit MSIS9659:

The other tweak I had to add to the plist is <key>CreateJamfConnectPassword</key> <false/>. This because otherwise Jamf Connect Login would create a keychain item for Jamf Connect Menu bar, and use the “domain\user” syntax again. This is fine, as that will allow Jamf Connect Menu Bar to work, but is not nice in view of user experience. I prefer the end user to authenticate with UPN in Jamf Connect Menu Bar as well. So, I tell Jamf Connect Login, NOT to create a keychain item. This opens up a discussion for a feature request I’ll review further, but the only consequence is that the end user will have to authenticate 1x manually in Jamf Connect Menu Bar to have the keychain item created.

Before we look at Jamf Connect Menu bar further, there is one more key I added in my JCL plist above: OIDCUsePassthroughAuth. Yes, that also works totally fine with ADFS!

That leaves us with Jamf Connect Menu Bar, which it’s basically nothing more adding the ShortNameAttribute and setting it to the custom claim created: ropgShortName:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>IdPSettings</key>
	<dict>
		<key>DiscoveryURL</key>
		<string>https://adfsttg.travellingtechguy.dev/adfs/.well-known/openid-configuration</string>
		<key>Provider</key>
		<string>Custom</string>
		<key>ROPGID</key>
		<string>ff201424-XXXX-XXXX-XXXX-60eb09355c3c</string>
                <key>ShortNameAttribute</key>
                <string>ropgShortName</string>
	</dict>
	<key>SignIn</key>
	<dict>
		<key>RequireSignIn</key>
		<true/>
                <key>AutoAuthenticate</key>
                <true/>
	</dict>
	<key>Kerberos</key>
	<dict>
		<key>AutoRenewTickets</key>
		<true/>
		<key>Realm</key>
		<string>TRAVELLINGTECHGUY.DEV</string>
	</dict>
</dict>
</plist>

After adding that all together, let’s look at some proof it all works.

User details of the account I used:

  • UPN: spaced.user@travellingtechguy.dev
  • Samaccountname: Spaced User

As said, after going through Jamf Connect Login, with only 1 authentication (thanks to OIDCUsePassthroughAuth working):

The account is created as “spaceduser”:

The user only needs to sign in 1x in Jamf Connect Menu Bar:

Kerberos works via Jamf Connect Menu Bar, with the real short name (including space if any):

In the com.jamf.connect.state.plist we get:

<key>oidcShortName</key>
<string>spaceduser</string>
<key>ropgShortName</key>
<string>spaced user</string>
<key>unique_name</key>
<string>TRAVELLINGTECHG\spaced user</string>
<key>upn</key>
<string>spaced.user@travellingtechguy.dev</string>

One more thing maybe: the username syntax JCL uses to create the account can be tweaked. It’s nothing more than changing the regex. Here I discussed going from “domain”TRAVELLINGTECHG\spaced user” to “spaceduser”. But you could go for “spaced.user” if you want to for instance:

c:[Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname", Issuer == "AD AUTHORITY"]
              => issue(Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", Value = regexreplace(c.Value, ".*\\", "") -replace "\s+", ".");

That’s it!

DISCLAIMER: Just keep in mind that this setup is not officially supported, but works fine for me. Tested on Jamf Connect 2.27. Additional functionality outside the above has not been tested (such as Enrolment Customisation, etc.)

As always, if you liked the post, hit the like button, tell your friends about it and leave a comment down below!

Brgds,
TTG