1515
1616namespace Microsoft . Identity . Web
1717{
18- // TODO: rename to EnsureScopesAttribute ? or MsalAuthorizeForScopesAttribute or AuthorizeForScopesAttribute
19-
2018 /// <summary>
21- /// Filter used on a controller action to trigger an incremental consent.
19+ /// Filter used on a controller action to trigger incremental consent.
2220 /// </summary>
2321 /// <example>
2422 /// The following controller action will trigger
@@ -42,21 +40,25 @@ public class AuthorizeForScopesAttribute : ExceptionFilterAttribute
4240 public string ScopeKeySection { get ; set ; }
4341
4442 /// <summary>
45- /// Handles the MsaUiRequiredExeception
43+ /// Handles the MsalUiRequiredException
4644 /// </summary>
4745 /// <param name="context">Context provided by ASP.NET Core</param>
4846 public override void OnException ( ExceptionContext context )
4947 {
5048 MsalUiRequiredException msalUiRequiredException = context . Exception as MsalUiRequiredException ;
49+
5150 if ( msalUiRequiredException == null )
5251 {
5352 msalUiRequiredException = context . Exception ? . InnerException as MsalUiRequiredException ;
5453 }
5554
5655 if ( msalUiRequiredException != null )
5756 {
58- if ( CanBeSolvedByReSignInUser ( msalUiRequiredException ) )
57+ if ( CanBeSolvedByReSignInOfUser ( msalUiRequiredException ) )
5958 {
59+ // Do not re-use the attribute param Scopes. For more info: https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/issues/273
60+ string [ ] scopes = null ;
61+
6062 // the users cannot provide both scopes and ScopeKeySection at the same time
6163 if ( ! string . IsNullOrWhiteSpace ( ScopeKeySection ) && Scopes != null && Scopes . Length > 0 )
6264 {
@@ -74,45 +76,52 @@ public override void OnException(ExceptionContext context)
7476 throw new InvalidOperationException ( $ "The { nameof ( ScopeKeySection ) } is provided but the IConfiguration instance is not present in the services collection") ;
7577 }
7678
77- Scopes = new string [ ] { configuration . GetValue < string > ( ScopeKeySection ) } ;
79+ scopes = new string [ ] { configuration . GetValue < string > ( ScopeKeySection ) } ;
7880 }
7981
80- var properties = BuildAuthenticationPropertiesForIncrementalConsent ( Scopes , msalUiRequiredException , context . HttpContext ) ;
82+ else
83+ scopes = Scopes ;
84+
85+ var properties = BuildAuthenticationPropertiesForIncrementalConsent ( scopes , msalUiRequiredException , context . HttpContext ) ;
8186 context . Result = new ChallengeResult ( properties ) ;
8287 }
8388 }
8489
8590 base . OnException ( context ) ;
8691 }
8792
88- private bool CanBeSolvedByReSignInUser ( MsalUiRequiredException ex )
93+ private bool CanBeSolvedByReSignInOfUser ( MsalUiRequiredException ex )
8994 {
9095 // ex.ErrorCode != MsalUiRequiredException.UserNullError indicates a cache problem.
9196 // When calling an [Authenticate]-decorated controller we expect an authenticated
9297 // user and therefore its account should be in the cache. However in the case of an
9398 // InMemoryCache, the cache could be empty if the server was restarted. This is why
9499 // the null_user exception is thrown.
95100
96- return ex . ErrorCode . ContainsAny ( new [ ] { MsalError . UserNullError , MsalError . InvalidGrantError } ) ;
101+ return ex . ErrorCode . ContainsAny ( new [ ] { MsalError . UserNullError , MsalError . InvalidGrantError } ) ;
97102 }
98103
99104 /// <summary>
100- /// Build Authentication properties needed for an incremental consent.
105+ /// Build Authentication properties needed for incremental consent.
101106 /// </summary>
102107 /// <param name="scopes">Scopes to request</param>
103108 /// <param name="ex">MsalUiRequiredException instance</param>
104109 /// <param name="context">current http context in the pipeline</param>
105110 /// <returns>AuthenticationProperties</returns>
106111 private AuthenticationProperties BuildAuthenticationPropertiesForIncrementalConsent (
107- string [ ] scopes , MsalUiRequiredException ex , HttpContext context )
112+ string [ ] scopes ,
113+ MsalUiRequiredException ex ,
114+ HttpContext context )
108115 {
109116 var properties = new AuthenticationProperties ( ) ;
110117
111- // Set the scopes, including the scopes that ADAL.NET / MASL.NET need for the Token cache
112- string [ ] additionalBuildInScopes =
113- { OidcConstants . ScopeOpenId , OidcConstants . ScopeOfflineAccess , OidcConstants . ScopeProfile } ;
118+ // Set the scopes, including the scopes that ADAL.NET / MSAL.NET need for the token cache
119+ string [ ] additionalBuiltInScopes =
120+ { OidcConstants . ScopeOpenId ,
121+ OidcConstants . ScopeOfflineAccess ,
122+ OidcConstants . ScopeProfile } ;
114123 properties . SetParameter < ICollection < string > > ( OpenIdConnectParameterNames . Scope ,
115- scopes . Union ( additionalBuildInScopes ) . ToList ( ) ) ;
124+ scopes . Union ( additionalBuiltInScopes ) . ToList ( ) ) ;
116125
117126 // Attempts to set the login_hint to avoid the logged-in user to be presented with an account selection dialog
118127 var loginHint = context . User . GetLoginHint ( ) ;
0 commit comments