2014-08-13 10:39:27 +01:00
|
|
|
//
|
|
|
|
// IssuedSecurityTokenProviderTest.cs
|
|
|
|
//
|
|
|
|
// Author:
|
|
|
|
// Atsushi Enomoto <atsushi@ximian.com>
|
|
|
|
//
|
|
|
|
// Copyright (C) 2006 Novell, Inc. http://www.novell.com
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
// a copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
// the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be
|
|
|
|
// included in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
//
|
2018-01-24 17:04:36 +00:00
|
|
|
#if !MOBILE && !XAMMAC_4_5
|
2014-08-13 10:39:27 +01:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Globalization;
|
|
|
|
using System.IO;
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
using System.Security.Cryptography.X509Certificates;
|
|
|
|
using System.Security.Cryptography.Xml;
|
|
|
|
using System.ServiceModel;
|
|
|
|
using System.ServiceModel.Channels;
|
|
|
|
using System.ServiceModel.Security;
|
|
|
|
using System.ServiceModel.Security.Tokens;
|
|
|
|
using System.IdentityModel.Tokens;
|
|
|
|
using System.Text;
|
|
|
|
using System.Xml;
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
|
|
using MonoTests.System.ServiceModel.Channels;
|
|
|
|
|
2019-02-04 20:11:37 +00:00
|
|
|
using MonoTests.Helpers;
|
|
|
|
|
2014-08-13 10:39:27 +01:00
|
|
|
namespace MonoTests.System.ServiceModel.Security.Tokens
|
|
|
|
{
|
|
|
|
[TestFixture]
|
|
|
|
public class IssuedSecurityTokenProviderTest
|
|
|
|
{
|
|
|
|
[Test]
|
|
|
|
public void DefaultValues ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
Assert.AreEqual (true, p.CacheIssuedTokens, "#1");
|
|
|
|
Assert.AreEqual (TimeSpan.FromMinutes (1), p.DefaultOpenTimeout, "#2");
|
|
|
|
Assert.AreEqual (TimeSpan.FromMinutes (1), p.DefaultCloseTimeout, "#3");
|
|
|
|
Assert.IsNotNull (p.IdentityVerifier, "#4");
|
|
|
|
Assert.AreEqual (60, p.IssuedTokenRenewalThresholdPercentage, "#5");
|
|
|
|
Assert.IsNull (p.IssuerAddress, "#6");
|
|
|
|
Assert.AreEqual (0, p.IssuerChannelBehaviors.Count, "#7");
|
|
|
|
Assert.AreEqual (SecurityKeyEntropyMode.CombinedEntropy, p.KeyEntropyMode, "#8");
|
|
|
|
Assert.AreEqual (TimeSpan.MaxValue, p.MaxIssuedTokenCachingTime, "#9");
|
|
|
|
Assert.AreEqual (MessageSecurityVersion.Default,
|
|
|
|
p.MessageSecurityVersion, "#10");
|
|
|
|
Assert.IsNull (p.SecurityAlgorithmSuite, "#11");
|
|
|
|
Assert.IsNull (p.SecurityTokenSerializer, "#12");
|
|
|
|
Assert.IsNull (p.TargetAddress, "#13");
|
|
|
|
Assert.AreEqual (true, p.SupportsTokenCancellation, "#14");
|
|
|
|
Assert.AreEqual (0, p.TokenRequestParameters.Count, "#15");
|
|
|
|
Assert.IsNull (p.IssuerBinding, "#16");
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (InvalidOperationException))]
|
|
|
|
public void OpenWithoutSerializer ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
p.Open ();
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (InvalidOperationException))]
|
|
|
|
public void OpenWithoutIssuerAddress ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
p.SecurityTokenSerializer = WSSecurityTokenSerializer.DefaultInstance;
|
|
|
|
p.Open ();
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (InvalidOperationException))]
|
|
|
|
public void OpenWithoutBinding ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
p.SecurityTokenSerializer = WSSecurityTokenSerializer.DefaultInstance;
|
|
|
|
p.IssuerAddress = new EndpointAddress ("http://localhost:8080");
|
|
|
|
p.Open ();
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (InvalidOperationException))]
|
|
|
|
public void OpenWithoutTargetAddress ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
p.SecurityTokenSerializer = WSSecurityTokenSerializer.DefaultInstance;
|
|
|
|
p.IssuerAddress = new EndpointAddress ("http://localhost:8080");
|
|
|
|
p.IssuerBinding = new BasicHttpBinding ();
|
|
|
|
|
|
|
|
// wiithout it indigo causes NRE
|
|
|
|
p.SecurityAlgorithmSuite = SecurityAlgorithmSuite.Default;
|
|
|
|
p.Open ();
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
public void Open ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (new BasicHttpBinding ());
|
|
|
|
try {
|
|
|
|
p.Open ();
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (InvalidOperationException))]
|
|
|
|
public void GetTokenWithoutOpen ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
}
|
|
|
|
|
|
|
|
// From WinFX beta2:
|
|
|
|
// System.ServiceModel.Security.SecurityNegotiationException :
|
|
|
|
// SOAP security negotiation with 'stream:dummy' for target
|
|
|
|
// 'stream:dummy' failed. See inner exception for more details.
|
|
|
|
// ----> System.InvalidOperationException : The request
|
|
|
|
// message must be protected. This is required by an operation
|
|
|
|
// of the contract ('IWsTrustFeb2005SecurityTokenService',
|
|
|
|
// 'http://tempuri.org/'). The protection must be provided by
|
|
|
|
// the binding ('BasicHttpBinding','http://tempuri.org/').
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (SecurityNegotiationException))]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
public void GetTokenNoSecureBinding ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (new BasicHttpBinding ());
|
|
|
|
try {
|
|
|
|
p.Open ();
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
// SymmetricSecurityBindingElement requires protection
|
|
|
|
// token parameters to build a channel or listener factory.
|
|
|
|
[ExpectedException (typeof (SecurityNegotiationException))]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
public void GetTokenWithoutProtectionTokenParameters ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (CreateIssuerBinding (null, false));
|
|
|
|
try {
|
|
|
|
p.Open ();
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SecurityNegotiationException (InvalidOperationException (
|
|
|
|
// "The service certificate is not provided for target
|
|
|
|
// 'stream:dummy'. Specify a service certificate in
|
|
|
|
// ClientCredentials."))
|
|
|
|
[Test]
|
|
|
|
[ExpectedException (typeof (SecurityNegotiationException))]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
public void GetTokenWithoutServiceCertificate ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (CreateIssuerBinding (null, true));
|
|
|
|
p.IssuerAddress = new EndpointAddress ("stream:dummy");
|
|
|
|
try {
|
|
|
|
p.Open (TimeSpan.FromSeconds (5));
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
[ExpectedException (typeof (MyException))]
|
|
|
|
public void GetTokenWrongResponse ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (CreateIssuerBinding (new RequestSender (OnGetTokenWrongResponse), true));
|
|
|
|
try {
|
|
|
|
p.Open (TimeSpan.FromSeconds (5));
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
[ExpectedException (typeof (MessageSecurityException))]
|
|
|
|
public void GetTokenUnsignedReply ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (CreateIssuerBinding (new RequestSender (OnGetTokenUnsignedReply), true));
|
|
|
|
try {
|
|
|
|
p.Open (TimeSpan.FromSeconds (5));
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// InnerException: System.InvalidOperationException:
|
|
|
|
// The issuer must provide a computed key in key entropy mode
|
|
|
|
// 'CombinedEntropy'.
|
|
|
|
[Test]
|
|
|
|
[Ignore ("todo")]
|
|
|
|
[ExpectedException (typeof (SecurityNegotiationException))]
|
|
|
|
public void GetTokenNoEntropyInResponseInCombinedMode ()
|
|
|
|
{
|
|
|
|
// FIXME: implement it after we get working token issuer.
|
|
|
|
// In the reply, do not include Nonce
|
|
|
|
}
|
|
|
|
|
|
|
|
// on the other hand, in Client entropy mode it must not
|
|
|
|
// provide entropy.
|
|
|
|
[Test]
|
|
|
|
[Ignore ("todo")]
|
|
|
|
[ExpectedException (typeof (SecurityNegotiationException))]
|
|
|
|
public void GetTokenIncludesEntropyInResponseInClientMode ()
|
|
|
|
{
|
|
|
|
// FIXME: implement it after we get working token issuer.
|
|
|
|
// specify SecurityKeyEntropyMode.ClientEntropy on
|
|
|
|
// client side. And in the reply, include Nonce.
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
[Ignore ("need to implement response")]
|
|
|
|
[Category ("NotWorking")]
|
|
|
|
public void GetToken ()
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p = SetupProvider (CreateIssuerBinding (new RequestSender (OnGetToken), true));
|
|
|
|
try {
|
|
|
|
p.Open (TimeSpan.FromSeconds (5));
|
|
|
|
p.GetToken (TimeSpan.FromSeconds (10));
|
|
|
|
} finally {
|
|
|
|
if (p.State == CommunicationState.Opened)
|
|
|
|
p.Close ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class MyException : Exception
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
Message OnGetTokenWrongResponse (Message input)
|
|
|
|
{
|
|
|
|
VerifyInput (input.CreateBufferedCopy (10000));
|
|
|
|
|
|
|
|
throw new MyException ();
|
|
|
|
}
|
|
|
|
|
|
|
|
Message OnGetTokenUnsignedReply (Message input)
|
|
|
|
{
|
|
|
|
XmlDocument doc = new XmlDocument ();
|
|
|
|
doc.LoadXml ("<Response>RESPONSE</Response>");
|
|
|
|
|
|
|
|
Message msg = Message.CreateMessage (input.Version, "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/IssueResponse", doc.DocumentElement);
|
|
|
|
msg.Headers.Add (MessageHeader.CreateHeader (
|
|
|
|
"Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", null, true));
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
|
|
|
|
Message OnGetToken (Message input)
|
|
|
|
{
|
|
|
|
MessageBuffer buf = input.CreateBufferedCopy (10000);
|
|
|
|
VerifyInput2 (buf);
|
|
|
|
|
|
|
|
// FIXME: create response message (when I understand what I should return.)
|
|
|
|
// throw new MyException ();
|
|
|
|
//*
|
|
|
|
XmlDocument doc = new XmlDocument ();
|
|
|
|
doc.LoadXml ("<Response>RESPONSE</Response>");
|
2019-02-04 20:11:37 +00:00
|
|
|
X509Certificate2 cert = new X509Certificate2 (TestResourceHelper.GetFullPathOfResource ("Test/Resources/test.pfx"), "mono");
|
2014-08-13 10:39:27 +01:00
|
|
|
SignedXml sxml = new SignedXml (doc);
|
|
|
|
MemoryStream ms = new MemoryStream (new byte [] {1, 2, 3});
|
|
|
|
sxml.AddReference (new Reference (ms));
|
|
|
|
sxml.SigningKey = cert.PrivateKey;
|
|
|
|
sxml.ComputeSignature ();
|
|
|
|
|
|
|
|
Message msg = Message.CreateMessage (input.Version, "http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/Issue", sxml.GetXml ());
|
|
|
|
msg.Headers.Add (MessageHeader.CreateHeader (
|
|
|
|
"Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", null, true));
|
|
|
|
|
|
|
|
return msg;
|
|
|
|
//*/
|
|
|
|
}
|
|
|
|
|
|
|
|
void VerifyInput (MessageBuffer buf)
|
|
|
|
{
|
|
|
|
Message input = buf.CreateMessage ();
|
|
|
|
/*
|
|
|
|
XmlWriterSettings settings = new XmlWriterSettings ();
|
|
|
|
settings.Indent = true;
|
|
|
|
using (XmlWriter w = XmlWriter.Create (Console.Error, settings)) {
|
|
|
|
buf.CreateMessage ().WriteMessage (w);
|
|
|
|
}
|
|
|
|
Console.Error.WriteLine ("******************** DONE ********************");
|
|
|
|
Console.Error.Flush ();
|
|
|
|
*/
|
|
|
|
|
|
|
|
Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue", input.Headers.Action, "GetToken.Request.Action");
|
|
|
|
Assert.IsNotNull (input.Headers.MessageId, "GetToken.Request.MessageID");
|
|
|
|
// in the raw Message it is "http://www.w3.org/2005/08/addressing/anonymous", but it is replaced by MessageHeaders implementation.
|
|
|
|
Assert.AreEqual (new EndpointAddress ("http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous"), input.Headers.ReplyTo, "GetToken.Request.ReplyTo");
|
|
|
|
|
|
|
|
// o:Security
|
|
|
|
// FIXME: test WSSecurity more
|
|
|
|
// <o:Security>
|
|
|
|
// <u:Timestamp>
|
|
|
|
// <u:Created>...</u:Created>
|
|
|
|
// <u:Expires>...</u:Expires>
|
|
|
|
// </u:Timestamp>
|
|
|
|
// <o:BinarySecurityToken>...</o:BinarySecurityToken>
|
|
|
|
// <e:EncryptedKey>
|
|
|
|
// <e:EncryptionMethod><DigestMethod/></e:EncryptionMethod>
|
|
|
|
// <KeyInfo>
|
|
|
|
// <o:SecurityTokenReference><o:Reference/></o:SecurityTokenReference>
|
|
|
|
// </KeyInfo>
|
|
|
|
// <e:CipherData>
|
|
|
|
// <e:CipherValue>...</e:CipherValue>
|
|
|
|
// </e:CipherData>
|
|
|
|
// </e:EncryptedKey>
|
|
|
|
// [
|
|
|
|
// <c:DerivedKeyToken>
|
|
|
|
// <o:SecurityTokenReference><o:Reference/></o:SecurityTokenReference>
|
|
|
|
// <c:Offset>...</c:Offset>
|
|
|
|
// <c:Length>...</c:Length>
|
|
|
|
// <c:Nonce>...</c:Nonce>
|
|
|
|
// </c:DerivedKeyToken>
|
|
|
|
// ]
|
|
|
|
// <e:ReferenceList>
|
|
|
|
// [
|
|
|
|
// <e:DataReference>
|
|
|
|
// ]
|
|
|
|
// </e:ReferenceList>
|
|
|
|
// <e:EncryptedData>
|
|
|
|
// <e:EncryptionMethod/>
|
|
|
|
// <KeyInfo> {{....}} </KeyInfo>
|
|
|
|
// <e:CipherData> {{....}} </e:CipherData>
|
|
|
|
// </e:EncryptedData>
|
|
|
|
// </o:Security>
|
|
|
|
int i = input.Headers.FindHeader ("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
|
|
|
|
Assert.IsTrue (i >= 0, "Security header existence");
|
|
|
|
MessageHeaderInfo info = input.Headers [i];
|
|
|
|
Assert.IsNotNull (info, "Security header item");
|
|
|
|
XmlReader r = input.Headers.GetReaderAtHeader (i);
|
|
|
|
|
|
|
|
// FIXME: test WSSecurity more
|
|
|
|
// <o:Security>
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadStartElement ("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
|
|
|
|
// <u:Timestamp>
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadStartElement ("Timestamp", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
|
|
|
|
// <u:Created>...</u:Created>
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadStartElement ("Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
|
|
|
|
r.ReadString ();
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadEndElement ();
|
|
|
|
// <u:Expires>...</u:Expires>
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadStartElement ("Expires", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
|
|
|
|
r.ReadString ();
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadEndElement ();
|
|
|
|
// </u:Timestamp>
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadEndElement ();
|
|
|
|
// <o:BinarySecurityToken>...</o:BinarySecurityToken>
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.ReadStartElement ("BinarySecurityToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
|
|
|
|
byte [] rawcert = Convert.FromBase64String (r.ReadString ());
|
|
|
|
r.ReadEndElement ();
|
|
|
|
X509Certificate2 cert = new X509Certificate2 (rawcert);
|
|
|
|
|
|
|
|
// FIXME: test EncryptedKey
|
|
|
|
r.MoveToContent ();
|
|
|
|
r.Skip ();
|
|
|
|
// <e:EncryptedKey>
|
|
|
|
// <e:EncryptionMethod><DigestMethod/></e:EncryptionMethod>
|
|
|
|
// <KeyInfo>
|
|
|
|
// <o:SecurityTokenReference><o:Reference/></o:SecurityTokenReference>
|
|
|
|
// </KeyInfo>
|
|
|
|
// <e:CipherData>
|
|
|
|
// <e:CipherValue>...</e:CipherValue>
|
|
|
|
// </e:CipherData>
|
|
|
|
// </e:EncryptedKey>
|
|
|
|
|
|
|
|
// FIXME: test DerivedKeyTokens
|
|
|
|
r.MoveToContent ();
|
|
|
|
while (r.LocalName == "DerivedKeyToken") {
|
|
|
|
r.Skip ();
|
|
|
|
r.MoveToContent ();
|
|
|
|
}
|
|
|
|
// [
|
|
|
|
// <c:DerivedKeyToken>
|
|
|
|
// <o:SecurityTokenReference><o:Reference/></o:SecurityTokenReference>
|
|
|
|
// <c:Offset>...</c:Offset>
|
|
|
|
// <c:Length>...</c:Length>
|
|
|
|
// <c:Nonce>...</c:Nonce>
|
|
|
|
// </c:DerivedKeyToken>
|
|
|
|
// ]
|
|
|
|
|
|
|
|
// <e:ReferenceList>
|
|
|
|
// [
|
|
|
|
// <e:DataReference>
|
|
|
|
// ]
|
|
|
|
// </e:ReferenceList>
|
|
|
|
// <e:EncryptedData>
|
|
|
|
// <e:EncryptionMethod/>
|
|
|
|
// <KeyInfo> {{....}} </KeyInfo>
|
|
|
|
// <e:CipherData> {{....}} </e:CipherData>
|
|
|
|
// </e:EncryptedData>
|
|
|
|
// </o:Security>
|
|
|
|
|
|
|
|
// SOAP Body
|
|
|
|
r = input.GetReaderAtBodyContents (); // just verifying itself ;)
|
|
|
|
}
|
|
|
|
|
|
|
|
XmlElement VerifyInput2 (MessageBuffer buf)
|
|
|
|
{
|
|
|
|
Message msg2 = buf.CreateMessage ();
|
|
|
|
StringWriter sw = new StringWriter ();
|
|
|
|
using (XmlDictionaryWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw))) {
|
|
|
|
msg2.WriteMessage (w);
|
|
|
|
}
|
|
|
|
XmlDocument doc = new XmlDocument ();
|
|
|
|
doc.PreserveWhitespace = true;
|
|
|
|
doc.LoadXml (sw.ToString ());
|
|
|
|
|
|
|
|
// decrypt the key with service certificate privkey
|
|
|
|
PaddingMode mode = PaddingMode.PKCS7; // not sure which is correct ... ANSIX923, ISO10126, PKCS7, Zeros, None.
|
|
|
|
EncryptedXml encXml = new EncryptedXml (doc);
|
|
|
|
encXml.Padding = mode;
|
2019-02-04 20:11:37 +00:00
|
|
|
X509Certificate2 cert2 = new X509Certificate2 (TestResourceHelper.GetFullPathOfResource ("Test/Resources/test.pfx"), "mono");
|
2014-08-13 10:39:27 +01:00
|
|
|
XmlNamespaceManager nsmgr = new XmlNamespaceManager (doc.NameTable);
|
|
|
|
nsmgr.AddNamespace ("s", "http://www.w3.org/2003/05/soap-envelope");
|
|
|
|
nsmgr.AddNamespace ("c", "http://schemas.xmlsoap.org/ws/2005/02/sc");
|
|
|
|
nsmgr.AddNamespace ("o", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
|
|
|
|
nsmgr.AddNamespace ("e", "http://www.w3.org/2001/04/xmlenc#");
|
|
|
|
nsmgr.AddNamespace ("dsig", "http://www.w3.org/2000/09/xmldsig#");
|
|
|
|
XmlNode n = doc.SelectSingleNode ("//o:Security/e:EncryptedKey/e:CipherData/e:CipherValue", nsmgr);
|
|
|
|
Assert.IsNotNull (n, "premise: enckey does not exist");
|
|
|
|
string raw = n.InnerText;
|
|
|
|
byte [] rawbytes = Convert.FromBase64String (raw);
|
|
|
|
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider) cert2.PrivateKey;
|
|
|
|
byte [] decryptedKey = EncryptedXml.DecryptKey (rawbytes, rsa, true);//rsa.Decrypt (rawbytes, true);
|
|
|
|
|
|
|
|
#if false
|
|
|
|
// create derived keys
|
|
|
|
Dictionary<string,byte[]> keys = new Dictionary<string,byte[]> ();
|
|
|
|
InMemorySymmetricSecurityKey skey =
|
|
|
|
new InMemorySymmetricSecurityKey (decryptedKey);
|
|
|
|
foreach (XmlElement el in doc.SelectNodes ("//o:Security/c:DerivedKeyToken", nsmgr)) {
|
|
|
|
n = el.SelectSingleNode ("c:Offset", nsmgr);
|
|
|
|
int offset = (n == null) ? 0 :
|
|
|
|
int.Parse (n.InnerText, CultureInfo.InvariantCulture);
|
|
|
|
n = el.SelectSingleNode ("c:Length", nsmgr);
|
|
|
|
int length = (n == null) ? 32 :
|
|
|
|
int.Parse (n.InnerText, CultureInfo.InvariantCulture);
|
|
|
|
n = el.SelectSingleNode ("c:Label", nsmgr);
|
|
|
|
byte [] label = (n == null) ? decryptedKey :
|
|
|
|
Convert.FromBase64String (n.InnerText);
|
|
|
|
n = el.SelectSingleNode ("c:Nonce", nsmgr);
|
|
|
|
byte [] nonce = (n == null) ? new byte [0] :
|
|
|
|
Convert.FromBase64String (n.InnerText);
|
|
|
|
byte [] derkey = skey.GenerateDerivedKey (
|
|
|
|
//SecurityAlgorithms.Psha1KeyDerivation,
|
|
|
|
"http://schemas.xmlsoap.org/ws/2005/02/sc/dk/p_sha1",
|
|
|
|
// FIXME: maybe due to the label, this key resolution somehow does not seem to work.
|
|
|
|
label,
|
|
|
|
nonce,
|
|
|
|
length * 8,
|
|
|
|
offset);
|
|
|
|
|
|
|
|
keys [el.GetAttribute ("Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd")] = derkey;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// decrypt the signature with the decrypted key
|
|
|
|
#if true
|
|
|
|
n = doc.SelectSingleNode ("//o:Security/e:EncryptedData/e:CipherData/e:CipherValue", nsmgr);
|
|
|
|
Assert.IsNotNull (n, "premise: encdata does not exist");
|
|
|
|
raw = n.InnerText;
|
|
|
|
rawbytes = Convert.FromBase64String (raw);
|
|
|
|
Rijndael aes = RijndaelManaged.Create ();
|
|
|
|
// aes.Key = keys [n.SelectSingleNode ("../../dsig:KeyInfo/o:SecurityTokenReference/o:Reference/@URI", nsmgr).InnerText.Substring (1)];
|
|
|
|
aes.Key = decryptedKey;
|
|
|
|
aes.Mode = CipherMode.CBC;
|
|
|
|
aes.Padding = mode;
|
|
|
|
MemoryStream ms = new MemoryStream ();
|
|
|
|
CryptoStream cs = new CryptoStream (ms, aes.CreateDecryptor (), CryptoStreamMode.Write);
|
|
|
|
cs.Write (rawbytes, 0, rawbytes.Length);
|
|
|
|
cs.Close ();
|
|
|
|
byte [] decryptedSignature = ms.ToArray ();
|
|
|
|
#else
|
|
|
|
Rijndael aes = RijndaelManaged.Create ();
|
|
|
|
// aes.Key = keys [n.SelectSingleNode ("../../dsig:KeyInfo/o:SecurityTokenReference/o:Reference/@URI", nsmgr).InnerText.Substring (1)];
|
|
|
|
aes.Key = decryptedKey;
|
|
|
|
aes.Mode = CipherMode.CBC;
|
|
|
|
aes.Padding = mode;
|
|
|
|
|
|
|
|
EncryptedData ed = new EncryptedData ();
|
|
|
|
n = doc.SelectSingleNode ("//o:Security/e:EncryptedData", nsmgr);
|
|
|
|
Assert.IsNotNull (n, "premise: encdata does not exist");
|
|
|
|
ed.LoadXml (n as XmlElement);
|
|
|
|
byte [] decryptedSignature = encXml.DecryptData (ed, aes);
|
|
|
|
#endif
|
|
|
|
//Console.Error.WriteLine (Encoding.UTF8.GetString (decryptedSignature));
|
|
|
|
//Console.Error.WriteLine ("============= Decrypted Signature End ===========");
|
|
|
|
|
|
|
|
// decrypt the body with the decrypted key
|
|
|
|
#if true
|
|
|
|
n = doc.SelectSingleNode ("//s:Body/e:EncryptedData/e:CipherData/e:CipherValue", nsmgr);
|
|
|
|
Assert.IsNotNull (n, "premise: encdata does not exist");
|
|
|
|
raw = n.InnerText;
|
|
|
|
rawbytes = Convert.FromBase64String (raw);
|
|
|
|
// aes.Key = keys [n.SelectSingleNode ("../../dsig:KeyInfo/o:SecurityTokenReference/o:Reference/@URI", nsmgr).InnerText.Substring (1)];
|
|
|
|
aes.Key = decryptedKey;
|
|
|
|
ms = new MemoryStream ();
|
|
|
|
cs = new CryptoStream (ms, aes.CreateDecryptor (), CryptoStreamMode.Write);
|
|
|
|
cs.Write (rawbytes, 0, rawbytes.Length);
|
|
|
|
cs.Close ();
|
|
|
|
byte [] decryptedBody = ms.ToArray ();
|
|
|
|
#else
|
|
|
|
// decrypt the body with the decrypted key
|
|
|
|
EncryptedData ed2 = new EncryptedData ();
|
|
|
|
XmlElement el = doc.SelectSingleNode ("/s:Envelope/s:Body/e:EncryptedData", nsmgr) as XmlElement;
|
|
|
|
ed2.LoadXml (el);
|
|
|
|
// aes.Key = keys [n.SelectSingleNode ("../../dsig:KeyInfo/o:SecurityTokenReference/o:Reference/@URI", nsmgr).InnerText.Substring (1)];
|
|
|
|
aes.Key = decryptedKey;
|
|
|
|
byte [] decryptedBody = encXml.DecryptData (ed2, aes);
|
|
|
|
#endif
|
|
|
|
//foreach (byte b in decryptedBody) Console.Error.Write ("{0:X02} ", b);
|
|
|
|
Console.Error.WriteLine (Encoding.UTF8.GetString (decryptedBody));
|
|
|
|
Console.Error.WriteLine ("============= Decrypted Body End ===========");
|
|
|
|
|
|
|
|
// FIXME: find out what first 16 bytes mean.
|
|
|
|
for (int mmm = 0; mmm < 16; mmm++) decryptedBody [mmm] = 0x20;
|
|
|
|
doc.LoadXml (Encoding.UTF8.GetString (decryptedBody));
|
|
|
|
Assert.AreEqual ("RequestSecurityToken", doc.DocumentElement.LocalName, "#b-1");
|
|
|
|
Assert.AreEqual ("http://schemas.xmlsoap.org/ws/2005/02/trust", doc.DocumentElement.NamespaceURI, "#b-2");
|
|
|
|
|
|
|
|
return doc.DocumentElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
Binding CreateIssuerBinding (RequestSender handler, bool tokenParams)
|
|
|
|
{
|
|
|
|
SymmetricSecurityBindingElement sbe =
|
|
|
|
new SymmetricSecurityBindingElement ();
|
|
|
|
if (tokenParams)
|
|
|
|
sbe.ProtectionTokenParameters = new X509SecurityTokenParameters ();
|
|
|
|
sbe.LocalServiceSettings.NegotiationTimeout = TimeSpan.FromSeconds (5);
|
|
|
|
sbe.KeyEntropyMode = SecurityKeyEntropyMode.ClientEntropy;
|
|
|
|
//sbe.IncludeTimestamp = false;
|
|
|
|
//sbe.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
|
|
|
|
|
|
|
|
// for ease of decryption, let's remove DerivedKeyToken.
|
|
|
|
sbe.SetKeyDerivation (false);
|
|
|
|
|
|
|
|
return new CustomBinding (
|
|
|
|
// new DebugBindingElement (),
|
|
|
|
sbe,
|
|
|
|
new TextMessageEncodingBindingElement (),
|
|
|
|
new HandlerTransportBindingElement (handler));
|
|
|
|
}
|
|
|
|
|
|
|
|
EndpointAddress GetSecureEndpointAddress (string uri)
|
|
|
|
{
|
|
|
|
return new EndpointAddress (new Uri (uri),
|
|
|
|
new X509CertificateEndpointIdentity (
|
2019-02-04 20:11:37 +00:00
|
|
|
new X509Certificate2 (TestResourceHelper.GetFullPathOfResource ("Test/Resources/test.pfx"), "mono")));
|
2014-08-13 10:39:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
IssuedSecurityTokenProvider SetupProvider (Binding binding)
|
|
|
|
{
|
|
|
|
IssuedSecurityTokenProvider p =
|
|
|
|
new IssuedSecurityTokenProvider ();
|
|
|
|
p.SecurityTokenSerializer = WSSecurityTokenSerializer.DefaultInstance;
|
|
|
|
p.IssuerAddress = GetSecureEndpointAddress ("stream:dummy");
|
|
|
|
p.IssuerBinding = binding;
|
|
|
|
|
|
|
|
// wiithout it indigo causes NRE
|
|
|
|
p.SecurityAlgorithmSuite = SecurityAlgorithmSuite.Default;
|
|
|
|
|
|
|
|
p.TargetAddress = new EndpointAddress ("http://localhost:9090");
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-01-24 17:04:36 +00:00
|
|
|
#endif
|
|
|
|
|