Skip to content

Instantly share code, notes, and snippets.

@tebeco
Created August 17, 2017 09:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tebeco/258fd795fbc4d8511d9f6fa01ab53f17 to your computer and use it in GitHub Desktop.
Save tebeco/258fd795fbc4d8511d9f6fa01ab53f17 to your computer and use it in GitHub Desktop.
David Fowler AuthN
jeffpapp [8:13 AM]
Yeah, I’d be interested in that. Just haven’t had to look at monitors in a year or so
damccull [8:13 AM]
Ah hah...I was using DefaultAuthenticationScheme when apparently I should be using DefaultScheme.
[8:14]
yep
[8:14]
thanks @jeffpapp
jeffpapp [8:14 AM]
what 28" 4K monitor do you have? Might have to order one up? Do you notice the difference with 4k?
davidfowl [8:14 AM]
@damccull just pass a string to the ctor
damccull [8:15 AM]
I tried that, @davidfowl but it would not work with the openidconnect for some reason. Adding DefaultChallengeScheme to the options as OpenIdConnectDefaults.AuthenticationScheme makes it work
davidfowl [8:15 AM]
ah
[8:15]
thats because you have a different challenge and authenticate scheme ?
damccull [8:16 AM]
Apparently. I'm still learning how this works and it's pfm to me atm
davidfowl [8:16 AM]
there's a learning curve
damccull [8:16 AM]
This tutorial I followed has me using cookie authentication with oidc + google sign in
davidfowl [8:17 AM]
the auth system has 5 verbs
[8:17]
Challenge, Forbid, SignIn, SignOut, Authenticate
damccull [8:17 AM]
although the migration from 1.x to 2.0 page on this also uses cookies + oidc...
[8:17]
Ooh that explains the ChallengeResult somewhat...
jeffpapp [8:17 AM]
yeah, cookies are the most common I would say
damccull [8:17 AM]
by 'verb' do you mean like...a command?
[8:18]
that I can send to it?
jeffpapp [8:18 AM]
are you talking oauth verbs @davidfowl ?
[8:18]
or .Net interface method overrides on the auth classes?
damccull [8:20 AM]
Hmm..I didn't know api endpoints could be cookie protected...but I guess that makes sense. I thought they had to be token authenticated for some reason.
davidfowl [8:21 AM]
not oauth verbs, the ASP.NET Core AuthN system
[8:22]
those verbs are part of the abstraction
damccull [8:22 AM]
@davidfowl in this case does 'verbs' mean a command I can send to the auth system?
davidfowl [8:23 AM]
sure
[8:23]
you can think of it that way
[8:23]
those are the top level methods that call into the authN system
jeffpapp [8:23 AM]
Those are part of HttpContext via extensions methods in .Net Core 2.0 right?
davidfowl [8:23 AM]
right
[8:23]
there's a service called IAuthenticationService
[8:24]
the extension methods are syntax sugar
[8:24]
over that service
jeffpapp [8:24 AM]
mmmmmm…. syntax sugar…..mmmmmmmm
davidfowl [8:24 AM]
:slightly_smiling_face:
jeffpapp [8:25 AM]
ok @davidfowl … now onto my question in #aspnet-core :wink:
damccull [8:25 AM]
So when I click log in, I return a new ChallengeResult that redirects me to the auth system, sending a 'Challenge' verb, which will redirect me to the provider I specify...and when that comes back I get redirected to SignIn verb?
davidfowl [8:25 AM]
gone too deep
[8:25]
back up
damccull [8:25 AM]
lol
davidfowl [8:25 AM]
you need to understand what those actions mean
damccull [8:25 AM]
got a link i can read about it?
davidfowl [8:25 AM]
no
[8:25]
i'm here explaning it
damccull [8:26 AM]
perfect
davidfowl [8:26 AM]
I mean there's probably a doc
[8:26]
but this is better
[8:26]
:stuck_out_tongue_winking_eye:
damccull [8:26 AM]
i hate to impose when there's a doc somewhere but I'll take live training over that any day of the week
jeffpapp [8:27 AM]
now we just need a live slack screen sharing
davidfowl [8:27 AM]
before explaining the verbs
[8:27]
we should talk about authentication handlers
damccull [8:27 AM]
ok
davidfowl [8:27 AM]
and authentication schemes
jeffpapp [8:27 AM]
oh shit… we’re getting deep now.. this is awesome!!
davidfowl [8:27 AM]
the entire system is basically a dictionary from scheme -> authentication handler
[8:28]
when you say ChallengeAsync("Cookies")
[8:28]
There's a lookup for the "Cookies" authN scheme
[8:28]
we find the associated handler and call ChallengeAsync on that
[8:28]
same for all other methods
damccull [8:29 AM]
.AddCookie() adds the handler that's being looked up?
davidfowl [8:29 AM]
correct
[8:29]
it uses the default name "Cookies"
jeffpapp [8:29 AM]
or
davidfowl [8:29 AM]
you can change that to whatever you want
damccull [8:29 AM]
cool
jeffpapp [8:29 AM]
AddIdentity() right
[8:29]
?
davidfowl [8:29 AM]
AddIdentity does a bunch of shit
[8:29]
adding cookies is one of the things it does
jeffpapp [8:29 AM]
yeah, and then there is more stuff you can register with in DI
davidfowl [8:29 AM]
but lets stay at the primitives
[8:30]
once you get it
[8:30]
everything will click
damccull [8:30 AM]
ok. i get the dictionary and handlers.
davidfowl [8:30 AM]
good
[8:30]
now next
damccull [8:31 AM]
add a handler with x string key, and calling into auth with that key uses that handler
davidfowl [8:31 AM]
yep
[8:31]
the key is that those verbs map to a specific auth handler
[8:31]
so the handler does whatever is most appropriate for the auth scheme
jeffpapp [8:32 AM]
gotta love the extensibility of what these guys have build :+1:
davidfowl [8:33 AM]
Challenge - "There is no authenticated user, do whatever needs to be done to change that"
damccull [8:33 AM]
So by default (options.DefaultScheme) it'll set all the schemes to one, ie. Cookies. But if I were to set ChallengeScheme to something different, it would use the handler associated with that second scheme for challenges only?
davidfowl [8:34 AM]
again too deep
damccull [8:34 AM]
k backing up
davidfowl [8:34 AM]
we're going to go over all the verbs first
damccull [8:34 AM]
k
jeffpapp [8:34 AM]
Would you expect some OAuth library would implement some AddOauth() in ConfigureServices?
davidfowl [8:34 AM]
jumping people
[8:35]
stick with the verbs
[8:35]
Challenge
[8:35]
we're at challenge
[8:35]
:slightly_smiling_face:
jeffpapp [8:35 AM]
Fair enough
davidfowl [8:35 AM]
unless you already know how it all works :smile:
damccull [8:35 AM]
I totally don't
jeffpapp [8:35 AM]
Nope, I would love to learn too
davidfowl [8:35 AM]
so I call ChallengeAsync("Cookies")
[8:35]
cookie auth redirects to the configured login url by default
[8:36]
the challenge behavior for cookies is a redirect to the login URL
jeffpapp [8:36 AM]
and that’s handled by the build in cookie auth or identity stuff right?
davidfowl [8:36 AM]
cookie authentication handler
[8:36]
identity is a higher level abstraction
[8:37]
put it out of your mind
[8:37]
these are the lower level lego pieces
jeffpapp [8:37 AM]
yeah, but identity calls cookie auth right?
bhjoellund
[8:37 AM]
:heart: LEGO
davidfowl [8:37 AM]
identity is a bunch of things
[8:37]
and you can use it in various ways
jeffpapp [8:37 AM]
I’m just trying to think from projects that I’ve had
davidfowl [8:37 AM]
sure
[8:37]
by default it uses cookies
[8:38]
if you're familiar with ASP.NET, cookie auth is Forms auth
[8:38]
just more appropriately named :slightly_smiling_face:
jeffpapp [8:38 AM]
yep
davidfowl [8:38 AM]
so Challenge
[8:38]
makes sense?
jeffpapp [8:38 AM]
yessir
davidfowl [8:38 AM]
lets talk about Challenge for google auth
[8:38]
there's a GoogleAuthenticationHandler
[8:39]
when you call `ChallengeAsync("Google")`
[8:39]
google will redirect to the google oauth endpoint with your configured client id and client secret
[8:40]
you enter credentials there and it will post back to your site
jeffpapp [8:40 AM]
I’m following
[8:40]
same for most oauth providers right?
davidfowl [8:41 AM]
yep
[8:41]
only difference is callback urls and secrets (edited)
jeffpapp [8:41 AM]
how does challenge work for WindowsAuth?
[8:41]
sorry, had to throw that curveball
davidfowl [8:42 AM]
IIS or HttpSysServer?
jeffpapp [8:42 AM]
IIS
[8:42]
so IIS configured with windows auth and the directory on the file system has a set of users right?
davidfowl [8:42 AM]
with allow anonymous or nah? (edited)
[8:43]
if you don't allow anonymous, the challenge happens before it even gets to your code
[8:43]
in IIS
damccull [8:43 AM]
Ok so googleauth is like cookieauth, except instead of redirecting to my login page, it redirects to google, passing my clientid and clientsecret?
jeffpapp [8:43 AM]
so then IIS handles it all right?
[8:43]
then it just passes a windows principal right?
davidfowl [8:43 AM]
@jeffpapp yes
damccull [8:43 AM]
and the info google needs to redirect back to me
davidfowl [8:43 AM]
> Ok so googleauth is like cookieauth,
no
[8:44]
thats not the right statement to make
[8:44]
google auth is nothing like cookie auth
[8:44]
google auth implements challenge
[8:44]
and cookie auth implements challenge
[8:44]
they do different things
damccull [8:44 AM]
ah ok
jeffpapp [8:46 AM]
doesn’t it depend on how you deal with google/microsoft/facebook auth/etc… eventually? In some cases you use that auth to cookie auth a user in your system right?
davidfowl [8:46 AM]
no
[8:46]
well
[8:46]
put it this way
[8:46]
we didnt get there yet (edited)
jeffpapp [8:46 AM]
good way of saying that
davidfowl [8:46 AM]
we're talking about challenge still
jeffpapp [8:46 AM]
let’s continue…
davidfowl [8:47 AM]
right (edited)
[8:47]
so we got challenge? (edited)
jeffpapp [8:47 AM]
sorry… I feel like I’m taking this off the rails a bit
davidfowl [8:47 AM]
nah
[8:47]
its fine
[8:47]
next verb
[8:47]
Authenticate
damccull [8:47 AM]
Challenge redirects to the right place to type in or otherwise provide credentials, in a nut shell?
davidfowl [8:48 AM]
challenge requests authentication
damccull [8:48 AM]
better way to say it
[8:49]
so the Authenticate verb, then.
davidfowl [8:50 AM]
Authenticate - "Give me the user information for this auth scheme"
[8:51]
so when you do AuthenticateAsync("Cookies")
[8:52]
the CookieAuthenticationHandler looks at the incoming request and decrypts the configured cookie name to get the user information
[8:54]
no questions?
chadt
[8:54 AM]
is saving this convo for later
damccull [8:54 AM]
I am sure there's one in my brain but...
[8:54]
hmm
[8:54]
@chadt me too once i figure out how. I'm actually taking notes :smile:
csrakowski
[8:54 AM]
No questions; following along nicely! :smile:
jeffpapp [8:55 AM]
Yep, continue along sir
damccull [8:55 AM]
Authenticate verb is not necessarily called in a chain with Challenge?
davidfowl [8:56 AM]
> Authenticate verb is not necessarily called in a chain with Challenge?
Not necessarily, nope
jeffpapp [8:56 AM]
I guess I confirm that cookies auth does challenge and authenticate together by itself?
damccull [8:56 AM]
cool
davidfowl [8:56 AM]
> I guess I confirm that cookies auth does challenge and authenticate together by itself?
what do you mean?
jeffpapp [8:57 AM]
Well, I would say that most people are used to using cookie auth.. and using that then cookie auth handlers do this for us right?
davidfowl [8:57 AM]
no
[8:57]
the cookie auth handler implements the verbs
[8:57]
and other things in the system trigger the verbs
[8:57]
together it makes an end to end that "just works"
[8:57]
what we're doing here is explaining which actors perform which actions
jeffpapp [8:58 AM]
yeah, that’s what I’m getting at
damccull [8:58 AM]
cool
davidfowl [8:58 AM]
things will start to click soon
[8:58]
I promise (edited)
jeffpapp [8:58 AM]
In a classic .Net individual account template we have stuff like Authorize handlers and everthing else that is doing a bunch of this for us right?
damccull [8:59 AM]
excellent i like clicks. they taste great.
davidfowl [8:59 AM]
@jeffpapp yes it does this and 50 other things
jwan
[8:59 AM]
Good morning all :coffee:
davidfowl [8:59 AM]
@jwan morning
csrakowski
[8:59 AM]
Good morning
damccull [8:59 AM]
@jwan @davidfowl is teaching authentication. It's epic.
davidfowl [9:00 AM]
so if you have cookie authentication configured (edited)
[9:00]
context.AuthenticateAsync("Cookies")
chadt
[9:00 AM]
(crap, I have to get the bus... and can't follow along) :cry:
davidfowl [9:00 AM]
it would get the user information from the cookies (if there was any)
damccull [9:01 AM]
@chadt I'll give you my notes later
jeffpapp [9:01 AM]
So that might redirect to a login page for example?
davidfowl [9:02 AM]
@jeffpapp why would Authenticate redirect to a login page
[9:02]
thats not its job
jeffpapp [9:03 AM]
Is that part of challenge? At what point does the cookies auth handler redirect to a login page?
davidfowl [9:03 AM]
@damccull care to answer that? (edited)
damccull [9:03 AM]
I was about to speculate, but I'll wait until we get furhter in since I am pretty sure I was about to deep dive again
[9:03]
hmm
[9:03]
let me think
davidfowl [9:04 AM]
remember don't think about the end to end system
[9:04]
think about individual verbs
damccull [9:04 AM]
Ok so the app determines there is no authenticated user when [Authorize] or similiar hits, and calls the verb Challenge, which redirects to the appropriate place
[9:04]
yes?
davidfowl [9:04 AM]
correct
jwan
[9:04 AM]
Are we talking in traditional MVC terms? As far as I know, if you're working on a .Net Core API, then redirects do not come into the equation, you just return an **unauthorized** if user provides invalid creds
davidfowl [9:04 AM]
we're talking about ASP.NET Core's authentication system
damccull [9:04 AM]
@jwan specifically aspnetcore 2.0
jwan
[9:05 AM]
hmm ok, I'll continue along with you :slightly_smiling_face:
damccull [9:05 AM]
if you were logged in, i suggest reading the backscroll
davidfowl [9:05 AM]
@jeffpapp did that answer your question? The first verb Challenge is what causes the redirect
[9:06]
that was the first thing we covered
jeffpapp [9:06 AM]
So authenciate fails so it rolls back to challenge?
davidfowl [9:06 AM]
no
damccull [9:06 AM]
So, while not necessarily called in a chain, the initial pattern on loading an [authorize] action is challenge->authenticate?
davidfowl [9:06 AM]
nope
[9:06]
dont jump ahead
damccull [9:06 AM]
k
davidfowl [9:07 AM]
we're talking about manual actions
damccull [9:07 AM]
ah ok.
jeffpapp [9:07 AM]
can we use cookie auth as an example?
davidfowl [9:07 AM]
we're building up to the authorize attribute
damccull [9:07 AM]
so taken at face value, manually triggering Challenge will redirect if necessary, and Authenticate will simply get the user info, and return if none?
batesm [9:08 AM]
The docs are so good they can answer these questions :yum:
davidfowl [9:08 AM]
yep
[9:08]
@batesm yea but this is a lesson
[9:08]
:slightly_smiling_face:
batesm [9:08 AM]
:blush:
damccull [9:08 AM]
@batesm there's no substitute for live lessons
davidfowl [9:08 AM]
@damccull yes you nailed it
[9:08]
thats where I need you to be
[9:09]
> so taken at face value, manually triggering Challenge will redirect if necessary, and Authenticate will simply get the user info, and return if none?
[9:09]
that ^
damccull [9:10 AM]
:nod:
jeffpapp [9:10 AM]
ok, so in Cookie auth. If it has a cookie then authenticate, otherwise challenge?
davidfowl [9:10 AM]
@jeffpapp nope
damccull [9:10 AM]
we' aren't to chaining yet @jeffpapp
davidfowl [9:10 AM]
^
damccull [9:10 AM]
this is like, open up a console app and type "ChallengeAsync()" to see what it does (edited)
jeffpapp [9:10 AM]
Ok
davidfowl [9:11 AM]
yes
[9:11]
next verb
[9:11]
the weirder ones
[9:11]
SignIn - "Persist user information into the request"
damccull [9:12 AM]
is that what writes out the cookie?
davidfowl [9:12 AM]
yep
[9:12]
forget that
damccull [9:12 AM]
done
davidfowl [9:12 AM]
:slightly_smiling_face:
thomascastiglione [9:13 AM]
into the _request_.. as in, get the user info which you could have got with Authenticate and put it in the http context?
bryan [9:13 AM]
joined #general
chadt
[9:13 AM]
@bryan :wave:
davidfowl [9:13 AM]
@thomascastiglione we haven't done an entire auth flow yet
damccull [9:14 AM]
so SignIn literally just takes some "user info" and stores it in a cookie...is that part of the http context until it hits the browser?
thomascastiglione [9:14 AM]
does Signin require a Challenge to have occurred?
davidfowl [9:14 AM]
@damccull for cookies that's what it does
[9:15]
@thomascastiglione nope
damccull [9:15 AM]
ok i'll take it at face value and pair the info with more stuff later
davidfowl [9:16 AM]
SignOut does the opposite
damccull [9:16 AM]
removes user info from the request
davidfowl [9:16 AM]
yep
thomascastiglione [9:16 AM]
i don't quite understand what "the request" is here
davidfowl [9:16 AM]
the http request
[9:16]
rather
[9:16]
the "http context"
jeffpapp [9:16 AM]
so how does that work in something like oauth?
davidfowl [9:17 AM]
it doesn;t
[9:17]
I was waiting for that question
[9:17]
it does not work
jeffpapp [9:17 AM]
does that go back to chaining?
thomascastiglione [9:17 AM]
oh no
davidfowl [9:17 AM]
no
[9:17]
this is where you get to use what you learnt so far
[9:17]
so
[9:17]
remember those 5 verbs
jeffpapp [9:17 AM]
:thumbsup:
davidfowl [9:17 AM]
we need to finish the last one
jeffpapp [9:17 AM]
Professor Fowler!
damccull [9:17 AM]
yeah
davidfowl [9:17 AM]
before I answer that question
jeffpapp [9:17 AM]
Fowl!
davidfowl [9:17 AM]
Forbid is the last one
damccull [9:18 AM]
I'm assuming that's when the app tells you to take a hike, you're not allowed in?
davidfowl [9:18 AM]
Forbid - "The user is authenticated but not authorized, do the right thing"
[9:18]
@damccull yap
[9:18]
it was introduced to break cycles
jeffpapp [9:19 AM]
Which is the result of multiple steps before it right?
davidfowl [9:19 AM]
> Which is the result of multiple steps before it right?
Yes, somebody decided to call Forbid
[9:19]
for some reason
[9:19]
the auth handler has no idea what the reason is
jeffpapp [9:19 AM]
what an a**hole :slightly_smiling_face:
damccull [9:19 AM]
Is "do the right thing" any number of things, like "display 'go away' page" or "redirect to login page again for better credentials", etc?
davidfowl [9:19 AM]
yep
[9:19]
so for cookie middleware
[9:20]
it redirects to the access denied page
damccull [9:20 AM]
By "break cycles" do you mean to prevent login loops for unauthorized users, since the app likes to auto-redirect?
davidfowl [9:21 AM]
@damccull yes
[9:21]
exactly that
[9:21]
ok we did the 5 verbs
[9:21]
keep it in your head
damccull [9:21 AM]
i have it in a word doc too
davidfowl [9:22 AM]
so back to @jeffpapp 's observation
[9:22]
how the shit does SignIn work for an oauth flow
[9:22]
it doesn't
jeffpapp [9:22 AM]
I’m so glad this is the kind os stuff you only have to setup once per project!
damccull [9:22 AM]
lol
davidfowl [9:23 AM]
turns out, all of these verbs aren't required
damccull [9:23 AM]
Not required always or not required depending on the auth handler?
davidfowl [9:24 AM]
auth handlers choose what they want to support
batesm [9:24 AM]
Do you mean in oauth?
davidfowl [9:24 AM]
its what we call "external auth"
damccull [9:24 AM]
so cookies does all 5, while oauth (and others) may not
davidfowl [9:24 AM]
twitter, google, etc
[9:24]
yes cookies does all 5
[9:25]
but remember these calls are abstract
thomascastiglione [9:25 AM]
so the reason that oauth doesn't need Signin.. is that because it doesn't need to push anything into the request?
davidfowl [9:25 AM]
so you can make up your own auth handler
[9:25]
@thomascastiglione correct!
thomascastiglione [9:26 AM]
question though: how is the fact of oauth signin having happened persisted? does it go in a session of some sort?
jeffpapp [9:26 AM]
same reason an oauth server might call authenticate but not challenge on an api request right?
davidfowl [9:26 AM]
@thomascastiglione nope
[9:26]
anybody making the connection yet
[9:27]
all of the oauth handlers have this property called SignInScheme
damccull [9:27 AM]
@davidfowl the oauth gives a token to the app, which Authenticate can decode to get all the info
davidfowl [9:27 AM]
@damccull nope
damccull [9:27 AM]
heh
batesm [9:27 AM]
In the UserLogin entity - ProviderKey is used to identify the user? Sorry i know its an aside but just looking to get confirmation
davidfowl [9:28 AM]
@batesm i think so
damccull [9:28 AM]
oh!
davidfowl [9:28 AM]
did it click yet?
jeffpapp [9:28 AM]
So something like an access token in oauth, that would skip a few verbs right @davidfowl ?
damccull [9:28 AM]
oauth doesn't care how user info is stored
batesm [9:28 AM]
Thanks. It might be a bit different in asp.net core but principally the same
damccull [9:28 AM]
it gives it to another auth provider
[9:28]
which handles Signin
davidfowl [9:29 AM]
BOOM (edited)
damccull [9:29 AM]
Which is why I currently have both Cookies and Oidc
davidfowl [9:29 AM]
:slightly_smiling_face:
jeffpapp [9:30 AM]
What is your recommendation if you have a normal web app with cookies auth and the an API with something like oauth? Separate projects?
davidfowl [9:30 AM]
identity server for the API
jeffpapp [9:31 AM]
I’ll have to look at identity server again. Last time I did it was overkill for verifying via oauth password grant
davidfowl [9:31 AM]
ok now lets go further
[9:32]
we got the 5 verbs
jeffpapp [9:32 AM]
but overall great info @davidfowl !!!
[9:32]
:clap: :clap: :clap:
damccull [9:32 AM]
so oauth provider pops you off to google, for example, then google posts back to the oauth provider, which then calls Authenticate verb on the SignInScheme handler? (edited)
davidfowl [9:32 AM]
we understand the external providers dont themselves implement sign in, but delegate to another scheme for persistance
[9:33]
ChallengeAsync("Google") -> goes off to google.com it posts back to your side
SignInAsync(SignInScheme)
damccull [9:33 AM]
ah, signin verb then
[9:33]
ok
jeffpapp [9:34 AM]
Ok, now onto the fun stuff @davidfowl .. Can I trust this .Net 2.0 SDK workaround that is current stopping us from building and/or running our production code.. https://github.com/dotnet/sdk/issues/1488
GitHub
.Net Core 2.0 SDK causes ASP.Net 1.1 Web App with project references to break · Issue #1488 · dotnet/sdk
After I installed the .Net Core 2.0 SDK I started getting an InvalidOperationException: Can not find assembly file Microsoft.CSharp.dll at 'C:\Projects\Temp\VS2017Issue\WebApplication1\bin\Debug\ne...
davidfowl [9:34 AM]
I dunno about that one
[9:34]
but I trust eric
[9:34]
so
[9:35]
listen to him
[9:35]
try it and see if it works
jeffpapp [9:35 AM]
It works to get everything running. I’m just concerned if using the newer DependencyModel will break something else we’re not seeing yet (edited)
damccull [9:36 AM]
alright. are we close to the whole sign in flow or is there a bunch more?:) I'm really enjoying this lesson.
davidfowl [9:36 AM]
yeah
[9:36]
so lets do a real flow
jeffpapp [9:36 AM]
Sounds like fun here
csrakowski
[9:37 AM]
This is my most productive morning in years :smile: Really good stuff @davidfowl
ibro [9:37 AM]
this is great stuff, thanks!
[9:37]
@damccull wanna share the notes or even better turn them into a blog post
davidfowl [9:37 AM]
:thumbsup::skin-tone-6:
[9:37]
[Authorize]
public class MyController : Controller
{
}
[9:37]
Consider this
damccull [9:37 AM]
@ibro yeah i'm planning to blog it if I can cohesively write it up tomorrow. I'll post a draft to you all for input.
ibro [9:38 AM]
awesome, sounds great!
damccull [9:38 AM]
So considered, Mr. Fowl.
davidfowl [9:38 AM]
request comes in, it ends up going to this particular controller
jeffpapp [9:38 AM]
whoa whoa whoa… didn’t we skip some middleware somewhere?
davidfowl [9:39 AM]
nope
batesm [9:39 AM]
Lol
davidfowl [9:39 AM]
lets start here
damccull [9:39 AM]
So far it all matches my config...
davidfowl [9:39 AM]
you aren't authenticated
damccull [9:39 AM]
I feel so...unknown...
davidfowl [9:39 AM]
request comes in, goes to the controller
[9:40]
the auth filter kicks in because of the attribute
[9:40]
tell me what happens based on what you learnt
[9:40]
in terms of the low level calls
damccull [9:41 AM]
first it's going to call challenge beceause there's no authenticated user
[9:41]
which will redirect to the login page or external provider (edited)
batesm [9:42 AM]
ClaimsPrincipal is checked first?
davidfowl [9:42 AM]
how did it get the principal?
[9:42]
where did it come from?
damccull [9:43 AM]
I think it shouldn't have a ClaimsPrincipal yet, which is why it knows to challenge?
batesm [9:43 AM]
Unauthenticated unless passed on my the web server?
[9:43]
By
davidfowl [9:43 AM]
what verb gives you user information
damccull [9:43 AM]
Authenticate
davidfowl [9:44 AM]
right
damccull [9:44 AM]
So it has to call Authenticate before challenge to even know if there's a user already authenticated?
davidfowl [9:45 AM]
correct
damccull [9:45 AM]
So request hits the auth filter, which first calls Authenticate, and since we're not logged in, next calls Challenge
davidfowl [9:46 AM]
yep
jeffpapp [9:46 AM]
So this is where it chains calls?
davidfowl [9:47 AM]
I wouldn't call it "chains"
[9:47]
we;re just talking about an end to end flow
jeffpapp [9:47 AM]
So it tries to authenticate first? If that fails then it challenges?
davidfowl [9:47 AM]
correct
jeffpapp [9:47 AM]
yeah, so it’s a work flow of sorts
davidfowl [9:47 AM]
now lets talk about the arguments passed into Authenticate and Challenge
jeffpapp [9:48 AM]
you should have written this in WWF :smirk:
[9:48]
that’s .netstandard compliant right?
bhjoellund
[9:49 AM]
So you use WWF for each branching statement in your code? :slightly_smiling_face:
jeffrey_k [9:50 AM]
joined #general
jeffpapp [9:50 AM]
Sorry… had to joke on that one
davidfowl [9:50 AM]
lol
batesm [9:50 AM]
I think it was called WF to avoid confusion with with wrestling. That said i have wrestled with it a lot!
davidfowl [9:50 AM]
what arguments are passed to ChallengeAsync and AuthenticateAsync
jeffpapp [9:51 AM]
Well, I’m looking at the cookie auth code and….
batesm [9:51 AM]
Hmmm is it open source? :relaxed:
jeffpapp [9:51 AM]
no args on authenticate
[9:51]
https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs#L153
GitHub
aspnet/Security
Security - Middleware for security and authorization of web apps.
damccull [9:52 AM]
Challenge gets provider and authProperties if it's in line with ChallengeResult
davidfowl [9:52 AM]
@jeffpapp says no args
[9:52]
@damccull says auth properties
[9:52]
any more takers
damccull [9:52 AM]
yeah but i'm probably wrong :smile:
jeffpapp [9:53 AM]
I say dependency injection… is that an answer
davidfowl [9:53 AM]
no thats not an answer
[9:53]
:slightly_smiling_face:
batesm [9:53 AM]
Isnt there a step before? How would it know to go straight to cookies?
davidfowl [9:53 AM]
@batesm you're on the right track
jeffpapp [9:53 AM]
:frowning:
damccull [9:53 AM]
@batesm DefaultScheme
davidfowl [9:53 AM]
@damccull yes!
damccull [9:53 AM]
or whatever scheme you specify in the Authorize attribute (edited)
batesm [9:53 AM]
Whatever is before that would have arguments?
jeffpapp [9:54 AM]
DefaultShceme figures out which handler to call?
davidfowl [9:54 AM]
if you specify an empty [Authorize]
[9:54]
it will use the default scheme
batesm [9:54 AM]
So the scheme then
damccull [9:55 AM]
So the methods have no arguments but they call the handler designated by the scheme? (edited)
davidfowl [9:55 AM]
the methods have overloads
[9:55]
they either take a scheme or they take nothing
[9:55]
if they take nothing, it means use the default scheme
damccull [9:55 AM]
cool
jeffpapp [9:56 AM]
where does the scheme come from?
davidfowl [9:56 AM]
^
[9:56]
its configured by you in ConfigureServices
jeffpapp [9:56 AM]
Startup?
davidfowl [9:56 AM]
yes
batesm [9:56 AM]
Authorize filter
davidfowl [9:56 AM]
in Startup
damccull [9:56 AM]
services.AddAuthentication(o => {
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
davidfowl [9:56 AM]
^
jeffpapp [9:56 AM]
which is new in 2.0
batesm [9:56 AM]
Or default in Startup
davidfowl [9:56 AM]
this is new in 2.0 yes
jeffpapp [9:57 AM]
well, new extensions in 2.0. The underlaying stuff didn’t change much right?
damccull [9:57 AM]
So [Authorize(scheme="Cookies")] will call the overload with a scheme, but [Authorize] will call the empty overload?
jeffrey_k [9:57 AM]
Hi I am new to the dotnet core project, but want to learn how it works from this side of the fence. What are some good channels to be a part of and/or is there a tutorial/documentation somewhere to start? Just some links would be appreciated.
jeffpapp [9:58 AM]
So if I configure identity in startup, that configures cookies under the covers, so all these methods will go to a CookieAuthHandler right?
damccull [9:59 AM]
@jeffrey_k this is a great channel. @davidfowl is currently teaching us about the aspnetcore 2.0 auth system. Also check out https://docs.microsoft.com/en-us/aspnet/core/
docs.microsoft.com
Introduction to ASP.NET Core (802B)
jeffpapp [10:00 AM]
Yeah, couldn’t agree more on the docs. Some of the best docs I’ve seen out there
davidfowl [10:00 AM]
@damccull basically yes. The attribute also supports specifying policies etc
[10:00]
btw I'm glossing over specific details
jeffrey_k [10:01 AM]
Thanks @jeffpapp and @damccull what about on compiling by own build - learning about that process? So I can see how that side works. (edited)
damccull [10:01 AM]
yep ok
jeffpapp [10:01 AM]
So @davidfowl can we talk about mixing something like cookie auth with ouath. I think that’s where it’s gets interesting
davidfowl [10:01 AM]
not yet
damccull [10:01 AM]
@jeffrey_k the docs walk you through the whole shebang, including building websites from the ground up
jeffpapp [10:01 AM]
and where I’ve always been confused if I’m doing it right
batesm [10:02 AM]
@davidfowl When you say the handler is overloaded and can be passed a scheme do you mean the challenge scheme?
damccull [10:02 AM]
@jeffpapp I want to get there too, but I think we need to understand it better before that stage
davidfowl [10:02 AM]
both challenge and authenticate
batesm [10:02 AM]
Ok
davidfowl [10:02 AM]
we'll leave and * there
[10:02]
because it doses something a little different
jeffpapp [10:02 AM]
I think he’s talking about the middleware which deals with scheme.. https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication/AuthenticationMiddleware.cs#L44
GitHub
aspnet/Security
Security - Middleware for security and authorization of web apps.
davidfowl [10:03 AM]
the middleware is the next thing!
[10:03]
:slightly_smiling_face:
damccull [10:03 AM]
@batesm from earlier, which you may have missed, the scheme is just a string that indicates which handler to use. Stored in a dictionary, apparently, but it's basically a key/value store to find a handler
davidfowl [10:03 AM]
yes
[10:03]
the authentication middleware is the other big piece
jeffpapp [10:04 AM]
BOOM.. I knew the middleware was coming up sometime. Always a good place to start debugging if your stuck
damccull [10:04 AM]
So before middleware, the flow, in review, is request->controller auth filter->Authenticate verb->Challenge verb (if not authenticated)
davidfowl [10:05 AM]
yeah
[10:05]
what other verb does it need?
damccull [10:05 AM]
Signin would be next
[10:05]
to persist the user info (edited)
jeffpapp [10:06 AM]
So does a request get to the Authorize filter before the middleware?
damccull [10:07 AM]
@jeffpapp I think it must, because middleware is only called when necessary even though it's registered in app startup.
davidfowl [10:07 AM]
forbid
damccull [10:07 AM]
hah i was totally wrong :smile:
davidfowl [10:07 AM]
forbid is also called by the attribute
[10:07]
well the filter
[10:07]
not attribute
jeffpapp [10:07 AM]
So the attribute sets something that the middleware handles?
damccull [10:08 AM]
The attribute is just a way to force some other code to execute before the controller's action does
jeffpapp [10:08 AM]
I thought it was the middleware that got run first before the MVC middleware that runs the attributes and controllers
damccull [10:08 AM]
in this case it adds a method that does authentication and authorization before it allows the action in question to run
davidfowl [10:08 AM]
we never spoke about what the middleware does
[10:08]
any guesses?
[10:09]
what verbs does it use
jeffpapp [10:09 AM]
well go on professor Fowl
davidfowl [10:09 AM]
this is an interactive session :smile:
[10:09]
helps you learn if you interact
damccull [10:09 AM]
so @davidfowl the authorize calls Authenticate, Challenge, and Forbid? Then the middleware must handle Signin and Signout (edited)
davidfowl [10:09 AM]
nope
[10:09]
remember the basics
[10:10]
auth scheme -> auth handler
[10:10]
each call is a literal pass through to the handler
jeffpapp [10:10 AM]
and that kicks off the whole process right?
davidfowl [10:10 AM]
different actors in the system call into the verbs
[10:10]
one of the jobs of the authentication middleware is to populate HttpContext.User
damccull [10:11 AM]
AuthorizeAttribute just invokes the handler, which then handles the verbs...ok
davidfowl [10:11 AM]
@damccull right
jeffpapp [10:11 AM]
https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication/AuthenticationMiddleware.cs#L45
GitHub
aspnet/Security
Security - Middleware for security and authorization of web apps.
[10:11]
Doesn’t the middleware call the handler
davidfowl [10:11 AM]
lets skip that piece of code
[10:11]
we're discussing the code below it
jeffpapp [10:12 AM]
the AuthenciateAsync?
damccull [10:12 AM]
Does the middleware, then, not actually call the verbs, but do the work once they're called by the handlers?
jeffpapp [10:12 AM]
does that equal the Authenciate verb? Or is that different?
davidfowl [10:13 AM]
@damccull the middleware calls AuthenticateAsync on the default scheme and sets context.User
jeffpapp [10:13 AM]
Sorry. I just remember debugging through all this back in the Beta and RC days
damccull [10:13 AM]
Ok...
jeffpapp [10:13 AM]
I’m probably stepping a few steps ahead
damccull [10:13 AM]
where did i get it in my head that the handlers called the verbs?
davidfowl [10:14 AM]
the call chain looks like this
jeffpapp [10:14 AM]
The handler still does a lot of the verbs too (edited)
[10:14]
https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.Cookies/CookieAuthenticationHandler.cs#L416
GitHub
aspnet/Security
Security - Middleware for security and authorization of web apps.
davidfowl [10:15 AM]
@jeffpapp I'm not sure what you're saying
jeffpapp [10:16 AM]
If you look in the various handlers (CookieAuthHandler for example), it handles Challenge, Authenticate, SignIn, Singout, etc…
[10:16]
It just starts in the HandleAuthenticateAsync method
[10:17]
Sorry, I had a doesnt’ that should have been does. My bad
davidfowl [10:17 AM]
context.AuthenticateAsync("Cookies") -> IAuthenticationService.AuthenticateAsync(context, "Cookies") -> GetHandler("Cookies").AuthenticateAsync(context) (edited)
damccull [10:17 AM]
I have speculations, but I am going to wait for further guidance before I confuse myself.
jeffpapp [10:18 AM]
listen to @davidfowl, I’m just remembering debugging through some of this
davidfowl [10:18 AM]
thats what the chain of responsibility boils down to
jeffpapp [10:18 AM]
I want to learn too
damccull [10:18 AM]
IAuthenticatoinService is the middleware?
davidfowl [10:18 AM]
no
[10:19]
so normally, httpContext.User has your user information
[10:19]
how did it get there?
damccull [10:20 AM]
Signin would have persisted it to the request
jeffpapp [10:20 AM]
So if you are looking at a HTTP request through a ASP.Net Core Web App wouldn’t you get authenticated because the AuthenticationMiddleware ran because you called app.AddAuthentication?
davidfowl [10:20 AM]
forget sign in
damccull [10:21 AM]
done
davidfowl [10:21 AM]
go back to the 5 verbs
damccull [10:21 AM]
that is a verb :disappointed:
jeffpapp [10:21 AM]
that is how I always understood it worked. If you don’t have that middleware then none of it works right?
davidfowl [10:21 AM]
which verb gets user information
damccull [10:21 AM]
Authenticate, but you said SignIn persists it to the request, so I assumed that would be the one to put it into the context
[10:21]
although, now I think that means to persist it ACROSS requests
davidfowl [10:21 AM]
@damccull you're not wrong
[10:22]
I'm just trying to lead you down a path
damccull [10:22 AM]
ok
davidfowl [10:22 AM]
Authenticate
jeffpapp [10:22 AM]
I guess I’m assuming all the verbs are handled under the covers by adding cookies auth for example
davidfowl [10:22 AM]
@jeffpapp no
[10:22]
its very simple, you're making it way more complicated than it needs to be
damccull [10:23 AM]
The middleware calls the Authenticate on the handler, it looks like to me...
davidfowl [10:23 AM]
yes!
jeffpapp [10:24 AM]
Ok, so base individual account template in VS with .net core 2.0. Startup has AddIdentity() and app.UseAuthentication(). AddIdentity() sets up all the cookie auth stuff, that is what is giving you cookie auth right?
davidfowl [10:24 AM]
@jeffpapp forget the template
[10:24]
forget identity
damccull [10:24 AM]
those are like super methods that combine everything we're learning now, @jeffpapp
jeffpapp [10:24 AM]
I guess I’m going at it from the setup not the implementation under the covers
davidfowl [10:24 AM]
thats the opposite of what I'm doing
damccull [10:24 AM]
@davidfowl is teaching us how to build the AddIdentity method
davidfowl [10:25 AM]
^
damccull [10:25 AM]
and things like it
jeffpapp [10:25 AM]
Yeah, I get that. I guess I’m just trying to understand how the out of the box example is doing all it’s magic
thomascastiglione [10:25 AM]
davidfowl
we understand the external providers dont themselves implement sign in, but delegate to another scheme for persistance
Posted in #generalToday at 9:32 AM
[10:26]
well, we do now that we've scrolled up anyway
[10:26]
is cookies the only builtin auth handler that has an impl of signin?
davidfowl [10:27 AM]
yes
damccull [10:27 AM]
AuthorizeAttribute triggers the middleware to run, right?
[10:27]
which then calls the handler
davidfowl [10:27 AM]
@damccull no
damccull [10:27 AM]
heh
davidfowl [10:27 AM]
middleware just runs
[10:27]
before anything else does
damccull [10:28 AM]
oh...so how come when I visit a non protected action it doesn't try to authenticate me?
[10:28]
or does it?
jeffpapp [10:28 AM]
the middleware kicks that process off right?
damccull [10:28 AM]
it must, but the controller doesn't give a rats ass if I'm authenticated or not
davidfowl [10:28 AM]
what does AuthenticateAsync do?
[10:28]
from your notes
damccull [10:28 AM]
Gets user info or returns
davidfowl [10:28 AM]
thats what the middleware does
damccull [10:29 AM]
oh...so it runs always, but nothing cares unless you tell it to
davidfowl [10:29 AM]
it gets the user information and sets it on context.User
damccull [10:29 AM]
makes sense now.
davidfowl [10:29 AM]
what scheme does it use?
damccull [10:29 AM]
default scheme
thomascastiglione [10:29 AM]
oh, i read about this a bit in an issue - someone was upset that context.User can also be set by another middleware, so it isn't a guarantee that Authenticate has happened
davidfowl [10:29 AM]
now we're cooking
jeffpapp [10:30 AM]
So can I configure one controller to use one scheme and another controller to use a different scheme?
csrakowski
[10:30 AM]
You should be able to set that in the attribute, iirc
thomascastiglione [10:30 AM]
or a different chain of schemes, since they each have to be 'terminated' by the cookies scheme..
jeffpapp [10:31 AM]
For example, a normal web app that uses cookie auth, and an api that uses oauth server side auth
davidfowl [10:31 AM]
@thomascastiglione you can't chain anything
[10:31]
@jeffpapp yes you can specify which scheme to use via the Authorize attribute
jeffpapp [10:31 AM]
Ok, that makes sense
thomascastiglione [10:31 AM]
if you can't, then how is it that the oauth scheme delegates SignIn to the cookies scheme?
damccull [10:32 AM]
Request->Middleware.AuthenticateAsync->Handler.AuthenticateAsync->populate context.user->if authorizeattribute present, check if context.user is useful->if not useful, challenge
[10:32]
is this correct, basically?
davidfowl [10:32 AM]
@damccull yes
[10:32]
nailed it :slightly_smiling_face:
jeffpapp [10:33 AM]
:clap: :clap: :clap:
[10:34]
Ok, now if you could only explain the difference between .netstandard20 and .netcoreapp2.0…
[10:34]
I kid.. I kid….
damccull [10:34 AM]
wow, let's finish this lesson first, lol
[10:36]
but the basic gist is that .netstandard is a set of APIs that should exist on ALL .net platforms of whatever version you're targeting. .netcoreapp is one of the platforms that should contain those APIs, so that if you build a library for .netstandard, it should run on any platform that implements the APIs of the version you target, (.netcore, .net framework, etc)
thomascastiglione [10:36 AM]
tbh TFMs are much simpler than security protocols
damccull [10:36 AM]
TFMs?
davidfowl [10:37 AM]
lol
csrakowski
[10:37 AM]
I have to agree with Thomas there
davidfowl [10:37 AM]
lesson over
[10:37]
:slightly_smiling_face:
[10:37]
hope people followed
damccull [10:37 AM]
I have learned much
[10:37]
I have notes and I will try to write them into a blog post tomorrow
davidfowl [10:37 AM]
@damccull will share his notes with the class
[10:37]
:slightly_smiling_face:
csrakowski
[10:37 AM]
Yeah, it was a really great session. Thanks @davidfowl ! :smile:
ibro [10:37 AM]
@damccull please do!
[10:37]
thanks David
damccull [10:37 AM]
Can I run the article by you @davidfowl, for accuracy?
davidfowl [10:38 AM]
yea
damccull [10:38 AM]
what's the best way, just pm you a link?
ibro [10:38 AM]
:clap::clap:
davidfowl [10:39 AM]
yea send me a link in here
damccull [10:40 AM]
ok. Thanks a lot! That was a freakin' great lesson, and demystified a major portion of what I've always considered black box.
thomascastiglione [10:40 AM]
it's very interesting
[10:41]
and helpful, since some time in the next few months i've got to put those pieces together differently in a framework plugin thing
jeffpapp [10:41 AM]
Make sure it gets to @jongalloway, because Jon loves community (edited)
thomascastiglione [10:41 AM]
looks like it'll be pretty easy to use the existing signin parts and the same mechanism of how UseIdentity handles Authenticate while just storing the user data somewhere custom
[10:42]
the way that authentication and authorisation communicate informally through the context is helpful
damccull [10:43 AM]
last question @davidfowl: i know you told me to forget it earlier, but now that we've gone through this whole thing, instead of cookies you could use a handler that stored user info in JWT for token auth, right? same deal in the end as long as you send the token to the user and retreive/decode it in the next request?
thomascastiglione [10:46 AM]
presumably the jwt scheme would handle signin, signout and authenticate, leaving challenge/forbid to oauth or passwords or whatever
davidfowl [10:46 AM]
how would it handle signin?
[10:46]
where does it store the bearer token?
[10:46]
its usually specified in a header
thomascastiglione [10:46 AM]
by returning a jwt as body and then redirecting? i think
[10:46]
it would depend on what the client does
[10:47]
since this flow would be for an api client, nto a browser..
[10:47]
stop me if that doesn't make sense
davidfowl [10:47 AM]
no it doesn't make sense
[10:47]
:slightly_smiling_face:
thomascastiglione [10:47 AM]
:black_square_for_stop:
davidfowl [10:47 AM]
our JWT Auth handler handles Challenge and Authenticate
thomascastiglione [10:48 AM]
how do you get the jwt to the client in the first place, though?
[10:48]
is that expected to be out of band?
davidfowl [10:48 AM]
Identity server
[10:48]
what issues bearer tokens?
thomascastiglione [10:50 AM]
that depends on what the client expects to issue them, since JWT can be used for anything..
jeffpapp [10:51 AM]
So do you depend on identity server to issue bearer tokens and then the middleware and handler authenticate tokens on each request right?
davidfowl [10:51 AM]
yes i can tell you what doesnt issue them
[10:51]
our stack :slightly_smiling_face:
thomascastiglione [10:52 AM]
fair enough
[10:53]
i was kind of running with @damccull's idea of using jwt as pseudo cookies
[10:53]
which a lot of APIs do
[10:53]
and could be implemented with a handler which sent out the tokens itself, as long as you use or make up some protocol on top of this stuff
davidfowl [10:57 AM]
yeah
[10:57]
totally possible
[10:57]
and I guess you would store the token in session?
damccull [11:01 AM]
probably, not really sure. ;D
[11:01]
what's a good, free blogging platform, btw, anyone?
csrakowski
[11:04 AM]
Wordpress is free, and suits most needs
jeffpapp [11:04 AM]
https://medium.com/ is another option that I’ve seen
Medium
Medium – Read, write and share stories that matter
Welcome to Medium, a place to read, write, and interact with the stories that matter most to you. Every day, thousands of voices read, write, and share important stories on Medium.
damccull [11:04 AM]
Hmm
bhjoellund
[11:12 AM]
I'd personally go with medium
They support expansion of gist links
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment