none
DirectoryServices - Windows Authentication / Impersonation - Access is denied Exception RRS feed

  • Question

  • Hi,

    I work on a WCF service to manage groups members from an ASP.NET MVC web application hosted on IIS webserver with Windows Authentification enabled. Like that :

    Client (web browser) -> Website (ASP.NET MVC 5) -> Webservice WCF -> AD

    Both Website and WCF webservice are on the same server.

    Users are connected successfully to the service with their identity but they can't change groups membership, Save() method of GroupPrincipal class returns "Access is denied" Exception.

    Server stack trace: 
       at System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
       at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
       at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
    
    Exception rethrown at [0]: 
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at GHESPAR_WEB.ServiceAPI.IGhesparService.AddMembersToGroup(String groupName, String[] users)
       at GHESPAR_WEB.ServiceAPI.GhesparServiceClient.AddMembersToGroup(String groupName, String[] users)
       at GHESPAR_WEB.Controllers.HomeController.AddUsersToGroup(String groupName, String[] users)

    At the same time, user can update membership list without any problem with RSAT, so it isn't a "simple" permission issue.

    The website works well on my computer with IIS Express and Visual Studio, with same AD and my Windows account. When I try with production server, access is denied too. So IIS is probably misconfigured or maybe my webservices.

    Source code :

    AddMembersToGroup() Method in WCF service :

    [OperationBehavior(Impersonation = ImpersonationOption.Required)]
    public void AddMembersToGroup(string groupName, string[] users)
    {
        string identity = ServiceSecurityContext.Current.WindowsIdentity.Name;
        string domain = identity.Split('\\')[0];
    
        using (HostingEnvironment.Impersonate())
        {
            using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
            {
                GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName);
    
                foreach (var user in users)
                {
                    group.Members.Add(context, IdentityType.Name, user);
                }
    
                group.Save(); // <- Access is denied exception
            }
        }
    }

    ServiceSecurityContext server side properties values when user is connected seems good.

    ServiceSecurityContext.Current.WindowsIdentity.ImpersonationLevel = Impersonation
    ServiceSecurityContext.Current.WindowsIdentity.IsAuthenticated = true
    ServiceSecurityContext.Current.WindowsIdentity.AuthenticationType = Negotiate
    ServiceSecurityContext.Current.WindowsIdentity.Name = "DOMAIN\USERNAME" (current connected user)

    I have same values with Visual studio debugger on my desktop computer and IIS Express.

    AddUsersToGroup() Controller Method in ASP.NET webapp :

    [HttpPost]
    [Route("addMembersToGroup")]
    public ActionResult AddUsersToGroup(string groupName, string[] users)
    {
        try
        {
            GhesparServiceClient client = new GhesparServiceClient();
            client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
            client.ChannelFactory.Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
            client.AddMembersToGroup(groupName, users);
            client.Close();
        }
        catch (FaultException<Fault> fault)
        {
            return Json(new { success = false, message = fault.Detail.Message });
        }
        catch (Exception e)
        {
            return Json(new { success = false, message = e.Message, trace = e.StackTrace });
        }
    
        return Json(new { success = true });
    }

    Configuration files on production server :

    WCF web.config : https://pastebin.com/YCUFSbaY

    ASP.NET web.config : https://pastebin.com/6FDPmPXH

    IIS configuration on production server :

    - I enabled ASP.NET Impersonation, Windows Authentification and disabled Anonymous Authentication for ASP.NET app.

    - I enabled Windows Authentification and disabled Anonymous Authentication for WCF app.

    - Switch Managed pipeline mode to "classic" and identity to ApplicationPoolIdentity for ASP.NET application pool.

    - Switch Managed pipeline mode to "Integrated" and identity to ApplicationPoolIdentity for WCF application pool.

    UPDATE: When I change the IIS WCF application pool to run under a user domain account instead of the Application Pool Identity, it works. How can I run a WCF application pool under current user identity without getting "Access is Denied" Exception on GroupPrincipal.Save() method ?

    UPDATE 2 : I tried with "ServiceSecurityContext.Current.WindowsIdentity.Impersonate()" instead of "HostingEnvironment.Impersonate()" to impersonate user identity before calling Save() Method but I got this exception : "An operations error occurred"

    Did I forget something ? :)

    Best regards.










    • Edited by _Hardware_ Friday, January 11, 2019 6:34 AM
    Friday, January 11, 2019 6:32 AM

Answers

  • I found the solution :)

    Impersonation-level token from WCF attributes can only be used for local resource access. To use delegation to access Network Resources, you must configure the computer object (webserver) in Active Directory to be trusted for delegation and run the WCF service under the Network Service account.

    And configure IIS 8 wcf webservice for constrained delegation via IIS configuration editor :

    system.webServer/security/authentication/windowsAuthentication -useAppPoolCredentials:true

    Documentation :

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff649252(v=pandp.10)#use-delegation-to-access-network-resources

    https://docs.microsoft.com/en-us/microsoft-desktop-optimization-pack/appv-v4/how-to-configure-the-server-to-be-trusted-for-delegation#to-configure-constrained-delegation-when-the-domain-functional-level-is-windows-server-2003-windows-server-2008-or-windows-server-2008-r2



    • Marked as answer by _Hardware_ Monday, January 14, 2019 3:28 PM
    • Edited by _Hardware_ Monday, January 14, 2019 3:29 PM
    Monday, January 14, 2019 3:28 PM

All replies

  • Hi _Hardware_,

    As far as I know, the only reason possibly cause the issue is Application identity, I suggest you try to change the wcf application pool identity to specified someone has the permission to change groups membership and set up the website application pool identity to LocalSystem.

    Best Regards

    Abraham

    Monday, January 14, 2019 5:39 AM
    Moderator
  • Thank you for your answer. When I change the wcf application pool identity to a user domain account who has the permission, it works. I can confirm the save() method check only user pool permissions and not the Windows identity of the current user, so this behavior doesn't suits my needs.

    There is no solution to do that without a service account on wcf application pool, to run this pool with current user identity ? That's the main purpose of backend impersonation mechanism. 

    ServiceSecurityContext.Current.WindowsIdentity.Impersonate() doesn't seems to work with GroupPrincipal.Save(), I don't know why. Maybe the current ServiceSecurityContext isn't compatible with AD connection PrincipalContext (ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing) ?

    if (ServiceSecurityContext.Current.WindowsIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation || ServiceSecurityContext.Current.WindowsIdentity.ImpersonationLevel == TokenImpersonationLevel.Delegation)
    {
        using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
        {
            using (PrincipalContext context = new PrincipalContext(ContextType.Domain, domain))
            {
                // Error : "An operations error occurred"
            }
        }
    }



    • Edited by _Hardware_ Monday, January 14, 2019 12:59 PM
    Monday, January 14, 2019 9:49 AM
  • Why do you need a domain user account to do anything using a WCF Web service?
    Monday, January 14, 2019 2:08 PM
  • I found the solution :)

    Impersonation-level token from WCF attributes can only be used for local resource access. To use delegation to access Network Resources, you must configure the computer object (webserver) in Active Directory to be trusted for delegation and run the WCF service under the Network Service account.

    And configure IIS 8 wcf webservice for constrained delegation via IIS configuration editor :

    system.webServer/security/authentication/windowsAuthentication -useAppPoolCredentials:true

    Documentation :

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ff649252(v=pandp.10)#use-delegation-to-access-network-resources

    https://docs.microsoft.com/en-us/microsoft-desktop-optimization-pack/appv-v4/how-to-configure-the-server-to-be-trusted-for-delegation#to-configure-constrained-delegation-when-the-domain-functional-level-is-windows-server-2003-windows-server-2008-or-windows-server-2008-r2



    • Marked as answer by _Hardware_ Monday, January 14, 2019 3:28 PM
    • Edited by _Hardware_ Monday, January 14, 2019 3:29 PM
    Monday, January 14, 2019 3:28 PM