Skip to content

Commit 4fb9841

Browse files
author
derisen
committed
review changes
1 parent 8ff002f commit 4fb9841

29 files changed

+868
-12993
lines changed

3-Authorization-II/1-call-api/API/TodoListAPI/Controllers/TodoListController.cs

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,25 @@ public TodoListController(TodoContext context)
2828
_context = context;
2929
}
3030

31+
/// <summary>
32+
/// Indicates if the AT presented has application or delegated permissions.
33+
/// </summary>
34+
/// <returns></returns>
35+
private bool IsAppOnlyToken()
36+
{
37+
// Add in the optional 'idtyp' claim to check if the access token is coming from an application or user.
38+
// See: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims
39+
if (HttpContext.User.Claims.Any(c => c.Type == "idtyp"))
40+
{
41+
return HttpContext.User.Claims.Any(c => c.Type == "idtyp" && c.Value == "app");
42+
}
43+
else
44+
{
45+
// alternatively, if an AT contains the roles claim but no scp claim, that indicates it's an app token
46+
return HttpContext.User.Claims.Any(c => c.Type == "roles") && HttpContext.User.Claims.Any(c => c.Type != "scp");
47+
}
48+
}
49+
3150
// GET: api/TodoItems
3251
[HttpGet]
3352
/// <summary>
@@ -49,7 +68,7 @@ public TodoListController(TodoContext context)
4968
)]
5069
public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
5170
{
52-
if (HasDelegatedPermissions(new string[] { _todoListRead, _todoListReadWrite }))
71+
if (!IsAppOnlyToken())
5372
{
5473
/// <summary>
5574
/// The 'oid' (object id) is the only claim that should be used to uniquely identify
@@ -65,12 +84,10 @@ public async Task<ActionResult<IEnumerable<TodoItem>>> GetTodoItems()
6584
/// </summary>
6685
return await _context.TodoItems.Where(x => x.Owner == HttpContext.User.GetObjectId()).ToListAsync();
6786
}
68-
else if (HasApplicationPermissions(new string[] { _todoListReadAll, _todoListReadWriteAll }))
87+
else
6988
{
7089
return await _context.TodoItems.ToListAsync();
7190
}
72-
73-
return null;
7491
}
7592

7693
// GET: api/TodoItems/5
@@ -83,16 +100,14 @@ public async Task<ActionResult<TodoItem>> GetTodoItem(int id)
83100
{
84101
// if it only has delegated permissions, then it will be t.id==id && x.Owner == owner
85102
// if it has app permissions the it will return t.id==id
86-
if (HasDelegatedPermissions(new string[] { _todoListRead, _todoListReadWrite }))
103+
if (!IsAppOnlyToken())
87104
{
88105
return await _context.TodoItems.FirstOrDefaultAsync(t => t.Id == id && t.Owner == HttpContext.User.GetObjectId());
89106
}
90-
else if (HasApplicationPermissions(new string[] { _todoListReadAll, _todoListReadWriteAll }))
107+
else
91108
{
92109
return await _context.TodoItems.FirstOrDefaultAsync(t => t.Id == id);
93110
}
94-
95-
return null;
96111
}
97112

98113
// PUT: api/TodoItems/5
@@ -111,31 +126,31 @@ public async Task<IActionResult> PutTodoItem(int id, TodoItem todoItem)
111126
}
112127

113128

114-
if (HasDelegatedPermissions(new string[] { _todoListReadWrite })
115-
&& _context.TodoItems.Any(x => x.Id == id && x.Owner == HttpContext.User.GetObjectId())
116-
&& todoItem.Owner == HttpContext.User.GetObjectId()
117-
||
118-
HasApplicationPermissions(new string[] { _todoListReadWriteAll })
119-
)
120-
{
121-
_context.Entry(todoItem).State = EntityState.Modified;
122-
123-
try
129+
if ((!IsAppOnlyToken() && _context.TodoItems.Any(x => x.Id == id && x.Owner == HttpContext.User.GetObjectId()))
130+
||
131+
IsAppOnlyToken())
124132
{
125-
await _context.SaveChangesAsync();
126-
}
127-
catch (DbUpdateConcurrencyException)
128-
{
129-
if (!_context.TodoItems.Any(e => e.Id == id))
130-
{
131-
return NotFound();
132-
}
133-
else
133+
if (_context.TodoItems.Any(x => x.Id == id && x.Owner == HttpContext.User.GetObjectId()))
134134
{
135-
throw;
135+
_context.Entry(todoItem).State = EntityState.Modified;
136+
137+
try
138+
{
139+
await _context.SaveChangesAsync();
140+
}
141+
catch (DbUpdateConcurrencyException)
142+
{
143+
if (!_context.TodoItems.Any(e => e.Id == id))
144+
{
145+
return NotFound();
146+
}
147+
else
148+
{
149+
throw;
150+
}
151+
}
136152
}
137153
}
138-
}
139154

140155
return NoContent();
141156
}
@@ -152,7 +167,7 @@ public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
152167
{
153168
string owner = HttpContext.User.GetObjectId();
154169

155-
if (HasApplicationPermissions(new string[] { _todoListReadWriteAll }))
170+
if (IsAppOnlyToken())
156171
{
157172
// with such a permission any owner name is accepted
158173
owner = todoItem.Owner;
@@ -182,39 +197,36 @@ public async Task<ActionResult<TodoItem>> DeleteTodoItem(int id)
182197
return NotFound();
183198
}
184199

185-
if ((HasDelegatedPermissions(new string[] { _todoListReadWrite })
186-
&& _context.TodoItems.Any(x => x.Id == id && x.Owner == HttpContext.User.GetObjectId()))
187-
|| HasApplicationPermissions(new string[] { _todoListReadWriteAll }))
200+
if ((!IsAppOnlyToken() && _context.TodoItems.Any(x => x.Id == id && x.Owner == HttpContext.User.GetObjectId()))
201+
||
202+
IsAppOnlyToken())
188203
{
189204
_context.TodoItems.Remove(todoItem);
190205
await _context.SaveChangesAsync();
191-
return todoItem;
192-
}
193-
else
194-
{
195-
return BadRequest();
196206
}
207+
208+
return NoContent();
197209
}
198210

199-
// Checks if the presented token has application permissions
200-
private bool HasApplicationPermissions(string[] permissionsNames)
201-
{
202-
var rolesClaim = User.Claims.Where(
203-
c => c.Type == ClaimConstants.Roles || c.Type == ClaimConstants.Role)
204-
.SelectMany(c => c.Value.Split(' '));
211+
//// Checks if the presented token has application permissions
212+
//private bool HasApplicationPermissions(string[] permissionsNames)
213+
//{
214+
// var rolesClaim = User.Claims.Where(
215+
// c => c.Type == ClaimConstants.Roles || c.Type == ClaimConstants.Role)
216+
// .SelectMany(c => c.Value.Split(' '));
205217

206-
var result = rolesClaim.Any(v => permissionsNames.Any(p => p.Equals(v)));
218+
// var result = rolesClaim.Any(v => permissionsNames.Any(p => p.Equals(v)));
207219

208-
return result;
209-
}
220+
// return result;
221+
//}
210222

211-
// Checks if the presented token has delegated permissions
212-
private bool HasDelegatedPermissions(string[] scopesNames)
213-
{
214-
var result = (User.FindFirst(ClaimConstants.Scp) ?? User.FindFirst(ClaimConstants.Scope))?
215-
.Value.Split(' ').Any(v => scopesNames.Any(s => s.Equals(v)));
223+
//// Checks if the presented token has delegated permissions
224+
//private bool HasDelegatedPermissions(string[] scopesNames)
225+
//{
226+
// var result = (User.FindFirst(ClaimConstants.Scp) ?? User.FindFirst(ClaimConstants.Scope))?
227+
// .Value.Split(' ').Any(v => scopesNames.Any(s => s.Equals(v)));
216228

217-
return result ?? false;
218-
}
229+
// return result ?? false;
230+
//}
219231
}
220232
}

3-Authorization-II/1-call-api/API/TodoListAPI/Startup.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11

2+
using System.Linq;
3+
using System.Net;
24
using Microsoft.AspNetCore.Builder;
35
using Microsoft.AspNetCore.Hosting;
46
using Microsoft.Extensions.Hosting;
@@ -7,6 +9,7 @@
79
using Microsoft.EntityFrameworkCore;
810
using Microsoft.Identity.Web;
911
using Microsoft.AspNetCore.Authentication.JwtBearer;
12+
using Microsoft.IdentityModel.Logging;
1013

1114
using TodoListAPI.Models;
1215

@@ -41,21 +44,24 @@ public void ConfigureServices(IServiceCollection services)
4144
/// Bear in mind that you can do any of the above checks within the individual routes and/or controllers as well.
4245
/// For more information, visit: https://docs.microsoft.com/azure/active-directory/develop/access-tokens#validate-the-user-has-permission-to-access-this-data
4346
/// </summary>
44-
options.Events.OnTokenValidated = async context =>
45-
{
46-
// Uncomment the lines below to validate the caller's tenant ID.
47+
48+
//options.Events.OnTokenValidated = async context =>
49+
//{
50+
// string[] allowedClientApps = { /* list of client ids to allow */ };
4751

48-
// string[] allowedTenants = {/* add a list of tenant IDs */ };
49-
// string tenantId = context.Principal.Claims.FirstOrDefault(x => x.Type == "tid")?.Value;
52+
// string clientappId = context?.Principal?.Claims
53+
// .FirstOrDefault(x => x.Type == "azp" || x.Type == "appid")?.Value;
5054

51-
// if (!allowedTenants.Contains(tenantId))
52-
// {
53-
// throw new Exception("This tenant is not authorized");
54-
// }
55-
56-
};
55+
// if (!allowedClientApps.Contains(clientappId))
56+
// {
57+
// throw new System.Exception("This client is not authorized");
58+
// }
59+
//};
5760
}, options => { Configuration.Bind("AzureAd", options); });
5861

62+
// The following flag can be used to get more descriptive errors in development environments
63+
IdentityModelEventSource.ShowPII = false;
64+
5965
services.AddDbContext<TodoContext>(opt => opt.UseInMemoryDatabase("TodoList"));
6066

6167
services.AddControllers();

0 commit comments

Comments
 (0)