Active Directory Some Users can not login

Issue #319 resolved
Ghislain Hachey created an issue

They are not members of more then 5-6 groups.

[NullReferenceException: Object reference not set to an instance of an object.] Softwords.Web.Providers.<GrantResourceOwnerCredentials>d__2.MoveNext() +8339 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Security.OAuth.<InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync>d__3f.MoveNext() +701 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Security.OAuth.<InvokeTokenEndpointAsync>d__22.MoveNext() +1758 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Security.OAuth.<InvokeAsync>d__0.MoveNext() +1213 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Security.Infrastructure.<Invoke>d__0.MoveNext() +541 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Security.Infrastructure.<Invoke>d__0.MoveNext() +776 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Security.Infrastructure.<Invoke>d__0.MoveNext() +776 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.AspNet.Identity.Owin.<Invoke>d__0.MoveNext() +450 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.AspNet.Identity.Owin.<Invoke>d__0.MoveNext() +450 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<RunApp>d__5.MoveNext() +203 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +62 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.<DoFinalWork>d__2.MoveNext() +193 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() +31 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +119 System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +365 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +134

Comments (3)

  1. Brian Lewis repo owner

    This issue can arise when you are using an entry in AspNetUsers to represent an Ad group; and there is no password set for that AspNetUser record.

    Quick solution: ensure that the columns PasswordHash and SecurityStamp have a value; ie not null. It doesn't actually matter what this value is, because you will not try to log in directly with this user Id. You can, for example, simply copy the values in these fields from another row. this error is thrown deep inside AspNet Identity; working around it in this way is the pragmatic strategy.

    More detail:

    When a user logs in using an AD account, Pineapples interrogates the AD to get a list of the groups of which the user is a member. It then looks for each of these groups as User Name in AspNetUsers. If the AD group corresponds to such a record, the current user is given :

    • all the roles assigned to the AD record

    • all the permissions assigned to the AD record

    Permissions are calculated using the aggregate of the permission claim across all such AspNetUser records representing groups to which the user belongs. see the stored proc GetEffectivePermissions in IdentitiesP for details.

    Note that if there is an AspNetUser record with name DOMAIN_USER this is always included in the list of the users "AD groups". So the simplest way to activate AD authentication is to include this AspNetUser record. All users will be authenticated, and will get any roles and permissions associated to this "user".

    If there is no DOMAIN_USER user, then at least one of the AD groups to which the user belongs must be represented by a record in AspNetUser. Otherwise the user cannot log in. So the simplest way to restrict access to members of a nominated group ( let's say "EMISUsers") is:

    • create the AspNetUser record for EMISUser. Note as per the comment above, the PermissionHash and SecurityStamp are not used, but must not be null

    • assign any roles and permissions to this user

    • remove the record for DOMAIN_USER

    In some cases, you could more simply get the same result by editing the DOMAIN_USER record in AspNetUser to change the name to EMISUsers.

  2. Brian Lewis repo owner

    Note another important issue with AD login on the server:

    The account running the web site must be an AD account, not a machine account or built-in account.

    The account running the web site is the account assigned to the IIS AppPool in which the site is running.

    The PrincipalContext that is interrogated to find the user and their groups is the PrincipalContext in which the apppool account is defined. So it follows that the apppool account must be an AD account to find users in the AD.

    Here's the relevant code in Softwords.Web ADUserManager:

           /// <summary>
            /// get the principal context for verifying a windows user login
            /// Note that this is the context of the 'active user' ( ie the user running the apppool)
            /// so, to verify against the AD, this apppool account should be an AD account too.
            /// </summary>
            /// <returns></returns>
            public ad.PrincipalContext getPrincipalContext()
            {
                return new ad.PrincipalContext(
                        (string.Equals(System.Environment.UserDomainName, System.Environment.MachineName, System.StringComparison.OrdinalIgnoreCase) ?
                               ad.ContextType.Machine : ad.ContextType.Domain),
                        System.Environment.UserDomainName);
            }
    
  3. Log in to comment