Security Architectures – Working with Software Development Teams (ISVs and in-house) • Creator and Maintainer of IdentityServer OSS Project – Certified OpenID Connect & OAuth 2.0 Implementation for .NET – https://identityserver.io email [email protected] blog http://leastprivilege.com twitter @leastprivilege slides https://speakerdeck.com/leastprivilege
HTTP runtime • MVC is Microsoft's primary application framework – combines web UI & API Console Application .NET (Core) ASP.NET Core Middleware Middleware User Agent MVC DI
Everything is based on ClaimsPrincipal – no more custom IPrincipal • It's all about services – authentication – authorization – claims transformation – data protection – anti-forgery – CORS – encoding • Middleware for automatic per-request invocation
implement specific authentication methods – Cookies for browser based authentication – Google, Facebook, and other social authentication* – OpenId Connect for external authentication – JSON web token (JWT) for token-based authentication • Middleware invokes handlers for request related processing – handlers can be also invoked manually * 20+ more https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
either using a named scheme, or default var claims = new Claim[] { new Claim("sub", "37734"), new Claim("name", "Brock Allen") }; var ci = new ClaimsIdentity(claims, "password", "name", "role"); var cp = new ClaimsPrincipal(ci); await HttpContext.SignInAsync(cp);
a good idea?? For giggles: "https://www.google.com/#q=<machineKey filetype:config" <system.web> <!– copied from http://machinekeys.ru seemed legit --> <machineKey decryptionKey="656E7...617365206865726547A5" validationKey="07C1493415E4405F08...6EF8B1F" /> </system.web>
other secrets – IDataProtectionProvider in DI • Uses a key container file – stored outside of application directory* – uses a key ring with automatic rotation – keys should be protected • Needs to be synchronized between nodes in a farm * https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/default-settings
claims – register an instance of IClaimsTransformation in DI – gets called from the handler's AuthenticateAsync method public class ClaimsTransformer : IClaimsTransformation { public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { return await CreateApplicationPrincipalAsync(principal); } } services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
business code and authorization logic – policy based authorization – resource/action based authorization – DI enabled ASP.NET 4.x version: https://github.com/DavidParks8/Owin-Authorization
middleware checks DefaultAuthenticate scheme Default authenticate handler calls AuthenticateAsync Cookie found? Populate HttpContext.User Request arrives at Controller [Authorize] ? Execute action method Get current user or call handler based on specified scheme AuthZ filter calls Challenge and redirects to LoginPath Is user authenticated? Account controller authenticates user and redirects back Is user authorized? AuthZ filter calls Forbid and redirects to AccessDeniedPath yes no yes no no yes no yes
login – Control URL user returns to and state with AuthenticationProperties – MVC ChallengeResult works with action result architecture var props = new AuthenticationProperties { RedirectUri = "/Home/Secure" }; await HttpContext.ChallengeAsync("Google", props); // or if using MVC: return Challenge("Google", props);
invoked Redirect to external provider External provider Authentication middleware asks handlers who wants to process request callback Handlers does the protocol post- processing Call sign-in handler (sets cookie containing external identity) Redirect to final URL
performs local account registration logic – AuthenticateAsync triggers cookie middleware – Create local account or load existing account – Use primary cookie middleware to log user in (and remove temp cookie) var tempUser = (await HttpContext.AuthenticateAsync("Temp")).Principal; var userIdClaim = tempUser.FindFirst(ClaimTypes.NameIdentifier); var provider = userIdClaim.Issuer; var userId = userIdClaim.Value; // create local account if new, or load existing local account var user = new ClaimsPrincipal(...); await HttpContext.SignInAsync(user); await HttpContext.SignOutAsync("Temp");
Web App Web API Web API Web API OpenID Connect OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 Security Token Service OpenID Connect OpenID Connect