using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.Text;
using System.Xml;
using System.Linq;
using System.Xml.Linq;
using dk.nsi.seal;
using dk.nsi.seal.dgwstypes;
using dk.nsi.seal.Factories;
using dk.nsi.seal.Model;
using dk.nsi.seal.Model.DomBuilders;
using dk.nsi.seal.Vault;
using NUnit.Framework;
using SealTest.AssertionTests.AssertionBuilders;
using GW = SealTest.SosiGW;
using invokeResponse = SealTest.NSTWsProvider.invokeResponse;
using System.Threading.Tasks;
using System.ServiceModel.Channels;
using dk.nsi.seal.EndpointBehaviors;
using static SealTest.SosiGW.SosiGWFacadeClient.EndpointConfiguration;
using static dk.nsi.seal.MessageHeaders.XmlMessageHeader;
using static dk.nsi.seal.MessageHeaders.IdCardMessageHeader;
namespace SealTest
{
[TestFixture]
public class SosiGwTest
{
private readonly ICredentialVault moces3Vault = CredentialVaultTestUtil.GetMoces3CredentialVault();
private readonly ICredentialVault voces3Vault = CredentialVaultTestUtil.GetVoces3CredentialVault();
///
/// Pre-Condition: User does not have an IdCard in the GW-cache.
///
/// Calls requestIdCardForSigning and signIdCard operations.
///
/// The newly created idcard is stored in SOSI-GW and can be used to call services through SOSI GW. In this example the test-service (NTS) is called.
///
[Test]
public async Task TestSosiGwRequestIdCardForSigningAndSignIdCardOces3()
{
var idCard = await DoLogin(moces3Vault.GetSystemCredentials(), "91026150", "0306894781", "KT2Z4");
await CallNts(idCard);
}
///
/// Pre-Condition: User does not have an IdCard in the GW-cache.
/// Input: Valid Boot Strap Token (BST). In this case it is a OIOH3BST token.
/// Output: Newly created and unsigned idcard.
///
/// The newly created idcard is stored in SOSI-GW and can be used to call services through SOSI GW. In this example the test-service (NTS) is called.
///
[Test]
public Task TestSosiGwCreateIdCardFromBST()
{
var assertionBuilderOIOH3Bst = OIOBSTAssertionBuilderHelper.CreateOIOH3BSTSAMLAssertionBuilder(moces3Vault, voces3Vault);
OIOBSTSAMLAssertionToIDCardRequestDOMBuilder oioh3RequestBuilder = OIOBSTAssertionBuilderHelper.CreateOIOH3RequestBuilderFromAssertionBuilder(moces3Vault);
oioh3RequestBuilder.SetOIOSAMLAssertion(assertionBuilderOIOH3Bst.Build());
oioh3RequestBuilder.UserAuthorizationCode = "KT2Z4"; // Findes i AuthorizationServiceStub for cpr 1802602810
var response = SendRequestSosiGw(oioh3RequestBuilder.Build());
var idCard = response.IdCard;
Assert.False(response.IsFault, response.FaultString);
Assert.Null(response.GetSigningCertificate());
return CallNts(idCard);
}
private static Task CallNts(IdCard idCard)
{
var binding = new CustomBinding();
binding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11WSAddressingAugust2004, Encoding.UTF8));
binding.Elements.Add(new HttpTransportBindingElement());
var client = new NSTWsProvider.NtsWSProviderClient(binding, new EndpointAddress("https://test1-cnsp.ekstern-test.nspop.dk:8443/nts/service"));
client.Endpoint.EndpointBehaviors.Add(new SealEndpointBehavior());
client.Endpoint.EndpointBehaviors.Add(new ViaBehavior(new Uri("http://test1.ekstern-test.nspop.dk:8080/sosigw/proxy/soap-request")));
var dgwsHeader = new Header
{
SecurityLevel = 4,
SecurityLevelSpecified = true,
Linking = new Linking { MessageID = Guid.NewGuid().ToString("D") }
};
using (new OperationContextScope(client.InnerChannel))
{
// Adding seal-security and dgws-header soap header
OperationContext.Current.OutgoingMessageHeaders.Add(IdCardHeader(idCard));
OperationContext.Current.OutgoingMessageHeaders.Add(XmlHeader(dgwsHeader));
// Throws Exception if not succesful.
return client.invokeAsync("test");
}
}
private OIOBSTSAMLAssertionToIDCardResponse SendRequestSosiGw(XDocument xDocument)
{
var response = WebPost(xDocument.Root, TestConstants.SosiGwCreateIdCardFromBst);
var modelBuilder = OIOSAMLFactory.CreateOIOBSTSAMLAssertionToIDCardResponseModelBuilder();
return modelBuilder.Build(new XDocument(response));
}
private XElement WebPost(XElement request, string url)
{
try
{
var WebRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
WebRequest.Method = "POST";
WebRequest.ContentType = "text/xml; charset=utf-8";
WebRequest.Headers.Add("SOAPAction", "http://sosi.org/webservices/sts/1.0/stsService/RequestSecurityToken");
using (var ms = new MemoryStream())
{
var w = new XmlTextWriter(ms, Encoding.UTF8);
request.Save(w);
w.Flush();
WebRequest.ContentLength = ms.Length;
ms.Position = 0;
ms.CopyTo(WebRequest.GetRequestStream());
}
var response = WebRequest.GetResponse();
return XElement.Load(response.GetResponseStream(), LoadOptions.PreserveWhitespace);
}
catch (WebException ex)
{
if (ex.Response == null) throw;
return XElement.Load(ex.Response.GetResponseStream());
}
}
public static async Task DoLogin(X509Certificate2 cert, string cvr, string cpr = "1802602810", string authorization = "ZXCVB")
{
var gwClient = new GW.SosiGWFacadeClient(SosiGWSoapBinding, "http://test1.ekstern-test.nspop.dk:8080/sosigw/service/sosigw");
var sec = MakeSecurity(MakeAssertionForSTS(cvr, cpr, authorization));
var dig = await gwClient.requestIdCardDigestForSigningAsync(sec, "whatever");
var csp = cert.GetRSAPrivateKey();
var sha1 = new SHA1Managed();
var hash = sha1.ComputeHash(dig.requestIdCardDigestForSigningResponse.DigestValue);
var rb = new GW.signIdCardRequestBody
{
SignatureValue = csp.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1),
KeyInfo = new GW.KeyInfo
{
Item = new GW.X509Data { Item = cert.Export(X509ContentType.Cert) }
}
};
var res = await gwClient.signIdCardAsync(sec, rb);
if (res.signIdCardResponse != GW.signIdCardResponse.ok)
{
throw new Exception("Gateway logon error");
}
var xAssertion = from element in SerializerUtil.Serialize(sec).Root.Elements()
where element.Name.LocalName == "Assertion"
select element;
var idCard = new UserIdCard
{
Xassertion = xAssertion.FirstOrDefault()
};
return idCard;
}
private static GW.Security MakeSecurity(GW.AssertionType assertion)
{
return new GW.Security
{
id = Guid.NewGuid().ToString("D"),
Timestamp = new GW.Timestamp { Created = DateTimeEx.UtcNowRound - TimeSpan.FromMinutes(5) },
Assertion = assertion
};
}
private static GW.AssertionType MakeAssertionForSTS(string cvr, string cpr = "1802602810", string authorization = "ZXCVB")
{
var vnow = DateTimeEx.UtcNowRound - TimeSpan.FromMinutes(5);
var ass = new GW.AssertionType
{
IssueInstant = vnow,
id = "IDCard",
Version = 2.0m,
Issuer = "WinPLC",
Conditions = new GW.Conditions
{
NotBefore = vnow,
NotOnOrAfter = vnow + TimeSpan.FromHours(8)
},
Subject = new GW.Subject
{
NameID = new GW.NameIDType
{
Format = GW.SubjectIdentifierType.medcomcprnumber,
Value = "2203333571"
},
SubjectConfirmation = new GW.SubjectConfirmation
{
ConfirmationMethod = GW.ConfirmationMethod.urnoasisnamestcSAML20cmholderofkey,
SubjectConfirmationData = new GW.SubjectConfirmationData
{
Item = new GW.KeyInfo
{
Item = "OCESSignature"
}
}
}
},
AttributeStatement = new[]
{
new GW.AttributeStatement
{
id = GW.AttributeStatementID.IDCardData,
Attribute = new[]
{
new GW.Attribute {Name = GW.AttributeName.sosiIDCardID, AttributeValue = Guid.NewGuid().ToString("D")},
new GW.Attribute {Name = GW.AttributeName.sosiIDCardVersion, AttributeValue = "1.0.1"},
new GW.Attribute {Name = GW.AttributeName.sosiIDCardType, AttributeValue = "user"},
new GW.Attribute {Name = GW.AttributeName.sosiAuthenticationLevel, AttributeValue = "4"}
}
},
new GW.AttributeStatement
{
id = GW.AttributeStatementID.UserLog,
Attribute = new[]
{
new GW.Attribute {Name = GW.AttributeName.medcomUserCivilRegistrationNumber, AttributeValue = cpr},
new GW.Attribute {Name = GW.AttributeName.medcomUserGivenName, AttributeValue = "Stine"},
new GW.Attribute {Name = GW.AttributeName.medcomUserSurName, AttributeValue = "Svendsen"},
new GW.Attribute {Name = GW.AttributeName.medcomUserEmailAddress, AttributeValue = "stineSvendsen@example.com"},
new GW.Attribute {Name = GW.AttributeName.medcomUserRole, AttributeValue = "læge"},
new GW.Attribute {Name = GW.AttributeName.medcomUserAuthorizationCode, AttributeValue = authorization}
}
},
new GW.AttributeStatement
{
id = GW.AttributeStatementID.SystemLog,
Attribute = new[]
{
new GW.Attribute {Name = GW.AttributeName.medcomITSystemName, AttributeValue = "Sygdom.dk"},
new GW.Attribute
{
Name = GW.AttributeName.medcomCareProviderID,
AttributeValue = cvr,
NameFormat = GW.SubjectIdentifierType.medcomcvrnumber,
NameFormatSpecified = true
},
new GW.Attribute {Name = GW.AttributeName.medcomCareProviderName, AttributeValue = "Statens Serum Institut"}
}
}
}
};
return ass;
}
}
}