Как да извикам net.pipe(named pipe) WCF услуга, представена като Windows Service ?

+2 гласа
259 прегледа
попитан 2016 април 18 от Nikoleta.V. (4,090 точки)

Имам проблем с извикването на WCF услуга с net.pipe чрез Windows impersonation през C# Windows service. 

За какво става въпрос 

Услугата чете от опашка и създава дъщерни домейни на приложението, всеки работещ в различен модул, в зависимост от какво е взето от опашката. Windows service-а се казва “JobQueueAgent”, а модулите са “Job”. Всеки модул може да се пусне като отделен потребител. Използваме impersonation вътре в модула, за да го постигнем. Ето как е логическата работа на услугата: 

JobQueueAgent (Windows Service – Primary User) >> Създава job domain >> Job Domain (App Domain) >> Impersonate на Sub User >> Пуска модула в нишка с impersonation >> Job (Module – Sub User) >> логика на модула 

“Primary User” и “Sub User” са домейн акаунти с права да се логват като услуги. 

Услугата върви на виртуален сървър с Windows Server 2012 R2. 

Ето и кода за impersonation, който използвам: 

namespace JobQueue.WindowsServices 

    using System; 

    using System.ComponentModel; 

    using System.Net; 

    using System.Runtime.InteropServices; 

    using System.Security.Authentication; 

    using System.Security.Permissions; 

    using System.Security.Principal; 

    internal sealed class ImpersonatedIdentity : IDisposable 

    { 

        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] 

        public ImpersonatedIdentity(NetworkCredential credential) 

        { 

            if (credential == null) throw new ArgumentNullException("credential"); 

            if (LogonUser(credential.UserName, credential.Domain, credential.Password, 5, 0, out _handle)) 

            { 

                _context = WindowsIdentity.Impersonate(_handle); 

            } 

            else 

            { 

                throw new AuthenticationException("Impersonation failed.", newWin32Exception(Marshal.GetLastWin32Error())); 

            } 

        } 

        ~ImpersonatedIdentity() 

        { 

            Dispose(); 

        } 

        public void Dispose() 

        { 

            if (_handle != IntPtr.Zero) 

            { 

                CloseHandle(_handle); 

                _handle = IntPtr.Zero; 

            } 

            if (_context != null) 

            { 

                _context.Undo(); 

                _context.Dispose(); 

                _context = null; 

            } 

            GC.SuppressFinalize(this); 

        } 

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 

        [return: MarshalAs(UnmanagedType.Bool)] 

        private static extern bool LogonUser(string userName, string domain, string password, int logonType,int logonProvider, out IntPtr handle); 

        [DllImport("kernel32.dll", SetLastError = true)] 

        [return: MarshalAs(UnmanagedType.Bool)] 

        private static extern bool CloseHandle(IntPtr handle); 

        private IntPtr _handle = IntPtr.Zero; 

        private WindowsImpersonationContext _context; 

    } 

Какъв е проблемът 

Някои модули изискват да се извика друга Windows услуга,която върви на сървъра, през net.pipe WCF. Net.pipe се чупи докато върви impersonation. 

Ето и exception-а, който получавам: 

    Unhandled Exception: System.ComponentModel.Win32Exception: Access is denied 

    Server stack trace: at System.ServiceModel.Channels.AppContainerInfo.GetCurrentProcessToken() at System.ServiceModel.Channels.AppContainerInfo.RunningInAppContainer() at System.ServiceModel.Channels.AppContainerInfo.get_IsRunningInAppContainer() at System.ServiceModel.Channels.PipeSharedMemory.BuildPipeName(String pipeGuid) 

Net.pipe успява да сработи,когато не минава през impersonation. Успява и когато потребителя,който impersonation-вам е добавен в администраторската група. Това предполага, че потребителя се нуждае от някакви права, за да направи това извикване по време на impersonation. Не можах да разбера какви права или достъп му трябват, за да го направи. Не е приемливо да му се дават администраторски права. 

Това известен проблем ли е? Има ли определени права, от които се нуждае потребителя? Какво да променя в кода,за да се оправи? 

1 отговор

0 гласа
отговорени 2016 април 19 от valeri.hristov (7,340 точки)

Проблемът се решава като промениш правата за достъп на thread identity. Ето как ще изглежда кодът:

using System;

using System.ComponentModel;

using System.Net;

using System.Runtime.InteropServices;

using System.Security.AccessControl;

using System.Security.Authentication;

using System.Security.Permissions;

using System.Security.Principal;

internal sealed class ImpersonatedIdentity : IDisposable

{

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]

    public ImpersonatedIdentity(NetworkCredential credential)

    {

        if (credential == null) throw new ArgumentNullException(nameof(credential));

        _processIdentity = WindowsIdentity.GetCurrent();

        var tokenSecurity = new TokenSecurity(new SafeTokenHandleRef(_processIdentity.Token), AccessControlSections.Access);

        if (!LogonUser(credential.UserName, credential.Domain, credential.Password, 5, 0, out _token))

        {

            throw new AuthenticationException("Impersonation failed.", new Win32Exception(Marshal.GetLastWin32Error()));

        }

        _threadIdentity = new WindowsIdentity(_token);

        tokenSecurity.AddAccessRule(new AccessRule<TokenRights>(_threadIdentity.User, TokenRights.TOKEN_QUERY, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Allow));

        tokenSecurity.ApplyChanges();

        _context = _threadIdentity.Impersonate();

    }

    ~ImpersonatedIdentity()

    {

        Dispose();

    }

    public void Dispose()

    {

        if (_processIdentity != null)

        {

            _processIdentity.Dispose();

            _processIdentity = null;

        }

        if (_token != IntPtr.Zero)

        {

            CloseHandle(_token);

            _token = IntPtr.Zero;

        }

        if (_context != null)

        {

            _context.Undo();

            _context.Dispose();

            _context = null;

        }

        GC.SuppressFinalize(this);

    }

    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]

    [return: MarshalAs(UnmanagedType.Bool)]

    private static extern bool LogonUser(string userName, string domain, string password, int logonType, int logonProvider, out IntPtr handle);

    [DllImport("kernel32.dll", SetLastError = true)]

    [return: MarshalAs(UnmanagedType.Bool)]

    private static extern bool CloseHandle(IntPtr handle);

    private WindowsIdentity _processIdentity;

    private WindowsIdentity _threadIdentity;

    private IntPtr _token = IntPtr.Zero;

    private WindowsImpersonationContext _context;

    [Flags]

    private enum TokenRights

    {

        TOKEN_QUERY = 8

    }

    private class TokenSecurity : ObjectSecurity<TokenRights>

    {

        public TokenSecurity(SafeHandle safeHandle, AccessControlSections includeSections)

            : base(false, ResourceType.KernelObject, safeHandle, includeSections)

        {

            _safeHandle = safeHandle;

        }

        public void ApplyChanges()

        {

            Persist(_safeHandle);

        }

коментиран 2016 април 20 от Nikoleta.V. (4,090 точки)
Благодаря ;)
...