web-dev-qa-db-ja.com

ヘッダーでユーザー名/パスワードをSOAP WCFサービスに渡すにはどうすればよいですか

サードパーティのWebサービスを使用しようとしています https://staging.identitymanagement.lexisnexis.com/identity-proofing/services/identityProofingServiceWS/v2?wsdl

既にサービス参照として追加していますが、ヘッダーの資格情報を渡す方法がわかりません。

ヘッダーリクエストをこの形式に一致させるにはどうすればよいですか?

<soapenv:Header>
    <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:UsernameToken wsu:Id="UsernameToken-49" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:Username>12345/userID</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/ oasis-200401-wss-username-token-profile-1.0#PasswordText">password123</wsse:Password>
            <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">d+VxCZX1cH/ieMkKEr/ofA==</wsse:Nonce>
            <wsu:Created>2012-08-04T20:25:04.038Z</wsu:Created>
        </wsse:UsernameToken>
    </wsse:Security>
</soapenv:Header>
23
vts

おそらくもっと賢い方法がありますが、次のようにヘッダーを手動で追加できます。

var client = new IdentityProofingService.IdentityProofingWSClient();

using (new OperationContextScope(client.InnerChannel))
{
    OperationContext.Current.OutgoingMessageHeaders.Add(
        new SecurityHeader("UsernameToken-49", "12345/userID", "password123"));
    client.invokeIdentityService(new IdentityProofingRequest());
}

ここで、SecurityHeaderはカスタム実装クラスであり、属性を使用してXMLシリアル化を構成することを選択したため、いくつかの他のクラスが必要です。

public class SecurityHeader : MessageHeader
{
    private readonly UsernameToken _usernameToken;

    public SecurityHeader(string id, string username, string password)
    {
        _usernameToken = new UsernameToken(id, username, password);
    }

    public override string Name
    {
        get { return "Security"; }
    }

    public override string Namespace
    {
        get { return "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"; }
    }

    protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(UsernameToken));
        serializer.Serialize(writer, _usernameToken);
    }
}


[XmlRoot(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
public class UsernameToken
{
    public UsernameToken()
    {
    }

    public UsernameToken(string id, string username, string password)
    {
        Id = id;
        Username = username;
        Password = new Password() {Value = password};
    }

    [XmlAttribute(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")]
    public string Id { get; set; }

    [XmlElement]
    public string Username { get; set; }

    [XmlElement]
    public Password Password { get; set; }
}

public class Password
{
    public Password()
    {
        Type = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText";
    }

    [XmlAttribute]
    public string Type { get; set; }

    [XmlText]
    public string Value { get; set; }
}

NonceビットをUsernameToken XMLに追加していませんが、Passwordに非常に似ています。 Created要素も追加する必要がありますが、単純な[XmlElement]

36
Thorarin

上記の答えはとても間違っています!カスタムヘッダーを追加しないでください。サンプルxmlから判断すると、これは標準のWS-Securityヘッダーです。 WCFはすぐに使用できるようにサポートしています。サービス参照を追加するときは、設定ファイルでbasicHttpBindingバインディングを作成する必要があります。 TransportWithMessageCredentialモードのセキュリティ要素とclientCredentialType = UserNameのメッセージ要素を含めるように変更する必要があります。

<basicHttpBinding>
  <binding name="usernameHttps">
    <security mode="TransportWithMessageCredential">
      <message clientCredentialType="UserName"/>
    </security>
  </binding>
</basicHttpBinding>

上記の構成は、HTTP経由のSOAPヘッダーでuserid/passwordを期待するようにWCFに指示しています。呼び出しを行う前にコードでid/passwordを設定できます。

var service = new MyServiceClient();
service.ClientCredentials.UserName.UserName = "username";
service.ClientCredentials.UserName.Password = "password";

この特定のサービスプロバイダーが標準から逸脱しない限り、動作するはずです。

59
Sergey

ハードコーディングされたカスタムヘッダーを追加しても機能する場合があります(時には拒否されることもあります)が、それはまったく間違った方法です。 WSSEの目的はセキュリティです。この正確な理由から、MicrosoftはMicrosoft Web Services Enhancements 2.0をリリースし、その後WSE 3.0をリリースしました。このパッケージをインストールする必要があります( http://www.Microsoft.com/en-us/download/details.aspx?id=14089 )。

特にSOAPとWS-Addressingで作業していない人にとっては、ドキュメントを理解するのは簡単ではありません。まず、「BasicHttpBinding」はSoap 1.1であり、同じことはできません。 WSHttpBindingとしてのメッセージヘッダーパッケージをインストールして例を参照してください。WSE3.0からDLLを参照する必要があります。また、メッセージを正しくセットアップする必要があります。またはWS Addressingヘッダーのバリエーション探しているのはUsernameToken構成です。

これはより長い説明であり、私はどこでも正しい答えを見つけることができないので、私は皆のために何かを書く必要があります。少なくとも、WSE 3.0パッケージから開始する必要があります。

2
Robin Briggs

私はここからより良い方法を得ました: WCF:カスタムヘッダーの作成、それらのヘッダーを追加および使用する方法

クライアントは自身を識別する
ここでの目標は、クライアントがメッセージを送信しているユーザーを判別するためにサーバーが使用できる何らかの情報を提供することです。次のC#コードは、ClientIdという名前のヘッダーを追加します。

var cl = new ActiveDirectoryClient();

var eab = new EndpointAddressBuilder(cl.Endpoint.Address);

eab.Headers.Add( AddressHeader.CreateAddressHeader("ClientId",       // Header Name
                                                   string.Empty,     // Namespace
                                                    "OmegaClient")); // Header Value
cl.Endpoint.Address = eab.ToEndpointAddress();

// Now do an operation provided by the service.
cl.ProcessInfo("ABC");

このコードが行っているのは、名前空間なしでsoapヘッダーに挿入されるOmegaClientの値を持つClientIdという名前のエンドポイントヘッダーを追加することです。

クライアントの構成ファイルのカスタムヘッダー
カスタムヘッダーを実行する別の方法があります。これは、エンドポイントの一部としてカスタムヘッダーを指定することにより、すべてのメッセージが送信されるクライアントのXml構成ファイルで実現できます。

<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IActiveDirectory" />
            </basicHttpBinding>
        </bindings>
        <client>
          <endpoint address="http://localhost:41863/ActiveDirectoryService.svc"
              binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IActiveDirectory"
              contract="ADService.IActiveDirectory" name="BasicHttpBinding_IActiveDirectory">
            <headers>
              <ClientId>Console_Client</ClientId>
            </headers>
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>
0
rebornx

Web.configにcustomBindingを追加しました。

<configuration>
  <system.serviceModel>
    <bindings>
      <customBinding>
        <binding name="CustomSoapBinding">
          <security includeTimestamp="false"
                    authenticationMode="UserNameOverTransport"
                    defaultAlgorithmSuite="Basic256"
                    requireDerivedKeys="false"
                    messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
          </security>
          <textMessageEncoding messageVersion="Soap11"></textMessageEncoding>
          <httpsTransport maxReceivedMessageSize="2000000000"/>
        </binding>
      </customBinding>
    </bindings>
    <client>
      <endpoint address="https://test.com:443/services/testService"
                binding="customBinding"
                bindingConfiguration="CustomSoapBinding"
                contract="testService.test"
                name="test" />
    </client>
  </system.serviceModel>
  <startup>
    <supportedRuntime version="v4.0"
                      sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

CustomBindingを追加した後、次のようにクライアントサービスにユーザー名とパスワードを渡すことができます。

service.ClientCridentials.UserName.UserName = "testUser";
service.ClientCridentials.UserName.Password = "testPass";

このようにして、ヘッダーでユーザー名とパスワードをSOAP WCFサービスに渡すことができます。

0
Asuman Senol

明らかに、この投稿は数年前から存在していましたが、実際、同様の問題を探しているときに見つけました。この場合、ユーザー名/パスワード情報をセキュリティヘッダーに追加する必要がありました。これは、セキュリティヘッダーの外側にヘッダー情報を追加することとは異なります。

これを行う正しい方法(カスタムバインディング/ authenticationMode = "CertificateOverTransport"の場合)(.Netフレームワークバージョン4.6.1の場合)は、通常どおりクライアント資格情報を追加することです。

    client.ClientCredentials.UserName.UserName = "[username]";
    client.ClientCredentials.UserName.Password = "[password]";

そして、セキュリティバインディング要素に「トークン」を追加します-認証モードが証明書に設定されている場合、ユーザー名/パスワードクレデンシャルはデフォルトでは含まれないためです。

このトークンは次のように設定できます。

    //Get the current binding 
    System.ServiceModel.Channels.Binding binding = client.Endpoint.Binding;
    //Get the binding elements 
    BindingElementCollection elements = binding.CreateBindingElements();
    //Locate the Security binding element
    SecurityBindingElement security = elements.Find<SecurityBindingElement>();

    //This should not be null - as we are using Certificate authentication anyway
    if (security != null)
    {
    UserNameSecurityTokenParameters uTokenParams = new UserNameSecurityTokenParameters();
    uTokenParams.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
security.EndpointSupportingTokenParameters.SignedEncrypted.Add(uTokenParams);
    }

   client.Endpoint.Binding = new CustomBinding(elements.ToArray());

それはそれを行う必要があります。上記のコード(ユーザー名トークンを明示的に追加する)がないと、クライアント資格情報にユーザー名情報を設定しても、それらの資格情報がサービスに渡されない場合があります。

0
Phantom2018

.Netクライアントは消費しようとしているWSLDの構造をサポートしていないため、HttpWebRequestとHttpWebResponseを使用してWebサービスを呼び出しているとします。

その場合、ヘッダーに次のようなセキュリティ認証情報を追加できます。

<soap:Envelpe>
<soap:Header>
    <wsse:Security soap:mustUnderstand='true' xmlns:wsse='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' xmlns:wsu='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'><wsse:UsernameToken wsu:Id='UsernameToken-3DAJDJSKJDHFJASDKJFKJ234JL2K3H2K3J42'><wsse:Username>YOU_USERNAME/wsse:Username><wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>YOU_PASSWORD</wsse:Password><wsse:Nonce EncodingType='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'>3WSOKcKKm0jdi3943ts1AQ==</wsse:Nonce><wsu:Created>2015-01-12T16:46:58.386Z</wsu:Created></wsse:UsernameToken></wsse:Security>
</soapHeather>
<soap:Body>
</soap:Body>


</soap:Envelope>

HTTPログを使用して、SOAPUIを使用してwsseセキュリティを取得できます。

安全なシナリオではないので注意してください。

0
Matvi

web.configlocalhostという名前のサービス参照があるとします。次のように移動できます

localhost.Service objWebService = newlocalhost.Service();
localhost.AuthSoapHd objAuthSoapHeader = newlocalhost.AuthSoapHd();
string strUsrName =ConfigurationManager.AppSettings["UserName"];
string strPassword =ConfigurationManager.AppSettings["Password"];

objAuthSoapHeader.strUserName = strUsrName;
objAuthSoapHeader.strPassword = strPassword;

objWebService.AuthSoapHdValue =objAuthSoapHeader;
string str = objWebService.HelloWorld();

Response.Write(str);
0
शेखर