5

WindowsIdentityを に変換するにはどうすればよいNetworkCredentialでしょうか。匿名の呼び出し元がブロックされていることを確認するために、WCF サービスをテストしています。これを行うには、次のようなことをしたい:

myProxy.ClientCredentials.Windows.ClientCredential = foo(WindowsIdentity.GetAnonymous());

aをa にfoo変換するメソッドWindowsIdentityNetworkCredential

4

3 に答える 3

4

Generally speaking foo does not exist. Since a NetworkCredential is a wider object that WindowsIdentity. That is to say I can use NetworkCredential where I need a WindowsIdentity but not the other way around.

The reason is due to security.

NetworkCredential means you are allowed to take this Identity and use its associated CREDENTIALS on ANOTHER machine.

This means that

  1. You have the users credentials as opposed to just its identity.
  2. That set of credentials is good for impersonation, not just local access.

I will assume that the credentials came from another machine (due to WCF). Again for security reasons, that Network Credential has been converted to a LocalCredential when crossing onto this machine (unless we are talking about Delegation rather than Impersonation). The client machine GAVE the right to use its credentials on the server machine and only the server machine.

If you want to get the NetworkCredential back out you need to do something called Delegation, because of what is called the Multi-Hop problem. This involves Kerberos, a three headed evil dog of the underworld. You don't want to deal with Kerberos.

Generally speaking, by default WCF proxies do not send credentials with their calls. You generally need to set the ClientCredentials or set

proxy.UseDefaultCredentials = true

Not providing either normally means no credentials and hence Anonymous auth.

于 2013-03-08T06:29:27.130 に答える
3

私自身の質問に答える: aを a
に変換することはできません。匿名の呼び出し元がブロックされているかどうかをテストするには、現在のスレッドをnull セッション トークンで偽装してから、WCF サービスを呼び出します。注: WindowsIdentity.GetAnonymousは使用しないでください。このメソッドは役に立ちません (間違って実装され、修正されていないと思います)。現在のスレッドを null セッション トークンで偽装するコード (エラー処理は行われません):WindowsIdentityNetworkCredential

    public static class Helper
    {
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        private static extern IntPtr GetCurrentThread();

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
        private static extern bool ImpersonateAnonymousToken(IntPtr handle);

        public static void ImpersonateAnonymousUser()
        {            
            ImpersonateAnonymousToken(GetCurrentThread());
        }
    }

        static string ToString(IIdentity identity)
        {
            return string.Format("{0} {1} {2}", identity.Name, identity.IsAuthenticated, identity.AuthenticationType); 
        }

        static void Main(string[] args)
        {            
            Console.WriteLine(ToString(WindowsIdentity.GetCurrent()));
            Helper.ImpersonateAnonymousUser();
            Console.WriteLine(ToString(WindowsIdentity.GetCurrent()));
        }

出力:

my machine\me True NTLM
NT AUTHORITY\ANONYMOUS LOGON False

Edmund のコメントに応えて、に設定proxy.ClientCredentials.Windows.ClientCredentialすると、null意図したことは実行されません - 匿名ユーザーとしてリクエストを行います。これが私の完全なテストコードとその出力です:

サービスコード:

public class Service1 : IService1
    {
        // note that if client is not authenticated, this code will never get a chance to execute
        // exception will happen before that
        // therefore there is no need to decorate this method with a
        // [PrincipalPermission(SecurityAction.Demand, Authenticated=true)] attribute        
        public string GetData()
        {
            try
            {
                var identity = Thread.CurrentPrincipal.Identity;
                return string.Concat(identity.Name, ",", identity.IsAuthenticated, ",", identity.AuthenticationType);
            }
            catch (Exception e)
            {
                return string.Concat(e.Message, "\\r\\n", e.StackTrace);
            }
        }
    }

サービス構成:

<services>      
      <service name="WcfService1.Service1">
        <host>
          <baseAddresses>
            <add baseAddress="http://mymachine/Service1/" />            
          </baseAddresses>                    
        </host>
        <endpoint address="Service1"
                  binding ="customBinding"
                  bindingConfiguration="myHttpBinding"
                  contract="WcfService1.IService1">          
        </endpoint>          
      </service>
    </services>
    <bindings>      
      <customBinding>
        <binding name="myHttpBinding">
            <reliableSession/>          
            <binaryMessageEncoding />          
            <httpTransport maxBufferSize="2147483647"
                           maxReceivedMessageSize="2147483647"
                           authenticationScheme="IntegratedWindowsAuthentication" />
          </binding>
      </customBinding>
    </bindings>

クライアントコード:

static void MakeRequest()
        {
            try
            {
                using (var svc = new Service1Client())
                {
                    Console.WriteLine(svc.GetData());
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
            }
        }

        static void Test3()
        {            
            Console.WriteLine("using {0}", ToString(WindowsIdentity.GetCurrent()));
            MakeRequest();
            Console.WriteLine();

            Console.WriteLine("setting svc.ClientCredentials.Windows.ClientCredential to null...");
            try
            {
                using (var svc = new Service1Client())
                {
                    svc.ClientCredentials.Windows.ClientCredential = null; 
                    Console.WriteLine(svc.GetData());
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
            }
            Console.WriteLine();

            ImpersonateAnonymousUser();
            Console.WriteLine("using {0}", ToString(WindowsIdentity.GetCurrent()));
            MakeRequest();
            Console.WriteLine();
        }

クライアント構成:

<bindings>
            <customBinding>
                <binding name="CustomBinding_IService1">
                    <reliableSession />
                    <binaryMessageEncoding />
                    <httpTransport authenticationScheme="Negotiate" />
                </binding>
            </customBinding>
        </bindings>
        <client>
            <endpoint address="mymachine/Service1/Service1.svc/Service1"
                binding="customBinding" bindingConfiguration="CustomBinding_IService1"
                contract="ServiceReference1.IService1" name="CustomBinding_IService1">
                <identity>
                    <servicePrincipalName value="host/mymachine" />
                </identity>
            </endpoint>
        </client>
      <behaviors>
        <endpointBehaviors>
          <!-- this setting protects the client by prohibiting the service to assume identity of client
          via imperonation and/or delegation and then doing bad things -->
          <behavior name="ImpersonationBehavior">
            <clientCredentials>
              <windows allowedImpersonationLevel="Identification"/>
            </clientCredentials>
          </behavior>
        </endpointBehaviors>
      </behaviors>

出力:

using mymachine\me True Negotiate
mymachine\me,True,Negotiate

setting svc.ClientCredentials.Windows.ClientCredential to null...
mymachine\me,True,Negotiate

using NT AUTHORITY\ANONYMOUS LOGON False
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be
 used for communication because it is in the Faulted state.

Server stack trace:
   at System.ServiceModel.Channels.CommunicationObject.Close(TimeSpan timeout)

Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage req
Msg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgDa
ta, Int32 type)
   at System.ServiceModel.ICommunicationObject.Close(TimeSpan timeout)
   at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.
Close(TimeSpan timeout)
   at System.ServiceModel.ClientBase`1.Close()
   at System.ServiceModel.ClientBase`1.System.IDisposable.Dispose()
   at TestClient.Program.MakeRequest()
于 2013-03-10T20:59:49.493 に答える
0

これを行う一連のテストがあり、このヘルパー メソッドを使用します。

public static ResponseType CallService(RequestType requestBody, NetworkCredential credential)
{
    ResponseType response;
    using (var channelFactory = new ChannelFactory<IMyService>("BasicHttpBinding_IMyService"))
    {
        channelFactory.Credentials.Windows.ClientCredential = credential;

        var client = channelFactory.CreateChannel();
        var request = new MyRequest()
            {
                MyService = requestBody
            };
        response = client.MyService(request).MyResponse1;
        ((IClientChannel)client).Close();

        channelFactory.Close();
    }
    return response;
}

テストでの使用:

var requestBody = GetRequestBody();//another helper method
var credential = new NetworkCredential
    {
        Domain = "MyDomain", 
        UserName = "MyUsername", 
        Password = "MyPassword"
    };
var response = CallService(requestBody, credential);
//Assert various user credentials


var response = CallService(requestBody, null);
//Assert anonymous
于 2013-03-10T20:08:11.570 に答える