1- using System . Net ;
1+ using System ;
2+ using System . Net ;
23using System . Security . Claims ;
34using Microsoft . AspNetCore . Http . HttpResults ;
45using Npgsql ;
5-
66using static NpgsqlRest . Auth . ClaimsDictionary ;
77
88namespace NpgsqlRest . Auth ;
99
10- internal static class AuthHandler
10+ public static class AuthHandler
1111{
1212 public static async Task HandleLoginAsync (
1313 NpgsqlCommand command ,
@@ -21,13 +21,12 @@ public static async Task HandleLoginAsync(
2121 string ? message = null ;
2222 string ? userId = null ;
2323 string ? userName = null ;
24- var authenticationType = options . AuthenticationOptions . DefaultAuthenticationType ;
25- var claims = new List < Claim > ( 10 ) ;
24+ var opts = options . AuthenticationOptions ;
25+ List < Claim > claims = new ( 10 ) ;
2626 var verificationPerformed = false ;
2727 var verificationFailed = false ;
2828
29-
30- await using ( var reader = await command . ExecuteReaderAsync ( ) )
29+ await using ( NpgsqlDataReader reader = await command . ExecuteReaderAsync ( ) )
3130 {
3231 if ( await reader . ReadAsync ( ) is false )
3332 {
@@ -44,12 +43,12 @@ public static async Task HandleLoginAsync(
4443 {
4544 var name1 = routine . OriginalColumnNames [ i ] ;
4645 var name2 = routine . ColumnNames [ i ] ;
47- var descriptor = routine . ColumnsTypeDescriptor [ i ] ;
46+ TypeDescriptor descriptor = routine . ColumnsTypeDescriptor [ i ] ;
4847
49- if ( options . AuthenticationOptions . StatusColumnName is not null )
48+ if ( opts . StatusColumnName is not null )
5049 {
51- if ( string . Equals ( name1 , options . AuthenticationOptions . StatusColumnName , StringComparison . OrdinalIgnoreCase ) ||
52- string . Equals ( name2 , options . AuthenticationOptions . StatusColumnName , StringComparison . OrdinalIgnoreCase ) )
50+ if ( string . Equals ( name1 , opts . StatusColumnName , StringComparison . OrdinalIgnoreCase ) ||
51+ string . Equals ( name2 , opts . StatusColumnName , StringComparison . OrdinalIgnoreCase ) )
5352 {
5453 if ( descriptor . IsBoolean )
5554 {
@@ -78,88 +77,47 @@ public static async Task HandleLoginAsync(
7877 }
7978 }
8079
81- if ( options . AuthenticationOptions . SchemeColumnName is not null )
80+ if ( opts . SchemeColumnName is not null )
8281 {
83- if ( string . Equals ( name1 , options . AuthenticationOptions . SchemeColumnName , StringComparison . OrdinalIgnoreCase ) ||
84- string . Equals ( name2 , options . AuthenticationOptions . SchemeColumnName , StringComparison . OrdinalIgnoreCase ) )
82+ if ( string . Equals ( name1 , opts . SchemeColumnName , StringComparison . OrdinalIgnoreCase ) ||
83+ string . Equals ( name2 , opts . SchemeColumnName , StringComparison . OrdinalIgnoreCase ) )
8584 {
8685 scheme = reader ? . GetValue ( i ) . ToString ( ) ;
8786 continue ;
8887 }
8988 }
9089
91- if ( options . AuthenticationOptions . MessageColumnName is not null )
90+ if ( opts . MessageColumnName is not null )
9291 {
93- if ( string . Equals ( name1 , options . AuthenticationOptions . MessageColumnName , StringComparison . OrdinalIgnoreCase ) ||
94- string . Equals ( name2 , options . AuthenticationOptions . MessageColumnName , StringComparison . OrdinalIgnoreCase ) )
92+ if ( string . Equals ( name1 , opts . MessageColumnName , StringComparison . OrdinalIgnoreCase ) ||
93+ string . Equals ( name2 , opts . MessageColumnName , StringComparison . OrdinalIgnoreCase ) )
9594 {
9695 message = reader ? . GetValue ( i ) . ToString ( ) ;
9796 continue ;
9897 }
9998 }
100-
101- string ? claimType ;
102- if ( options . AuthenticationOptions . UseActiveDirectoryFederationServicesClaimTypes )
103- {
104- if ( ClaimTypesDictionary . TryGetValue ( name1 . ToLowerInvariant ( ) , out claimType ) is false )
105- {
106- if ( ClaimTypesDictionary . TryGetValue ( name2 . ToLowerInvariant ( ) , out claimType ) is false )
107- {
108- claimType = name1 ;
109- }
110- }
111- }
112- else
99+ var ( userNameCurrent , userIdCurrent ) = AddClaimFromReader ( opts , i , descriptor , reader ! , claims , name1 , name2 ) ;
100+ if ( userNameCurrent is not null )
113101 {
114- claimType = name1 ;
102+ userName = userNameCurrent ;
115103 }
116-
117- if ( reader ? . IsDBNull ( i ) is true )
104+ if ( userIdCurrent is not null )
118105 {
119- claims . Add ( new Claim ( claimType , "" ) ) ;
120- if ( string . Equals ( claimType , options . AuthenticationOptions . DefaultNameClaimType , StringComparison . Ordinal ) )
121- {
122- userName = null ;
123- }
124- else if ( string . Equals ( claimType , options . AuthenticationOptions . DefaultUserIdClaimType , StringComparison . Ordinal ) )
125- {
126- userId = null ;
127- }
128- }
129- else if ( descriptor . IsArray )
130- {
131- object [ ] ? values = reader ? . GetValue ( i ) as object [ ] ;
132- for ( int j = 0 ; j < values ? . Length ; j ++ )
133- {
134- claims . Add ( new Claim ( claimType , values [ j ] ? . ToString ( ) ?? "" ) ) ;
135- }
136- }
137- else
138- {
139- string ? value = reader ? . GetValue ( i ) ? . ToString ( ) ;
140- claims . Add ( new Claim ( claimType , value ?? "" ) ) ;
141- if ( string . Equals ( claimType , options . AuthenticationOptions . DefaultNameClaimType , StringComparison . Ordinal ) )
142- {
143- userName = value ;
144- }
145- else if ( string . Equals ( claimType , options . AuthenticationOptions . DefaultUserIdClaimType , StringComparison . Ordinal ) )
146- {
147- userId = value ;
148- }
106+ userId = userIdCurrent ;
149107 }
150108 }
151109
152110 // hash verification last
153- if ( options . AuthenticationOptions . HashColumnName is not null &&
154- options . AuthenticationOptions . PasswordHasher is not null &&
155- options . AuthenticationOptions . PasswordParameterNameContains is not null )
111+ if ( opts . HashColumnName is not null &&
112+ opts . PasswordHasher is not null &&
113+ opts . PasswordParameterNameContains is not null )
156114 {
157115 for ( int i = 0 ; i < routine . ColumnCount ; i ++ )
158116 {
159117 var name1 = routine . OriginalColumnNames [ i ] ;
160118 var name2 = routine . ColumnNames [ i ] ;
161- if ( string . Equals ( name1 , options . AuthenticationOptions . HashColumnName , StringComparison . OrdinalIgnoreCase ) ||
162- string . Equals ( name2 , options . AuthenticationOptions . HashColumnName , StringComparison . OrdinalIgnoreCase ) )
119+ if ( string . Equals ( name1 , opts . HashColumnName , StringComparison . OrdinalIgnoreCase ) ||
120+ string . Equals ( name2 , opts . HashColumnName , StringComparison . OrdinalIgnoreCase ) )
163121 {
164122 if ( reader ? . IsDBNull ( i ) is false )
165123 {
@@ -173,15 +131,15 @@ options.AuthenticationOptions.PasswordHasher is not null &&
173131 {
174132 var parameter = command . Parameters [ j ] ;
175133 var name = ( parameter as NpgsqlRestParameter ) ? . ActualName ;
176- if ( name is not null && name . Contains ( options . AuthenticationOptions . PasswordParameterNameContains , // found password parameter
134+ if ( name is not null && name . Contains ( opts . PasswordParameterNameContains , // found password parameter
177135 StringComparison . OrdinalIgnoreCase ) )
178136 {
179137 foundPasswordParameter = true ;
180138 var pass = parameter ? . Value ? . ToString ( ) ;
181139 if ( pass is not null && parameter ? . Value != DBNull . Value )
182140 {
183141 verificationPerformed = true ;
184- if ( options . AuthenticationOptions . PasswordHasher ? . VerifyHashedPassword ( hash , pass ) is false )
142+ if ( opts . PasswordHasher ? . VerifyHashedPassword ( hash , pass ) is false )
185143 {
186144 logger ? . VerifyPasswordFailed ( endpoint , userId , userName ) ;
187145 context . Response . StatusCode = ( int ) HttpStatusCode . NotFound ;
@@ -196,7 +154,7 @@ options.AuthenticationOptions.PasswordHasher is not null &&
196154 {
197155 logger ? . CantFindPasswordParameter ( endpoint ,
198156 command . Parameters . Select ( p => ( p as NpgsqlRestParameter ) ? . ActualName ) ? . ToArray ( ) ,
199- options . AuthenticationOptions . PasswordParameterNameContains ) ;
157+ opts . PasswordParameterNameContains ) ;
200158 }
201159 }
202160 }
@@ -209,12 +167,12 @@ options.AuthenticationOptions.PasswordHasher is not null &&
209167 {
210168 if ( verificationFailed is true )
211169 {
212- if ( string . IsNullOrEmpty ( options . AuthenticationOptions . PasswordVerificationFailedCommand ) is false )
170+ if ( string . IsNullOrEmpty ( opts . PasswordVerificationFailedCommand ) is false )
213171 {
214172 using var failedCommand = connection ? . CreateCommand ( ) ;
215173 if ( failedCommand is not null )
216174 {
217- failedCommand . CommandText = options . AuthenticationOptions . PasswordVerificationFailedCommand ;
175+ failedCommand . CommandText = opts . PasswordVerificationFailedCommand ;
218176 var paramCount = failedCommand . CommandText . PgCountParams ( ) ;
219177 if ( paramCount >= 1 )
220178 {
@@ -235,12 +193,12 @@ options.AuthenticationOptions.PasswordHasher is not null &&
235193 }
236194 else
237195 {
238- if ( string . IsNullOrEmpty ( options . AuthenticationOptions . PasswordVerificationSucceededCommand ) is false )
196+ if ( string . IsNullOrEmpty ( opts . PasswordVerificationSucceededCommand ) is false )
239197 {
240198 using var succeededCommand = connection ? . CreateCommand ( ) ;
241199 if ( succeededCommand is not null )
242200 {
243- succeededCommand . CommandText = options . AuthenticationOptions . PasswordVerificationSucceededCommand ;
201+ succeededCommand . CommandText = opts . PasswordVerificationSucceededCommand ;
244202 var paramCount = succeededCommand . CommandText . PgCountParams ( ) ;
245203
246204 if ( paramCount >= 1 )
@@ -265,9 +223,9 @@ options.AuthenticationOptions.PasswordHasher is not null &&
265223 {
266224 var principal = new ClaimsPrincipal ( new ClaimsIdentity (
267225 claims ,
268- scheme ?? authenticationType ,
269- nameType : options . AuthenticationOptions . DefaultNameClaimType ,
270- roleType : options . AuthenticationOptions . DefaultRoleClaimType ) ) ;
226+ scheme ?? opts . DefaultAuthenticationType ,
227+ nameType : opts . GetUserNameClaimType ( ) ,
228+ roleType : opts . GetRoleClaimType ( ) ) ) ;
271229
272230 if ( Results . SignIn ( principal : principal , authenticationScheme : scheme ) is not SignInHttpResult result )
273231 {
@@ -283,6 +241,71 @@ options.AuthenticationOptions.PasswordHasher is not null &&
283241 }
284242 }
285243
244+ public static ( string ? userName , string ? userId ) AddClaimFromReader (
245+ NpgsqlRestAuthenticationOptions options ,
246+ int i ,
247+ TypeDescriptor descriptor ,
248+ NpgsqlDataReader reader ,
249+ List < Claim > claims ,
250+ string name1 ,
251+ string name2 )
252+ {
253+ string ? claimType ;
254+ string ? userName = null ;
255+ string ? userId = null ;
256+
257+ if ( options . UseActiveDirectoryFederationServicesClaimTypes )
258+ {
259+ if ( ClaimTypesDictionary . TryGetValue ( name1 . ToLowerInvariant ( ) , out claimType ) is false )
260+ {
261+ if ( ClaimTypesDictionary . TryGetValue ( name2 . ToLowerInvariant ( ) , out claimType ) is false )
262+ {
263+ claimType = name1 . Replace ( "_" , "" ) ;
264+ }
265+ }
266+ }
267+ else
268+ {
269+ claimType = name1 . Replace ( "_" , "" ) ;
270+ }
271+
272+ if ( reader ? . IsDBNull ( i ) is true )
273+ {
274+ claims . Add ( new Claim ( claimType , "" ) ) ;
275+ if ( string . Equals ( claimType , options . GetUserNameClaimType ( ) , StringComparison . Ordinal ) )
276+ {
277+ userName = null ;
278+ }
279+ else if ( string . Equals ( claimType , options . GetUserIdClaimType ( ) , StringComparison . Ordinal ) )
280+ {
281+ userId = null ;
282+ }
283+ }
284+ else if ( descriptor . IsArray )
285+ {
286+ object [ ] ? values = reader ? . GetValue ( i ) as object [ ] ;
287+ for ( int j = 0 ; j < values ? . Length ; j ++ )
288+ {
289+ claims . Add ( new Claim ( claimType , values [ j ] ? . ToString ( ) ?? "" ) ) ;
290+ }
291+ }
292+ else
293+ {
294+ string ? value = reader ? . GetValue ( i ) ? . ToString ( ) ;
295+ claims . Add ( new Claim ( claimType , value ?? "" ) ) ;
296+ if ( string . Equals ( claimType , options . GetUserNameClaimType ( ) , StringComparison . Ordinal ) )
297+ {
298+ userName = value ;
299+ }
300+ else if ( string . Equals ( claimType , options . GetUserIdClaimType ( ) , StringComparison . Ordinal ) )
301+ {
302+ userId = value ;
303+ }
304+ }
305+
306+ return ( userName , userId ) ;
307+ }
308+
286309 public static async Task HandleLogoutAsync ( NpgsqlCommand command , Routine routine , HttpContext context )
287310 {
288311 if ( routine . IsVoid )
0 commit comments