33
44using Aliencube . Azure . Extensions . EasyAuth . Emulator . Models ;
55
6+ using Microsoft . AspNetCore . Components . Server . ProtectedBrowserStorage ;
7+
68namespace Aliencube . Azure . Extensions . EasyAuth . Emulator . Services ;
79
810public interface IEasyAuthService
@@ -11,76 +13,119 @@ public interface IEasyAuthService
1113
1214 Guid UserId { get ; }
1315
16+ Guid ClientId { get ; }
17+
18+ Guid TenantId { get ; }
19+
1420 IEnumerable < string > UserRoles { get ; }
1521
16- Task < IEnumerable < MsClientPrincipalClaim > > GetUserClaims ( string ? identityProvider ) ;
22+ IdentityProviderType GetIdentityProvider ( string ? identityProvider ) ;
1723
18- Task < bool > UserSignInAsync ( HttpContext ? context , string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims ) ;
24+ Task < IEnumerable < MsClientPrincipalClaim > > GetDefaultUserClaims ( string ? identityProvider ) ;
25+
26+ Task < bool > UserSignInAsync ( ProtectedSessionStorage session , UserSignInContext signInContext ) ;
1927}
2028
21- public class EasyAuthService ( UserIdGenerator userId ) : IEasyAuthService
29+ public class EasyAuthService ( IHttpContextAccessor accessor , IdGenerator generator ) : IEasyAuthService
2230{
31+ private readonly HttpContext ? _context = accessor . HttpContext ;
32+
2333 public JsonSerializerOptions JsonSerializerOptions { get ; } = new ( ) { WriteIndented = true } ;
2434
25- public Guid UserId { get ; } = userId . Value ;
35+ public Guid UserId { get ; } = generator . UserId ;
36+
37+ public Guid ClientId { get ; } = generator . ClientId ;
38+
39+ public Guid TenantId { get ; } = generator . TenantId ;
2640
2741 public IEnumerable < string > UserRoles { get ; } = [ "User" , "Admin" ] ;
2842
29- public async Task < IEnumerable < MsClientPrincipalClaim > > GetUserClaims ( string ? identityProvider )
43+ public IdentityProviderType GetIdentityProvider ( string ? identityProvider )
44+ {
45+ if ( string . IsNullOrWhiteSpace ( identityProvider ) == true )
46+ {
47+ return IdentityProviderType . None ;
48+ }
49+
50+ if ( identityProvider . Equals ( "aad" , StringComparison . InvariantCultureIgnoreCase ) )
51+ {
52+ return IdentityProviderType . EntraID ;
53+ }
54+
55+ return Enum . TryParse < IdentityProviderType > ( identityProvider , true , out var result ) ? result : IdentityProviderType . None ;
56+ }
57+
58+ public async Task < IEnumerable < MsClientPrincipalClaim > > GetDefaultUserClaims ( string ? identityProvider )
3059 {
31- var claims = new List < MsClientPrincipalClaim > ( )
60+ List < MsClientPrincipalClaim > ? claims ;
61+ var provider = this . GetIdentityProvider ( identityProvider ) ;
62+ if ( provider == IdentityProviderType . None )
63+ {
64+ claims = [ ] ;
65+ return await Task . FromResult ( claims ) . ConfigureAwait ( false ) ;
66+ }
67+
68+ claims = provider switch
3269 {
33- new ( ) { Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" , Value = this . UserId . ToString ( ) } ,
34- new ( ) { Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" , Value = "User" } ,
35- new ( ) { Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" , Value = "Admin" } ,
70+ IdentityProviderType . EntraID =>
71+ [
72+ new ( ) { Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/objectidentifier" , Value = this . UserId . ToString ( ) } ,
73+ new ( ) { Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" , Value = "User" } ,
74+ new ( ) { Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" , Value = "Admin" } ,
75+ ] ,
76+ IdentityProviderType . GitHub => [ ] ,
77+ _ => [ ] ,
3678 } ;
3779
3880 return await Task . FromResult ( claims ) . ConfigureAwait ( false ) ;
3981 }
4082
41- public async Task < bool > UserSignInAsync ( HttpContext ? context , string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims )
83+ public async Task < bool > UserSignInAsync ( ProtectedSessionStorage session , UserSignInContext signInContext )
4284 {
43- var provider = ParseIdentityProvider ( identityProvider ) ;
85+ var provider = this . GetIdentityProvider ( signInContext . IdentityProvider ) ;
4486 if ( provider == IdentityProviderType . None )
4587 {
4688 return await Task . FromResult ( false ) . ConfigureAwait ( false ) ;
4789 }
4890
4991 var clientPrincipal = provider switch
5092 {
51- IdentityProviderType . EntraID => this . BuildEntraIDMsClientPrincipal ( identityProvider , userId , username , userRoles , userClaims ) ,
52- IdentityProviderType . GitHub => this . BuildGitHubMsClientPrincipal ( identityProvider , userId , username , userRoles , userClaims ) ,
93+ IdentityProviderType . EntraID => this . BuildEntraIDMsClientPrincipal ( signInContext ) ,
94+ IdentityProviderType . GitHub => this . BuildGitHubMsClientPrincipal ( signInContext ) ,
5395 _ => null ,
5496 } ;
5597
56- context ! . Response . Headers . Append ( "X-MS-CLIENT-PRINCIPAL-NAME" , username ! ) ;
57- context ! . Response . Headers . Append ( "X-MS-CLIENT-PRINCIPAL-ID" , Guid . NewGuid ( ) . ToString ( ) ) ;
58- context ! . Response . Headers . Append ( "X-MS-CLIENT-PRINCIPAL-IDP" , identityProvider ! ) ;
59-
6098 var serialised = JsonSerializer . Serialize ( clientPrincipal , JsonSerializerOptions ) ;
6199 var encoded = Convert . ToBase64String ( Encoding . UTF8 . GetBytes ( serialised ) ) ;
62- context ! . Response . Headers . Append ( "X-MS-CLIENT-PRINCIPAL" , encoded ) ;
100+ var principal = new Dictionary < string , string > ( )
101+ {
102+ { "X-MS-CLIENT-PRINCIPAL-NAME" , signInContext . Username ! } ,
103+ { "X-MS-CLIENT-PRINCIPAL-ID" , signInContext . UserId ! . ToString ( ) } ,
104+ { "X-MS-CLIENT-PRINCIPAL-IDP" , signInContext . IdentityProvider ! } ,
105+ { "X-MS-CLIENT-PRINCIPAL" , encoded } ,
106+ } ;
107+ await session . SetAsync ( "easyauth" , principal ) . ConfigureAwait ( false ) ;
63108
64109 return await Task . FromResult ( true ) . ConfigureAwait ( false ) ;
65110 }
66111
67- private MsClientPrincipal BuildEntraIDMsClientPrincipal ( string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims )
112+ private MsClientPrincipal BuildEntraIDMsClientPrincipal ( UserSignInContext context )
68113 {
69114 var utcNow = DateTimeOffset . UtcNow ;
70115 var defaultClaims = new List < MsClientPrincipalClaim > ( )
71116 {
72- new ( ) { Type = "aud" , Value = userId } ,
73- new ( ) { Type = "iss" , Value = "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000 /v2.0" } ,
117+ new ( ) { Type = "aud" , Value = context . ClientId } ,
118+ new ( ) { Type = "iss" , Value = $ "https://login.microsoftonline.com/{ context . TenantId } /v2.0" } ,
74119 new ( ) { Type = "iat" , Value = $ "{ utcNow . ToUnixTimeSeconds ( ) } " } ,
75120 new ( ) { Type = "nbf" , Value = $ "{ utcNow . ToUnixTimeSeconds ( ) } " } ,
76121 new ( ) { Type = "nbf" , Value = $ "{ utcNow . AddMinutes ( 90 ) . ToUnixTimeSeconds ( ) } " } ,
77122 new ( ) { Type = "aio" , Value = $ "{ Convert . ToBase64String ( Guid . NewGuid ( ) . ToByteArray ( ) ) } " } ,
78- new ( ) { Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" , Value = username } ,
79- new ( ) { Type = "http://schemas.microsoft.com/identity/claims/identityprovider" , Value = "https://sts.windows.net/00000000-0000-0000-0000-000000000000 /" } ,
123+ new ( ) { Type = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" , Value = context . Username } ,
124+ new ( ) { Type = "http://schemas.microsoft.com/identity/claims/identityprovider" , Value = $ "https://sts.windows.net/{ context . TenantId } /" } ,
80125 } ;
81126
82- var userRoleClaims = ( userRoles ? . Split ( '\n ' , StringSplitOptions . RemoveEmptyEntries ) ?? [ ] ) . Select ( p => new MsClientPrincipalClaim ( ) { Type = "roles" , Value = p } ) ;
83- var userClaimClaims = JsonSerializer . Deserialize < IEnumerable < MsClientPrincipalClaim > > ( userClaims ?? "[]" , JsonSerializerOptions ) ?? [ ] ;
127+ var userRoleClaims = ( context . UserRoles ? . Split ( '\n ' , StringSplitOptions . RemoveEmptyEntries ) ?? [ ] ) . Select ( p => new MsClientPrincipalClaim ( ) { Type = "roles" , Value = p } ) ;
128+ var userClaimClaims = JsonSerializer . Deserialize < IEnumerable < MsClientPrincipalClaim > > ( context . UserClaims ?? "[]" , JsonSerializerOptions ) ?? [ ] ;
84129
85130 var claims = new List < MsClientPrincipalClaim > ( ) ;
86131 claims . AddRange ( defaultClaims ) ;
@@ -95,7 +140,7 @@ private MsClientPrincipal BuildEntraIDMsClientPrincipal(string? identityProvider
95140 }
96141 var principal = new MsClientPrincipal ( )
97142 {
98- IdentityProvider = identityProvider ,
143+ IdentityProvider = context . IdentityProvider ,
99144 NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" ,
100145 RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" ,
101146 Claims = claims ,
@@ -104,23 +149,8 @@ private MsClientPrincipal BuildEntraIDMsClientPrincipal(string? identityProvider
104149 return principal ;
105150 }
106151
107- private MsClientPrincipal BuildGitHubMsClientPrincipal ( string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims )
152+ private MsClientPrincipal BuildGitHubMsClientPrincipal ( UserSignInContext context )
108153 {
109154 throw new NotImplementedException ( ) ;
110155 }
111-
112- private static IdentityProviderType ParseIdentityProvider ( string ? identityProvider )
113- {
114- if ( string . IsNullOrWhiteSpace ( identityProvider ) == true )
115- {
116- return IdentityProviderType . None ;
117- }
118-
119- if ( identityProvider . Equals ( "aad" , StringComparison . InvariantCultureIgnoreCase ) )
120- {
121- return IdentityProviderType . EntraID ;
122- }
123-
124- return Enum . TryParse < IdentityProviderType > ( identityProvider , true , out var result ) ? result : IdentityProviderType . None ;
125- }
126156}
0 commit comments