サードパーティの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>
おそらくもっと賢い方法がありますが、次のようにヘッダーを手動で追加できます。
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]
。
上記の答えはとても間違っています!カスタムヘッダーを追加しないでください。サンプル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";
この特定のサービスプロバイダーが標準から逸脱しない限り、動作するはずです。
ハードコーディングされたカスタムヘッダーを追加しても機能する場合があります(時には拒否されることもあります)が、それはまったく間違った方法です。 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パッケージから開始する必要があります。
私はここからより良い方法を得ました: 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>
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サービスに渡すことができます。
明らかに、この投稿は数年前から存在していましたが、実際、同様の問題を探しているときに見つけました。この場合、ユーザー名/パスワード情報をセキュリティヘッダーに追加する必要がありました。これは、セキュリティヘッダーの外側にヘッダー情報を追加することとは異なります。
これを行う正しい方法(カスタムバインディング/ 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());
それはそれを行う必要があります。上記のコード(ユーザー名トークンを明示的に追加する)がないと、クライアント資格情報にユーザー名情報を設定しても、それらの資格情報がサービスに渡されない場合があります。
.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セキュリティを取得できます。
安全なシナリオではないので注意してください。
web.config
にlocalhost
という名前のサービス参照があるとします。次のように移動できます
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);