At my current gig we use IdentityServer to help us manage security for our API. Our aim is to run quite a few virtual machines in the cloud, so pricing is key. Linux machines are much cheaper than Windows boxes, so getting the IdentityServer running happily on Mono is crucial.
Requirements
This blog assumes you are running a Debian based Linux distro. This example specifically is using Debian/Jessie. The concepts should easily translate though to other distributions including Ubunutu.
For quick iterations, I would also recommend running a local VM via Vagrant or Docker. It makes testing from scratch much easier. (Make sure to open up port 44319 if you go down this route!)
Installing Mono
Installing Mono can be surprisingly tricky. The package references change from time to time. The following works at the time of the blog posting:
# Installing Mono 4.0.4 | |
sudo apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF | |
echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list | |
echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list | |
sudo apt-get update | |
sudo apt-get install -y mono-devel ca-certificates-mono fsharp nuget curl unzip git |
vagrant@vagrant-debian-jessie:~$ mono --version Mono JIT compiler version 4.0.4 (Stable 4.0.4.1/5ab4c0d Tue Aug 25 23:11:51 UTC 2015) Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com TLS: __thread SIGSEGV: altstack Notifications: epoll Architecture: amd64 Disabled: none Misc: softdebug LLVM: supported, not enabled. GC: sgen
Installing DNX (beta7)
Use the following (taken from the Docker repo) to install DNX beta7:
(Run each command as root)
export DNX_VERSION=1.0.0-beta7 | |
export DNX_USER_HOME=/opt/dnx | |
mkdir -p /opt/dnx | |
curl -sSL https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | DNX_USER_HOME=$DNX_USER_HOME DNX_BRANCH=v$DNX_VERSION sh | |
bash -c "source $DNX_USER_HOME/dnvm/dnvm.sh && dnvm install $DNX_VERSION -a default && dnvm alias default | xargs -i ln -s $DNX_USER_HOME/runtimes/{} $DNX_USER_HOME/runtimes/default" | |
export PATH=$PATH:$DNX_USER_HOME/runtimes/default/bin |
root@vagrant-debian-jessie:~# dnx --version Microsoft .NET Execution environment Version: 1.0.0-beta7-15532 Type: Mono Architecture: x64 OS Name: Linux
Installing libuv
Libuv is the node.js asynchronous I/O library that Kestrel is based off of. Kestrel needs this to serve the IdentityServer over HTTP.
(Run each command as root)
apt-get -qqy install autoconf automake build-essential libtool | |
export LIBUV_VERSION=1.4.2 | |
curl -sSL https://github.com/libuv/libuv/archive/v${LIBUV_VERSION}.tar.gz | tar zxfv – -C /usr/local/src && cd /usr/local/src/libuv-$LIBUV_VERSION && sh autogen.sh && ./configure && make && make install && cd ~ && rm -rf /usr/local/src/libuv-$LIBUV_VERSION && ldconfig |
Installing IDP
We are going to take a simple example from the IdentityServer Samples repo and start it up. There are a few minor changes that need to be made, so make sure to read the last section before trying to start the identity server.
(Run as root)
mkdir -p /var/lib/dnx/idp3 | |
cd /var/lib/dnx/idp3 | |
git clone https://github.com/IdentityServer/IdentityServer3.Samples.git | |
cd ./IdentityServer3.Samples/source/AspNet5Host/src/IdentityServerAspNet5 | |
dnu restore |
Now we need to edit project.json to add the Kestrel package and a command to run Kestrel.
Add a dependency for Kestrel so that your dependencies look like this:
"dependencies": { "Microsoft.AspNet.Server.Kestrel": "1.0.0-beta7", "Microsoft.AspNet.Server.IIS": "1.0.0-beta7", "Microsoft.AspNet.Server.WebListener": "1.0.0-beta7", "Microsoft.Owin": "3.0.1", "Microsoft.AspNet.DataProtection": "1.0.0-beta7", "Microsoft.AspNet.Owin": "1.0.0-beta7", "IdentityServer3": "2.0.1" },
Also add a command to start Kestrel so that your commands look like this:
"commands": { "web": "Microsoft.AspNet.Hosting --config hosting.ini", "kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:44319" },
Finally we need to edit Startup.cs.
using Microsoft.AspNet.Builder; using Microsoft.Framework.DependencyInjection; using System.Security.Cryptography.X509Certificates; using IdentityServer3.Core.Configuration; using Microsoft.Dnx.Runtime; namespace IdentityServerAspNet5 { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddDataProtection(); } public void Configure(IApplicationBuilder app, IApplicationEnvironment env) { var certFile = env.ApplicationBasePath + "/idsrv3test.pfx"; var idsrvOptions = new IdentityServerOptions { Factory = new IdentityServerServiceFactory() .UseInMemoryUsers(Users.Get()) .UseInMemoryClients(Clients.Get()) .UseInMemoryScopes(Scopes.Get()), RequireSsl = false, SigningCertificate = new X509Certificate2(certFile, "idsrv3test") }; app.UseIdentityServer(idsrvOptions); } } }
I changed the path for the pfx file so that Linux was happy with it, and I added the RequireSsl flag to make testing easier up front. You’ll of course want to take this out later!
Running the IDP
Finally we are ready to start the identity server.
Simply run dnx kestrel and you should be set!
root:/var/lib/dnx/.../IdentityServerAspNet5# dnx kestrel
You can now browse to http://localhost:44319 to see the welcome page of the application.
Did you get an API consumer working on Mono with app.UseOpenIdConnectAuthentication ?
We have a Web API on DNX beta7 that works with the IdentityServer. Currently we’re doing more or less the following:
We are consuming the JWT’s server side and doing some manual work around processing them. We’ve had to roll our own XYZ several times because of issues with Mono.
Hope that helps?
Ah you’re using DNX. I’m pretty new to IdSrv, how does your WebAPI know where to connect to your IdSrv service? I don’t see it in your UseOAuthBearerAuthentication MW
We have a single page application so we’re sending users that aren’t authenticated over to the IDP on the front end (via Javascript). Then after they login, a bunch of redirects happen and eventually we have a JWT we can process and use.