powershell, ADFS, MFA, authentication comments edit

Building and deploying a custom ADFS external authentication provider can be tedious. In this post, we will address these concerns by creating automated build and deploy scripts with Powershell. This post will not go into the details of how to create an ADFS external authentication provider. You can read about custom ADFS authentication providers in detail via the following excellent blog posts:

Getting Setup

The full source for the code used in this post is available on Github.

I’m developing this with Visual Studio 2015 (VS 2012 should be OK), targeting .NET Framework 4.5, and I’m using Powershell v5 (although Powershell v3 or higher should be fine).

Goals

  1. Automatically sign all assemblies that could be referenced by our provider. All assemblies must be signed so that they can be installed into the GAC on the ADFS server. If this is not done, our provider will not be able to locate the referenced assemblies. The assembly signing process should occur on every build of our provider.

  2. Allow for a developer to deploy the provider to the ADFS server with zero manual steps. This is very important!. As far as I know, there is no way to remotely debug a custom provider. So, for us developers of these providers, we must make our code changes locally, deploy them to our test ADFS server, and then observe (not debug, just observe) our changes. This is an incredible annoyance and is also a serious detriment to productivity. As a result, I really want the developer to be able to rapidly deploy and enable the custom provider to speed up their dev time and to stay sane. I will detail the various steps that I think make up a full deploy a bit further on in this post.

Deployment must be fast and thorough to keep developers productive (and sane)

What Constitutes a Full Provider Deployment?

The following are described as if they are happening on the ADFS server.

  1. Disable any currently installed instances of the provider
    • Attempting to remove an enabled provider via Powershell will throw errors and not work
  2. Remove the provider from ADFS
  3. Remove the provider’s assembly and dependent assemblies from the GAC
  4. Delete all provider files (.dll’s, built artifacts, etc)
  5. Copy newly built provider files from developer computer
  6. Add the provider’s assembly and dependent assemblies to the GAC
  7. Add the provider to ADFS
  8. Enable the provider in ADFS
  9. Ensure relevant ADFS windows services are up and running.

After a full deployment, the developer should merely have to refresh the browser in which they are testing their website in order to be exposed to their latest changes to the provider.

Step 1 - Assembly signing

I’ve added a NuGet package to the project to get a 3rd party assembly reference, specifically the Twilio package because sending SMS messages during the custom authentication processes could occur. Adding the Twilio NuGet package to the provider project will install two assemblies, Twilio.Api.dll and RestSharp.dll - but they are not signed assemblies! Because our provider’s assembly is signed, it can only use/reference other signed assemblies. To get around this, we can disassemble the 3rd party assemblies, sign them, and recompile them (see: Signing an Unsigned Assembly).

This can be accomplished a number of different ways, but I think that a Post-Build event in the provider project is an ideal method. This assures that all assemblies will be signed when a developer does a build from within Visual Studio or if a sys admin does a full deploy and MSBuild is manually used to build the provider project.

Let’s start with a batch file and project Post-Build event. Add a postbuild.bat file to the provider project, and add this Post-Build event:

call "$(ProjectDir)postbuild.bat" $(TargetDir)

Here are the contents of postbuild.bat

set targetdir = %1

# First create all the strong key file
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\sn.exe" -k %targetdir%Twilio.Api.snk
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\sn.exe" -k %targetdir%RestSharp.snk


# decompile the DLLS to IL so we can add strong names
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\ildasm.exe" /all /out="%targetdir%Twilio.Api.il" %targetdir%Twilio.Api.dll
"C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\ildasm.exe" /all /out="%targetdir%RestSharp.il" %targetdir%RestSharp.dll

# delete the dll files so we can compile them
del  %targetdir%Twilio.Api.dll /F /Q
del  %targetdir%RestSharp.dll /F /Q

#recompile the dlls with strong names
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" /dll /Resource=%targetdir%Twilio.Api.res /out=%targetdir%Twilio.Api.dll /Key=%targetdir%Twilio.Api.snk %targetdir%Twilio.Api.il
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ilasm.exe" /dll /Resource=%targetdir%RestSharp.res /out=%targetdir%RestSharp.dll /Key=%targetdir%RestSharp.snk %targetdir%RestSharp.il

#cleanup

@echo off
pushd %targetdir%
for /f %%F in ('dir /b /a-d ^| findstr /vile ".dll .Resources.resources .config"') do del "%%F"

Building the project will now get our assembly signing job done. However, this approach has the downside of not being generic. If a developer adds another NuGet package or assembly reference, they would have to update the postbuild.bat file accordingly. That’s not cool. We can convert this postbuild action to Powershell and make it better.

postbuild.ps1

[Cmdletbinding()]
param(
	[string]$targetdir,
	[string]$providerAssemblyName
)

# Disassemble, sign, and recompile all 3rd party assemblies
Get-ChildItem -Path $targetdir -Include *.dll -Recurse | Where-Object {	$_.Name -ne "$($providerAssemblyName).dll"} |
Select-Object -ExpandProperty FullName | Format-DllPaths | Invoke-Sn | Invoke-Ildasm | Invoke-Ilasm > $null

#cleanup
Remove-Item -Path "$($targetdir)*" -Exclude *.dll,*.Resources.resources -Recurse -Force > $null

I’ve omitted the implementation of the functions used above, but you can view the full source on Github. With this new Powershell script, we can change our Post-Build event to now be this:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -file "$(ProjectDir)Scripts/postbuild.ps1" $(TargetDir) $(ProjectName)

Step 2 - Deployment

The Powershell scripts for the deployment make use of Powershell Remoting, so make sure that is set up beforehand. I’m not going to post all of the scripts’ contents here (somewhat lengthy), but please [feel free to look over them on Github][https://github.com/ryanwischkaemper/adfs-mfa-provider/tree/master/DemoAuthenticationProvider/Scripts/ADFSProviderPublisher]. They cover and satisfy the goals that I laid out earlier, as well as the various steps that constitute a full deployment. Of course, there is always room for improvement, and I eagerly welcome feedback. Also, the scripts only target a single server, but they could fairly easily be adapted to target multiple servers.

Using these scripts, a developer can quickly configure a target ADFS server (and several other related config params) in the Publish-AuthProvider.ps1 file and then execute that same file to quickly and entirely deploy their provider! Hope this helps out with your workflows when developing these things.

aurelia, nodewebkit, nw.js, ES6, gulp comments edit

This is the second post regarding creating a nw.js (node-webkit) app with Aurelia. The first post can be found here In this followup post, we will make our aurelia-nw app and its build process production ready. The completed source code is available on GitHub.

I have taken the project where we left off in the previous post (view source here), and I added the content from the Aurelia demo project. I made some minor changes such as using LESS for my styles, moving the styles folder inside the src folder, and updating the gulp tasks respectively. The updated project can now be found here, and it is the starting point for this post.

Creating a Production Release

Goals:

  1. Minify and uglify all Javascript
  2. Minify all HTML/CSS
  3. Use semver to manage versioning
  4. Ensure various production values are set (i.e toolbar: false in our nw manifest properties)
  5. Isolate all release builds from the rest of the codebase, then use node-webkit-builder to compile

Release Arguments

In order to differentiate between a normal (development) build and a release build, I’ll use yargs so that we can do something along the lines of gulp build --release. I’ll also use gulp-bump to increase the app’s version. After installing those packages (npm install yargs gulp-bump --save-dev), add a args.js file in the gulp folder.

gulp\args.js:

var yargs = require('yargs');

var argv           = yargs.argv,
    validBumpTypes = "major|minor|patch|prerelease".split("|"),
    bump           = (argv.bump || 'patch').toLowerCase(),
    isRelease      = argv.release ? true : false;

if (validBumpTypes.indexOf(bump) === -1) {
  throw new Error('Unrecognized bump "' + bump + '".');
}

module.exports = {
  bump: bump,
  isRelease: isRelease
};

Minification

In each of the (relevant)gulp tasks, I will require gulp\args to determine if the build is a release build. Using gulp-if, I will either run the task for release or development. If it is a release build, then all output will be directed to a dist folder. Once it is there, I’ll use node-webkit-builder to compile it.

I won’t go into each library that is used for minification and uglification - they are pretty standard.

Here is the project after these modifications have been made. Running gulp build --release will produce a dist folder with the same structure as the build folder, but everything will be minified/uglified.

Versioning

When I build a production release, I would like the version of the app to be increased using semver. Let’s add a gulp task for that.

gulp\tasks\prepare-release.js:

var gulp        = require('gulp'),
    runSequence = require('run-sequence'),
    args        = require('../args'),
    paths       = require('../paths'),
    bump        = require('gulp-bump');

gulp.task('prepare-release', function(done){
  return runSequence(
    'build',
    'bump-version',
    done
  );
});

gulp.task('bump-version', function () {
  return gulp.src('./package.json')
    .pipe(bump({type: args.bump})) //major|minor|patch|prerelease
    .pipe(gulp.dest('./'))
    .pipe(gulp.dest(paths.dist));
});

This can be called like so: gulp prepare-release --release --bump minor

Prepping the Dist Folder

I want to call node-webkit-builder’s build() on the dist folder, and I want it to look something like this:

|-- app
    |-- app.js
    |-- app.html
    |-- etc..
|-- content
    |--styles
|-- jspm_packages
|-- node_modules
|-- index.html
|-- config.js
|-- package.json

A gulp task can be added to simply copy index.html, config.js, and package.json; but I don’t want to copy all of the node modules and jspm packages. I only want to include the packages that are being used - after all, most of the node packages are used for development only. Let’s add a gulp task for that.

gulp.task('npm-dependencies', function(){
  var buffer, packages, keys;

  buffer = fs.readFileSync('./package.json');
  packages = JSON.parse(buffer.toString());
  keys = [];

  for (var key in packages.dependencies) {
    keys.push('./node_modules/' + key + '/**/*');
  }

  return gulp.src(keys, {base: './'})
    .pipe(gulp.dest(paths.dist));
});

Miscellaneous Production Values

When I release the app, I want some of the NW.js manifest properties to be changed (mainly the display of the toolbar and the frame). I’ll add a gulp task and use gulp-json-editor to do this.

gulp.task('prep-nw-properties', function () {
  return gulp.src(paths.dist + 'package.json')
    .pipe(jeditor(function (json) {

      json.window.toolbar = false;
      json.window.frame = false;

      return json;
    }))
    .pipe(gulp.dest(paths.dist));
});

Building

Once the dist folder is prepped, I’ll build it with node-webkit-builder.

gulp.task('build-release', ['prepare-release'], function(cb){
  var nw = new NwBuilder(config.nwBuilderConfig);

  nw.on('log', gutil.log);
  nw.build(cb);

  return nw;
});

That’s it! At this point, we have a ready-to-release production build alongside a development build. Running gulp build-release --release will produce binaries for each platform that was supplied in a release folder in the project’s root. It’s not perfect right now, but it is effective. I’ll dive into some of the those imperfections in a future post. Here is the source for the project at this point.

aurelia, nodewebkit, nw.js, ES6 comments edit

This is part 1 of a series that outlines creating an nw.js (node-webkit) app with Aurelia. Part 2 can be found here

Set Up a Barebones NW.js App

Since we will be writing all of our Javascript in ES6 format, let’s create a src folder to contain it. When we compile it to ES5 with Babel, we’ll output it to a build folder. Let’s also create a package.json file in our root directory (npm init) for project description and managing node dependencies - this will also contain our nw manifest properties. Here are what the manifest properties look like:

{
  "name": "aurelia-nw",
  "version": "1.0.0",
  "main": "index.html",
  "window": {
  	"title": "Aurelia-NW.js",
  	"toolbar": true,
  	"frame": true,
  	"position": "center",
  	"fullscreen": false,
  	"resizable": true,
  	"always-on-top": false,
  	"width": 1400,
  	"height": 650,
  	"min_width": 600,
  	"min_height": 400
  }
}

For this example, we’ll make use of a library called node-webkit-builder to build and run our app. First, install it via npm install node-webkit-builder --save-dev. Now add a gulpfile.js to our root directory. All of the gulp tasks that we will define can be placed in this one gulpfile.js, but I prefer to break them out into their own files and that is how I will continue on with this example. Create a folder named gulp in the root directory, and create a folder named tasks inside of it. Now install require-dir (npm install require-dir --save-dev), and inside of gulpfile.js add this line:

 require('require-dir')('gulp/tasks');

Inside of the tasks folder, we’ll add run.js and configure node-webkit-builder to run our app (use whichever platform options you need):

var gulp = require('gulp'),
	NwBuilder = require('node-webkit-builder'),
	paths = require('../paths');

gulp.task('run', function(cb){
	var nw = new NwBuilder({
		files: paths.root + '**/**',
		platforms: ['win64'],
		buildDir: paths.temp,
		cacheDir: paths.nwCache,
		version: '0.12.0' // this is the nw.js version we are using
	});

	nw.run(cb);

	return nw;
});

paths.js is just a file where I am storing file path config info. It looks like this

module.exports = {
  root: './',
	src: './src/',
	build: './build/',
	dist: './dist/',
	temp: './temp',
	nwCache: './nwCache'
}

We’ll now add a index.html to our root directory:

<!DOCTYPE html>
<html>
<head lang="en">
	<meta charset="UTF-8">
	<title>Aurelia-NW.js</title>
</head>
<body>
	<h1>Loading...</h1>
</body>
</html>

Now run gulp run, and our nw app will start up for us. The project thus far can be found here.

Add Aurelia

Time to add Aurelia! Make sure jspm is installed (npm install -g jspm), then run jspm init. Choose all of the defaults except for the transpiler - choose Babel for that. In the generated config.js file, edit the top set of options to look like this:

{
  "transpiler": "babel",
   "babelOptions": {
     "optional": [
       "runtime",
       "es7.decorators",
       "es7.classProperties"
     ]
   },
   "paths": {
     "*": "build/*.js",
     "github:*": "jspm_packages/github/*.js",
     "npm:*": "jspm_packages/npm/*.js"
   }
}

Now install Aurelia via jspm. To do this, we’ll copy this section into our package.json (it’s from the Aurelia starter app) and run jspm install -y.

"jspm": {
    "directories": {},
    "dependencies": {
      "aurelia-animator-css": "github:aurelia/animator-css@^0.2.0",
      "aurelia-bootstrapper": "github:aurelia/bootstrapper@^0.12.0",
      "aurelia-dependency-injection": "github:aurelia/dependency-injection@^0.7.0",
      "aurelia-framework": "github:aurelia/framework@^0.11.0",
      "aurelia-http-client": "github:aurelia/http-client@^0.8.1",
      "aurelia-router": "github:aurelia/router@^0.8.0",
      "bootstrap": "github:twbs/bootstrap@^3.3.4",
      "css": "github:systemjs/plugin-css@^0.1.9",
      "font-awesome": "npm:font-awesome@^4.3.0"
    },
    "devDependencies": {
      "babel": "npm:babel-core@^5.1.13",
      "babel-runtime": "npm:babel-runtime@^5.1.13",
      "core-js": "npm:core-js@^0.9.4"
    }
  }

Now configure index.html to load Aurelia:

<body aurelia-app>
	<h1>Loading...</h1>

	<script src="jspm_packages/system.js"></script>
	<script src="config.js"></script>
	<script>
		System.import('aurelia-bootstrapper');
	</script>
</body>

Add a simple Aurelia viewmodel and view.

src\app.js:

export class App {
	title = 'Aurelia via NW.js';
}

src\app.html

<template>
	<h1>${title}</h1>
</template>

The last thing we need to do in order to run this via nw is to compile our ES6 Javascript to ES5. Let’s set up a gulp task to do that.

gulp\tasks\build.js

var gulp = require('gulp'),
	paths = require('../paths'),
	sourcemaps = require('gulp-sourcemaps'),
	plumber = require('gulp-plumber'),
	to5 = require('gulp-babel'),
	assign = Object.assign || require('object.assign');

gulp.task('build-scripts', function(){
	var compilerOptions = {
		modules: 'system',
		moduleIds: false,
		comments: false,
		compact: false,
		stage: 2,
		optional: [
			"es7.decorators",
			"es7.classProperties"
		]
	};
	return gulp.src(paths.src + '**/*.js')
		.pipe(plumber())
		.pipe(sourcemaps.init({loadMaps: true}))
		.pipe(to5(assign({}, compilerOptions, {modules: 'system'})))
		.pipe(sourcemaps.write({includeContent: true}))
		.pipe(gulp.dest(paths.build));
});

gulp.task('build-html', function(){
	return gulp.src(paths.src + '**/*.html')
		.pipe(gulp.dest(paths.build));
});

And if we modify our run task like so:

gulp.task('run', ['build-scripts', 'build-html'], function (cb) { ...

then we can run gulp run and see Aurelia running with NW.js.

The project thus far can be found on here on Github. So far, we have only accomplished the minimum amount of setup to get Aurlia running within nw. In the next post, we’ll set up (and automate via gulp) styles, versioning, tests, production ready builds, and file watching for more rapid development.

bower, node, visualstudio, asp.net comments edit

Modern client side development usually involves working with a large number of open source libraries. jQuery, Angular, Knockout, Meteor, and Backbone are some of the most popular, but more than likely you’ll also want to use a variety of others as well. When pulling these libraries into your project, it’s extremely important to do it in an organized, structured way. If you were to pull a 3rd party C# library into your project, you’d use NuGet because it manages what versions of the library you are going to use and it has a large selection to choose from. While NuGet is great for C# libraries, it is lacking in it’s choice of client side libraries.

Enter Bower

There is a large web development ecosystem that encompasses more than just the .Net world, and one of the most popular client side package managers used in that ecosystem is Bower.

Bower does necessitate having NodeJS installed, so if you haven’t done that yet head over to their download page and run the installer. This post won’t go into detail on how to use bower or node - there are a large amount of tutorials already on the web.

Using Bower, your client side dependencies will be managed much the same as your C# libraries are managed via NuGet.

Create the Solution

Overall Project Structure

I’m using Visual Studio 2013, but VS2012 will work as well. Create a new ASP.Net MVC project, and add a public folder to it. This folder will contain all of our Javascript, CSS, and images - all of which are publicly visible to anyone inspecting our website. Inside of that folder, add a app folder to contain our custom Javascript, a content folder to contain our stylesheets and images, and a vendor folder to contain any 3rd party client side libraries installed via Bower.

Now lets configure Bower to pull in the client side libraries we want. Add a bower.json file to the root of the project. You can do this manually or via bower init from a command prompt. Add the following to bower.json (these will be generated for you if you used bower init) until it looks something like this:


{
  "name": "AngularApp",
  "version": "1.0.0",
  "authors": [
    "Ryan Wischkaemper"
  ],
  "description": "A basic AngularJS app"
}

Next, add a .bowerrc file to the root of the project. We’ll put on line of JSON in this file:

{
  "directory": "public/vendor"
}

This tells Bower where to install the libraries we want. If this file is excluded or no directory is set, the installation directory will default to bower_components. Now lets install our first Bower package. Open a command prompt to the root directory of the project, and run bower install -save angular. When it finishes, check your bower.json file and notice how angular was added in a newly created dependencies section. Continue to do this with any client side libraries you want. For this project, my bower.json looks like this:

{
  "name": "AngularApp",
  "version": "1.0.0",
  "authors": [
    "Ryan Wischkaemper"
  ],
  "description": "A basic AngularJS app",
  "dependencies": {
    "fontawesome": "~4.3.0",
    "angular": "~1.3.13",
    "bootstrap": "~3.3.2",
    "moment": "~2.9.0",
    "angular-animate": "~1.3.13",
    "toastr": "~2.1.0",
    "lodash": "~3.2.0",
    "angular-bootstrap": "~0.12.0",
    "angular-route": "~1.3.13"
  }
}

Source code for this demo is available on Github

At this point, you could use the ASP.Net bundling system to bring your Bower libraries into your Razor pages. An alternative is to automatically include your Bower libraries via an automated task runner such as Gulp or Grunt.