4
4
using Microsoft . AspNetCore . Http ;
5
5
using Microsoft . AspNetCore . Identity ;
6
6
using Microsoft . AspNetCore . Mvc ;
7
+ using Microsoft . IdentityModel . Tokens ;
7
8
using OpenIddict . Abstractions ;
8
9
using OpenIddict . Server . AspNetCore ;
9
10
using System ;
@@ -16,10 +17,14 @@ namespace ClassifiedAds.IdentityServer.Controllers
16
17
{
17
18
public class AuthorizationController : Controller
18
19
{
20
+ private readonly UserManager < User > _userManager ;
19
21
private readonly SignInManager < User > _signInManager ;
20
22
21
- public AuthorizationController ( SignInManager < User > signInManager )
23
+ public AuthorizationController (
24
+ UserManager < User > userManager ,
25
+ SignInManager < User > signInManager )
22
26
{
27
+ _userManager = userManager ;
23
28
_signInManager = signInManager ;
24
29
}
25
30
@@ -69,8 +74,7 @@ public async Task<IActionResult> Authorize()
69
74
[ HttpPost ( "~/connect/token" ) ]
70
75
public async Task < IActionResult > Exchange ( )
71
76
{
72
- var request = HttpContext . GetOpenIddictServerRequest ( ) ??
73
- throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
77
+ var request = HttpContext . GetOpenIddictServerRequest ( ) ?? throw new InvalidOperationException ( "The OpenID Connect request cannot be retrieved." ) ;
74
78
75
79
ClaimsPrincipal claimsPrincipal ;
76
80
@@ -101,6 +105,57 @@ public async Task<IActionResult> Exchange()
101
105
// Retrieve the claims principal stored in the refresh token.
102
106
claimsPrincipal = ( await HttpContext . AuthenticateAsync ( OpenIddictServerAspNetCoreDefaults . AuthenticationScheme ) ) . Principal ;
103
107
}
108
+ else if ( request . IsPasswordGrantType ( ) )
109
+ {
110
+ var user = await _userManager . FindByNameAsync ( request . Username ) ;
111
+ if ( user == null )
112
+ {
113
+ var properties = new AuthenticationProperties ( new Dictionary < string , string >
114
+ {
115
+ [ OpenIddictServerAspNetCoreConstants . Properties . Error ] = OpenIddictConstants . Errors . InvalidGrant ,
116
+ [ OpenIddictServerAspNetCoreConstants . Properties . ErrorDescription ] = "The username/password couple is invalid."
117
+ } ) ;
118
+
119
+ return Forbid ( properties , OpenIddictServerAspNetCoreDefaults . AuthenticationScheme ) ;
120
+ }
121
+
122
+ // Validate the username/password parameters and ensure the account is not locked out.
123
+ var result = await _signInManager . CheckPasswordSignInAsync ( user , request . Password , lockoutOnFailure : true ) ;
124
+ if ( ! result . Succeeded )
125
+ {
126
+ var properties = new AuthenticationProperties ( new Dictionary < string , string >
127
+ {
128
+ [ OpenIddictServerAspNetCoreConstants . Properties . Error ] = OpenIddictConstants . Errors . InvalidGrant ,
129
+ [ OpenIddictServerAspNetCoreConstants . Properties . ErrorDescription ] = "The username/password couple is invalid."
130
+ } ) ;
131
+
132
+ return Forbid ( properties , OpenIddictServerAspNetCoreDefaults . AuthenticationScheme ) ;
133
+ }
134
+
135
+ // Create the claims-based identity that will be used by OpenIddict to generate tokens.
136
+ var identity = new ClaimsIdentity (
137
+ authenticationType : TokenValidationParameters . DefaultAuthenticationType ,
138
+ nameType : OpenIddictConstants . Claims . Name ,
139
+ roleType : OpenIddictConstants . Claims . Role ) ;
140
+
141
+ // Add the claims that will be persisted in the tokens.
142
+ identity . SetClaim ( OpenIddictConstants . Claims . Subject , await _userManager . GetUserIdAsync ( user ) )
143
+ . SetClaim ( OpenIddictConstants . Claims . Email , await _userManager . GetEmailAsync ( user ) )
144
+ . SetClaim ( OpenIddictConstants . Claims . Name , await _userManager . GetUserNameAsync ( user ) ) ;
145
+
146
+ // Set the list of scopes granted to the client application.
147
+ identity . SetScopes ( new [ ]
148
+ {
149
+ OpenIddictConstants . Scopes . OpenId ,
150
+ OpenIddictConstants . Scopes . Email ,
151
+ OpenIddictConstants . Scopes . Profile ,
152
+ OpenIddictConstants . Scopes . Roles
153
+ } . Intersect ( request . GetScopes ( ) ) ) ;
154
+
155
+ identity . SetDestinations ( GetDestinations ) ;
156
+
157
+ return SignIn ( new ClaimsPrincipal ( identity ) , OpenIddictServerAspNetCoreDefaults . AuthenticationScheme ) ;
158
+ }
104
159
else
105
160
{
106
161
throw new InvalidOperationException ( "The specified grant type is not supported." ) ;
@@ -134,5 +189,51 @@ public async Task<IActionResult> LogoutPost()
134
189
} ) ;
135
190
}
136
191
192
+ private static IEnumerable < string > GetDestinations ( Claim claim )
193
+ {
194
+ // Note: by default, claims are NOT automatically included in the access and identity tokens.
195
+ // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
196
+ // whether they should be included in access tokens, in identity tokens or in both.
197
+
198
+ switch ( claim . Type )
199
+ {
200
+ case OpenIddictConstants . Claims . Name :
201
+ yield return OpenIddictConstants . Destinations . AccessToken ;
202
+
203
+ if ( claim . Subject . HasScope ( OpenIddictConstants . Scopes . Profile ) )
204
+ {
205
+ yield return OpenIddictConstants . Destinations . IdentityToken ;
206
+ }
207
+
208
+ yield break ;
209
+
210
+ case OpenIddictConstants . Claims . Email :
211
+ yield return OpenIddictConstants . Destinations . AccessToken ;
212
+
213
+ if ( claim . Subject . HasScope ( OpenIddictConstants . Scopes . Email ) )
214
+ {
215
+ yield return OpenIddictConstants . Destinations . IdentityToken ;
216
+ }
217
+
218
+ yield break ;
219
+
220
+ case OpenIddictConstants . Claims . Role :
221
+ yield return OpenIddictConstants . Destinations . AccessToken ;
222
+
223
+ if ( claim . Subject . HasScope ( OpenIddictConstants . Scopes . Roles ) )
224
+ {
225
+ yield return OpenIddictConstants . Destinations . IdentityToken ;
226
+ }
227
+
228
+ yield break ;
229
+
230
+ // Never include the security stamp in the access and identity tokens, as it's a secret value.
231
+ case "AspNet.Identity.SecurityStamp" : yield break ;
232
+
233
+ default :
234
+ yield return OpenIddictConstants . Destinations . AccessToken ;
235
+ yield break ;
236
+ }
237
+ }
137
238
}
138
239
}
0 commit comments