OpenIdConnect wip
ASPNET Security libraries
- simplified ASPNET Security-like libraries.
- rewritten from scratch ASPNET Security libraries.
- "light" functional-style libraries [90% OOP-free].
Security libraries
- Authentication.Cookies.
- Authentication.Facebook.
- Authentication.Google.
- Authentication.Twitter.
- Authentication.BearerToken.
- Authentication.OAuth2.
- Authentication.OpenIdConnect.
- Authorization.
- DataProtection.
Design
- security services [authentication and authorization services] represent the mechanism backbone.
- security services [high-level functions] act as security behaviour controllers and represent public API.
- security libraries were written following some of FP principles [pure functions, high-order functions, immutability, data/behaviour separation, static methods/functions as first-class citiziens, result pattern].
- DI is used as thin layer usually over functional security services [eg. SignInCookie have 2 implementations with/without DI services]. DI services implementations are registred as usual with specific method extensions [eg. AddCookiesServices, AddFacebookServices].
- security mechanism is based on security services [authentication scheme free-mechanism]:
- authentication middleware receive authentication service as param [UseAuthentication extension].
- authorization middleware receive challenge and forbid services as params [UseAuthorization extension].
- oauth callback endpoints receive signin service as param [eg. MapFacebook].
- authentication libraries implement specific authentication services [eg. AuthenticateCookie, SignInCookie, ChallengeGoogle, AuthenticateFacebook].
- authorization library implement authorization services [eg. Authorize].
- high-level functions usually use declarative style [eg. SignInCookie].
- usually impure functions [with side-effects].
- built on top of low-level and intermediate-level functions.
- intermediate-level functions use imperative/declarative style [eg. SetAuthorizationParams].
- low-level functions usually use imperative style and are one-liners [eg. IsSecuredCookie].
- usually pure [without side effects] or semi-pure functions [side effects on parameters].
- high-intermediate-low-level hierarchy design I named it lego principle. It could be seen also as a functions pyramid having at the base low-level functions.
- no else strategy [0 (zero) else branches].
Processes
- there are 2 different security processes: local authentication and remote authentication.
- local authentication process [cookie]:
- each request [when use authentication middlware] call authentication func [eg. AuthenticateCookie]. Based on authentication result the middleware set HttpContext.User prop.
- then each request [when use authorization middlware] call authorization func [eg. Authorize]. Based on authorization policies result is decided if the request is allowed, unauthenticated/challenged or unauthorized/forbidden.
- signin/signout funcs are used on specific endpoints/controller actions implememted by devs.
- remote authentication process [OAuth2 protocol]:
- when called, the challenge endpoint [eg. registered with MapFacebook] build and send an authorization request to authorization server.
- after processing the authorization request the authorization server redirect response to callback endpoint [eg. registered with MapFacebook]. That endpoint receive authorization server response and call callback func [eg. CallbackFacebook, CallbackOAuth]. The callback func has 2 steps:
- authentication: AuthenticateOAuth oauth authentication func has 3 substeps:
- PostAuthorization - validate the authorization code and the request from the authorization server [local].
- ExchangeCodeForTokens - exchange with the authorization server the authorization code for the access [and refresh] tokens [remote].
- AccessUserInfo - using access token gets from the authorization server the user informations [remote].
- The authentication step transform user informations received from authorization server into security claims, add them to the claims identity, create an authentication ticket and return the AuthenticationResult.
- signin: after oauth authentication step when authentication succedded then the signin func is called [eg. *SiginInCookie^, SignInBearerToken]. Signin func is set on oauth endpoints registration.
- after callback redirection next requests will use local authentication process.
Remarks
- completely rewritten authentication mechanism.
- partially rewritten authorization mechamism [keeping compatibility with ASPNET authorization policies mechanism].
- cookie authentication services surgically implement session-based cookies feature [using IsSessionBasedCookie func]. Authenticating, signingin and signingout services are completely independent each other [no dependencies on HttpContext features]. AuthenticationSessionCookie, SignInSessionCookie and SignOutSessionCookie session-based cookies services are completely isolated from non-session based versions.
- authentication options implementation contains only data [eg. CookieAuthenticationOptions]. Cookie authentication services [non DI-based ones] receive all dependencies as parameters.
- Microsoft ASPNET authentication options implementation contains data and behaviour/services [eg. SessionStore, TicketDataFormat, SystemClock for CookieAuthenticationOptions]. This design have some advantages comparing with my implementation allowing options:
- to have different services from those registered on DI.
- to encapsulate and carry on those services through the authentication process [reducing the number of parameters so].
- AuthenticateOAuth oauth authentication func use template method design pattern allowing oauth libraries to override/decorate when neccessary postAuthenticate, exchangeCodeForTokens or accessUserInfo authentication substeps [eg. AuthenticateTwitter, AuthenticateFacebook].
- redirecting remarks:
- ChallengeOAuth and ChallengeOidc funcs redirect to authorization server [ChallengeOidc could use form instead of redirection].
- CallbackOAuth and CallbackOidc funcs redirect to original url or when callback authentication error to AccessDeniedPath or ErrorPath authentication options props depending of error type.
- SigninCookie, SignOutCookie, Challenge*, Forbid* etc. no redirections [webapi oriented functionality]. when redirections are neccessary those funcs could be decorated and redirected to AuthenticationProperties.RedirectUri or to AuthenticationOptions.ReturnUrlParameter query parameter.
- cookies remarks:
- AuthenticationCookieOptions.ExpiresAfter single place to control AuthenticationTicket [cookies] persistency.
- AuthenticationCookieOptions.CookieName single place to control cookies names.
- oidc remarks:
- pkce is the recommended solution regarding security for authorization code flow.
- implicit and hybrid flows not supported based on oidc best practices [even supported by oidc rfc].
- nonce is not neccessary because implicit and hybrid are only flows with required nonce parameter.
Project goals
- to untangle/demystify the ASPNET authentication/authorization mechanisms and local/remote processes.
- to simplify authentication/authorization mechanisms [ASPNET schema-based free mechanism].
- to demonstrate a functional programming implementation.
- to demonstrate a practical alternative to OOP.
Benchmark
| Method |
InvocationCount |
Mean |
Error |
StdDev |
Median |
Ratio |
RatioSD |
Gen0 |
Gen1 |
Gen2 |
Allocated |
Alloc Ratio |
| FPSignin |
128 |
64.34 μs |
1.196 μs |
1.119 μs |
64.69 μs |
1.00 |
0.00 |
- |
- |
- |
7.96 KB |
1.00 |
| OOPSignin |
128 |
79.98 μs |
3.247 μs |
9.212 μs |
79.56 μs |
1.13 |
0.14 |
7.8125 |
7.8125 |
7.8125 |
116.21 KB |
14.59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| FPSignin |
512 |
45.75 μs |
5.065 μs |
14.934 μs |
39.12 μs |
1.00 |
0.00 |
1.9531 |
- |
- |
7.96 KB |
1.00 |
| OOPSignin |
512 |
97.08 μs |
7.432 μs |
21.679 μs |
95.52 μs |
2.41 |
1.12 |
9.7656 |
9.7656 |
9.7656 |
445.7 KB |
56.01 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| FPSignin |
1024 |
28.83 μs |
2.009 μs |
5.533 μs |
26.26 μs |
1.00 |
0.00 |
1.9531 |
- |
- |
7.95 KB |
1.00 |
| OOPSignin |
1024 |
186.15 μs |
26.776 μs |
78.949 μs |
211.04 μs |
6.32 |
3.02 |
14.6484 |
13.6719 |
13.6719 |
915.64 KB |
115.12 |
- for InvocationCount > 2048 OOP benchmark start running extremely slow.