Earlier we looked at the automated building and packaging of Kerberos.NET using VS Online. At this point the only thing we get out of it in this state is knowing the code compiles and any tests pass — which I suppose is actually quite a feat on it’s own considering I had no indicator of either when I started. We can, of course, do better! The last piece we need is automated publishing of the final nuget package to the feed for others to consume.

As it turns out this is relatively straightforward to do. The process is:

  1. Defining artifacts to keep after build succeeds
  2. Create a On-Release task that uploads the package to nuget

Defining the build artifacts is easy. All you need to do is specify that the output of the build should go to the staging directory, which is the variable $(Build.ArtifactStagingDirectory). You can also explicitly set the Version here too, if you happen to be using the build system to increment build versions.

Set Build Output Directory

Now all you need to do is publish the collected artifacts to nuget. To do that you first need to configure the nuget service, similar to how you configured Github. First go to the settings via the gear icon and select Services. Add a new service and find the nuget option. This’ll prompt for connection details:

Adding the Nuget Service

The Feed URL for nuget.org is https://api.nuget.org/v3/index.json. The ApiKey can be found in your Nuget account API Keys. If you don’t have an API Key, go ahead and create one, setting the expiration to 365 days. Oh, and be sure to set a reminder for 365 days from now to tell you the key needs regenerating. *grumble*

Lastly verify the connection and hit Ok. Once your service is configured you can go back to your build and select the Releases tab. Hit the + icon to add a new release definition. Create an empty template and give the environment a name. Click into the environment and add a new task to the Agent Phase. Add the Nuget task. Set the command to push, configure the path to the packages. In this case we used $(System.DefaultWorkingDirectory)/Kerberos.NET CI/drop/*.nupkg. Then of course, select the Nuget service you created earlier.

Configure the Task for Push

Now that we have a release task, we can kick off a new build, or just work with an existing build that has the artifacts. At the top of the build details screen is a Release button. This brings up the release dialog that lets us kick off the process.

Kick off the Release

Go ahead and kick off the release. It’ll take a few seconds to kick off, but once it’s done and if all things went well you should see the new package available in nuget (yes, the version numbers are different — I don’t want to kick off a new package without any changes).

Nuget Shows our Package!

Now I don’t have to worry about manually futzing with generating and upload package files — if I’m happy with the given build all I need to do is tell it to release.

The next logical step for the Kerberos.NET project is setting up automated builds and releases. What exactly does this entail? Basically, I want a build to kick off any time changes are committed to the main repo, and automatically generate a production-ready Nuget package that is available to upload if deemed worthy of release.

If you’ve done any sort of build automation or release management before, you’ve got a pretty good idea of how to make this work. For a given build service do the following:

  1. Observe changes to repo
  2. Pull down changes
  3. Build project(s)
  4. Package the packages
  5. Artifact the necessary files for future release

And if you’re really wanting to be fancy:

  1. Push packages to nuget repository on release signal

I chose to use Visual Studio Online to do this for me. I can use hosted build agents to build and package the project without a ton of effort. This is how I did it.

First, you need to have a Visual Studio Online account. If you don’t have one, go set one up. It’s easy.

Next, you need to create a new Team Project. Give it a name, select the Version Control and Work Item types. You can leave these as the defaults unless you have specific reasons to use the other options. The options don’t matter at all if you’re using Github because you’ll never commit or track work here.

Now you need to wire it into Github to track changes. Select the gear icon at the top to get into the project settings and select the Services tab.

Select the Services Tab

Add a new Service Endpoint and select Github:

Select Github

Now you can configure which account to connect to Github as. Just select the Authorize button and you’ll see a popup asking to be… authorized. There are more advanced options to configure if you’re specifying things like personal access tokens too. Your browser may block the Authorize pop up window. You’ll need to allow the pop up before it’ll allow you to continue.

Authorize Github

Now you can start configuring the build. Select the Builds and Releases tab and click the New button.

Add a New Build

And now you need to select a build template. We’re now building a .NET Core project in the case of Kerberos.NET, so you can start with an empty process or select the ASP.NET Core template.

Select your Build Template

Next you’ll want to configure the Get sources step, which will checkout changes to the repo. You need to select the Github tab. It’ll automatically populate the fields because you previously registered Github as a service. Select which repository you want to use and configure branches or other settings.

Configure Get Sources

Next you’ll need to configure the Restore/Build/Test/Publish steps. By default these steps are configured as .NET Core 1.*, which in our case is incorrect. We need to use .NET Core 2.0.

Select .NET Core 2.*

You’ll need to do this for the 4 steps. You can probably leave all the other settings alone and the system will just pick up any projects it needs to build or test — assuming you’ve got tests.

One thing I’d recommend you do is also add the new task before the restore or build called the “.NET Core Tool Installer”.

Add .NET Tools Installer

The reason for this is that it’ll download and install any runtimes or SDKs for any future versions of .NET that haven’t been added to the build agents yet. This isn’t strictly necessary, but it may save you some headaches in the future (or in the past, in my case, because the 2.* versions weren’t available when I originally set this up).

Install .NET Builds

From there you can configure the build/test/publish steps as necessary. Once you think you’re in a good spot go ahead and queue it up:

Save and Queue the build

You’ll be asked which queue to use. You’ll want the Hosted VS2017 agent in this case because of .NET Core 2.0.

Queue the Build

The build should then kick off with and you can track the results based on the console output or the logs. You can see there’s been some, uh, trial-and-error.

Build Build Build.

Once you’ve got a working build you can start configuring how you want it to kick off through the Triggers mechanism.

Trigger on Commit

In this case trigger when there are changes to the master branch. The Pull Requests option is super-handy when you’re working with teams and actually use PRs — there’s only been one PR with Kerberos.NET, and that was before builds were set up. You should consider committing to the project!

Once your build is ready to go you can even badge it to see the most recent build status easily:

Badge the Build

And now you have can embed the status wherever you want:

Next time we can look at automatically publishing.

I started the Kerberos.NET project with a simple intention: be able to securely parse Kerberos tickets for user authentication without requiring an Active Directory infrastructure. This had been relatively successful so far, but one major milestone that I hadn’t hit yet was making sure it worked with .NET Core. It now works with .NET Core.

Porting a Project

There is no automated way to port a project to .NET Core. This is because it’s a fundamentally different way of doing things in .NET and things are bound to break (I’m sure that’s not actually the reason). There is documentation available, but it’s somewhat high-level and not necessarily useful when you’re in the weeds tracking down weird dependency issues. Given that, you’re kinda stuck just copying over the code and doing the build-break-tweak-build-wtf dance until you have something working. This was my process.

  1. Create a new .NET Standard project — Standard dictates the API level the library is compatible with; Core dictates the runtime compatibility. I didn’t have any particular targeting requirements, so I made it as broad as possible. Now any runtime supporting .NET Standard can use this library.
  2. Copy all the code from the main project into the new project — I probably could have created the .NET Standard project in the same location, but it’s often easier to start with a blank slate and move things in.
  3.  Build!
  4. Build fails — MemoryCache/ObjectCache don’t exist in the current API set. Thankfully this is isolated to just the Ticket Replay detection, so I was able to temporarily convert it to a simple dictionary. I eventually found a library that replaces the original caching library.
  5. Build fails again — SecurityIdentifier doesn’t exist in the current API set either. Doh! I wasn’t going to hold my breath waiting for this to be moved over, so I created my own class that had the same usefulness. This also gave me the opportunity to fix some ugly code required to merge RIDs into SIDs, which added a nice little performance boost.
  6. Build succeeds!
  7. Unload/remove the original .NET 4.6 projects from the solution.
  8. Adjust test project dependencies to use the new project instead.
  9. Run!

Once I was able to get the test projects up and running I could run them through the test cases and verify everything worked correctly. Everything worked, except for the AES support. 😒

Porting a Project with a Dependency

I added support for AES tickets a while back and it was built in such a way that it lived in a separate package because it had an external dependency on BouncyCastle. I’m not a fan of core packages taking dependencies on third parties, so I built it as an add-on that you could wire-in later. This worked relatively well, until I needed to migrate to .NET Core.

It turns out there are a number of Core/Standard/PCL packages for BouncyCastle, but what’s the right one? Weeeeelll, none of them, of course!

At this point I decided to suck it up and figure out how to make SHA1 do what I want. One option was to muck with the internals of the SHA1Managed class with reflection, but that turned out to be a bad idea because the original developers went out of their way to make it difficult to get access to intermediate values (there are philosophical arguments here. I don’t fault them for it, but it’s really frustrating). I considered rewriting the class based on the reference source, but that too was problematic for the same basic reason. Eventually I ended up porting the BouncyCastle implementation because it was relatively self-contained, and already worked the way I needed.

Security note: You should never trust crypto code written by some random person you found on the internet. That said, there’s a higher chance of finding a vulnerability in other parts of the code than with the port of this algorithm, so…

This actually works out well because now all the code can go back into a single package without any dependencies whatsoever. Neat!

Porting a Nuget Package

The nuget pieces didn’t really change much, but now the manifest is defined in the project file itself, and packages are built automatically.

Simpler Package Management

Now the package is just an artifact of the build, which will be useful if/when I ever move this to an automated build process.

Active Directory has had the ability to issue claims for users and devices since Server 2012. Claims allow you to add additional values to a user’s kerberos ticket and then make access decisions based on those values at the client level. This is pretty cool because you normally can only make access decisions based on group membership, which is fairly static in nature. Claims can change based on any number of factors, but originate as attributes on the user or computer object in Active Directory. Not so coincidentally, this is exactly how claims on the web work via a federation service like ADFS.

Of course, claims aren’t enabled by default on Windows for compatibility reasons. You can enable them through Group Policy:

Computer Configuration > Policies > Administrative Templates > System > KDC > KDC support for claims, compound authentication and Kerberos armoring

Allow Claims in Group Policy

You can configure claims through the Active Directory Administrative Center Dynamic Access Control.

Active Directory Administrative Center Dynamic Access Control

You can see the Claim Types option on the left hand menu. From there you can add a claim by hitting the New > Claim Type menu.

The configuration is pretty simple. Find the attribute of the user or device you want to issue, and select whether it should be issued for users or computers or both. You can configure more advanced settings below the fold, but you only need to select the attribute for this to work.

Add New Claim Type

Once the claim type is configured you can modify attributes of a user through the Attribute Editor in either ADAC or the AD Users and Computers console.

User Attributes in ADAC

That’s all it takes to get use claims. You do have to sign out and back in before these claims will take effect though since Active Directory issues claims in the Kerberos tickets, and the tickets are only issued during sign in (or the myriad other times it does, but sign out/in is the most effective).

However, once you’ve signed out and back in you can pop open PowerShell and see the claims in your token:

[System.Security.Principal.WindowsIdentity]::getcurrent().claims | fl type, value

Type : ad://ext/department:88d4d68c39060f49
Value : Super secret division

Windows 8 and higher automatically extract the claims from the PAC in the ticket and make them available in the user token. Additionally, .NET understands claims natively and can extract them from the Windows token.

And of course now Kerberos.NET! The library will automatically parse any user or device claims and stick them in to the resultant claims produced during authentication:

Kerberos Claims

No configuration necessary. The library will do all the work. Enjoy!

Kerberos requires the use of shared secrets to validate tickets. These secrets need to be stored somewhere. Windows stores them in the registry — the Security hive specifically. Other platforms store them in keytab files.

Keytab files are useful because they’re a well known construct and are supported by many platforms. What’s interesting about them is that they store the derived value used to encrypt the ticket, and not the real secret. This means you don’t need to worry about how the salt is derived, and can just use the value without having to know how to manipulate the underlying key to match. In other words, you don’t need to worry about Active Directory being out of spec.

It turns out the format is actually pretty simple.

entry ::=
    principal
    timestamp (32 bits)
    key version (8 bits)
    enctype (16 bits)
    key length (32 bits)
    key contents

principal ::=
    count of components (32 bits) [includes realm in version 1]
    realm (data)
    component1 (data)
    component2 (data)
    ...
    name type (32 bits) [omitted in version 1]

data ::=
    length (16 bits)
    value (length bytes)

It’s just a list of entries that map out realm, principal name, encryption type, and key value. It was a simple enough format that it was added to Kerberos.NET and is now natively supported.

Of course, one of the primary motivations for adding it is because Microsoft supports generation of keytab files from Active Directory (sorta).

There’s a tool in the Remote Server Administration Tools (RSAT) package that generates keytab files for interoperability with other platforms and it uses the Active Directory salt method. To generate a file you run this command:

ktpass 
   /princ HTTP/test.identityintervention.com@IDENTITYINTERVENTION.COM 
   /mapuser IDENTITYINTER\server01$ 
   /pass P@ssw0rd! 
   /out sample.keytab 
   /crypto all 
   /ptype KRB5_NT_SRV_INST 
   /mapop set

The documentation for the ktpass tool is really well (surprisingly well?) documented, but there are only a few key parameters that need to be set.


ParameterDescription
/princThe SPN of the application.
/mapuserThe samAccountName of the identity in Active Directory.
/passThe password that will be used — note that the tool will set the mapuser identity password to this value in Active Directory.
/cryptoThe list of encryption algorithms that will have entries generated.
/ptypeThe type of principal.

Using the above sample as a template will generate a keytab file that is compatible with Kerberos.NET.