1

Webサービス(WCFではなく古いWebサービス)があり、IIS7.0を使用してそのWebサービスと通信しています。IIS 7.0ではWindows認証のみが有効になっています(匿名でも無効になっています)。サービス呼び出しを行うときに、コード内で特定のWindowsIDを指定できる必要があります。私はこれが次の方法で設定ファイルで行うことができることを示す多くの場所を見つけました...

<authentication mode="Windows" />
<identity impersonate="true" userName="UserName" password="P@ssw0rd" />

しかし、私はこれと同じことをコードで行う必要があります。「どうしてそんな風にやりたいのか」と思っている方も多いのではないでしょうか。大きな長い説明に立ち入ることなく、最も簡単な答えは、それらが私の要件だからです。

これが私のコードのようです...

HttpTransportBindingElement transport = useHttps ? new HttpsTransportBindingElement() : new HttpTransportBindingElement();
transport.ManualAddressing = false;
transport.MaxBufferPoolSize = 134217728; // 128MB
transport.MaxReceivedMessageSize = 134217728; // 128MB
transport.AllowCookies = false;
transport.AuthenticationScheme = AuthenticationSchemes.Negotiate;
transport.BypassProxyOnLocal = false;
transport.DecompressionEnabled = true;
transport.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
transport.KeepAliveEnabled = true;
transport.MaxBufferSize = 134217728; // 128MB,
transport.ProxyAuthenticationScheme = AuthenticationSchemes.Negotiate;
transport.Realm = "";
transport.TransferMode = TransferMode.Buffered;
transport.UnsafeConnectionNtlmAuthentication = false;
transport.UseDefaultWebProxy = false;

TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement
{
    MaxReadPoolSize = 64,
    MaxWritePoolSize = 16,
    MessageVersion = MessageVersion.Soap12,
    WriteEncoding = Encoding.UTF8,
    ReaderQuotas = new XmlDictionaryReaderQuotas
    {
        MaxDepth = 32,
        MaxStringContentLength = 134217728, // 128MB
        MaxArrayLength = 134217728, // 128MB
        MaxBytesPerRead = 4096,
        MaxNameTableCharCount = 16384
    }
};

CustomBinding binding = new CustomBinding();
binding.Elements.Add(encoding);
binding.Elements.Add(transport);

ServicePointManager.Expect100Continue = false;

generalSoapClient general = new generalSoapClient(binding, new EndpointAddress("http://localhost/site/ws/general.asmx"));
NetworkCredential iisCredentials = new NetworkCredential("UserName", "P@ssw0rd");
general.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
general.ClientCredentials.Windows.ClientCredential = iisCredentials;
string session = general.CreateDomainUserSessionFromInstance();

クライアント側の.configファイルには何も定義されていません。すべてがコードで構成されます。

私のWebサービスメソッドは次のようになります(認証に関係のないコードが欠落しています)...

[WebMethod(EnableSession = true)]
[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
public string CreateDomainUserSessionFromInstance()
{
    if(HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated)
    {
        WindowsIdentityRequest authenticationRequest = new WindowsIdentityRequest(instanceName, HttpContext.Current.User.Identity as WindowsIdentity);
        response = authManager.Login(authenticationRequest);
    }

    return response.SessionContext.SessionToken;
}

サーバー側の私のweb.configは次のようになります...

<system.web>
    <authentication mode="Windows" />
    <identity impersonate="true" />
    <authorization>
        <!--<allow users="*" />-->
        <deny users="?" />
    </authorization>
</system.web>

<customBinding>
    <binding name="textHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00">
      <textMessageEncoding>
        <readerQuotas maxArrayLength="1024000000" maxStringContentLength="1024000000" />
      </textMessageEncoding>
      <httpTransport maxReceivedMessageSize="1024000000" maxBufferSize="1024000000" authenticationScheme="Negotiate" />
  </customBinding>

<deny users="?" />次のエラーが発生した場合..." HTTPリクエストはクライアント認証スキーム'Negotiate'で許可されていません。サーバーから受信した認証ヘッダーは''<allow users="*" /> "でした。 Webサービスにアクセスしますが、これHttpContext.Current.User.Identity.IsAuthenticatedは誤りであり、空です。インターネットで読んだことは、匿名アクセスを拒否する.Name必要があるということです。deny users="?" />

私はWebサービスを初めて使用するため、残念ながら、このコードのほとんどはギリシャ語です。私たちのWebサービスは当初匿名認証を許可していましたが、Windows認証を要求するように要件が変更されました。

私は数日かけて多くのWebサイトを読んで、すべてを正しく構成しようとしましたが、正しい組み合わせが見つからないようです。
私は何が間違っているのですか?それは単純なことですか、それとも私はベースから離れていますか?

4

1 に答える 1

1

偽装するために使用するクラスは次のとおりです。

public class Impersonator :
    IDisposable
{
    private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;


    public Impersonator(
        string userName,
        string domainName,
        string password )
    {
        ImpersonateValidUser( userName, domainName, password );
    }


    public void Dispose()
    {
        UndoImpersonation();
    }


    #region P/Invoke.
    // ------------------------------------------------------------------

    [DllImport("advapi32.dll", SetLastError=true)]
    private static extern int LogonUser(
        string lpszUserName,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern int DuplicateToken(
        IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);

    [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
    private static extern bool RevertToSelf();

    [DllImport("kernel32.dll", CharSet=CharSet.Auto)]
    private static extern  bool CloseHandle(
        IntPtr handle);

    private const int LOGON32_LOGON_INTERACTIVE = 2;
    private const int LOGON32_PROVIDER_DEFAULT = 0;


    #region Private member.
    // ------------------------------------------------------------------

    /// <summary>
    /// Does the actual impersonation.
    /// </summary>
    /// <param name="userName">The name of the user to act as.</param>
    /// <param name="domainName">The domain name of the user to act as.</param>
    /// <param name="password">The password of the user to act as.</param>
    private void ImpersonateValidUser(
        string userName, 
        string domain, 
        string password )
    {
        WindowsIdentity tempWindowsIdentity = null;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;

        try
        {
            if ( RevertToSelf() )
            {
                if ( LogonUser(
                    userName, 
                    domain, 
                    password,
                    LOGON32_LOGON_NEW_CREDENTIALS,
                    LOGON32_PROVIDER_DEFAULT, 
                    ref token ) != 0 )
                {
                    if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 )
                    {
                        tempWindowsIdentity = new WindowsIdentity( tokenDuplicate );
                        impersonationContext = tempWindowsIdentity.Impersonate();
                    }
                    else
                    {
                        throw new Win32Exception( Marshal.GetLastWin32Error() );
                    }
                }
                else
                {
                    throw new Win32Exception( Marshal.GetLastWin32Error() );
                }
            }
            else
            {
                throw new Win32Exception( Marshal.GetLastWin32Error() );
            }
        }
        finally
        {
            if ( token!= IntPtr.Zero )
            {
                CloseHandle( token );
            }
            if ( tokenDuplicate!=IntPtr.Zero )
            {
                CloseHandle( tokenDuplicate );
            }
        }
    }

    /// <summary>
    /// Reverts the impersonation.
    /// </summary>
    private void UndoImpersonation()
    {
        if ( impersonationContext.IsNotNull() )
        {
            impersonationContext.Undo();
        }   
    }

    private WindowsImpersonationContext impersonationContext = null;

    // ------------------------------------------------------------------
    #endregion
}
于 2013-01-15T19:25:19.010 に答える