Skip to content

Commit 5d8fdf2

Browse files
afifi-insmconnew
authored andcommitted
Add MultiCredentialSecurityTokenManager to handle CoreWCF service certificates and enable tests
1 parent 078cab1 commit 5d8fdf2

File tree

14 files changed

+230
-50
lines changed

14 files changed

+230
-50
lines changed

src/System.Private.ServiceModel/tests/Common/Scenarios/ScenarioTestHelpers.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ public static void CloseCommunicationObjects(params ICommunicationObject[] objec
210210
{
211211
comObj.Abort();
212212
}
213+
catch (System.Net.WebSockets.WebSocketException)
214+
{
215+
// WCF Client has a bug which throws WebSocketException when the server closes the connection.
216+
// The remote party closed the WebSocket connection without completing the close handshake.
217+
comObj.Abort();
218+
}
213219
}
214220
}
215221

src/System.Private.ServiceModel/tests/Scenarios/Binding/Http/NetHttpBindingTests.4.0.0.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
public class Binding_Http_NetHttpBindingTests : ConditionalWcfTest
1111
{
1212
[WcfTheory]
13-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
1413
[InlineData(NetHttpMessageEncoding.Binary)]
1514
[InlineData(NetHttpMessageEncoding.Text)]
1615
[InlineData(NetHttpMessageEncoding.Mtom)]

src/System.Private.ServiceModel/tests/Scenarios/Binding/Http/NetHttpsBindingTests.4.1.0.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ public class Binding_Http_NetHttpsBindingTests : ConditionalWcfTest
1515
[InlineData(NetHttpMessageEncoding.Mtom)]
1616
[Issue(3572, OS = OSID.OSX)]
1717
[Condition(nameof(Root_Certificate_Installed),
18-
nameof(SSL_Available),
19-
nameof(Skip_CoreWCFService_FailedTest))]
18+
nameof(SSL_Available))]
2019
[OuterLoop]
2120
public static void DefaultCtor_NetHttps_Echo_RoundTrips_String(NetHttpMessageEncoding messageEncoding)
2221
{
@@ -83,8 +82,7 @@ public static void TransportWithMessageCredential_NotSupported_NetHttps()
8382
[WcfFact]
8483
[Issue(3572, OS = OSID.OSX)]
8584
[Condition(nameof(Root_Certificate_Installed),
86-
nameof(SSL_Available),
87-
nameof(Skip_CoreWCFService_FailedTest))]
85+
nameof(SSL_Available))]
8886
[OuterLoop]
8987
public static void NonDefaultCtor_NetHttps_Echo_RoundTrips_String()
9088
{

src/System.Private.ServiceModel/tests/Scenarios/Client/ExpectedExceptions/ExpectedExceptionTests.4.1.0.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ public static void DuplexCallback_Throws_FaultException_ReturnsFaultedTask()
328328
}
329329

330330
[WcfFact]
331-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
332331
[OuterLoop]
333332
// Verify product throws MessageSecurityException when the Dns identity from the server does not match the expectation
334333
public static void TCP_ServiceCertExpired_Throw_MessageSecurityException()
@@ -372,7 +371,6 @@ public static void TCP_ServiceCertExpired_Throw_MessageSecurityException()
372371
}
373372

374373
[WcfFact]
375-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
376374
[OuterLoop]
377375
// Verify product throws SecurityNegotiationException when the service cert is revoked
378376
public static void TCP_ServiceCertRevoked_Throw_SecurityNegotiationException()
@@ -420,7 +418,6 @@ public static void TCP_ServiceCertRevoked_Throw_SecurityNegotiationException()
420418
}
421419

422420
[WcfFact]
423-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
424421
[OuterLoop]
425422
// Verify product throws SecurityNegotiationException when the service cert only has the ClientAuth usage
426423
public static void TCP_ServiceCertInvalidEKU_Throw_SecurityNegotiationException()

src/System.Private.ServiceModel/tests/Scenarios/Extensibility/WebSockets/WebSocketTests.4.1.0.cs

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,12 @@ public static void WebSocket_Http_Duplex_Buffered(NetHttpMessageEncoding message
168168
"The logging done by the Server was not returned via the Callback.");
169169

170170
// *** CLEANUP *** \\
171-
((ICommunicationObject)client).Close();
172-
channelFactory.Close();
171+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
172+
if (!ScenarioTestHelpers.IsLocalHost())
173+
{
174+
((ICommunicationObject)client).Close();
175+
channelFactory.Close();
176+
}
173177
}
174178
finally
175179
{
@@ -236,8 +240,12 @@ public static void WebSocket_Http_Duplex_Buffered_KeepAlive(NetHttpMessageEncodi
236240
"The logging done by the Server was not returned via the Callback.");
237241

238242
// *** CLEANUP *** \\
239-
((ICommunicationObject)client).Close();
240-
channelFactory.Close();
243+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
244+
if (!ScenarioTestHelpers.IsLocalHost())
245+
{
246+
((ICommunicationObject)client).Close();
247+
channelFactory.Close();
248+
}
241249
}
242250
finally
243251
{
@@ -416,7 +424,6 @@ public static void WebSocket_Https_Duplex_Buffered(NetHttpMessageEncoding messag
416424
}
417425

418426
[WcfTheory]
419-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
420427
[InlineData(NetHttpMessageEncoding.Binary)]
421428
[InlineData(NetHttpMessageEncoding.Text)]
422429
[InlineData(NetHttpMessageEncoding.Mtom)]
@@ -472,8 +479,12 @@ public static void WebSocket_Http_RequestReply_Streamed(NetHttpMessageEncoding m
472479
}
473480

474481
// *** CLEANUP *** \\
475-
((ICommunicationObject)client).Close();
476-
channelFactory.Close();
482+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
483+
if (!ScenarioTestHelpers.IsLocalHost())
484+
{
485+
((ICommunicationObject)client).Close();
486+
channelFactory.Close();
487+
}
477488
}
478489
finally
479490
{
@@ -487,7 +498,6 @@ public static void WebSocket_Http_RequestReply_Streamed(NetHttpMessageEncoding m
487498
[InlineData(NetHttpMessageEncoding.Text)]
488499
[InlineData(NetHttpMessageEncoding.Mtom)]
489500
[Issue(1438, OS = OSID.Windows_7)] // not supported on Win7
490-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
491501
[OuterLoop]
492502
public static void WebSocket_Http_RequestReply_Buffered(NetHttpMessageEncoding messageEncoding)
493503
{
@@ -527,8 +537,12 @@ public static void WebSocket_Http_RequestReply_Buffered(NetHttpMessageEncoding m
527537
}
528538

529539
// *** CLEANUP *** \\
530-
((ICommunicationObject)client).Close();
531-
channelFactory.Close();
540+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
541+
if (!ScenarioTestHelpers.IsLocalHost())
542+
{
543+
((ICommunicationObject)client).Close();
544+
channelFactory.Close();
545+
}
532546
}
533547
finally
534548
{
@@ -541,7 +555,6 @@ public static void WebSocket_Http_RequestReply_Buffered(NetHttpMessageEncoding m
541555
[InlineData(NetHttpMessageEncoding.Binary)]
542556
[InlineData(NetHttpMessageEncoding.Text)]
543557
[InlineData(NetHttpMessageEncoding.Mtom)]
544-
[Condition(nameof(Skip_CoreWCFService_FailedTest))]
545558
[Issue(1438, OS = OSID.Windows_7)] // not supported on Win7
546559
[OuterLoop]
547560
public static void WebSocket_Http_RequestReply_Buffered_KeepAlive(NetHttpMessageEncoding messageEncoding)
@@ -582,8 +595,12 @@ public static void WebSocket_Http_RequestReply_Buffered_KeepAlive(NetHttpMessage
582595
}
583596

584597
// *** CLEANUP *** \\
585-
((ICommunicationObject)client).Close();
586-
channelFactory.Close();
598+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
599+
if (!ScenarioTestHelpers.IsLocalHost())
600+
{
601+
((ICommunicationObject)client).Close();
602+
channelFactory.Close();
603+
}
587604
}
588605
finally
589606
{
@@ -596,8 +613,7 @@ public static void WebSocket_Http_RequestReply_Buffered_KeepAlive(NetHttpMessage
596613
[InlineData(NetHttpMessageEncoding.Binary)]
597614
[InlineData(NetHttpMessageEncoding.Text)]
598615
[InlineData(NetHttpMessageEncoding.Mtom)]
599-
[Condition(nameof(Root_Certificate_Installed),
600-
nameof(Skip_CoreWCFService_FailedTest))]
616+
[Condition(nameof(Root_Certificate_Installed))]
601617
[Issue(3572, OS = OSID.OSX)]
602618
[Issue(1438, OS = OSID.Windows_7)] // not supported on Win7
603619
[OuterLoop]
@@ -638,8 +654,12 @@ public static void WebSocket_Https_RequestReply_Buffered(NetHttpMessageEncoding
638654
}
639655

640656
// *** CLEANUP *** \\
641-
((ICommunicationObject)client).Close();
642-
channelFactory.Close();
657+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
658+
if (!ScenarioTestHelpers.IsLocalHost())
659+
{
660+
((ICommunicationObject)client).Close();
661+
channelFactory.Close();
662+
}
643663
}
644664
finally
645665
{
@@ -652,8 +672,7 @@ public static void WebSocket_Https_RequestReply_Buffered(NetHttpMessageEncoding
652672
[InlineData(NetHttpMessageEncoding.Binary)]
653673
[InlineData(NetHttpMessageEncoding.Text)]
654674
[InlineData(NetHttpMessageEncoding.Mtom)]
655-
[Condition(nameof(Root_Certificate_Installed),
656-
nameof(Skip_CoreWCFService_FailedTest))]
675+
[Condition(nameof(Root_Certificate_Installed))]
657676
[Issue(3572, OS = OSID.OSX)]
658677
[Issue(1438, OS = OSID.Windows_7)] // not supported on Win7
659678
[OuterLoop]
@@ -696,8 +715,12 @@ public static void WebSocket_Https_RequestReply_Buffered_KeepAlive(NetHttpMessag
696715
}
697716

698717
// *** CLEANUP *** \\
699-
((ICommunicationObject)client).Close();
700-
channelFactory.Close();
718+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
719+
if (!ScenarioTestHelpers.IsLocalHost())
720+
{
721+
((ICommunicationObject)client).Close();
722+
channelFactory.Close();
723+
}
701724
}
702725
finally
703726
{
@@ -862,8 +885,12 @@ public static void WebSocket_Http_VerifyWebSocketsUsed()
862885
Assert.True(responseFromService, String.Format("Response from the service was not expected. Expected: 'True' but got {0}", responseFromService));
863886

864887
// *** CLEANUP *** \\
865-
((ICommunicationObject)client).Close();
866-
channelFactory.Close();
888+
// Close the client and channel factory if not running on localhost. CoreWCF has a bug in Close method (on Linux).
889+
if (!ScenarioTestHelpers.IsLocalHost())
890+
{
891+
((ICommunicationObject)client).Close();
892+
channelFactory.Close();
893+
}
867894
}
868895
finally
869896
{

src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Https/HttpsTests.4.1.1.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,7 @@ public static void Https_SecModeTrans_CertValMode_PeerTrust_Fails_Not_In_Trusted
125125
[WcfFact]
126126
[Condition(nameof(Root_Certificate_Installed),
127127
nameof(Client_Certificate_Installed),
128-
nameof(SSL_Available),
129-
nameof(Skip_CoreWCFService_FailedTest))]
128+
nameof(SSL_Available))]
130129
[Issue(1945, OS = OSID.OSX)] // OSX doesn't support the TrustedPeople certificate store
131130
[OuterLoop]
132131
// Asking for PeerOrChainTrust should succeed if the certificate is
@@ -175,8 +174,7 @@ public static void Https_SecModeTrans_CertValMode_PeerOrChainTrust_Succeeds_Chai
175174
[Issue(2870, OS = OSID.OSX)]
176175
[Condition(nameof(Root_Certificate_Installed),
177176
nameof(Client_Certificate_Installed),
178-
nameof(SSL_Available),
179-
nameof(Skip_CoreWCFService_FailedTest))]
177+
nameof(SSL_Available))]
180178
[OuterLoop]
181179
// Asking for ChainTrust should succeed if the certificate is
182180
// chain-trusted.

src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeCertificateCanonicalNameTests.4.1.0.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@ public class Tcp_ClientCredentialTypeCertificateCanonicalNameTests : Conditional
2626

2727
[WcfFact]
2828
[Issue(3572, OS = OSID.OSX)]
29-
[Condition(nameof(Root_Certificate_Installed),
30-
nameof(Skip_CoreWCFService_FailedTest))]
29+
[Condition(nameof(Root_Certificate_Installed))]
3130
[OuterLoop]
3231
public static void Certificate_With_CanonicalName_Localhost_Address_EchoString()
3332
{

src/System.Private.ServiceModel/tests/Scenarios/Security/TransportSecurity/Tcp/ClientCredentialTypeTests.4.1.1.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ public partial class Tcp_ClientCredentialTypeTests : ConditionalWcfTest
1818
[Condition(nameof(Root_Certificate_Installed),
1919
nameof(Client_Certificate_Installed),
2020
nameof(Peer_Certificate_Installed),
21-
nameof(SSL_Available),
22-
nameof(Skip_CoreWCFService_FailedTest))]
21+
nameof(SSL_Available))]
2322
[OuterLoop]
2423
// Asking for PeerTrust alone should succeed
2524
// if the certificate is in the TrustedPeople store. For this test
@@ -125,8 +124,7 @@ public static void NetTcp_SecModeTrans_CertValMode_PeerTrust_Fails_Not_In_Truste
125124
[Issue(1945, OS = OSID.OSX)]
126125
[Condition(nameof(Root_Certificate_Installed),
127126
nameof(Client_Certificate_Installed),
128-
nameof(SSL_Available),
129-
nameof(Skip_CoreWCFService_FailedTest))]
127+
nameof(SSL_Available))]
130128
[OuterLoop]
131129
// Asking for PeerOrChainTrust should succeed if the certificate is
132130
// chain-trusted, even though it is not in the TrustedPeople store.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if NET
6+
using CoreWCF.Description;
7+
using CoreWCF.IdentityModel.Selectors;
8+
using CoreWCF.Security;
9+
using CoreWCF.Security.Tokens;
10+
11+
namespace WcfService
12+
{
13+
public class MultiCredentialSecurityTokenManager : ServiceCredentialsSecurityTokenManager
14+
{
15+
private readonly MultiCredentialServiceCredentials _parent;
16+
private readonly Dictionary<string, ServiceCredentials> _map;
17+
18+
public MultiCredentialSecurityTokenManager(
19+
MultiCredentialServiceCredentials parent,
20+
Dictionary<string, ServiceCredentials> map)
21+
: base(parent)
22+
{
23+
_parent = parent;
24+
_map = map;
25+
}
26+
27+
public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
28+
{
29+
if (tokenRequirement is RecipientServiceModelSecurityTokenRequirement recipientRequirement)
30+
{
31+
var uri = recipientRequirement.ListenUri?.AbsolutePath;
32+
if (!string.IsNullOrEmpty(uri) && _map.TryGetValue(uri, out var creds))
33+
{
34+
return creds.CreateSecurityTokenManager().CreateSecurityTokenProvider(tokenRequirement);
35+
}
36+
}
37+
return _parent.CreateOriginalSecurityTokenManager().CreateSecurityTokenProvider(tokenRequirement);
38+
}
39+
40+
public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
41+
{
42+
if (tokenRequirement is RecipientServiceModelSecurityTokenRequirement recipientRequirement)
43+
{
44+
var uri = recipientRequirement.ListenUri?.AbsolutePath;
45+
if (!string.IsNullOrEmpty(uri) && _map.TryGetValue(uri, out var creds))
46+
{
47+
return creds.CreateSecurityTokenManager().CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
48+
}
49+
}
50+
51+
return _parent.CreateOriginalSecurityTokenManager().CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
52+
}
53+
}
54+
}
55+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#if NET
6+
using CoreWCF.Description;
7+
using CoreWCF.IdentityModel.Selectors;
8+
9+
namespace WcfService
10+
{
11+
public class MultiCredentialServiceCredentials : ServiceCredentials
12+
{
13+
private readonly Dictionary<string, ServiceCredentials> _serviceCredentialsMap = new();
14+
15+
public void AddServiceCredentials(string path, ServiceCredentials credentials)
16+
{
17+
_serviceCredentialsMap[path] = credentials;
18+
}
19+
20+
public IReadOnlyDictionary<string, ServiceCredentials> ServiceCredentialsMap => _serviceCredentialsMap;
21+
22+
public override SecurityTokenManager CreateSecurityTokenManager()
23+
{
24+
return new MultiCredentialSecurityTokenManager(this, _serviceCredentialsMap);
25+
}
26+
27+
internal SecurityTokenManager CreateOriginalSecurityTokenManager()
28+
{
29+
return base.CreateSecurityTokenManager();
30+
}
31+
32+
protected override ServiceCredentials CloneCore()
33+
{
34+
var clone = new MultiCredentialServiceCredentials();
35+
foreach (var kvp in _serviceCredentialsMap)
36+
{
37+
clone.AddServiceCredentials(kvp.Key, kvp.Value.Clone());
38+
}
39+
return clone;
40+
}
41+
}
42+
}
43+
#endif

0 commit comments

Comments
 (0)