We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Security, Identity and Authorization in ASP.NET 5

00:00

Formal Metadata

Title
Security, Identity and Authorization in ASP.NET 5
Alternative Title
A run around the new ASP.NET Data Protection - Authorization Stacks
Title of Series
Number of Parts
133
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
With the advent of ASP.NET v5 we’ve taken the opportunity to throw away the old, bad things and drag code kicking and screaming into 2015. We killed [Authorize(Users=)] and replaced it with something more flexible and more configurable. We switched to claims everything. We finally got rid of machine key as well, and have replaced it with something that rotates keys, syncs cross instances of Azure websites and could even use an NTFS share or a database as a key store. By the end of this session you should be prepared to bring in the new and improved bits to help you security your apps in a more flexible and testable way.
36
61
Thumbnail
1:11:04
73
107
WeightInformation securityApplication service providerAuthorizationIdentity managementSoftware developerKey (cryptography)Coding theoryVirtual machineLimit (category theory)Rule of inferenceWritingExpressionMachine codeSynchronizationPoint cloudPhysical systemDefault (computer science)ArchitectureInstance (computer science)Information securityBitWeightSoftware repositoryData storage deviceVideo gamePresentation of a groupDemo (music)Default (computer science)Computer fileSynchronizationServer (computing)Exterior algebraMultiplication signMathematicsWeb 2.0Information privacyOperating systemKey (cryptography)LoginFilesharing-SystemApplication service providerLink (knot theory)TwitterWebsiteConfiguration spaceCore dumpVirtual machineAxiom of choiceDecision theorySurfaceCuboidGame controllerMachine codeHTTP cookieCartesian coordinate systemMultiplicationRemote procedure callAuthenticationInstance (computer science)Computer architectureAuthorizationImplementationFigurate numberComa BerenicesTraffic reportingWindowInternet service providerPoint cloudGroup actionCoefficient of determinationPhysical systemIdentity managementProjective planePlanningComputer animation
Software developerVideo game consoleWritingoutputString (computer science)Computer wormSampling (statistics)BitEncryptionRevision controlInternet service providerData miningComputer configurationMachine codeSemiconductor memoryKey (cryptography)Sign (mathematics)Different (Kate Ryan album)Electronic signatureMathematicsComa BerenicesInformation privacyUnit testingDerivation (linguistics)outputComputer wormSurfaceComputer animation
Software developerLine (geometry)Machine codeDefault (computer science)Data modelForm (programming)MathematicsWeb 2.0Internet service providerString (computer science)CiphertextLine (geometry)Sampling (statistics)Machine codeDemo (music)Game controllerSoftware testingVideo gamePhysical systemForcing (mathematics)Revision controlParameter (computer programming)Discrete element methodString (computer science)Computer animation
Form (programming)Derivation (linguistics)String (computer science)Software developerRevision controlSpacetimeEuclidean vectorInformation securityToken ringoutputConfiguration spacePhysical systemKey (cryptography)Control flowDefault (computer science)AlgorithmEncryptionComputer wormVideo game consoleStructural loadExpressionElectric currentUser profileWindows RegistryProcess (computing)Virtual machineMobile appSynchronizationRead-only memoryKey (cryptography)Insertion lossUser profileDefault (computer science)EncryptionDirectory serviceFile systemNamespaceIntrusion detection systemWeb 2.0Canonical ensembleGoodness of fitoutputCartesian coordinate systemQuicksortMobile appData centerException handlingProfil (magazine)Message passingData storage deviceVirtual machineApplication service providerWindows RegistryInstance (computer science)Computer fileScripting languageSoftware bug2 (number)Parameter (computer programming)WindowString (computer science)Revision controlConnectivity (graph theory)AlgorithmPhysical systemForm (programming)Type theoryAuthenticationView (database)Video game consoleSampling (statistics)Computing platformInterface (computing)Ring (mathematics)Moving averageMechanism designMathematicsComputer wormIdentifiabilityMultiplication signLengthBefehlsprozessorGastropod shellCASE <Informatik>Power (physics)Proof theorySoftware testingUniform resource locatorBlogInternet forumShared memoryWeightDifferent (Kate Ryan album)Computer animation
Software developerKey (cryptography)Information privacyCASE <Informatik>File systemWindowPattern languagePlanningFigurate numberCore dumpKey (cryptography)WeightInternet service providerWindows RegistryIntegrated development environmentServer (computing)Configuration spaceSynchronizationFood energyWeb 2.0Point cloudPublic key certificateBitComputer fileDirectory serviceComputer animation
Internet service providerConfiguration spaceSoftware developerPublic key certificateEncryptionKey (cryptography)Machine codeCryptographyIntegrated development environmentMechanism designMobile appData storage deviceWritingComputer fileComputer filePattern languageKey (cryptography)Cartesian coordinate systemPublic key certificateInformation privacyInternet service providerServer (computing)Virtual machineApplication service providerDirectory serviceWeb 2.0Sampling (statistics)IdentifiabilityWindowMultiplication signData storage device9 (number)Software testingLimit (category theory)Goodness of fitNormal (geometry)Level (video gaming)PasswordMultiplicationWindows RegistryShared memoryPhysical systemRing (mathematics)Information securitySocial classRoutingInterface (computing)Hecke operatorImplementationBlogChemical equationPoint (geometry)Default (computer science)Machine codeMobile appElectronic program guidePoisson-KlammerCASE <Informatik>Sign (mathematics)AuthenticationHTTP cookie2 (number)Meta elementFilesharing-SystemRootComputer animation
Software developerVirtual machineAlgorithmPoint (geometry)Application service providerWeightSocial classForm (programming)Configuration spaceInformation securityPrice indexAuthenticationHTTP cookieInteractive televisionWeb browserClient (computing)AuthorizationWeb 2.0Coma BerenicesAlgorithmPoint (geometry)Computer wormEncryptionDefault (computer science)HTTP cookieOperator (mathematics)Key (cryptography)Virtual machineQuicksortInformation securityIdentity managementCryptographySystem administrator1 (number)Software developerWindowCartesian coordinate systemCASE <Informatik>Form (programming)Gastropod shellMachine codeWeightDiagramWeb pagePower (physics)MereologyMultiplication signInterface (computing)Functional (mathematics)WebsiteConfiguration spaceShared memorySoftwareWritingDifferent (Kate Ryan album)Information privacyGame controllerBitAttribute grammarLimit (category theory)Application service providerAuthenticationMiddlewareHacker (term)Internet service providerRotationRight angleLastteilungLoginExtension (kinesiology)Computer animation
Numbering schemeComputer configurationAuthenticationLoginAuthorizationHTTP cookieWeb pageWritingCartesian coordinate systemAuthenticationSingle-precision floating-point formatConfiguration spaceCross-site scriptingMobile appComputer configuration3 (number)Hecke operator1 (number)Forcing (mathematics)Computer animation
Identity managementFlagPrincipal idealTexture mappingTransformation (genetics)Software developerIcosahedronIdentity managementMachine codeMappingPrincipal idealObject (grammar)Social classTransformation (genetics)Category of beingType theoryLoginPeer-to-peerBitPlanningOperator (mathematics)Single-precision floating-point formatAuthenticationRoundness (object)Set (mathematics)MiddlewareDivisorHookingComputer animation
Transformation (genetics)Software developerAuthorizationNP-hardCoding theoryAuthenticationSound effectIdentity managementMultiplication signTransformation (genetics)Attribute grammarWordAuthorizationMathematicsAuthenticationGame controllerRule of inferenceToken ringHTTP cookieDirectory serviceWindowType theoryElectronic mailing listMachine codeRight angleDecision theoryImplementationCategory of beingDemo (music)Performance appraisalWeb 2.0Goodness of fitComputer animation
AuthorizationComputer configurationInternet service providerSoftware developerContext awarenessComputer iconData typeParameter (computer programming)System administratorMereologyCombinational logicProjective planeEntire functionMultiplication signPerformance appraisalDependent and independent variablesApplication service providerConfiguration spaceMaxima and minimaInterface (computing)Type theorySocial classInternet service providerSlide ruleAuthorizationElectronic mailing listMachine codeBitExistenceLogical constantContext awarenessCASE <Informatik>Attribute grammarConfidence intervalComputer animation
Software developerContext awarenessPerformance appraisalAuthenticationPerformance appraisalContext awarenessSingle-precision floating-point formatDatabaseOrder (biology)Presentation of a groupPower (physics)Point (geometry)MultiplicationComputer animation
Software developerContext awarenessSpacetimeOvalContent (media)Line (geometry)Data typeString (computer science)FreewareImpulse responseImperative programmingMenu (computing)AuthorizationOrdinary differential equationInternet service providerView (database)MultiplicationGraph coloringWeb pageResultantFunctional (mathematics)Group actionGame controllerAttribute grammarSocial classInformation securityAuthorizationOperator (mathematics)Application service providerMachine codeNumberCountingType theoryAddress spaceView (database)EmailInstance (computer science)GoogolPatch (Unix)Software repositoryRule of inferenceBitDemo (music)Goodness of fitInternet service providerPresentation of a groupVisualization (computer graphics)Imperative programmingJackson-MethodeInjektivitätClassical physicsScripting languageCASE <Informatik>Endliche ModelltheorieDirected graphGame theorySoftware testingMathematicsFacebookPay televisionAuthenticationCopyright infringementLogic gateLoginComputer animation
Software developerAuthorizationOperations researchSystem administratorMilitary operationFluid staticsReading (process)Context awarenessOperator (mathematics)Type theorySystem administratorCombinational logicAuthorizationFunctional (mathematics)Attribute grammarQuicksortPhysical systemSystem callGroup actionSocial classReal numberCoefficient of determinationLibrary (computing)Multiplication signCategory of beingDifferent (Kate Ryan album)Surjective functionComputer animation
Software developerAuthorizationData typeOvalContext awarenessIdentity managementView (database)Machine codeMultiplication signMathematicsBitResultantSampling (statistics)Demo (music)Game controllerContext awarenessLevel (video gaming)Computer animationSource code
Software developerAuthenticationNumbering schemeLimit (category theory)Token ringData modelView (database)AuthorizationWeb 2.0AuthenticationPoint (geometry)Game controllerNumbering schemeException handlingMultiplicationDifferent (Kate Ryan album)Information securityFigurate numberToken ringSampling (statistics)Vulnerability (computing)Goodness of fitSubsetApplication service providerProjective planeMobile WebType theoryComputer animationSource code
Software developerWeightApplication service providerData typeAuthenticationSample (statistics)AuthorizationRule of inferenceElectric currentHTTP cookieDifferent (Kate Ryan album)Sampling (statistics)CuboidIdentity managementPasswordVideo gamePoint (geometry)Token ringSystem callComputer animation
Software developerAuthenticationNumbering schemeLimit (category theory)Token ringComputer configurationAuthorizationInternet service providerOvalChemical equationIdentity managementHTTP cookieNumbering schemeCategory of beingAttribute grammarCASE <Informatik>Product (business)AuthenticationBoss CorporationMultiplicationLine (geometry)Machine codeOffice suiteAuthorizationComputer animation
WeightApplication service providerKeyboard shortcutSoftware developerVariable (mathematics)Integrated development environmentControl flowDefault (computer science)TouchscreenKey (cryptography)Data storage deviceSampling (statistics)Semiconductor memoryIdentity managementCASE <Informatik>Coma BerenicesHoaxDisk read-and-write headWeb 2.0GoogolRevision controlIntegrated development environmentVariable (mathematics)Decision theorySoftware developerCartesian coordinate systemFigurate numberMereologyGame controllerRotationBitQuicksortView (database)Attribute grammarSoftware frameworkEndliche ModelltheorieField (computer science)Lie groupEmailBlogPoint (geometry)Right angleSequelMathematicsSynchronizationInternetworkingConnected spacePresentation of a groupSocial classSensitivity analysisAuthorizationToken ringContext awarenessVirtual machineInformation securityMachine codeProcess (computing)Power (physics)Link (knot theory)Slide ruleVery-high-bit-rate digital subscriber lineError messageCross-site scriptingTouchscreenSubject indexingDefault (computer science)Information privacyForm (programming)WritingValidity (statistics)Application service providerMilitary baseDependent and independent variablesLatent heatShared memoryGoodness of fitDrop (liquid)Tracing (software)Storage area networkComputer animation
Transcript: English(auto-generated)
Thank you for coming. My name is Barry Dorans. I am the ASP.NET and the .NET Core security person, along with various bits of Azure and other things that get dumped on my lap to generally make me unhappy. I tweet as at blowdart.
It is not a very technical Twitter account. There are people in the room that know me. They will bear this out. It will usually be ranting, swearing, and posting cartoons and the odd picture of my doc. My website is idunno.org. It will have links to the presentation and to the GitHub repos that contain
the awful, awful demos. My GitHub repo also has a workshop that I gave yesterday morning that takes you through the new authorization pieces, which have step-by-step instructions, which will probably make more sense than this presentation.
So some of you were in Dominic's session, which was the previous session to this in room two. And he has covered the new authentication pieces. I am going to ignore that, because we didn't change much. And so it's not as exciting for me as the new stuff
that we've done. I am going to talk about data protection. And I am going to talk about authorization. Two things where we took what we had before, threw them out the window, gave no real nod to backwards compatibility, and rewrote everything to make your life more difficult. Because we like doing that. It makes you feel more technical when
you have to rewrite your code. So I'm going to cover the changes that we've made. I'm going to show you how to use them. And hopefully by the end of the day or the end of the session, you will be able to write code for our new APIs. So first up is data protection. How many of you have had to synchronize machine keys
with web.config across multiple machines? I am really sorry. Machine keys seemed like a great idea five years ago. It is not a great idea. It should never have been done like that.
But we didn't have much alternative at the time. So we've thrown away machine key because it's really hard to synchronize things across multiple servers and change them all at the same time. Because it was really hard, people would not rotate their encryption keys. And that is generally a bad idea.
If you go onto GitHub and search for machine key or web.config and machine key, you will find that people check their machine keys into GitHub. And once I have your machine key, I basically have remote code execution on your application. I can also forge your login cookies
so I can pretend to be whoever I want in your application. So machine keys were meant to be a secret, but they were stored in plain text, in a configuration file, in your project, so they never remained secret for that long. So we've thrown them away. And we have replaced all the machine key APIs
with a data protection stack. Now, the data protection stack is generally aimed at transient data, things that you don't care about if it gets lost. However, with a little work, you can use it for permanent data as long as you implement a permanent key store. And we give you a couple of implementations
of that that we'll come onto as I go along. So we have a key store where we create keys for you. And when we create keys, we will rotate keys for you. The default for the key store is the file system, and it actually works off file shares as well. So if you are in a web farm, you can have a machine that holds all your keys,
and you share them via Windows, and you point all your other machines in the web farm to this key store. And lo and behold, it all magically works. We protect the keys based on the operating system that you are running. So we will detect the scenarios that you are running in,
and we will choose the most appropriate protection for you. You can always override it, but we try and do the best one possible that we know about. If you store things in the cloud, you're going to have to configure the protection yourself. Because we don't know enough about your architecture in the cloud, because we're isolated from it,
and you're going to have to do a little bit of work, and we'll come onto that in a minute. So using data protection, you create an instance of an IData protection provider, and we provide a bunch of them out of the box. And through the magic of DI everywhere in ASP.NET 5, that's actually done for you, and you can inject that into your controllers or anything that you have registered with the DI system,
and it will magically appear. From your data protection provider, you will create a data protector. This is the thing that does the work. And to protect things, you call protect. And to unprotect things, you call unprotect. That's it. There are two methods. You can't really go wrong with two methods.
We took the decision with this and with a bunch of other things we've done in ASP.NET that the API surface is a security feature. It has been too easy for far too long for you to use some of our APIs to do the wrong thing. So we are removing a lot of choice from you,
so we will do the right thing for you by default. You can override some of our decisions, but not all of them. So here we have a little bit of sample code. The sample code is all up in GitHub with working samples. They weren't working last week because I had updated to the latest version of things
and we broke things again. We have been breaking things a lot recently, but it should be settled down by now. The API surfaces will not change. So I am creating a data protection provider and I'm creating the ephemeral one, which is the one that we use for unit tests. It puts all the keys in memory and then throws them away again once we're done.
From that data protection provider, I am creating a protector. I am taking some input. I'm calling protector.protect, and I get a bunch of payload out and I'm calling protector.unprotect to get it back again. Nice and simple. You don't need to worry about keys anymore.
We create them for you. We isolate them. We do subkey derivation to create a different encryption key and a different signing key. You don't even need to worry about signing. We will always encrypt and sign for you using authenticated signatures, which is something that we didn't used to do. We gave you the option to just do encryption
without signing, and that's an incredibly dumb idea. And so we've stepped back from that. So now you will see exciting samples. It's kind of hard to write an exciting sample for four lines of code, especially when all it does is protect and unprotect.
But the samples are there on GitHub, and it's all linked to, and you can see how to use it in real life. So if I go test, protect, and then I have a bunch of encrypted and signed data, and I click unprotect, and lo and behold, I get test back, just as you would expect. And that's about as exciting as my demos are going to get for the day,
because at the end of this, this is all infrastructure, and it's kind of hard to make exciting infrastructure demos. So nice and simple. We can go look at the code. I can go to my controller. And if I pop down here, we have an IDataProtector,
and it's being shoved into our system via the magic of DI. And then if I scroll down, I create a protector. And lo and behold, I create an unprotector. Yes, it's slightly more than four lines of code, but that's what MVC forces me to do.
There are command line versions of this, which are literally four lines of code. So when you create a protector, there is one parameter that you must provide, and we do not do it for you. It is called a purpose string. And a purpose string is a way that we isolate encryption keys
and signing keys within your application from each other. So the way the key system works is we create a master key, and then when you create a new purpose, we take that purpose and we munch it with the master key. We perform all sorts of magic to derive a subkey from it,
and then we use that. So the canonical example in ASP.NET comes from web forms. The encryption key that was used for forms authentication is entirely different to the encryption key that is used for view state. And the way that we did that is we provided the purpose, and that purpose then feeds into machine key,
and we derive subkeys from it. So you need to choose good purpose strings. And what we generally suggest that you do is you take the namespace and type name of the component that is going to use the data protector, and then stick a version ID on the end because we like version IDs.
You should never, ever base your purpose strings solely on user input because then the user can insert something bad and try and decrypt things for a different purpose. So that's what we don't want you to do. So don't do that. Next question that usually comes up
is how do I control the keys? How do I get access to the keys? You don't. They're not for you, you naughty people. We are going to do all of this for you. We will create keys. We will control and accl the keys. We will rotate them, and we will expire them all automatically for you. All you can do is configure the intervals
at which we create new keys. That's it. Because if you start wanting to have access to the keys, then there's the risk that you can't control the keys properly, and you dump them out in an exception message and all sorts of other things. So we have taken that from you, and you just have to trust us that we're doing the right thing.
We have a bunch of algorithmic defaults, and we chose what we figured was a good compromise by default. Yes, we could have gone for an enormous key length, but the algorithms that we are using don't particularly require enormous key lengths. So rather than waste the CPU time
on generating a 496-bit key, we provide a 512 one. We roll it every three months. And the way that rolling works, especially in web farms, is one of the instances of the web farm will wake up and go, hey, this key's about to expire in about a week. I'm going to generate a new one.
It dumps it into your shared directory and then just starts encrypting and signing things with this new key. And when all the other instances get this coming in, every single payload has a key identifier in it. They go, we don't know what this key identifier is. Therefore, we're going to refresh our key ring. It will load the new keys. And if by magic, everything works.
And we have tested this for a change. I know that certainly some of the beta stuff we threw out quite quickly. But we tested this by setting up 48 instances of IIS, setting the key rolling defaults to one hour, and then just sending fiddler at them just
to see what happens. And it worked. So I'm pretty confident that our key rolling mechanisms will work. As some of you may know, Azure has not been that wonderful about rotating encryption keys and has caused downtime, not this year or last year, but the year before. And that was all very embarrassing. So we've tried very hard to make this foolproof for you.
Each individual key is saved as an individual file in the key ring. So we don't need to worry about file locking. And it just all happens magically. You can override the defaults. You can't make them weaker.
You can only make them stronger. So like I say, where the key stores are is very dependent on platform. But you can create your own. We provide interfaces for that, and it's reasonably simple. We have samples where you can put things in Azure Blob Storage. If you are working for a bank, you may want to use your HSM to store the keys.
You can write them against HSMs. We've tested that against some failed stuff. So default key store locations, if you are running underneath IIS Express, which is what you're doing in dev, or you're running against normal IIS with the user profile loaded, which is not normal, or you're running in a console app because all of this works in console apps,
then we will store keys in your app data folder and use Windows DP API to protect the keys. If you don't have a user profile loaded and you haven't coded it to use a file share, you can run a PowerShell script because there's a little tiny bug in the way
that we're doing things with IIS. And the PowerShell script will set things up so stuff gets stored in the registry. It's very hard to back up the registry. When I talk about all of this, I recommend that you use the file system. If you're in Azure Web Apps, we actually use the file system and there's a special folder in Azure Web Apps
that they developed just for us. And so the keys will get dumped into this folder and then they magically run around all the Azure data centers and propagate themselves around. So you have it running in Dublin, and your Dublin instance creates a new key and it will pop up in Australia in under a second, which is very nice.
Otherwise, we have ephemeral keys which are stored in memory that get thrown away when your application stops. So if you want to use this for persistent data, you need to make sure you are using a persistent key store. For Linux and Mac OS, we store them in the profile directory.
So you need to make sure that your profile directory is ackled appropriately. On Windows, we know app data is ackled appropriately. On Linux, all bets are off, unfortunately, and you need to do that work for yourself. Woo. So the keys are dumped on the file system
where the keys are stored in the registry. If they're on the file system, we need to actually protect them in a certain way. So on Windows, we have DPAPI. We have DPING if you're in an Active Directory environment, although why you want to put your web servers in an AD environment, I honestly have no idea.
But that's actually quite nice because the DPAPI keys will roam via AD, so you will get key synchronization with no work whatsoever. Or you can use a good old X.509 certificate. And that's what we recommend on Linux, on Mac OS, or in the cloud. Eventually, it will work on Linux and Mac OS,
but the .NET core people haven't quite implemented that one tiny important bit. They promised me it will be there in RC2. We will see. Or if you're feeling, you know, I'm going to throw caution to the wind, you can opt to have your keys dumped on the file system
in plain text. Don't do that. So here we have how we configured data protection. If you've messed around with all the ASP.NET V5 stuff, you will recognize the pattern of how to configure things. We are adding data protection to our services collection, and then we are configuring it.
And in this example configuration, we are persisting keys to the file system, and I'm showing that you can run it on a remote server. We are protecting keys with a certificate, and I am providing the thumbprint of the certificate. And then we have this application name thing. So if you are on a single machine and they all share the same directory,
every single application is also isolated from each other by this concept of an application name. If you want to use X.509, and trust me, you do, you can use self-signed certs. We honestly don't care. If you want to have them load automatically,
they must be in your trusted root store, and that can be the root store for an individual user. That's absolutely fine. We don't have to put them in at a machine level because that's an interesting security problem. But the certificates must be trusted, or you can load them from a PFX file, which means you're now hardcoding a password in your code.
So that's not generally a good idea, but it's certainly possible. And the certificates must be valid. They must not be passed their expiry ID. I did? Expiry ID. I'm running ahead of myself now. We honestly do not care about the purpose or the OAID of the certificate. So you can use a normal self-signed cert
that you would use for your testing. For decrypting, there is a limitation in the XML classes. We are using XML to store our keys, because XML has built-in encryption, and JSON does not. And I much prefer less than and greater than signs to curly brackets. So to decrypt, your certificates
must be in the certificate store. It doesn't matter if your X.509 certificate has expired. All the system will do in the case of expiry is it will go, well, this is expired. I can no longer encrypt using it. But we can still decrypt using it. That's absolutely fine. So when you rotate your X.509 certificate,
as everybody remembers to do every two years, no. Leave the old one in there, and all your old data will still be accessible. So like I say, even if you share the key ring between multiple applications, applications are isolated from each other.
For most of the time, it's based on the IIS meta base ID, because I work for Microsoft. We would honestly like you to host on Windows. But if you are not hosting on Windows, if you're in a command line environment, if you're hosting on Linux or Mac OS, then you need to set up your own application identifier. If you want app isolation, use something like a GUID.
But if you have multiple applications that you want to share the key ring, or if you are in a web farm, and you want them to share the key ring, and you will for cookie authentication and a bunch of other stuff, then you should set a fixed application identifier.
So you load balance, you just create a folder, point everything to the folder, make sure you're protecting it with X.509, and make sure everything has the same application ID, and away you go. We provide you an implementation of the file share
and an implementation of the registry by default. There is a sample for Azure Blob Storage. The Azure Key Vault people keep promising me that they will write one themselves, so you can use Azure Key Vault. If you want to use an HSM, if you're hosting in Amazon or whatever the heck else, well, we provide interfaces and sample code for you to write your own key store.
This is not a happy bunny. So other features in data protection. We have the concept of time limited payloads. After a certain amount of time, you will no longer be able to decrypt it, and there's absolutely no way you can do it. We provide you key revocation functions.
However, we do not provide you with any code to call these. Key revocation is there for when an evil hacker breaches your website and steals your keys, and you want to mark all the data that's been encrypted with those keys as bad. So this is dangerous. And people have thought previously
that when you expire a key, you should revoke it. And once you revoked it, that's a one time operation, and you aren't ever getting anything back. So we provide you with the interfaces and with instructions in the documentation, because yes, there is documentation for this. I realize that a lot of the ASP.NET 5 documentation has been lacking, but data protection
is probably the best documented part of it. There are over 40 pages. There are even little byte-wise diagrams of what's in each byte in the payload. It's not very interesting, but it is there. So we provide you with key revocation, and you can call it yourself if you wire up some code.
And we imagine you're using PowerShell for this, or some sort of other weirdness. You can set a machine-wide policy for algorithms. It's entirely optional. So what would happen in that case is if a developer is creating a data protection provider by default, we look for the machine-wide policy
if no one is specifying anything else. So a machine-wide policy can override the defaults that we have provided, as long as developers in their application have also not overridden their default. In that case, the developer wins. We finally moved away from Windows administrators having the upper hand and put it in the hands of developers.
We have extensibility points for custom algorithms. This is not for you. This is for the Russians and the Chinese, because people who are coding in Russia and people who are coding in China are not allowed to use a bunch of US-sourced encryption
algorithms. They must use the ones that are specified for their country. Now as Microsoft, we are not allowed to distribute those algorithms. So if anyone here is from Russia and you want to use Gost, you're going to have to wire up yourself. But people have done this, and they assure me that it works.
And again, that is documented. This is not for you to write your own custom encryption algorithm. Don't write your own custom encryption algorithm. I've seen it before. It's not pretty. It's very easy to write an encryption algorithm that you can't break, but we're all stupid. It's very hard to write things that other people can't break.
We have a bunch of in-house cryptographers that scare the pants off me. If we use encryption in various strange ways, we have to go get their approval. And I'm sitting there, and I'm actually quiet, which is quite strange. So backwards compatibility.
Those of you who are stuck on web.config right now, you can replace all the web.config and machine key stuff with the new stuff, because we care. Actually, it's there for forms authentication, backwards compatibility. It's not really backwards compatibility. What we're doing is we are replacing the forms
authentication protection stuff in 4.5 with the new stuff. So really, it's forwards compatibility. So that's how you share cookies between 4.5 and 5 and get the things to work. But this works in ASP.NET 4.5, in .NET 4.5, on the desktop.
So it might be a good idea, if you are still suffering with machine key, to start looking at replacing it with something that's an awful lot better. And like I say, it's documented. All our documentation is on docs.asp.net, which actually is on HTTPS now. I need to update that URL, because I finally got them a certificate last month.
So that's data protection. No more machine key. We've taken away the dangerous APIs that would let you encrypt but not sign. And we've hidden the ability for you to create your own keys, because we don't trust anyone. Are we happy with that?
Is this a better improvement for you? You no longer have to rotate machine keys. You no longer have to load balance it. All you have to do is have a network share somewhere that all your machines see. Those of you that have gone through the pain of changing machine keys should frankly be applauding right now.
But it's a British audience and not an American one, so I know that doesn't happen. I got applause last time I said that, and it was kind of shocking. For those of you who were in Dominic's talk, he covered some of this. But there's more people here than there are in Dominic's talk. Yes. So I will cover a little bit of it.
Cookie middleware has been problematic in the past. If you put an authorized attribute on your controller and a user was already logged in, they would get bounced back to the login page. There was no way to tell the difference between 401s and 403s. Forbidden being you don't have an identity,
or unauthorized being you have an identity, but you can't do it. So we now have the ability to tell the difference. You can configure cookie middleware so it has an unauthorized page that will say something like you're trying to look at things that you're not supposed to be looking at. Stay at your desk, pack your stuff,
security will be there in five minutes. So lo and behold, boring configuration, but it looks like that. Some people for some reason want to write single page application apps and use cookie authentication. In my mind, this is a really, really bad idea
because it exposes your apps to cross site request forgery. However, if you want to do that, you can shoot yourself in the foot if you want. But people who were writing those complained that cookie authentication would do redirect. You can turn the redirects off by using
options.automaticchallenge, and then you will get raw 401s versus 403s, and you can react to those in your jQuery or whatever the heck else you are using to send XML HTTP requests. We have moved on from custom principles.
We have finally moved to claims principle everywhere. If you have made an investment in implementing your own i principle object, you're going to have to throw it away. We don't support it anymore. Everything is a claims principle. Now I realize that claims principle is a problematic class.
What a principle used to have was a mapping of a principle to an identity, and it was a one to one mapping. When claims principle came in, it overrode that, and it was now one to many mapping because you could have many identities on a single principle. And the API around that is a bit pants.
You have an identity property which pulls out the first identity in the collection, and that's still there for backwards compatibility no matter how much I complain. But you also have an identities collection. Now to be fair, in most circumstances, you will only end up with a one to one mapping unless you're doing something really weird.
The really weird example is you have two factor off, and that's only there for certain sensitive operations. So a user logs in, and they get their first identity. And then they try and do something really special, and you demand them to type in their two factor off code. And you would get a second identity, and you could check both.
We have the concept of middleware. Everyone that's been using Katana for ages is well aware of this. It's just things that hook into the HTTP pipeline that run. And you can set authentication middleware to be automatic or not. You set them to automatic as they run on every single request.
If you have more than one middleware running automatically, things get really strange. So we generally recommend that you only run one. And we have claims transformation, which is a way that you can mutate the current identity on every single request, like that. So every single time you get an identity that comes in,
claims transformation will run. And you can mess about with the claims all you like. Then we have authorization changes. And those of you that were in Dominic's talk know that he got quite excited and quite complimentary about this. And he's German.
So getting compliments out of Dominic is a hard thing. And we actually made him happy. So what used to happen was we had the authorize attribute. The authorize attribute would, for some stupid reason, take a list of usernames.
So you hard coded usernames in your authorize attribute. And then when someone got married and their surname hyphenated, everything fell apart. We do not give you that ability anymore. You can no longer specify a list of users.
You can also specify the authorize attribute with roles. Unfortunately, I could not get this one removed, because that's how Active Directory works. So Windows were not happy when I suggested this. So you can still authorize based
on a list of hard coded roles. I strongly advise you don't do this and you move to claims. What we added were code based policies. How many of you here have ended up writing your own authorize attribute previously? How bad did that suck?
I have seen some awful implementations of that with glaring holes. You can still write your own authorize attribute, but it will do nothing. The authorize attribute now has no code behind it whatsoever.
So if you want to write one, knock yourself out. None of your code's ever going to run. Instead, what we have added is we have added code based policies. So you take all the stuff that was in your authorize attribute and you write policies for it. We've also extended things so authorization can work on a resource.
Often you want to make decisions based on not just who the user is, but on what they're trying to access and what they're trying to do to it. So if you imagine a Word document, a Word document has a property of an owner. So an owner is pretty likely going to have edit permissions,
but other people may not. You need to have the document loaded to find out who the owner is. So that is our resource and we've got resource based authorization built on that. And for those of you that are writing SPAPs and are doing it properly and are swapping cookies for JWT tokens, all well and good. For those of you that are doing both, which I've seen
and that's quite strange, we now allow you to filter the authentication identity that is going to come through to your controller or come through to your code based on an authentication type. So you may say, this Web API controller I only want to allow bearer tokens through to
and it will ignore any identity that has been constructed from a cookie. So that's kind of nice. So policies is the big thing. And a policy is made up of one or more requirements that must be fulfilled for the policy to succeed.
And each requirement may have one or more handlers. And for a requirement to succeed, only one of the handlers has to succeed. Even if a requirement fails, we're going to evaluate everything else, because people like to put logging
inside their authorization rules. So we're not going to short circuit. We will run everything. But every single requirement must succeed for authorization to succeed. Does that make sense? It will become clearer when I show a little demo
or when I show code. So we will start off with a policy requiring a role. Like I say, please don't do this. This is here for backwards compatibility. And there is an entire project on GitHub with various weird combinations of these things that you can look at. And some of them are really sarcastic.
Some of them are like looking for Taco Tuesday, so it will only pass if it's a Tuesday. You can only get into Tequila Taco Tuesday if it passes and you're over 21, because America has a weird drinking age. So a straightforward policy requiring a role. You configure policies just like you configure everything
else in ASP.NET, and it's part of DI, so you can do it in Configure Services. You have a name for your policy, and then you have the requirements for the policy. In this case, it is requiring the administration role. And now, authorize finally has something new. It has the policy parameter where you specify
the name of your policy. If you're anything like me, you can't successfully retype the name of your policy a second time. So what I recommend you do is you have a static class and you put your policy names in there as public constants.
And then you can use them in both creating your policy via add policy and inside the authorize attribute. So I said we should be moving to claims. And here is an example of a policy that requires two claims. First of all, it requires the existence of an administration claim, which is a little bit strange
because policies are made up of a claim name and a claim value. Often you will be wanting to perform evaluations based on the claim value. So in our second example here, we require a claim called one of many and then we just have a long list of values
that you would require. And it can be one of those. It's not an and, it's an or. And then again, we just apply it with the authorize attribute. And now we come on to code. I am well aware that this is really hard to see. The slides will be made available.
So what we are doing is we are implementing a requirement called over 18 requirement. And the way you implement a requirement is you write a class and you apply the empty interface I authorization requirement to it. A requirement does not have to have any data associated with it.
Often it will. If I was showing an even more complicated example, and this one lives in GitHub, you might have a minimum age requirement. And when you configure your policy, you specify the age as a parameter. In fact, you know what? I'm gonna swap to here
because the font size is bigger. And we will go over 18. So I authorization requirement. But like I say, that doesn't have to have data. The way that you express your code
is in an authorization handler. And it takes in a type of your requirement. In this case, I am just putting the two together. And the code here, the thing that you used to put in your authorize attribute, goes into handle.
Handle takes a context, which is the user that is trying to do something, plus various pieces around that. In MVC, it will give you things like the HTTP context. You can get access to the request. You can get access to the response. Please don't do anything to the response in here. You can get access to routing data
and all that sort of stuff. And then this is the requirement that we're trying to fulfill. And so what I'm doing inside here is I'm accessing context.user. I'm going to see if he has a date of birth claim. If he doesn't have a date of birth claim, I'm gonna bail. If he does have a date of birth claim, I'm gonna mess around with it, get his age out of it.
And if he's over 18, I'm going to succeed. Is that clear? Because this is all very different. So what should a handler return? That is a deliberately bad example. Most of your handlers should never, ever
call context.fail. If your evaluation of a requirement succeeds, then you call context.succeed and you pass in the requirement that has succeeded. If your evaluation fails, you do nothing at all.
If you find something so horrific, like my user database has just been dropped and I need to stop everything, that's when you call context.fail. And the reason that you don't call context.fail when your single handler evaluates and decides
that the evaluation is not successful is because there may be other handlers for your requirement. So like I said, a requirement may have multiple handlers. And in order for that requirement to succeed, only one of those handlers has to succeed. We would like handlers to be as granular as possible.
So if you have a requirement that may be fulfilled in multiple ways, and it may be an or of those multiple ways, then you should be writing multiple handlers for each of those ways. If it's an and, by all means write a single handler and shove everything inside.
So here is an example for multiple handlers for a requirement. I'm going to switch back to Visual Studio because it has much bigger fonts, and I'm pretty sure you can't see that at the back. The handler in the PowerPoint presentation is safe for work. The handler in the GitHub repo is really sarcastic
and takes inspiration from South Park. So I have a no gingers requirement. I can get away with this in the UK because most of you understand. I'm looking around the audience now at hair color,
and I think I'm good. Americans do not understand the ginger thing. They really don't. They prefer to go on how much money you make, or race, or something like that. So we have a requirement. As you can see, it implements nothing at all. That's quite simple.
So I have a no gingers authorization handler. And you can see I can get DI in here because everything is registered through DI, and everything in ASP.NET is using the magic of DI. So in my handler class, I'm going to log something through my DI logger.
I really need to rewrite this for tomorrow. For tomorrow, I'm giving this to banking customers. And the person that has set the demo up is Ginger, which is why I wrote this in the first place. And then I got an email when he looked at the GitHub repo and went, you can't do that. Fortunately, he got an eye infection this week. So he's wandering around with an eye patch.
So I'm going to make them all pirate examples. I don't know why they're putting me in front of customers. It's a really bad idea. So I'm going to look for a hair color claim. And you will note that I have spelt color correctly. I'm also checking the issuer of the claim,
because claims have the concept of an issuer. So the same claim name can be shared by multiple people. If you use social authentication, Google will return an email address. If you use Facebook, it will return an email address. And they have the same name. And the way that they vary is by the issuer. So you ought to be checking issuer whilst you're doing operations based on claims.
So I'm looking for the hair color. If he has a hair color, and it has a value, and it's not Ginger, then I will succeed my no gingers requirement. And that's all well and good. However, and this is where I got onto dangerous ground looking around the room, what about bald people?
You can't tell the hair color of bald people because they have no hair. They do not have a hair color claim. So I'm going to check for baldies. And I'm going to assume that anyone that does not have a hair color claim is bald. And I'm going to let them through.
Now in reality, you would probably do something like count the number of freckles and demand a DNA test. But that's a bit heavy for an example. So we're going to assume that bald people are good because they don't have any hair, therefore they're not ginger. So this is an example of a requirement with multiple handlers. And this is why we do not call contacts.fail.
Because our first one, where we're looking for a hair color claim, and if it exists, we're checking that it's not ginger. Well, if we called fail there, the bald people policy would not work because we've called fail and it overrides everything else. So when you're getting into multiple handlers for a single requirement, all you ever really
need to do is call contacts.succeed. Fail is there for things like I can no longer find my user's database. So is this clearer now with my really bad example? Yes? OK, we're all feeling inspired by Cartman.
So through the magic of DI, we put all of this stuff inside an authorization service. And because it's a service, you can take instances of it into your controllers or any other class that you have registered through DI.
So we've had declarative policies where you're putting it in the attribute. But we still have imperative stuff. Now, the way imperative stuff used to work was you would either isolate the bits that were in your authorized attribute in a second class and call that. Or more usually, what I used to see were people cutting and pasting rules into their controllers.
And then something would get updated in one place and would not get updated in another, and it was all horrible. So now, through the magic of DI, we have an authorization service available to us. And we can call the authorizeAsync function on it. And we can pass in the current user and the policy
that we want to evaluate. And then take actions based upon it within your action function. If something fails, you return challenge result. And depending on what your middleware is, it will redirect you to a login page. It will bounce to forbidden if you're already logged in. And it all takes care of that magically for you.
We even have dependency injection in views. I have mixed feelings about this, I have to admit. Because I think it encourages too much code in views that would be better put in a view model. But never mind. Some people like it. Some people also like PHP.
But this actually harkens back to classic active server pages all written in VB script, which I find a little bit scary because I can still remember that stuff. But you can inject the authorization service in any other DI class or instance that you want using the at inject.
And then again, you can call authorizeAsync with the current user and a policy within your views. And then you might, for example, hide an edit button. I should make it perfectly clear that you should never, ever rely on changing your view as your sole method of security. For heaven's sake, if you're doing something in a view
to hide a UI element, make sure that you replicate that check in the controller. Because otherwise, someone's just going to come along and type the URL in and bypass your view completely and get to places that they shouldn't do. So duplicate your checks.
And finally, with all of this, we have resource-based authorization. So this is linked to a resource type and the operations that you can perform upon it. So a document can be edited by its owner or administrator. The document is the resource. Edit is the operation. So we have a combination of the user
who is trying to do something, what they're trying to do, which is the operation, and what they're trying to do it to, which is our resource. So we have a handy-dandy class called Operation Authorization Requirement. You can write your own requirements. We don't care. I kind of recommend you subclass from this,
because otherwise, you will have to write a handle function for every single requirement. So you just have one sort of master requirement and have a property in there where you can tell what the operation is, which is why we provide that for you. And again, you just write a handler for it. And the only difference this time, instead
of taking type T where T is a requirement, we're taking type T where T is a requirement, and we've added the resource type onto it. So you can see up there with the authorization handler with document. And our handle function now also takes the resource, because it would be kind of useless without it. So here's an example where we're going to take a user.
We're going to look for his documents claim. And if he has a documents claim saying that he can access the documents library, and he's trying to edit something, and he is the document author, then we will succeed. And this becomes very common in real world practices. That's kind of where we're getting to be, because you want to actually perform
an action on something. You can't do this in attributes. It must be imperative, because in attributes, none of the data binding has happened, and none of your resources have been loaded. So because it's all DI, you need to actually register the darn handler in the DI system, which
you do via addSingleton. And there are examples of this in the code. And because I'm running out of time, I'm not even going to run anything. It's not that impressive, frankly. You've seen what one of my demos looked like. They all look like that.
So here we have an example of I want to completely bail, because I never ever want David Fowler to have access to my sample. So that's a good reason for calling context.fail. Here we have where I'm going to map permissions against documents, and our document claim has a value of crud. And I'm going to pull that out and turn it into claims,
and away we go. And then inside our controller, we are calling authorizeAsync, and we're going to say, can I create something? And we're returning challengeResult if it fails. So are we OK with that? The samples make a little bit more sense,
especially the node-gangers one. I encourage you to share that with your friends. For those of you that are writing SPAPs, that are writing Web API stuff, you will hopefully have encountered by now, if you're using ASP.NET 5, there is no difference between a Web API controller and an MVC controller,
which is both a good and a bad thing in my opinion. But OK, never mind. All I'm supposed to care about is security. So you can limit policy based to an authentication scheme. So you can only accept bearer tokens on a Web API endpoint, which is a good idea, because there's no CSRF vulnerabilities at that point. And if you have multiple authentication middlewares, you don't configure any of them to be automatic. And the way you do that, wrong sample.
And again, we have it in the solution. I have multiple auth types. And set a startup project. We will see exactly how bad my UI skills are.
Oh look, I styled this one. Wow. I actually must have cared. This is about as good as my examples get. So look, I will log in with a cookie identity.
And we can see the cookie identity down here. And I'm going to call an API endpoint via really bad JavaScript, because I cannot write JavaScript to save my life. And it will return an alert box. And it says I'm Barry, which is what we expect. And then I've written horrible, horrible bearer middleware,
which you should not use as a sample. And I've already put this in the comments, because all it does is it checks a username and no password. And I'm going to pick a different username here. So I'm logged in with cookie with Adam, or with Barry. And I'm going to send a bearer token for Adam. And lo and behold, this is one of those samples where I end up with two identities.
And that's not generally what we want. If we have a bearer token, we should be using that for calling our API calls. So we can limit it. And if I click the other button, it's now ignoring the cookie generated identity, which a lot of people asked for.
Personally, I'm like, once you've taken your cookie identity and exchanged it for a bearer token, throw it away. But apparently some people don't like that. So there is another new property on the authorize attribute called active authentication schemes, where you can choose the scheme that you want.
And a scheme here is not an HTTP scheme. It is basically a marker. It is a single name. When you are configuring middleware, there is an authentication scheme property. And you can set that value to be what you want. So you can have multiple cookie auths running at once. And then the active authentication schemes is that name that you configured when you were configuring the middleware.
You could also do this in policy, because we would much rather you did everything in policy, because it's a lot nicer, and it generates a lot more code. And the more code that we write, the less our bosses annoy us, because they think lines of code is a way to measure productivity. So you can do it in policy by using the authentication
schemes collection. A couple of other things. None of the policy stuff is limited to ASP.NET. I need to take the Nancy people out and get them drunk and get them to commit to using this, because there are no ASP.NET dependencies.
So the authorization context that you get in a handler is kind of Spartan. If you want access to MVC specific stuff, well, MVC has its own authorization context that is inheriting from our base authorization context. So just cast to that, and you will be able to get the request and the response
and the routing data out. Couple of miscellaneous changes. All binding is now whitelist based. You can no longer use the exclude attribute, because it was silly. What people would do is they would write a class. They would exclude the sensitive data from data binding to prevent against over binding attacks.
And then a colleague would come in, add a new property, and forget to update the attribute. So now, if you're using ASP.NET data binding, you must specifically include each field that you want to participate in data binding. Obviously, if we're doing things the right way,
we are doing things with view models that never contain anything that's sensitive. And you are most certainly not ever binding your entity framework models to your views and accepting those via posts, because that's a silly idea. Tag helpers. If you move to the new fancy tag helper stuff,
we will always create a CSRF token for you to protect you against cross site request forgery. Currently, you must still apply the validate anti-forgery token attribute to your controller methods. Hopefully, by RC2, we will be doing all of this automatically for you. And we will be excluding JSON requests,
because that's always created CSRF problems in validating things. So we're going to be a bit smarter about it. If you are sending an HTTP post with form data, we will validate that there is an anti-forgery token on there. And we will expect one. If you're doing a JSON post, then we don't have to worry.
Unless you've turned CORS on, in which case that's your problem, because CORS is not on by default. And if you're using CORS, you should know what you're doing at that point. Environment defaults. The default environment for all of ASP.NET v5 is release. This makes David Fowler really unhappy, and I'm really pleased with it.
You have a concept of release and debug bills that is no longer how we make decisions. It is based on the environment. And the default environment is release, which means you get no friendly error messages to help when you're debugging. The friendly error messages that would dump parts of your web.config onto the screen,
or full stack traces. We don't want to do that. And this is controlled by an environment variable, and it is a pain to change. When you install Visual Studio, we will set your machine to be a developer machine. When you deploy your application,
there's no Visual Studio there, it will be released by default. You can add the yellow screen of death in if you want, but that's your decision, and you must do it in code. And the reason that we use environment variables is because people have been checking their web.config and their Azure publishing credentials into GitHub, or we've had web.configs that have ended up being indexed by Google.
You can't check in environment variables. So I realize this is kind of hard to do. It depends on how well written your hosting environment is, how they let you set this. We've given guidance to hosters on how they're supposed to address it, and Azure does it well because, of course, they got bigger heads up than us. But that's how they've been doing
web.config for a while now. So instead of injecting web.config, they're just injecting environment variables. So that one makes Fowler unhappy, which obviously makes me happy, because I like that. So I have covered the new security features in ASP.NET 5. I want you to go away and stop using machine key.
Let data protection manage your keys. Let it cope with synchronization by creating a share folder. Make sure that you use x509 to protect your keys when they are at rest. And then move across the new policies and hopefully stop writing your own authorization attribute. We believe that we have made policies so flexible
that you do not need to do this. If you believe that is not the case, by all means, drop me an email. You're a bit late for version one, but we will try and make changes to accommodate your scenarios if they are not really narrow use cases just for you in 1.1.
So there aren't microphones in this room, so I will just sort of hopefully try and remember to repeat your question like a good professional presenter does, not that a professional presenter would have a no gingers policy. So do we have any questions?
Hello, sir. So the question is, if you are using a shared key store in your web form, a shared folder, what happens if you lose connectivity?
Everything goes to hell. Actually, that's not true. So any keys that have existed before are loaded in memory and will continue to work. It's just you won't get key rotation until that key store comes back again. And if you worry about that and you're not on a NAS or a SAN for that sort of thing where it doesn't ever go down, then I
would suggest implementing things in SQL or blob storage or whatever your 99.999% uptime store is. And it is pretty easy to do. I mean, when I can have PMs write sample things for Azure blob storages, I can be assured
that it's simple to do. Although I say that, I'm now in the PM org, but I'm still a dev. And it's all sorts of strange. And eventually, my manager is going to change my job title to be PM just to annoy me. Does that answer your question? Great. Anyone else have questions? I think we have about a minute left.
No? Have I dazzled? Are we not impressed? Are we pleased that there's no longer any machine key and you don't have to write your unauthorized attribute? Because this is my entire contribution to ASP.NET vNext code-wise. And then stopping Fowler and making security mistakes. But that's minimal compared to this. This is the stuff that you see. So I hope that you are pleased with it.
I hope you never, ever have to write an authorized attribute again. If you do, please drop me an email because I would like to know what the weird-ass things you are doing are so we can evaluate them and show you our love by trying to make it an awful lot easier for you. Thank you very much for coming.
All the code samples are on GitHub. The PowerPoint slides will be available on ideno.org in about 20 minutes when I get back to the hotel. And ideno.org has links to the GitHub repros as well. Thank you.