@@ -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}
0 commit comments