1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
|
//-----------------------------------------------------------------------
// <copyright file="OpenIdTestBase.cs" company="Outercurve Foundation">
// Copyright (c) Outercurve Foundation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Test.OpenId {
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using DotNetOpenAuth.Configuration;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Messages;
using DotNetOpenAuth.OpenId.Provider;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.Test.Messaging;
using DotNetOpenAuth.Test.Mocks;
using DotNetOpenAuth.Test.OpenId.Extensions;
using NUnit.Framework;
using IAuthenticationRequest = DotNetOpenAuth.OpenId.Provider.IAuthenticationRequest;
public class OpenIdTestBase : TestBase {
protected internal const string IdentifierSelect = "http://specs.openid.net/auth/2.0/identifier_select";
protected internal static readonly Uri BaseMockUri = new Uri("http://localhost/");
protected internal static readonly Uri BaseMockUriSsl = new Uri("https://localhost/");
protected internal static readonly Uri OPUri = new Uri(BaseMockUri, "/provider/endpoint");
protected internal static readonly Uri OPUriSsl = new Uri(BaseMockUriSsl, "/provider/endpoint");
protected internal static readonly Uri[] OPLocalIdentifiers = new[] { new Uri(OPUri, "/provider/someUser0"), new Uri(OPUri, "/provider/someUser1") };
protected internal static readonly Uri[] OPLocalIdentifiersSsl = new[] { new Uri(OPUriSsl, "/provider/someUser0"), new Uri(OPUriSsl, "/provider/someUser1") };
// Vanity URLs are Claimed Identifiers that delegate to some OP and its local identifier.
protected internal static readonly Uri VanityUri = new Uri(BaseMockUri, "/userControlled/identity");
protected internal static readonly Uri VanityUriSsl = new Uri(BaseMockUriSsl, "/userControlled/identity");
protected internal static readonly Uri RPUri = new Uri(BaseMockUri, "/relyingparty/login");
protected internal static readonly Uri RPUriSsl = new Uri(BaseMockUriSsl, "/relyingparty/login");
protected internal static readonly Uri RPRealmUri = new Uri(BaseMockUri, "/relyingparty/");
protected internal static readonly Uri RPRealmUriSsl = new Uri(BaseMockUriSsl, "/relyingparty/");
/// <summary>
/// Initializes a new instance of the <see cref="OpenIdTestBase"/> class.
/// </summary>
internal OpenIdTestBase() {
this.AutoProviderScenario = Scenarios.AutoApproval;
}
public enum Scenarios {
AutoApproval,
AutoApprovalAddFragment,
ApproveOnSetup,
AlwaysDeny,
}
internal Scenarios AutoProviderScenario { get; set; }
protected RelyingPartySecuritySettings RelyingPartySecuritySettings { get; private set; }
protected ProviderSecuritySettings ProviderSecuritySettings { get; private set; }
[SetUp]
public override void SetUp() {
base.SetUp();
this.RelyingPartySecuritySettings = OpenIdElement.Configuration.RelyingParty.SecuritySettings.CreateSecuritySettings();
this.ProviderSecuritySettings = OpenIdElement.Configuration.Provider.SecuritySettings.CreateSecuritySettings();
this.AutoProviderScenario = Scenarios.AutoApproval;
Identifier.EqualityOnStrings = true;
this.HostFactories.InstallUntrustedWebReqestHandler = true;
}
[TearDown]
public override void Cleanup() {
base.Cleanup();
Identifier.EqualityOnStrings = false;
}
/// <summary>
/// Forces storage of an association in an RP's association store.
/// </summary>
/// <param name="relyingParty">The relying party.</param>
/// <param name="providerEndpoint">The provider endpoint.</param>
/// <param name="association">The association.</param>
internal static void StoreAssociation(OpenIdRelyingParty relyingParty, Uri providerEndpoint, Association association) {
// Only store the association if the RP is not in stateless mode.
if (relyingParty.AssociationManager.AssociationStoreTestHook != null) {
relyingParty.AssociationManager.AssociationStoreTestHook.StoreAssociation(providerEndpoint, association);
}
}
/// <summary>
/// Returns the content of a given embedded resource.
/// </summary>
/// <param name="path">The path of the file as it appears within the project,
/// where the leading / marks the root directory of the project.</param>
/// <returns>The content of the requested resource.</returns>
internal static string LoadEmbeddedFile(string path) {
if (!path.StartsWith("/")) {
path = "/" + path;
}
path = "DotNetOpenAuth.Test.OpenId" + path.Replace('/', '.');
Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream(path);
if (resource == null) {
throw new ArgumentException();
}
using (StreamReader sr = new StreamReader(resource)) {
return sr.ReadToEnd();
}
}
internal static IdentifierDiscoveryResult GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl) {
return GetServiceEndpoint(user, providerVersion, servicePriority, useSsl, false);
}
internal static IdentifierDiscoveryResult GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl, bool delegating) {
var providerEndpoint = new ProviderEndpointDescription(
useSsl ? OPUriSsl : OPUri,
new string[] { Protocol.Lookup(providerVersion).ClaimedIdentifierServiceTypeURI });
var local_id = useSsl ? OPLocalIdentifiersSsl[user] : OPLocalIdentifiers[user];
var claimed_id = delegating ? (useSsl ? VanityUriSsl : VanityUri) : local_id;
return IdentifierDiscoveryResult.CreateForClaimedIdentifier(
claimed_id,
claimed_id,
local_id,
providerEndpoint,
servicePriority,
10);
}
/// <summary>
/// Gets a default implementation of a simple provider that responds to authentication requests
/// per the scenario that is being simulated.
/// </summary>
/// <remarks>
/// This is a very useful method to pass to the OpenIdCoordinator constructor for the Provider argument.
/// </remarks>
internal void RegisterAutoProvider() {
this.Handle(OPUri).By(
async (req, ct) => {
var provider = new OpenIdProvider(new MemoryCryptoKeyAndNonceStore(), this.HostFactories);
return await this.AutoProviderActionAsync(provider, req, ct);
});
}
/// <summary>
/// Gets a default implementation of a simple provider that responds to authentication requests
/// per the scenario that is being simulated.
/// </summary>
/// <remarks>
/// This is a very useful method to pass to the OpenIdCoordinator constructor for the Provider argument.
/// </remarks>
internal async Task<HttpResponseMessage> AutoProviderActionAsync(OpenIdProvider provider, HttpRequestMessage req, CancellationToken ct) {
IRequest request = await provider.GetRequestAsync(req, ct);
Assert.That(request, Is.Not.Null);
if (!request.IsResponseReady) {
var authRequest = (IAuthenticationRequest)request;
switch (this.AutoProviderScenario) {
case Scenarios.AutoApproval:
authRequest.IsAuthenticated = true;
break;
case Scenarios.AutoApprovalAddFragment:
authRequest.SetClaimedIdentifierFragment("frag");
authRequest.IsAuthenticated = true;
break;
case Scenarios.ApproveOnSetup:
authRequest.IsAuthenticated = !authRequest.Immediate;
break;
case Scenarios.AlwaysDeny:
authRequest.IsAuthenticated = false;
break;
default:
// All other scenarios are done programmatically only.
throw new InvalidOperationException("Unrecognized scenario");
}
}
return await provider.PrepareResponseAsync(request, ct);
}
internal Task<IEnumerable<IdentifierDiscoveryResult>> DiscoverAsync(Identifier identifier, CancellationToken cancellationToken = default(CancellationToken)) {
var rp = this.CreateRelyingParty(true);
return rp.DiscoverAsync(identifier, cancellationToken);
}
/// <summary>
/// Simulates an extension request and response.
/// </summary>
/// <param name="protocol">The protocol to use in the roundtripping.</param>
/// <param name="requests">The extensions to add to the request message.</param>
/// <param name="responses">The extensions to add to the response message.</param>
/// <remarks>
/// This method relies on the extension objects' Equals methods to verify
/// accurate transport. The Equals methods should be verified by separate tests.
/// </remarks>
internal async Task RoundtripAsync(Protocol protocol, IEnumerable<IOpenIdMessageExtension> requests, IEnumerable<IOpenIdMessageExtension> responses) {
var securitySettings = new ProviderSecuritySettings();
var cryptoKeyStore = new MemoryCryptoKeyStore();
var associationStore = new ProviderAssociationHandleEncoder(cryptoKeyStore);
Association association = HmacShaAssociationProvider.Create(
protocol,
protocol.Args.SignatureAlgorithm.Best,
AssociationRelyingPartyType.Smart,
associationStore,
securitySettings);
this.HandleProvider(
async (op, req) => {
ExtensionTestUtilities.RegisterExtension(op.Channel, Mocks.MockOpenIdExtension.Factory);
var key = cryptoKeyStore.GetCurrentKey(
ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, TimeSpan.FromSeconds(1));
op.CryptoKeyStore.StoreKey(
ProviderAssociationHandleEncoder.AssociationHandleEncodingSecretBucket, key.Key, key.Value);
var request = await op.Channel.ReadFromRequestAsync<CheckIdRequest>(req, CancellationToken.None);
var response = new PositiveAssertionResponse(request);
var receivedRequests = request.Extensions.Cast<IOpenIdMessageExtension>();
CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(requests.ToArray(), receivedRequests.ToArray());
foreach (var extensionResponse in responses) {
response.Extensions.Add(extensionResponse);
}
return await op.Channel.PrepareResponseAsync(response);
});
{
var rp = this.CreateRelyingParty();
ExtensionTestUtilities.RegisterExtension(rp.Channel, Mocks.MockOpenIdExtension.Factory);
var requestBase = new CheckIdRequest(protocol.Version, OpenIdTestBase.OPUri, AuthenticationRequestMode.Immediate);
OpenIdTestBase.StoreAssociation(rp, OpenIdTestBase.OPUri, association);
requestBase.AssociationHandle = association.Handle;
requestBase.ClaimedIdentifier = "http://claimedid";
requestBase.LocalIdentifier = "http://localid";
requestBase.ReturnTo = OpenIdTestBase.RPUri;
foreach (IOpenIdMessageExtension extension in requests) {
requestBase.Extensions.Add(extension);
}
var redirectingRequest = await rp.Channel.PrepareResponseAsync(requestBase);
Uri redirectingResponseUri;
this.HostFactories.AllowAutoRedirects = false;
using (var httpClient = rp.Channel.HostFactories.CreateHttpClient()) {
using (var redirectingResponse = await httpClient.GetAsync(redirectingRequest.Headers.Location)) {
Assert.AreEqual(HttpStatusCode.Found, redirectingResponse.StatusCode);
redirectingResponseUri = redirectingResponse.Headers.Location;
}
}
var response =
await
rp.Channel.ReadFromRequestAsync<PositiveAssertionResponse>(
new HttpRequestMessage(HttpMethod.Get, redirectingResponseUri), CancellationToken.None);
var receivedResponses = response.Extensions.Cast<IOpenIdMessageExtension>();
CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray());
}
}
protected internal void HandleProvider(Func<OpenIdProvider, HttpRequestMessage, Task<HttpResponseMessage>> provider) {
var op = this.CreateProvider();
this.Handle(OPUri).By(async req => {
return await provider(op, req);
});
}
protected Realm GetMockRealm(bool useSsl) {
var rpDescription = new RelyingPartyEndpointDescription(useSsl ? RPUriSsl : RPUri, new string[] { Protocol.V20.RPReturnToTypeURI });
return new MockRealm(useSsl ? RPRealmUriSsl : RPRealmUri, rpDescription);
}
protected Identifier GetMockIdentifier(ProtocolVersion providerVersion) {
return this.GetMockIdentifier(providerVersion, false);
}
protected Identifier GetMockIdentifier(ProtocolVersion providerVersion, bool useSsl) {
return this.GetMockIdentifier(providerVersion, useSsl, false);
}
protected Identifier GetMockIdentifier(ProtocolVersion providerVersion, bool useSsl, bool delegating) {
var se = GetServiceEndpoint(0, providerVersion, 10, useSsl, delegating);
this.RegisterMockXrdsResponse(se);
return se.ClaimedIdentifier;
}
protected Identifier GetMockDualIdentifier() {
Protocol protocol = Protocol.Default;
var opDesc = new ProviderEndpointDescription(OPUri, protocol.Version);
var dualResults = new IdentifierDiscoveryResult[] {
IdentifierDiscoveryResult.CreateForClaimedIdentifier(VanityUri.AbsoluteUri, OPLocalIdentifiers[0], opDesc, 10, 10),
IdentifierDiscoveryResult.CreateForProviderIdentifier(protocol.ClaimedIdentifierForOPIdentifier, opDesc, 20, 20),
};
this.RegisterMockXrdsResponse(VanityUri, dualResults);
return VanityUri;
}
/// <summary>
/// Creates a standard <see cref="OpenIdRelyingParty"/> instance for general testing.
/// </summary>
/// <returns>The new instance.</returns>
protected OpenIdRelyingParty CreateRelyingParty() {
return this.CreateRelyingParty(false);
}
/// <summary>
/// Creates a standard <see cref="OpenIdRelyingParty"/> instance for general testing.
/// </summary>
/// <param name="stateless">if set to <c>true</c> a stateless RP is created.</param>
/// <returns>The new instance.</returns>
protected OpenIdRelyingParty CreateRelyingParty(bool stateless) {
var rp = new OpenIdRelyingParty(stateless ? null : new MemoryCryptoKeyAndNonceStore(), this.HostFactories);
return rp;
}
/// <summary>
/// Creates a standard <see cref="OpenIdProvider"/> instance for general testing.
/// </summary>
/// <returns>The new instance.</returns>
protected OpenIdProvider CreateProvider() {
var op = new OpenIdProvider(new MemoryCryptoKeyAndNonceStore(), this.HostFactories);
return op;
}
}
}
|