Session.Permissions is null when populated with empty list

In this code:

  public override Task<IHttpResult> OnAuthenticatedAsync(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo, CancellationToken token = default)
        {
            // populate session with roles + permissions from autoRepo
            var authRepo = authService.TryResolve<IAuthRepository>();
            var userAuth = authRepo.GetUserAuthByUserName(session.UserAuthName);
            var roles = authRepo.GetRoles(userAuth);
            var permissions = authRepo.GetPermissions(userAuth);
            session.Roles = roles.ToList();
            session.Permissions = permissions.ToList();
            // other stuff

            return base.OnAuthenticatedAsync(authService, session, tokens, authInfo, token);
        }

When I debug the session.Permissions is set to an empty list.

However when calling a regular service right after:

public class MyServices : Service {
    public SomethingResponse Get(Something request)
    {
        var session = GetSession();
        // session.Permissions is null

The session object inside the service has AuthProvider = “jwt”, if that is of any help, and it is configured like this:

new AuthUserSession(),
new JwtAuthProvider(AppSettings) {               
      AuthKeyBase64 = AppSettings.GetString("AuthKeyBase64"),
      ExpireTokensIn = TimeSpan.FromHours(8),                 // default is 14 days
      RequireSecureConnection=false,                          // SSL is terminated on the reverse proxy
},

Is there any reason Permissions is NULL instead of an empty list? Of course I can do a lot of NULL checks, or even use the ?. operator everywhere, but if I forget I’ll have a bug.

You can’t rely on the state of the UserSession when it’s hydrated from a cache so use null guards if you need to manually inspect nested access.

But if you just need to Validate they have the required roles/permissions use the required roles/permissions attributes instead

On Request DTOs:
https://docs.servicestack.net/declarative-validation#type-validators

On Service classes:
https://docs.servicestack.net/authentication-and-authorization#requiredrole-and-requiredpermission-attributes

That’s okay, I’ll use null guards then.

I’m not always using the attributes, since I need to modify my OrmLite queries depending on the permissions (attribute based access control for list-queries).

In that case you can also use the .Safe() extension method when needing to iterate a nullable generic collection, e.g:

foreach (var role in session.Roles.Safe())
{
    //...
}
1 Like

That is fantastic!

I just finished adding the null safe operator like this:

allowed = session.Permissions?.Contains("CreateProcessOfType_" + pDef.Type);

just to find that null does’t count as false, having to add a separate null check anyway.

allowed = session.Permissions?.Contains("CreateProcessOfType_" + pDef.Type) ?? false;

However the Safe() extension makes the code cleaner:

allowed = session.Permissions.Safe().Contains("CreateProcessOfType_" + pDef.Type);

This is probably “creative use” of the Permissions system, but it seems to work.

2 Likes