1+ using System . Text ;
12using System . Text . Json ;
23
4+ using Aliencube . Azure . Extensions . EasyAuth . Emulator . Models ;
5+
36namespace Aliencube . Azure . Extensions . EasyAuth . Emulator . Services ;
47
58public interface IEasyAuthService
69{
710 JsonSerializerOptions JsonSerializerOptions { get ; }
11+
812 Guid UserId { get ; }
913
1014 IEnumerable < string > UserRoles { get ; }
1115
12- Task < IEnumerable < MsClientPrincipalClaim > > GetUserClaims ( string ? authenticationType ) ;
16+ Task < IEnumerable < MsClientPrincipalClaim > > GetUserClaims ( string ? identityProvider ) ;
17+
18+ Task < bool > UserSignInAsync ( HttpContext ? context , string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims ) ;
1319}
1420
1521public class EasyAuthService ( UserIdGenerator userId ) : IEasyAuthService
1622{
1723 public JsonSerializerOptions JsonSerializerOptions { get ; } = new ( ) { WriteIndented = true } ;
24+
1825 public Guid UserId { get ; } = userId . Value ;
26+
1927 public IEnumerable < string > UserRoles { get ; } = [ "User" , "Admin" ] ;
20- public async Task < IEnumerable < MsClientPrincipalClaim > > GetUserClaims ( string ? authenticationType )
28+
29+ public async Task < IEnumerable < MsClientPrincipalClaim > > GetUserClaims ( string ? identityProvider )
2130 {
2231 var claims = new List < MsClientPrincipalClaim > ( )
2332 {
@@ -28,4 +37,90 @@ public async Task<IEnumerable<MsClientPrincipalClaim>> GetUserClaims(string? aut
2837
2938 return await Task . FromResult ( claims ) . ConfigureAwait ( false ) ;
3039 }
40+
41+ public async Task < bool > UserSignInAsync ( HttpContext ? context , string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims )
42+ {
43+ var provider = ParseIdentityProvider ( identityProvider ) ;
44+ if ( provider == IdentityProviderType . None )
45+ {
46+ return await Task . FromResult ( false ) . ConfigureAwait ( false ) ;
47+ }
48+
49+ var clientPrincipal = provider switch
50+ {
51+ IdentityProviderType . EntraID => this . BuildEntraIDMsClientPrincipal ( identityProvider , userId , username , userRoles , userClaims ) ,
52+ IdentityProviderType . GitHub => this . BuildGitHubMsClientPrincipal ( identityProvider , userId , username , userRoles , userClaims ) ,
53+ _ => null ,
54+ } ;
55+
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+
60+ var serialised = JsonSerializer . Serialize ( clientPrincipal , JsonSerializerOptions ) ;
61+ var encoded = Convert . ToBase64String ( Encoding . UTF8 . GetBytes ( serialised ) ) ;
62+ context ! . Response . Headers . Append ( "X-MS-CLIENT-PRINCIPAL" , encoded ) ;
63+
64+ return await Task . FromResult ( true ) . ConfigureAwait ( false ) ;
65+ }
66+
67+ private MsClientPrincipal BuildEntraIDMsClientPrincipal ( string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims )
68+ {
69+ var utcNow = DateTimeOffset . UtcNow ;
70+ var defaultClaims = new List < MsClientPrincipalClaim > ( )
71+ {
72+ new ( ) { Type = "aud" , Value = userId } ,
73+ new ( ) { Type = "iss" , Value = "https://login.microsoftonline.com/00000000-0000-0000-0000-000000000000/v2.0" } ,
74+ new ( ) { Type = "iat" , Value = $ "{ utcNow . ToUnixTimeSeconds ( ) } " } ,
75+ new ( ) { Type = "nbf" , Value = $ "{ utcNow . ToUnixTimeSeconds ( ) } " } ,
76+ new ( ) { Type = "nbf" , Value = $ "{ utcNow . AddMinutes ( 90 ) . ToUnixTimeSeconds ( ) } " } ,
77+ 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/" } ,
80+ } ;
81+
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 ) ?? [ ] ;
84+
85+ var claims = new List < MsClientPrincipalClaim > ( ) ;
86+ claims . AddRange ( defaultClaims ) ;
87+ if ( userRoleClaims . Any ( ) == true )
88+ {
89+ claims . AddRange ( userRoleClaims ) ;
90+ }
91+ if ( userClaimClaims . Any ( ) == true )
92+ {
93+ var userClaimClaimsWithoutUsername = userClaimClaims . Where ( p => p . Type ! . Equals ( "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" , StringComparison . InvariantCultureIgnoreCase ) != true ) ;
94+ claims . AddRange ( userClaimClaimsWithoutUsername ) ;
95+ }
96+ var principal = new MsClientPrincipal ( )
97+ {
98+ IdentityProvider = identityProvider ,
99+ NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" ,
100+ RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" ,
101+ Claims = claims ,
102+ } ;
103+
104+ return principal ;
105+ }
106+
107+ private MsClientPrincipal BuildGitHubMsClientPrincipal ( string ? identityProvider , string ? userId , string ? username , string ? userRoles , string ? userClaims )
108+ {
109+ throw new NotImplementedException ( ) ;
110+ }
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+ }
31126}
0 commit comments