@@ -466,6 +466,114 @@ public async Task Authorize_WhenConsentNotRequired_ReturnsSignInResult()
466466 // Assert
467467 Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
468468 }
469+
470+ [ Fact ]
471+ public async Task Authorize_WhenUserHasRoles_IncludesRoleClaimsInSignInResult ( )
472+ {
473+ // Arrange
474+ var testApp = new object ( ) ;
475+ var oidcAppManager = new Mock < IOpenIddictApplicationManager > ( ) ;
476+ var userManager = MockUserManager . CreateMockUserManager < DevOidcToolkitUser > ( ) ;
477+ var signInManager = MockSignInManager . CreateMockSignInManager < DevOidcToolkitUser > ( ) ;
478+
479+ oidcAppManager . Setup ( x => x . FindByClientIdAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
480+ . ReturnsAsync ( testApp ) ;
481+ oidcAppManager . Setup ( x => x . GetConsentTypeAsync ( testApp , It . IsAny < CancellationToken > ( ) ) )
482+ . ReturnsAsync ( ConsentTypes . Implicit ) ;
483+
484+ var testUser = new DevOidcToolkitUser
485+ {
486+ Id = "user123" ,
487+ UserName = "testuser" ,
488+ Email = "test@example.com" ,
489+ FirstName = "Test" ,
490+ LastName = "User"
491+ } ;
492+
493+ userManager . Setup ( x => x . GetUserAsync ( It . IsAny < ClaimsPrincipal > ( ) ) )
494+ . ReturnsAsync ( testUser ) ;
495+ userManager . Setup ( x => x . GetRolesAsync ( testUser ) )
496+ . ReturnsAsync ( new List < string > { "admin" , "editor" } ) ;
497+
498+ var claimsIdentity = new ClaimsIdentity ( ) ;
499+ var principal = new ClaimsPrincipal ( claimsIdentity ) ;
500+ signInManager . Setup ( x => x . CreateUserPrincipalAsync ( testUser ) )
501+ . ReturnsAsync ( principal ) ;
502+
503+ var controller = CreateController (
504+ oidcAppManager . Object ,
505+ userManager . Object ,
506+ signInManager . Object ,
507+ isAuthenticated : true ,
508+ userId : testUser . Id ,
509+ userName : testUser . UserName ) ;
510+
511+ var request = new OpenIddictRequest { Scope = "openid profile" } ;
512+ var feature = new OpenIddictServerAspNetCoreFeature { Transaction = new ( ) { Request = request } } ;
513+ controller . HttpContext . Features . Set ( feature ) ;
514+
515+ // Act
516+ var result = await controller . Authorize ( ) ;
517+
518+ // Assert
519+ var signInResult = Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
520+ var roleClaims = signInResult . Principal . FindAll ( Claims . Role ) . Select ( c => c . Value ) . ToList ( ) ;
521+ Assert . Contains ( "admin" , roleClaims ) ;
522+ Assert . Contains ( "editor" , roleClaims ) ;
523+ }
524+
525+ [ Fact ]
526+ public async Task Authorize_WhenUserHasNoRoles_NoRoleClaimsInSignInResult ( )
527+ {
528+ // Arrange
529+ var testApp = new object ( ) ;
530+ var oidcAppManager = new Mock < IOpenIddictApplicationManager > ( ) ;
531+ var userManager = MockUserManager . CreateMockUserManager < DevOidcToolkitUser > ( ) ;
532+ var signInManager = MockSignInManager . CreateMockSignInManager < DevOidcToolkitUser > ( ) ;
533+
534+ oidcAppManager . Setup ( x => x . FindByClientIdAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
535+ . ReturnsAsync ( testApp ) ;
536+ oidcAppManager . Setup ( x => x . GetConsentTypeAsync ( testApp , It . IsAny < CancellationToken > ( ) ) )
537+ . ReturnsAsync ( ConsentTypes . Implicit ) ;
538+
539+ var testUser = new DevOidcToolkitUser
540+ {
541+ Id = "user123" ,
542+ UserName = "testuser" ,
543+ Email = "test@example.com" ,
544+ FirstName = "Test" ,
545+ LastName = "User"
546+ } ;
547+
548+ userManager . Setup ( x => x . GetUserAsync ( It . IsAny < ClaimsPrincipal > ( ) ) )
549+ . ReturnsAsync ( testUser ) ;
550+ userManager . Setup ( x => x . GetRolesAsync ( testUser ) )
551+ . ReturnsAsync ( new List < string > ( ) ) ;
552+
553+ var claimsIdentity = new ClaimsIdentity ( ) ;
554+ var principal = new ClaimsPrincipal ( claimsIdentity ) ;
555+ signInManager . Setup ( x => x . CreateUserPrincipalAsync ( testUser ) )
556+ . ReturnsAsync ( principal ) ;
557+
558+ var controller = CreateController (
559+ oidcAppManager . Object ,
560+ userManager . Object ,
561+ signInManager . Object ,
562+ isAuthenticated : true ,
563+ userId : testUser . Id ,
564+ userName : testUser . UserName ) ;
565+
566+ var request = new OpenIddictRequest { Scope = "openid profile" } ;
567+ var feature = new OpenIddictServerAspNetCoreFeature { Transaction = new ( ) { Request = request } } ;
568+ controller . HttpContext . Features . Set ( feature ) ;
569+
570+ // Act
571+ var result = await controller . Authorize ( ) ;
572+
573+ // Assert
574+ var signInResult = Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
575+ Assert . Empty ( signInResult . Principal . FindAll ( Claims . Role ) ) ;
576+ }
469577}
470578
471579
@@ -885,6 +993,124 @@ public async Task AuthorizePost_WhenConsentNotRequired_ReturnsSignInResult()
885993 // Assert
886994 Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
887995 }
996+
997+ [ Fact ]
998+ public async Task AuthorizePost_WhenUserHasRoles_IncludesRoleClaimsInSignInResult ( )
999+ {
1000+ // Arrange
1001+ var testApp = new object ( ) ;
1002+ var oidcAppManager = new Mock < IOpenIddictApplicationManager > ( ) ;
1003+ var userManager = MockUserManager . CreateMockUserManager < DevOidcToolkitUser > ( ) ;
1004+ var signInManager = MockSignInManager . CreateMockSignInManager < DevOidcToolkitUser > ( ) ;
1005+
1006+ oidcAppManager . Setup ( x => x . FindByClientIdAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
1007+ . ReturnsAsync ( testApp ) ;
1008+
1009+ var testUser = new DevOidcToolkitUser
1010+ {
1011+ Id = "user123" ,
1012+ UserName = "testuser" ,
1013+ Email = "test@example.com" ,
1014+ FirstName = "Test" ,
1015+ LastName = "User"
1016+ } ;
1017+
1018+ userManager . Setup ( x => x . GetUserAsync ( It . IsAny < ClaimsPrincipal > ( ) ) )
1019+ . ReturnsAsync ( testUser ) ;
1020+ userManager . Setup ( x => x . GetRolesAsync ( testUser ) )
1021+ . ReturnsAsync ( new List < string > { "admin" , "editor" } ) ;
1022+
1023+ var claimsIdentity = new ClaimsIdentity ( ) ;
1024+ var principal = new ClaimsPrincipal ( claimsIdentity ) ;
1025+ signInManager . Setup ( x => x . CreateUserPrincipalAsync ( testUser ) )
1026+ . ReturnsAsync ( principal ) ;
1027+
1028+ var controller = CreateController (
1029+ oidcAppManager . Object ,
1030+ userManager . Object ,
1031+ signInManager . Object ,
1032+ isAuthenticated : true ,
1033+ userId : testUser . Id ,
1034+ userName : testUser . UserName ) ;
1035+
1036+ controller . ControllerContext . HttpContext . Request . Method = "POST" ;
1037+ controller . ControllerContext . HttpContext . Request . ContentType = "application/x-www-form-urlencoded" ;
1038+ controller . ControllerContext . HttpContext . Request . Form = new FormCollection ( new Dictionary < string , Microsoft . Extensions . Primitives . StringValues >
1039+ {
1040+ [ "consent" ] = "yes"
1041+ } ) ;
1042+
1043+ var request = new OpenIddictRequest { Scope = "openid profile" } ;
1044+ var feature = new OpenIddictServerAspNetCoreFeature { Transaction = new ( ) { Request = request } } ;
1045+ controller . HttpContext . Features . Set ( feature ) ;
1046+
1047+ // Act
1048+ var result = await controller . AuthorizePost ( ) ;
1049+
1050+ // Assert
1051+ var signInResult = Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
1052+ var roleClaims = signInResult . Principal . FindAll ( Claims . Role ) . Select ( c => c . Value ) . ToList ( ) ;
1053+ Assert . Contains ( "admin" , roleClaims ) ;
1054+ Assert . Contains ( "editor" , roleClaims ) ;
1055+ }
1056+
1057+ [ Fact ]
1058+ public async Task AuthorizePost_WhenUserHasNoRoles_NoRoleClaimsInSignInResult ( )
1059+ {
1060+ // Arrange
1061+ var testApp = new object ( ) ;
1062+ var oidcAppManager = new Mock < IOpenIddictApplicationManager > ( ) ;
1063+ var userManager = MockUserManager . CreateMockUserManager < DevOidcToolkitUser > ( ) ;
1064+ var signInManager = MockSignInManager . CreateMockSignInManager < DevOidcToolkitUser > ( ) ;
1065+
1066+ oidcAppManager . Setup ( x => x . FindByClientIdAsync ( It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
1067+ . ReturnsAsync ( testApp ) ;
1068+
1069+ var testUser = new DevOidcToolkitUser
1070+ {
1071+ Id = "user123" ,
1072+ UserName = "testuser" ,
1073+ Email = "test@example.com" ,
1074+ FirstName = "Test" ,
1075+ LastName = "User"
1076+ } ;
1077+
1078+ userManager . Setup ( x => x . GetUserAsync ( It . IsAny < ClaimsPrincipal > ( ) ) )
1079+ . ReturnsAsync ( testUser ) ;
1080+ userManager . Setup ( x => x . GetRolesAsync ( testUser ) )
1081+ . ReturnsAsync ( new List < string > ( ) ) ;
1082+
1083+ var claimsIdentity = new ClaimsIdentity ( ) ;
1084+ var principal = new ClaimsPrincipal ( claimsIdentity ) ;
1085+ signInManager . Setup ( x => x . CreateUserPrincipalAsync ( testUser ) )
1086+ . ReturnsAsync ( principal ) ;
1087+
1088+ var controller = CreateController (
1089+ oidcAppManager . Object ,
1090+ userManager . Object ,
1091+ signInManager . Object ,
1092+ isAuthenticated : true ,
1093+ userId : testUser . Id ,
1094+ userName : testUser . UserName ) ;
1095+
1096+ controller . ControllerContext . HttpContext . Request . Method = "POST" ;
1097+ controller . ControllerContext . HttpContext . Request . ContentType = "application/x-www-form-urlencoded" ;
1098+ controller . ControllerContext . HttpContext . Request . Form = new FormCollection ( new Dictionary < string , Microsoft . Extensions . Primitives . StringValues >
1099+ {
1100+ [ "consent" ] = "yes"
1101+ } ) ;
1102+
1103+ var request = new OpenIddictRequest { Scope = "openid profile" } ;
1104+ var feature = new OpenIddictServerAspNetCoreFeature { Transaction = new ( ) { Request = request } } ;
1105+ controller . HttpContext . Features . Set ( feature ) ;
1106+
1107+ // Act
1108+ var result = await controller . AuthorizePost ( ) ;
1109+
1110+ // Assert
1111+ var signInResult = Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
1112+ Assert . Empty ( signInResult . Principal . FindAll ( Claims . Role ) ) ;
1113+ }
8881114}
8891115
8901116public class ConnectControllerExchangeTests
@@ -1094,6 +1320,74 @@ public async Task Exchange_WithUnsupportedGrantType_ReturnsBadRequest()
10941320 Assert . Equal ( Errors . UnsupportedGrantType , errorResponse . Error ) ;
10951321 Assert . Equal ( "The specified grant type is not supported." , errorResponse . ErrorDescription ) ;
10961322 }
1323+
1324+ [ Fact ]
1325+ public async Task Exchange_WithAuthorizationCodeGrant_RoleClaimsIncludedInIdentityToken ( )
1326+ {
1327+ // Arrange
1328+ var oidcAppManager = new Mock < IOpenIddictApplicationManager > ( ) ;
1329+ var userManager = MockUserManager . CreateMockUserManager < DevOidcToolkitUser > ( ) ;
1330+ var signInManager = MockSignInManager . CreateMockSignInManager < DevOidcToolkitUser > ( ) ;
1331+
1332+ var controller = CreateController (
1333+ oidcAppManager . Object ,
1334+ userManager . Object ,
1335+ signInManager . Object ) ;
1336+
1337+ var request = new OpenIddictRequest
1338+ {
1339+ GrantType = GrantTypes . AuthorizationCode ,
1340+ Code = "test-code"
1341+ } ;
1342+
1343+ // Simulate the principal stored in the authorization code, which includes role claims
1344+ // set by ProcessAuthorizationRequest
1345+ var identity = new ClaimsIdentity (
1346+ authenticationType : OpenIddictServerAspNetCoreDefaults . AuthenticationScheme ,
1347+ nameType : Claims . Name ,
1348+ roleType : Claims . Role ) ;
1349+
1350+ identity . AddClaim ( Claims . Subject , "user123" ) ;
1351+ identity . AddClaim ( new Claim ( Claims . Role , "admin" ) ) ;
1352+ identity . AddClaim ( new Claim ( Claims . Role , "editor" ) ) ;
1353+
1354+ var principal = new ClaimsPrincipal ( identity ) ;
1355+ var ticket = new AuthenticationTicket ( principal , null , OpenIddictServerAspNetCoreDefaults . AuthenticationScheme ) ;
1356+
1357+ var authServiceMock = new Mock < IAuthenticationService > ( ) ;
1358+ authServiceMock
1359+ . Setup ( x => x . AuthenticateAsync ( It . IsAny < HttpContext > ( ) , It . IsAny < string > ( ) ) )
1360+ . ReturnsAsync ( AuthenticateResult . Success ( ticket ) ) ;
1361+
1362+ var serviceProvider = new ServiceCollection ( )
1363+ . AddSingleton ( authServiceMock . Object )
1364+ . BuildServiceProvider ( ) ;
1365+
1366+ controller . ControllerContext . HttpContext . RequestServices = serviceProvider ;
1367+
1368+ var feature = new OpenIddictServerAspNetCoreFeature
1369+ {
1370+ Transaction = new ( )
1371+ {
1372+ Request = request ,
1373+ EndpointType = OpenIddictServerEndpointType . Token
1374+ }
1375+ } ;
1376+ controller . HttpContext . Features . Set ( feature ) ;
1377+
1378+ // Act
1379+ var result = await controller . Exchange ( ) ;
1380+
1381+ // Assert
1382+ var signInResult = Assert . IsType < Microsoft . AspNetCore . Mvc . SignInResult > ( result ) ;
1383+ var roleClaims = signInResult . Principal . FindAll ( Claims . Role ) . ToList ( ) ;
1384+ Assert . NotEmpty ( roleClaims ) ;
1385+ foreach ( var roleClaim in roleClaims )
1386+ {
1387+ Assert . Contains ( Destinations . AccessToken , roleClaim . GetDestinations ( ) ) ;
1388+ Assert . Contains ( Destinations . IdentityToken , roleClaim . GetDestinations ( ) ) ;
1389+ }
1390+ }
10971391}
10981392
10991393
0 commit comments