Skip to content

Commit b0e7503

Browse files
authored
Update WCF TransportSecurity Sample to support NET Core (#6207)
1 parent 3499221 commit b0e7503

File tree

8 files changed

+272
-184
lines changed

8 files changed

+272
-184
lines changed

framework/wcf/Basic/Binding/Basic/TransportSecurity/CS/client/App.config

+1-2
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,4 @@
2020
</bindings>
2121

2222
</system.serviceModel>
23-
24-
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/></startup></configuration>
23+
</configuration>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Microsoft.Samples.TransportSecurity
2+
{
3+
// This partial class constructor is needed as the service is hosted in IIS and advertises both HTTP and HTTPS endpoints.
4+
// This causes the generated client to have 2 configurations so a default constructor can't be generated as it's unknown which to use.
5+
// By adding this constructor, we can choose which endpoint we wish to use as the default.
6+
public partial class CalculatorClient
7+
{
8+
#if NET6_0_OR_GREATER
9+
public CalculatorClient() : this(EndpointConfiguration.BasicHttpBinding_ICalculator1) { }
10+
#endif
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"ExtendedData": {
3+
"inputs": [
4+
"https://localhost/servicemodelsamples/service.svc"
5+
],
6+
"collectionTypes": [
7+
"System.Array",
8+
"System.Collections.Generic.Dictionary`2"
9+
],
10+
"namespaceMappings": [
11+
"*, Microsoft.Samples.TransportSecurity"
12+
],
13+
"sync": true,
14+
"targetFramework": "net6.0",
15+
"typeReuseMode": "None"
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by a tool.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
namespace Microsoft.Samples.TransportSecurity
11+
{
12+
13+
14+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
15+
[System.ServiceModel.ServiceContractAttribute(Namespace="http://Microsoft.Samples.TransportSecurity", ConfigurationName="Microsoft.Samples.TransportSecurity.ICalculator")]
16+
public interface ICalculator
17+
{
18+
19+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Add", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/AddResponse")]
20+
double Add(double n1, double n2);
21+
22+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Add", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/AddResponse")]
23+
System.Threading.Tasks.Task<double> AddAsync(double n1, double n2);
24+
25+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Subtract", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/SubtractResponse")]
26+
double Subtract(double n1, double n2);
27+
28+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Subtract", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/SubtractResponse")]
29+
System.Threading.Tasks.Task<double> SubtractAsync(double n1, double n2);
30+
31+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Multiply", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/MultiplyResponse")]
32+
double Multiply(double n1, double n2);
33+
34+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Multiply", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/MultiplyResponse")]
35+
System.Threading.Tasks.Task<double> MultiplyAsync(double n1, double n2);
36+
37+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Divide", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/DivideResponse")]
38+
double Divide(double n1, double n2);
39+
40+
[System.ServiceModel.OperationContractAttribute(Action="http://Microsoft.Samples.TransportSecurity/ICalculator/Divide", ReplyAction="http://Microsoft.Samples.TransportSecurity/ICalculator/DivideResponse")]
41+
System.Threading.Tasks.Task<double> DivideAsync(double n1, double n2);
42+
}
43+
44+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
45+
public interface ICalculatorChannel : Microsoft.Samples.TransportSecurity.ICalculator, System.ServiceModel.IClientChannel
46+
{
47+
}
48+
49+
[System.Diagnostics.DebuggerStepThroughAttribute()]
50+
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
51+
public partial class CalculatorClient : System.ServiceModel.ClientBase<Microsoft.Samples.TransportSecurity.ICalculator>, Microsoft.Samples.TransportSecurity.ICalculator
52+
{
53+
54+
/// <summary>
55+
/// Implement this partial method to configure the service endpoint.
56+
/// </summary>
57+
/// <param name="serviceEndpoint">The endpoint to configure</param>
58+
/// <param name="clientCredentials">The client credentials</param>
59+
static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
60+
61+
public CalculatorClient(EndpointConfiguration endpointConfiguration) :
62+
base(CalculatorClient.GetBindingForEndpoint(endpointConfiguration), CalculatorClient.GetEndpointAddress(endpointConfiguration))
63+
{
64+
this.Endpoint.Name = endpointConfiguration.ToString();
65+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
66+
}
67+
68+
public CalculatorClient(EndpointConfiguration endpointConfiguration, string remoteAddress) :
69+
base(CalculatorClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
70+
{
71+
this.Endpoint.Name = endpointConfiguration.ToString();
72+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
73+
}
74+
75+
public CalculatorClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) :
76+
base(CalculatorClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
77+
{
78+
this.Endpoint.Name = endpointConfiguration.ToString();
79+
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
80+
}
81+
82+
public CalculatorClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
83+
base(binding, remoteAddress)
84+
{
85+
}
86+
87+
public double Add(double n1, double n2)
88+
{
89+
return base.Channel.Add(n1, n2);
90+
}
91+
92+
public System.Threading.Tasks.Task<double> AddAsync(double n1, double n2)
93+
{
94+
return base.Channel.AddAsync(n1, n2);
95+
}
96+
97+
public double Subtract(double n1, double n2)
98+
{
99+
return base.Channel.Subtract(n1, n2);
100+
}
101+
102+
public System.Threading.Tasks.Task<double> SubtractAsync(double n1, double n2)
103+
{
104+
return base.Channel.SubtractAsync(n1, n2);
105+
}
106+
107+
public double Multiply(double n1, double n2)
108+
{
109+
return base.Channel.Multiply(n1, n2);
110+
}
111+
112+
public System.Threading.Tasks.Task<double> MultiplyAsync(double n1, double n2)
113+
{
114+
return base.Channel.MultiplyAsync(n1, n2);
115+
}
116+
117+
public double Divide(double n1, double n2)
118+
{
119+
return base.Channel.Divide(n1, n2);
120+
}
121+
122+
public System.Threading.Tasks.Task<double> DivideAsync(double n1, double n2)
123+
{
124+
return base.Channel.DivideAsync(n1, n2);
125+
}
126+
127+
public virtual System.Threading.Tasks.Task OpenAsync()
128+
{
129+
return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndOpen));
130+
}
131+
132+
private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
133+
{
134+
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ICalculator))
135+
{
136+
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
137+
result.MaxBufferSize = int.MaxValue;
138+
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
139+
result.MaxReceivedMessageSize = int.MaxValue;
140+
result.AllowCookies = true;
141+
return result;
142+
}
143+
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ICalculator1))
144+
{
145+
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
146+
result.MaxBufferSize = int.MaxValue;
147+
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
148+
result.MaxReceivedMessageSize = int.MaxValue;
149+
result.AllowCookies = true;
150+
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
151+
return result;
152+
}
153+
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
154+
}
155+
156+
private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration)
157+
{
158+
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ICalculator))
159+
{
160+
return new System.ServiceModel.EndpointAddress("http://localhost/servicemodelsamples/service.svc");
161+
}
162+
if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ICalculator1))
163+
{
164+
return new System.ServiceModel.EndpointAddress("https://localhost/servicemodelsamples/service.svc");
165+
}
166+
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
167+
}
168+
169+
public enum EndpointConfiguration
170+
{
171+
172+
BasicHttpBinding_ICalculator,
173+
174+
BasicHttpBinding_ICalculator1,
175+
}
176+
}
177+
}

framework/wcf/Basic/Binding/Basic/TransportSecurity/CS/client/Properties/AssemblyInfo.cs

-22
This file was deleted.

framework/wcf/Basic/Binding/Basic/TransportSecurity/CS/client/client.cs

+26-18
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
//----------------------------------------------------------------
44

55
using System;
6-
using System.Net;
6+
using System.IdentityModel.Selectors;
7+
using System.IdentityModel.Tokens;
78
using System.Security.Cryptography.X509Certificates;
9+
using System.ServiceModel.Security;
810

911
namespace Microsoft.Samples.TransportSecurity
1012
{
@@ -17,10 +19,12 @@ static void Main()
1719
{
1820
// WARNING: This code is only needed for test certificates such as those created by makecert. It is
1921
// not recommended for production code.
20-
PermissiveCertificatePolicy.Enact("CN=ServiceModelSamples-HTTPS-Server");
21-
2222
// Create a client
2323
CalculatorClient client = new CalculatorClient();
24+
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication = new X509ServiceCertificateAuthentication();
25+
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
26+
MyX509CertificateValidator myX509CertificateValidator = new MyX509CertificateValidator("CN=ServiceModelSamples-HTTPS-Server");
27+
client.ClientCredentials.ServiceCertificate.SslCertificateAuthentication.CustomCertificateValidator = myX509CertificateValidator;
2428

2529
// Call the Add service operation.
2630
double value1 = 100.00D;
@@ -57,30 +61,34 @@ static void Main()
5761

5862
// WARNING: This code is only needed for test certificates such as those created by makecert. It is
5963
// not recommended for production code.
60-
class PermissiveCertificatePolicy
64+
public class MyX509CertificateValidator : X509CertificateValidator
6165
{
62-
string subjectName;
63-
static PermissiveCertificatePolicy currentPolicy;
64-
PermissiveCertificatePolicy(string subjectName)
65-
{
66-
this.subjectName = subjectName;
67-
ServicePointManager.ServerCertificateValidationCallback +=
68-
new System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidate);
69-
}
66+
private string _allowedIssuerName;
7067

71-
public static void Enact(string subjectName)
68+
public MyX509CertificateValidator(string allowedIssuerName)
7269
{
73-
currentPolicy = new PermissiveCertificatePolicy(subjectName);
70+
if (string.IsNullOrEmpty(allowedIssuerName))
71+
{
72+
throw new ArgumentNullException("allowedIssuerName", "[MyX509CertificateValidator] The string parameter allowedIssuerName was null or empty.");
73+
}
74+
75+
_allowedIssuerName = allowedIssuerName;
7476
}
7577

76-
bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
78+
public override void Validate(X509Certificate2 certificate)
7779
{
78-
if (cert.Subject == subjectName)
80+
// Check that there is a certificate.
81+
if (certificate == null)
7982
{
80-
return true;
83+
throw new ArgumentNullException("certificate", "[MyX509CertificateValidator] The X509Certificate2 parameter certificate was null.");
8184
}
8285

83-
return false;
86+
// Check that the certificate issuer matches the configured issuer.
87+
if (!certificate.Subject.Contains(_allowedIssuerName))
88+
{
89+
throw new SecurityTokenValidationException
90+
(string.Format("Certificate was not issued by a trusted issuer. Expected: {0}, Actual: {1}", _allowedIssuerName, certificate.IssuerName.Name));
91+
}
8492
}
8593
}
8694
}

0 commit comments

Comments
 (0)