ArgumentNullException with custom auth provider in ServiceStack

106 views Asked by At

I've made a custom auth provider for LDAP (Active Directory) based on the CredentialsAuthProvider. Following the docs I've overridden TryAuthenticate and OnAuthenticated, returning true at the end. I've also tried without OnAuthenticated.

I'm using UseDistinctRoleTables for the OrmLiteAuthRepository, and I've observed in the tables that roles are being created in UserRole.

However I'm getting the exception: ArgumentNullException. Fieldname "s".

"stackTrace": "[Authenticate: 20/03/2020 16:46:30]:
[REQUEST: {provider:Credentials,userName:xxxx,password:yyyy}]
System.ArgumentNullException: Value cannot be null.
Parameter name: s
   at lambda_method(Closure , Object , List`1 )
   at ServiceStack.OrmLite.SqlExpression`1.EvaluateExpression(Expression m) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\Expressions\\SqlExpression.cs:line 2374
   at ServiceStack.OrmLite.SqlExpression`1.VisitBinary(BinaryExpression b) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\Expressions\\SqlExpression.cs:line 1658
   at ServiceStack.OrmLite.SqlExpression`1.VisitBinary(BinaryExpression b) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\Expressions\\SqlExpression.cs:line 1622
   at ServiceStack.OrmLite.SqlExpression`1.VisitLambda(LambdaExpression lambda) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\Expressions\\SqlExpression.cs:line 1589
   at ServiceStack.OrmLite.SqlExpression`1.AppendToWhere(String condition, Expression predicate) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\Expressions\\SqlExpression.cs:line 555
   at ServiceStack.OrmLite.ReadExpressionCommandExtensions.Select[T](IDbCommand dbCmd, Expression`1 predicate) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\Expressions\\ReadExpressionCommandExtensions.cs:line 22
   at ServiceStack.OrmLite.OrmLiteExecFilter.Exec[T](IDbConnection dbConn, Func`2 filter) in C:\\BuildAgent\\work\\27e4cc16641be8c0\\src\\ServiceStack.OrmLite\\OrmLiteExecFilter.cs:line 64
   at ServiceStack.Auth.OrmLiteAuthRepositoryBase`2.<>c__DisplayClass33_0.<GetRoles>b__0(IDbConnection db) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack.Server\\Auth\\OrmLiteAuthRepository.cs:line 571
   at ServiceStack.Auth.OrmLiteAuthRepository`2.Exec[T](Func`2 fn) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack.Server\\Auth\\OrmLiteAuthRepository.cs:line 51
   at ServiceStack.Auth.AuthenticateService.Post(Authenticate request) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Auth\\AuthenticateService.cs:line 231
   at ServiceStack.Host.ServiceRunner`1.ExecuteAsync(IRequest req, Object instance, TRequest requestDto) in C:\\BuildAgent\\work\\3481147c480f4a2f\\src\\ServiceStack\\Host\\ServiceRunner.cs:line 133",

I've stripped down my code. In Startup.cs:

Plugins.Add(new AuthFeature( () => new AuthUserSession(),
            new IAuthProvider[] {
                new LdapCredentialsAuthProvider(AppSettings),
1

There are 1 answers

2
mythz On BEST ANSWER

The issue is ServiceStack's AuthenticateService is trying to populate the AuthenticateResponse Roles and Permissions but your Custom AuthProvider isn't populating the session.UserAuthId which is used to query the Auth Repository for the roles.

The solution is for your Custom AuthProvider to populate the Sessions UserAuthId with the Id of the Authenticated User.

You can also prevent this Exception by disabling ServiceStack from trying to populate the Roles/Permissions by setting IncludeRolesInAuthenticateResponse=false, e.g:

Plugins.Add(new AuthFeature( () => new AuthUserSession(),
    new IAuthProvider[] {
        new LdapCredentialsAuthProvider(AppSettings),                     
    }, 
    "/login.html"
) {
    IncludeRolesInAuthenticateResponse = false,
});

In the next ServiceStack v5.8.1 now on MyGet it wont try attempting to retrieve the roles if the UserAuthId isn't populated, but your Custom AuthProvider should still be populating it with the Unique Id of the Authenticated User.