Implement IManageRoles on the RedisAuthRepository

Are there any plans to implement IManageRoles for RedisAuthRepository? If not, would it be difficult to make an implementation myself, given the fact that I am using ServiceStack only for a few months? If it is not too difficult I could try and make it available if this is of any interest and someone would support me, if I have questions.

I have my entire user management for several services moved from SQL Server to Redis and it would help me a lot… However I am quite new to ServiceStack and therefore not so familiar with the ServiceStack code… I am coding 20+ years but was mainly doing C/C++, Java, SQL on many different servers, MiddleWare and other ‘legacy’ stuff. Now doing C# and NoSQL…

RedisAuthRepository already implements IManageApiKeys

Hmm, I was looking for IManageRoles and NOT IManageApiKeys. And if I look at the right spot, this is only implemented by OrmLiteAuthRepositoryBase.

I found that hint in old Release Notes, but when looking at the source on GitHub I could not see, that it is implemented on Redis (maybe I am blind…)

Apologies I read that wrong, Redis shouldn’t need to implement IManageRoles because the User Roles are blobbed with the UserAuth POCO, OrmLite uses it because they include an option to maintain the User Roles in distinct tables.

What’s the reason for wanting RedisAuthRepository to implement IManageRoles?

No problem! I am not happy with the current implementation because I cannot pack all information I need into a single string field, I need a complex object. Here is what I would need:

public interface IRole
{
    string Name { get; set; }
    string Description { get; set; }
    string ApplicationId { get; set; }  //could also be a int, Guid, but string is more universal
    RoleType Type { get; set; }
}

public enum RoleType
{
    SystemRole,
    StandardRole,
    ApplicationRole,
    // maybe others.....
}

public class Role : IRole
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string ApplicationId { get; set; }
    public RoleType Type { get; set; }
    // maybe other props if needed

    public Role()
    {
        Type = RoleType.ApplicationRole;
    }

    // stuff for Redis only
    // hash:IRole:Name>ApplicationId
    // hash:IRole:RoleType>RoleType
    // hash:IUserAuth:UserName:Role>RoleName
    // hash:IRole:Name>IUserAuth:UserName
    // also your nice UserNameOrEmail ....
}

And this is an example how I would use it:

    public void Dosomething()
    {
        var adminRole = new Role
        {
            Name = "Administrator",
            Description = "General Administrator role, has no limitations",
            ApplicationId = "All",
            Type = RoleType.SystemRole
        };

        var userRole = new Role
        {
            Name = "User",
            Description = "General user role, allowed to perform standard business operations",
            ApplicationId = "All",
            Type = RoleType.SystemRole
        };
        var invoiceApproverRole = new Role
        {
            Name = "ApproveInvoices",
            Description = "Members are allowed to approve invoices",
            ApplicationId = "Invoice",
            Type = RoleType.ApplicationRole
        };
        var invoicePosterRole = new Role
        {
            Name = "PostInvoices",
            Description = "Members are allowed to post approved invoices",
            ApplicationId = "Invoice",
            Type = RoleType.ApplicationRole
        };
    }

The background is: I have multiple applications (services) that use the same (single-signon) user / role database (Moved from SQLServer/NHibernate to Redis). Business data is stored on MongoDB and still some stuff on MSSQL / PostgreSQL. Some general roles like ‘User’ and ‘Administrator’ are available everywhere. Usually an Administrator can do admin things like creating a new user, a user can do standard business stuff like query addresses, products, invoices etc.

Every application may define specific roles as outlined above for an invoicing application. I have some more complex scenarios, e.g. a payroll application which has a few more roles to cover…

The UI offers a possibility to assign roles to specific users in a specific application. Technically this requires the ability to

  • List all roles per application
  • List all role types
  • Find all roles that a user is member of
  • The stuff which is already there: addUserToRole, removeUserFromRole, …

All my apps are multi-tenant, so I have extended my IUserAuth implementation with a property
int TenantId, which is a fixed length integer hash calculated from some mandatory props of my tenant object (Name, parts of the address etc). So I have access to the tenant via this ID. I have created one database per tenant which is very easy when using MongoDB and quite heavy when using any RDBMS… (I made some comments on Stackoverflow yesterday…)

Thats about it. If you think this could be useful for Servicestack let me know if I can be of any help. Please remember that I am quite new to ServiceStack and also C# (which means I am still discovering a lot of new things…) but a C/C++, Java, Groovy and SQL / BI hacker for 20+ years.

Ok you’d need to implement a bespoke solution to cater for your custom requirements, we wouldn’t want it in ServiceStack since it’s not generically applicable to all and we have an existing simple integrated implementation.

I see that you have Role definitions, but do you really need the entire Role complex type on each User? Wouldn’t you just require the name that references the Role definition? If you’re still expecting to control access to services with [RequiredRole("User")] then I don’t see why you need the additional metadata stored with each user. (Also “ApproveInvoices” and “PostInvoices” sounds like permissions to me).

On a side note, I’d strongly recommend against using interfaces on models as you’d typically never mock models and they can cause runtime serialization issues if used/configured incorrectly.

Either way if you want to implement a custom solution I’d first look to see if you can get by just a Custom AuthUserSession containing all the info you need as perhaps you can get by just overriding the HasRole() and HasPermission() implementations. Your Custom AuthProvider could populate the User Session with additional info you need, which may save you from implementing a custom Auth Repository. But you’d still need to source the additional info from somewhere, this previous answer goes through a few different ways of linking additional metadata with users.

Ok, thanks for your tips. I will look at this again in more details.