AspNetWindowsAuthProvider Feeback/Question

  • I primarily use this to leverage integrated(Kerberos/Negotiate) authentication from Windows. One early thing I needed do to was map a user’s AD groups to ServiceStack Roles. Initially, I extended the LoadUserAuthInfo function to do an AD lookup to groups, then dump the list of groups to the user’s AuthUserSession.Roles. This, while a common way people do AD authorization outside of Windows, is a bit expensive because of the LDAP lookup for every auth request. The original IIS request does contain the Kerberos ticket (with the AD groups already burned into the ticket), but I couldn’t get the request without subclassing AspNetWindowsAuthProvider:

    public class CustomWindowsAuthProvider : AspNetWindowsAuthProvider
    {
    public CustomWindowsAuthProvider(IAppHost appHost) : base(appHost)
    {

    }

    public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
    {
    var request = authService.Request.OriginalRequest as System.Web.HttpRequestWrapper;

    using (WindowsIdentity userId = request?.LogonUserIdentity)
    {
    List roles = new List();
    if (userId?.Groups != null)
    foreach (var group in userId.Groups)
    {
    // Remove the domain name from the name of the group, if it has it, and you don’t need it.
    var groupName = new SecurityIdentifier(group.Value).Translate(typeof(NTAccount)).ToString();
    if (groupName.Contains("\"))
    groupName = groupName.Split(’\’)[1];
    roles.Add(groupName);
    }
    session.Roles = roles;
    }
    return base.OnAuthenticated(authService, session, tokens, authInfo);
    }

    }

It would be nice if something similar to the above was burned into the base AspNetAuthProvider. (I’m not sure if the above works for all scenarios).

  • Give an IIS setup with integrated authentication, how does the .NET SSE client authenticate? I didn’t see a Credentials property for the SSE client.

I don’t want to bake this impl into AspNetWindowsAuthProvider which looks like it’s using untested heuristics. But you can use the OnAuthenticated() Session or Auth Events to populate the User Session with these roles.

I’ve just added a change to short-circuit calling IsInRole() if the role already exists in the session in this commit so only the roles the Users aren’t populated with will be. I’ve also added the PopulateUserRoles delegate which will let you override how Users Roles are populated in this commit, so you can override how roles are populated with:

new AspNetWindowsAuthProvider (...) {
    PopulateUserRoles = (request, user, session) => {
        using (WindowsIdentity userId = request?.LogonUserIdentity)
        {
            List roles = new List();
            if (userId?.Groups != null)
                foreach (var group in userId.Groups)
                {
                    // Remove the domain name from the name of the group, if it has it, and you don't need it. 
                    var groupName = new SecurityIdentifier(group.Value).Translate(typeof(NTAccount)).ToString();
                    if (groupName.Contains("\")) 
                    groupName = groupName.Split('\')[1]; 
                    roles.Add(groupName);
                }
            session.Roles = roles;
        }
    }
}

These changes are available from v4.5.7+ that’s now available on MyGet.

You can use the EventStreamRequestFilter to set credentials for connecting to the SSE /event-stream and populate the internal ServiceClient with:

var client = new ServerEventsClient(baseUrl, channel) {
    EventStreamRequestFilter = req => req.Credentials = CredentialCache.DefaultCredentials
};
((ServiceClientBase)client.ServiceClient).Credentials = CredentialCache.DefaultCredentials;
2 Likes

Perfect, thanks so much!