Slide 1

Slide 1 text

Authorization for modern Applications Dominick Baier & Brock Allen https://identityserver.io [email protected] @leastprivilege / @brocklallen

Slide 2

Slide 2 text

2 @leastprivilege / @brocklallen Me • Independent Consultant – Specializing on Application 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

Slide 3

Slide 3 text

3 @leastprivilege / @brocklallen PolicyServer Free OSS version https://github.com/policyserver Commercal version https://solliance.net/products/policyserver

Slide 4

Slide 4 text

4 @leastprivilege / @brocklallen Authorization is hard! • Many approaches – roles, permissions, resource-based, ACLs… (and permutations) – queries vs commands • No standard solution – often very application specific – blurry line between authorization and business rules – XACML good example of failed attempt to standardize

Slide 5

Slide 5 text

5 @leastprivilege / @brocklallen XACML

Slide 6

Slide 6 text

6 @leastprivilege / @brocklallen Observations • Different levels of authorization lend to different abstractions Application/API application access feature feature feature access application logic ? Access token/global policy Role/permission checks Custom business logic / app specific authorization framework

Slide 7

Slide 7 text

7 @leastprivilege / @brocklallen Remember Windows AzMan? https://blogs.msdn.microsoft.com/donovanf/2007/03/07/windows-authorization-manager-azman-the-best-kept-secret/

Slide 8

Slide 8 text

8 @leastprivilege / @brocklallen Modern Applications Browser Native App Server App "Thing" Web App Web API Web API Web API Identity Provider

Slide 9

Slide 9 text

9 @leastprivilege / @brocklallen Overloaded Security Token { "iss": "https://idsrv4", "exp": 1340819380, "aud": [ "api1", "api2"], "amr": [ "password" ], "auth_time": 12340819300 "sub": "182jmm199", "name": "Doug Ross", "role": [ "Approver", "Doctor" ], "permission": [ "DeleteData", "ManageCustomers", "ChangeTreatmentPlan" ] } authentication metadata identity authorization data roles

Slide 10

Slide 10 text

10 @leastprivilege / @brocklallen Token Usage Patient Data API Oncology API Cardiac API

Slide 11

Slide 11 text

11 @leastprivilege / @brocklallen Permissions and Tokens • Separation of concerns – authentication vs authorization – identity system does not have intimate knowledge of application specific authorization rules • "do authorization as close as possible to the resource you are trying to protect" • Tokens can be re-used at several places – claims might have different meaning for each consumer – token & claim bloat • Permissions might change – only way to update the data would be to get a new token

Slide 12

Slide 12 text

12 @leastprivilege / @brocklallen Identity != Permissions

Slide 13

Slide 13 text

13 @leastprivilege / @brocklallen Identity + Permissions == Authorization

Slide 14

Slide 14 text

14 @leastprivilege / @brocklallen Modern Applications Browser Native App Server App "Thing" Web App Web API Web API Web API Identity Provider Policy Provider

Slide 15

Slide 15 text

15 @leastprivilege / @brocklallen Patient API Oncology API Cardiac API Identity Provider Policy Provider authentication + token request get client specific permissions call APIs get API specific permissions Admin UI

Slide 16

Slide 16 text

16 @leastprivilege / @brocklallen Management API Client API App specific roles (static / dynamic) Roles to permission mappings … Applications Admin UI Client Library Our conclusion { "sub": "jd9j91199j1", "role": "Doctor", "contractor": "true" } Policy Provider application context

Slide 17

Slide 17 text

17 @leastprivilege / @brocklallen Management API Client API App specific roles (static / dynamic) Roles to permission mappings … Applications Admin UI Client Library Our conclusion { "roles": [ "Approver", "…" ], "permissions": [ "ChangeTreatmentPlan", "…" ] } Policy Provider

Slide 18

Slide 18 text

18 @leastprivilege / @brocklallen Client Integration • Provide a client library to call the policy provider – client library takes care of caching & refreshing • Augment the ClaimsPrincipal – e.g. using claims transformation in pipeline • Use a specialized authorization API – e.g. ASP.NET Core Authorization

Slide 19

Slide 19 text

19 @leastprivilege / @brocklallen Client Library public class TreatmentController : Controller { private readonly PolicyServerClient _client; public TreatmentController(PolicyServerRuntimeClient client) { _client = client; } public async Task Update(TreatmentUpdateModel model) { var policy = await _client.EvaluateAsync(User); // or var isDoctor = await _client.IsInRoleAsync(User, "Doctor"); // or var allowed = await _client.HasPermissionAsync(User, "PrescribeMedication"); } }

Slide 20

Slide 20 text

20 @leastprivilege / @brocklallen Augment the ClaimsPrincipal • Inject roles and permissions into current principal – backwards compat with existing libraries [Authorize(Roles = "Doctor")] public async Task Update(TreatmentUpdateModel model) { var isDoctor = User.HasClaim("role", "Doctor"); var permissions = User.FindAll("permission"); }

Slide 21

Slide 21 text

21 @leastprivilege / @brocklallen ASP.NET Core Authorization • New authorization library from Microsoft – created for ASP.NET Core, but has been back-ported by the community* • Introduces a policy-based framework – decoupling authorization logic from business code – extensible – testable * https://github.com/DavidParks8/Owin-Authorization

Slide 22

Slide 22 text

22 @leastprivilege / @brocklallen ASP.NET Core Authorization Policies services.AddAuthorization(options => { options.AddPolicy("PrescribeMedication", policy => { policy.RequireAuthenticatedUser(); policy.RequireClaim("permission", "PrescribeMedication"); }); }); [Authorize("PrescribeMedication")] public IActionResult Update() { // stuff } Startup Controller

Slide 23

Slide 23 text

23 @leastprivilege / @brocklallen Programmatically using policies public class TreatmentController : Controller { private readonly IAuthorizationService _authz; public TreatmentController(IAuthorizationService authz) { _authz = authz; } public async Task Update() { var allowed = await _authz.AuthorizeAsync(User, "PrescribeMedication"); if (!allowed) return Challenge(); return View(); } }

Slide 24

Slide 24 text

24 @leastprivilege / @brocklallen …or from a View @using Microsoft.AspNetCore.Authorization @inject IAuthorizationService _authz @if (await _authz.AuthorizeAsync(User, "PrescribeMedication")) { }

Slide 25

Slide 25 text

25 @leastprivilege / @brocklallen ASP.NET Core Policy Provider • Extensibility point that allows creating policies on the fly – no need to create explicit "permission policies" anymore // this policy is not statically defined // but gets created dynamically [Authorize("PrescribeMedication")] public IActionResult Prescribe() { // stuff } Controller

Slide 26

Slide 26 text

26 @leastprivilege / @brocklallen Custom Requirements public class MedicationRequirement : IAuthorizationRequirement { public string MedicationName { get; set; } public int Amount { get; set; } }

Slide 27

Slide 27 text

27 @leastprivilege / @brocklallen Requirement Handler public class MedicationRequirementHandler : AuthorizationHandler { private readonly PolicyServerClient _client; public MedicationRequirementHandler(PolicyServerClient client) { _client = client; } protected override async Task HandleRequirementAsync( AuthorizationHandlerContext context, MedicationRequirement requirement) { var user = context.User; var allowed = false; if (await _client.HasPermissionAsync(user, "PrescribeMedication")) { if (requirement.Amount < 10) allowed = true; else allowed = await _client.IsInRoleAsync(user, "Doctor"); if (allowed || requirement.MedicationName == "placebo") { context.Succeed(requirement); } } } }

Slide 28

Slide 28 text

28 @leastprivilege / @brocklallen Using a custom Requirement public async Task Prescribe(int amount) { var meds = new MedicationRequirement { MedicationName = "aspirin", Amount = amount }; var allowed = await _authz.AuthorizeAsync(User, meds); if (!allowed) return Challenge(); return View("Confirm"); }

Slide 29

Slide 29 text

29 @leastprivilege / @brocklallen Global ASP.NET Core authorization policy public void ConfigureServices(IServiceCollection services) { services.AddMvc(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() // add arbitrary complex policy .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }); }

Slide 30

Slide 30 text

30 @leastprivilege / @brocklallen Summary • Different levels of authorization lend to different abstractions Application/API application access feature feature feature access application logic ? Access token/global policy Role/permission checks Custom business logic / app specific authorization framework

Slide 31

Slide 31 text

31 @leastprivilege / @brocklallen Resources • https://leastprivilege.com/2016/12/16/identity-vs-permissions/ • https://docs.microsoft.com/en-us/aspnet/core/security/authorization/ • https://github.com/PolicyServer/PolicyServer.Local • https://solliance.net/products/policyserver

Slide 32

Slide 32 text

32 @leastprivilege / @brocklallen Thanks! …and (because I always forget) - we have stickers!