15
15
16
16
namespace Microsoft . Identity . Web
17
17
{
18
- // TODO: rename to EnsureScopesAttribute ? or MsalAuthorizeForScopesAttribute or AuthorizeForScopesAttribute
19
-
20
18
/// <summary>
21
- /// Filter used on a controller action to trigger an incremental consent.
19
+ /// Filter used on a controller action to trigger incremental consent.
22
20
/// </summary>
23
21
/// <example>
24
22
/// The following controller action will trigger
@@ -42,21 +40,25 @@ public class AuthorizeForScopesAttribute : ExceptionFilterAttribute
42
40
public string ScopeKeySection { get ; set ; }
43
41
44
42
/// <summary>
45
- /// Handles the MsaUiRequiredExeception
43
+ /// Handles the MsalUiRequiredException
46
44
/// </summary>
47
45
/// <param name="context">Context provided by ASP.NET Core</param>
48
46
public override void OnException ( ExceptionContext context )
49
47
{
50
48
MsalUiRequiredException msalUiRequiredException = context . Exception as MsalUiRequiredException ;
49
+
51
50
if ( msalUiRequiredException == null )
52
51
{
53
52
msalUiRequiredException = context . Exception ? . InnerException as MsalUiRequiredException ;
54
53
}
55
54
56
55
if ( msalUiRequiredException != null )
57
56
{
58
- if ( CanBeSolvedByReSignInUser ( msalUiRequiredException ) )
57
+ if ( CanBeSolvedByReSignInOfUser ( msalUiRequiredException ) )
59
58
{
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
+
60
62
// the users cannot provide both scopes and ScopeKeySection at the same time
61
63
if ( ! string . IsNullOrWhiteSpace ( ScopeKeySection ) && Scopes != null && Scopes . Length > 0 )
62
64
{
@@ -74,45 +76,52 @@ public override void OnException(ExceptionContext context)
74
76
throw new InvalidOperationException ( $ "The { nameof ( ScopeKeySection ) } is provided but the IConfiguration instance is not present in the services collection") ;
75
77
}
76
78
77
- Scopes = new string [ ] { configuration . GetValue < string > ( ScopeKeySection ) } ;
79
+ scopes = new string [ ] { configuration . GetValue < string > ( ScopeKeySection ) } ;
78
80
}
79
81
80
- var properties = BuildAuthenticationPropertiesForIncrementalConsent ( Scopes , msalUiRequiredException , context . HttpContext ) ;
82
+ else
83
+ scopes = Scopes ;
84
+
85
+ var properties = BuildAuthenticationPropertiesForIncrementalConsent ( scopes , msalUiRequiredException , context . HttpContext ) ;
81
86
context . Result = new ChallengeResult ( properties ) ;
82
87
}
83
88
}
84
89
85
90
base . OnException ( context ) ;
86
91
}
87
92
88
- private bool CanBeSolvedByReSignInUser ( MsalUiRequiredException ex )
93
+ private bool CanBeSolvedByReSignInOfUser ( MsalUiRequiredException ex )
89
94
{
90
95
// ex.ErrorCode != MsalUiRequiredException.UserNullError indicates a cache problem.
91
96
// When calling an [Authenticate]-decorated controller we expect an authenticated
92
97
// user and therefore its account should be in the cache. However in the case of an
93
98
// InMemoryCache, the cache could be empty if the server was restarted. This is why
94
99
// the null_user exception is thrown.
95
100
96
- return ex . ErrorCode . ContainsAny ( new [ ] { MsalError . UserNullError , MsalError . InvalidGrantError } ) ;
101
+ return ex . ErrorCode . ContainsAny ( new [ ] { MsalError . UserNullError , MsalError . InvalidGrantError } ) ;
97
102
}
98
103
99
104
/// <summary>
100
- /// Build Authentication properties needed for an incremental consent.
105
+ /// Build Authentication properties needed for incremental consent.
101
106
/// </summary>
102
107
/// <param name="scopes">Scopes to request</param>
103
108
/// <param name="ex">MsalUiRequiredException instance</param>
104
109
/// <param name="context">current http context in the pipeline</param>
105
110
/// <returns>AuthenticationProperties</returns>
106
111
private AuthenticationProperties BuildAuthenticationPropertiesForIncrementalConsent (
107
- string [ ] scopes , MsalUiRequiredException ex , HttpContext context )
112
+ string [ ] scopes ,
113
+ MsalUiRequiredException ex ,
114
+ HttpContext context )
108
115
{
109
116
var properties = new AuthenticationProperties ( ) ;
110
117
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 } ;
114
123
properties . SetParameter < ICollection < string > > ( OpenIdConnectParameterNames . Scope ,
115
- scopes . Union ( additionalBuildInScopes ) . ToList ( ) ) ;
124
+ scopes . Union ( additionalBuiltInScopes ) . ToList ( ) ) ;
116
125
117
126
// Attempts to set the login_hint to avoid the logged-in user to be presented with an account selection dialog
118
127
var loginHint = context . User . GetLoginHint ( ) ;
0 commit comments