1
//-----------------------------------------------------------------------
2 // <copyright file="TestSupport.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth
.Test
.OpenId
{
9 using System
.Collections
.Generic
;
11 using System
.Reflection
;
12 using DotNetOAuth
.Test
.OpenId
.UI
;
13 using DotNetOpenAuth
.Messaging
;
14 using DotNetOpenAuth
.OpenId
;
15 using DotNetOpenAuth
.OpenId
.Provider
;
16 using DotNetOpenAuth
.OpenId
.RelyingParty
;
17 using DotNetOpenAuth
.Test
.Mocks
;
18 ////using DotNetOpenAuth.Test.UI;
21 public class TestSupport
{
22 public const string HostTestPage
= "HostTest.aspx";
24 public const string ProviderPage
= "ProviderEndpoint.aspx";
26 public const string DirectedProviderEndpoint
= "DirectedProviderEndpoint.aspx";
28 public const string MobileConsumerPage
= "RelyingPartyMobile.aspx";
30 public const string ConsumerPage
= "RelyingParty.aspx";
32 public const string OPDefaultPage
= "OPDefault.aspx";
34 public static readonly ILog Logger
= LogManager
.GetLogger("DotNetOpenId.Test");
36 public static readonly string TestWebDirectory
= Path
.GetFullPath(Path
.Combine(Directory
.GetCurrentDirectory(), @"..\..\src\DotNetOpenId.TestWeb"));
38 private const string IdentityPage
= "IdentityEndpoint.aspx";
40 private const string DirectedIdentityPage
= "DirectedIdentityEndpoint.aspx";
42 public enum Scenarios
{
43 // Authentication test scenarios
46 AutoApprovalAddFragment
,
52 /* Extension test scenarios */
55 /// Provides all required and requested fields.
57 ExtensionFullCooperation
,
60 /// Provides only those fields marked as required.
62 ExtensionPartialCooperation
,
65 public static Uri ReturnTo
{
66 get { return TestSupport.GetFullUrl(TestSupport.ConsumerPage); }
69 public static Realm Realm
{
70 get { return new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri); }
73 public static Identifier
GetDelegateUrl(Scenarios scenario
) {
74 return GetDelegateUrl(scenario
, false);
77 public static Identifier
GetDelegateUrl(Scenarios scenario
, bool useSsl
) {
78 return new UriIdentifier(GetFullUrl("/" + scenario
, null, useSsl
));
81 public static Uri
GetFullUrl(string url
) {
82 return GetFullUrl(url
, null, false);
85 public static Uri
GetFullUrl(string url
, string key
, object value) {
86 var dictionary
= new Dictionary
<string, string> {
87 { key, value.ToString() }
,
89 return GetFullUrl(url
, dictionary
, false);
92 public static Uri
GetFullUrl(string url
, IDictionary
<string, string> args
, bool useSsl
) {
93 Uri defaultUriBase
= new Uri(useSsl
? "https://localhost/" : "http://localhost/");
94 Uri baseUri
= UITestSupport
.Host
!= null ? UITestSupport
.Host
.BaseUri
: defaultUriBase
;
95 UriBuilder builder
= new UriBuilder(new Uri(baseUri
, url
));
96 MessagingUtilities
.AppendQueryArgs(builder
, args
);
101 /// Returns the content of a given embedded resource.
103 /// <param name="path">The path of the file as it appears within the project,
104 /// where the leading / marks the root directory of the project.</param>
105 /// <returns>The content of the requested resource.</returns>
106 internal static string LoadEmbeddedFile(string path
) {
107 if (!path
.StartsWith("/")) {
110 path
= "DotNetOpenAuth.Test.OpenId" + path
.Replace('/', '.');
111 Stream resource
= Assembly
.GetExecutingAssembly().GetManifestResourceStream(path
);
112 if (resource
== null) {
113 throw new ArgumentException();
115 using (StreamReader sr
= new StreamReader(resource
)) {
116 return sr
.ReadToEnd();
120 ////internal static UriIdentifier GetOPIdentityUrl(Scenarios scenario, bool useSsl) {
121 //// var args = new Dictionary<string, string> {
122 //// { "user", scenario.ToString() },
124 //// return new UriIdentifier(GetFullUrl("/" + OPDefaultPage, args, useSsl));
126 internal static UriIdentifier
GetIdentityUrl(Scenarios scenario
, ProtocolVersion providerVersion
) {
127 return GetIdentityUrl(scenario
, providerVersion
, false);
130 internal static UriIdentifier
GetIdentityUrl(Scenarios scenario
, ProtocolVersion providerVersion
, bool useSsl
) {
131 var dictionary
= new Dictionary
<string, string> {
132 { "user", scenario.ToString() }
,
133 { "version", providerVersion.ToString() }
,
135 return new UriIdentifier(GetFullUrl("/" + IdentityPage
, dictionary
, useSsl
));
138 internal static MockIdentifier
GetMockIdentifier(Scenarios scenario
, MockHttpRequest mockRequest
, ProtocolVersion providerVersion
) {
139 return GetMockIdentifier(scenario
, mockRequest
, providerVersion
, false);
142 internal static MockIdentifier
GetMockIdentifier(Scenarios scenario
, MockHttpRequest mockRequest
, ProtocolVersion providerVersion
, bool useSsl
) {
143 ServiceEndpoint se
= GetServiceEndpoint(scenario
, providerVersion
, 10, useSsl
);
144 return new MockIdentifier(GetIdentityUrl(scenario
, providerVersion
, useSsl
), mockRequest
, new ServiceEndpoint
[] { se }
);
147 internal static ServiceEndpoint
GetServiceEndpoint(Scenarios scenario
, ProtocolVersion providerVersion
, int servicePriority
, bool useSsl
) {
148 var providerEndpoint
= new ProviderEndpointDescription(GetFullUrl("/" + ProviderPage
, null, useSsl
), new string[] { Protocol.Lookup(providerVersion).ClaimedIdentifierServiceTypeURI }
);
149 return ServiceEndpoint
.CreateForClaimedIdentifier(
150 GetIdentityUrl(scenario
, providerVersion
, useSsl
),
151 GetIdentityUrl(scenario
, providerVersion
, useSsl
),
152 GetDelegateUrl(scenario
, useSsl
),
159 /// A default implementation of a simple provider that responds to authentication requests
160 /// per the scenario that is being simulated.
162 /// <param name="provider">The OpenIdProvider on which the process messages.</param>
164 /// This is a very useful method to pass to the OpenIdCoordinator constructor for the Provider argument.
166 internal static void AutoProvider(OpenIdProvider provider
) {
168 while ((request
= provider
.GetRequest()) != null) {
169 if (!request
.IsResponseReady
) {
170 var authRequest
= (DotNetOpenAuth
.OpenId
.Provider
.IAuthenticationRequest
)request
;
171 var scenario
= (Scenarios
)Enum
.Parse(typeof(Scenarios
), new Uri(authRequest
.LocalIdentifier
).AbsolutePath
.TrimStart('/'));
173 case TestSupport
.Scenarios
.AutoApproval
:
174 authRequest
.IsAuthenticated
= true;
176 case Scenarios
.AutoApprovalAddFragment
:
177 authRequest
.SetClaimedIdentifierFragment("frag");
178 authRequest
.IsAuthenticated
= true;
180 case TestSupport
.Scenarios
.ApproveOnSetup
:
181 authRequest
.IsAuthenticated
= !authRequest
.Immediate
;
183 case Scenarios
.AlwaysDeny
:
184 authRequest
.IsAuthenticated
= false;
187 // All other scenarios are done programmatically only.
188 throw new InvalidOperationException("Unrecognized scenario");
192 request
.Response
.Send();
196 ////internal static UriIdentifier GetDirectedIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion) {
197 //// return GetDirectedIdentityUrl(scenario, providerVersion, false);
200 ////internal static UriIdentifier GetDirectedIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
201 //// return new UriIdentifier(GetFullUrl("/" + DirectedIdentityPage, new Dictionary<string, string> {
202 //// { "user", scenario.ToString() },
203 //// { "version", providerVersion.ToString() },
207 ////internal static IRelyingPartyApplicationStore RelyingPartyStore;
208 ////internal static IProviderAssociationStore ProviderStore;
210 /////// Generates a new, stateful <see cref="OpenIdRelyingParty"/> whose direct messages
211 /////// will be automatically handled by an internal <see cref="OpenIdProvider"/>
212 /////// that uses the shared <see cref="ProviderStore"/>.
214 ////internal static OpenIdRelyingParty CreateRelyingParty(NameValueCollection fields) {
215 //// return CreateRelyingParty(RelyingPartyStore, null, fields);
217 ////internal static OpenIdRelyingParty CreateRelyingParty(IRelyingPartyApplicationStore store, NameValueCollection fields) {
218 //// return CreateRelyingParty(store, null, fields);
221 /////// Generates a new <see cref="OpenIdRelyingParty"/> whose direct messages
222 /////// will be automatically handled by an internal <see cref="OpenIdProvider"/>
223 /////// that uses the shared <see cref="ProviderStore"/>.
225 ////internal static OpenIdRelyingParty CreateRelyingParty(IRelyingPartyApplicationStore store, Uri requestUrl, NameValueCollection fields) {
226 //// var rp = new OpenIdRelyingParty(store, requestUrl ?? GetFullUrl(ConsumerPage), fields ?? new NameValueCollection());
227 //// if (fields == null || fields.Count == 0) {
228 //// Assert.IsNull(rp.Response);
230 //// rp.DirectMessageChannel = new DirectMessageTestRedirector(ProviderStore);
233 ////internal static DotNetOpenId.RelyingParty.IAuthenticationRequest CreateRelyingPartyRequest(bool stateless, Scenarios scenario, ProtocolVersion version, bool useSsl) {
234 //// // Publish RP discovery information
235 //// MockHttpRequest.RegisterMockRPDiscovery();
237 //// var rp = TestSupport.CreateRelyingParty(stateless ? null : RelyingPartyStore, null);
238 //// var rpReq = rp.CreateRequest(TestSupport.GetMockIdentifier(scenario, version, useSsl), Realm, ReturnTo);
240 //// // Sidetrack: verify URLs and other default properties
242 //// Assert.AreEqual(AuthenticationRequestMode.Setup, rpReq.Mode);
243 //// Assert.AreEqual(Realm, rpReq.Realm);
244 //// Assert.AreEqual(ReturnTo, rpReq.ReturnToUrl);
250 /////// Generates a new <see cref="OpenIdRelyingParty"/> ready to process a
251 /////// response from an <see cref="OpenIdProvider"/>.
253 ////internal static IAuthenticationResponse CreateRelyingPartyResponse(IRelyingPartyApplicationStore store, IResponse providerResponse) {
254 //// return CreateRelyingPartyResponse(store, providerResponse, false);
256 ////internal static IAuthenticationResponse CreateRelyingPartyResponse(IRelyingPartyApplicationStore store, IResponse providerResponse, bool requireSsl) {
257 //// if (providerResponse == null) throw new ArgumentNullException("providerResponse");
259 //// var opAuthWebResponse = (Response)providerResponse;
260 //// var opAuthResponse = (EncodableResponse)opAuthWebResponse.EncodableMessage;
261 //// var rp = CreateRelyingParty(store, opAuthResponse.RedirectUrl,
262 //// opAuthResponse.EncodedFields.ToNameValueCollection());
263 //// rp.Settings.RequireSsl = requireSsl;
264 //// // Get the response now, before trying the replay attack. The Response
265 //// // property is lazily-evaluated, so the replay attack can be evaluated first
266 //// // and pass, while this one that SUPPOSED to pass fails, if we don't force it now.
267 //// var response = rp.Response;
269 //// // Side-track to test for replay attack while we're at it.
270 //// // This simulates a network sniffing user who caught the
271 //// // authenticating query en route to either the user agent or
272 //// // the consumer, and tries the same query to the consumer in an
273 //// // attempt to spoof the identity of the authenticating user.
275 //// Logger.Info("Attempting replay attack...");
276 //// var replayRP = CreateRelyingParty(store, opAuthResponse.RedirectUrl,
277 //// opAuthResponse.EncodedFields.ToNameValueCollection());
278 //// replayRP.Settings.RequireSsl = requireSsl;
279 //// Assert.AreNotEqual(AuthenticationStatus.Authenticated, replayRP.Response.Status, "Replay attack succeeded!");
280 //// } catch (OpenIdException) { // nonce already used
281 //// // another way to pass
284 //// // Return the result of the initial response (not the replay attack one).
285 //// return response;
288 /////// Generates a new <see cref="OpenIdProvider"/> that uses the shared
289 /////// store in <see cref="ProviderStore"/>.
291 ////internal static OpenIdProvider CreateProvider(NameValueCollection fields) {
292 //// return CreateProvider(fields, false);
294 ////internal static OpenIdProvider CreateProvider(NameValueCollection fields, bool useSsl) {
295 //// Protocol protocol = fields != null ? Protocol.Detect(fields.ToDictionary()) : Protocol.V20;
296 //// Uri opEndpoint = GetFullUrl(ProviderPage, null, useSsl);
297 //// var provider = new OpenIdProvider(ProviderStore, opEndpoint, opEndpoint, fields ?? new NameValueCollection());
298 //// return provider;
300 ////internal static OpenIdProvider CreateProviderForRequest(DotNetOpenId.RelyingParty.IAuthenticationRequest request) {
301 //// IResponse relyingPartyAuthenticationRequest = request.RedirectingResponse;
302 //// var rpWebMessageToOP = (Response)relyingPartyAuthenticationRequest;
303 //// var rpMessageToOP = (IndirectMessageRequest)rpWebMessageToOP.EncodableMessage;
304 //// var opEndpoint = (ServiceEndpoint)request.Provider;
305 //// var provider = new OpenIdProvider(ProviderStore, opEndpoint.ProviderEndpoint,
306 //// opEndpoint.ProviderEndpoint, rpMessageToOP.EncodedFields.ToNameValueCollection());
307 //// return provider;
309 ////internal static IResponse CreateProviderResponseToRequest(
310 //// DotNetOpenId.RelyingParty.IAuthenticationRequest request,
311 //// Action<DotNetOpenId.Provider.IAuthenticationRequest> prepareProviderResponse) {
313 //// // Sidetrack: Verify the return_to and realm URLs
314 //// var consumerToProviderQuery = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
315 //// Protocol protocol = Protocol.Detect(consumerToProviderQuery.ToDictionary());
316 //// Assert.IsTrue(consumerToProviderQuery[protocol.openid.return_to].StartsWith(request.ReturnToUrl.AbsoluteUri, StringComparison.Ordinal));
317 //// Assert.AreEqual(request.Realm.ToString(), consumerToProviderQuery[protocol.openid.Realm]);
320 //// var op = TestSupport.CreateProviderForRequest(request);
321 //// var opReq = (DotNetOpenId.Provider.IAuthenticationRequest)op.Request;
322 //// prepareProviderResponse(opReq);
323 //// Assert.IsTrue(opReq.IsResponseReady);
324 //// return opReq.Response;
326 ////internal static IAuthenticationResponse CreateRelyingPartyResponseThroughProvider(
327 //// DotNetOpenId.RelyingParty.IAuthenticationRequest request,
328 //// Action<DotNetOpenId.Provider.IAuthenticationRequest> providerAction) {
329 //// var rpReq = (AuthenticationRequest)request;
330 //// var opResponse = CreateProviderResponseToRequest(rpReq, providerAction);
331 //// // Be careful to use whatever store the original RP was using.
332 //// var rp = CreateRelyingPartyResponse(rpReq.RelyingParty.Store, opResponse,
333 //// ((AuthenticationRequest)request).RelyingParty.Settings.RequireSsl);
334 //// Assert.IsNotNull(rp);
339 ////public void SetUp() {
340 //// log4net.Config.XmlConfigurator.Configure(Assembly.GetExecutingAssembly().GetManifestResourceStream("DotNetOpenId.Test.Logging.config"));
346 ////public void TearDown() {
347 //// log4net.LogManager.Shutdown();
350 ////internal static void ResetStores() {
351 //// RelyingPartyStore = new ApplicationMemoryStore();
352 //// ProviderStore = new ProviderMemoryStore();
355 ////internal static void SetAuthenticationFromScenario(Scenarios scenario, DotNetOpenId.Provider.IAuthenticationRequest request) {
356 //// Assert.IsTrue(request.IsReturnUrlDiscoverable);
357 //// switch (scenario) {
358 //// case TestSupport.Scenarios.ExtensionFullCooperation:
359 //// case TestSupport.Scenarios.ExtensionPartialCooperation:
360 //// case TestSupport.Scenarios.AutoApproval:
361 //// // immediately approve
362 //// request.IsAuthenticated = true;
364 //// case TestSupport.Scenarios.AutoApprovalAddFragment:
365 //// request.SetClaimedIdentifierFragment("frag");
366 //// request.IsAuthenticated = true;
368 //// case TestSupport.Scenarios.ApproveOnSetup:
369 //// request.IsAuthenticated = !request.Immediate;
371 //// case TestSupport.Scenarios.AlwaysDeny:
372 //// request.IsAuthenticated = false;
375 //// throw new InvalidOperationException("Unrecognized scenario");
380 /////// Uses an RPs stored association to resign an altered message from a Provider,
381 /////// to simulate a Provider that deliberately sent a bad message in an attempt
382 /////// to thwart RP security.
384 ////internal static void Resign(NameValueCollection nvc, IRelyingPartyApplicationStore store) {
385 //// Debug.Assert(nvc != null);
386 //// Debug.Assert(store != null);
387 //// var dict = Util.NameValueCollectionToDictionary(nvc);
388 //// Protocol protocol = Protocol.Detect(dict);
389 //// Uri providerEndpoint = new Uri(nvc[protocol.openid.op_endpoint]);
390 //// string assoc_handle = nvc[protocol.openid.assoc_handle];
391 //// Association assoc = store.GetAssociation(providerEndpoint, assoc_handle);
392 //// Debug.Assert(assoc != null, "Association not found in RP's store. Maybe you're communicating with a hosted OP instead of the TestSupport one?");
393 //// IList<string> signed = nvc[protocol.openid.signed].Split(',');
394 //// var subsetDictionary = new Dictionary<string, string>();
395 //// foreach (string signedKey in signed) {
396 //// string keyName = protocol.openid.Prefix + signedKey;
397 //// subsetDictionary.Add(signedKey, dict[keyName]);
399 //// nvc[protocol.openid.sig] = Convert.ToBase64String(assoc.Sign(subsetDictionary, signed));
402 ////public static IAssociationStore<AssociationRelyingPartyType> ProviderStoreContext {
404 //// return DotNetOpenId.Provider.OpenIdProvider.HttpApplicationStore;
407 ////internal static MockIdentifier GetMockOPIdentifier(Scenarios scenario, UriIdentifier expectedClaimedId) {
408 //// return GetMockOPIdentifier(scenario, expectedClaimedId, false, false);
410 ////internal static MockIdentifier GetMockOPIdentifier(Scenarios scenario, UriIdentifier expectedClaimedId, bool useSslOpIdentifier, bool useSslProviderEndpoint) {
411 //// var fields = new Dictionary<string, string> {
412 //// { "user", scenario.ToString() },
414 //// Uri opEndpoint = GetFullUrl(DirectedProviderEndpoint, fields, useSslProviderEndpoint);
415 //// Uri opIdentifier = GetOPIdentityUrl(scenario, useSslOpIdentifier);
416 //// ServiceEndpoint se = ServiceEndpoint.CreateForProviderIdentifier(
419 //// new string[] { Protocol.V20.OPIdentifierServiceTypeURI },
423 //// // Register the Claimed Identifier that directed identity will choose so that RP
424 //// // discovery on that identifier can be mocked up.
425 //// MockHttpRequest.RegisterMockXrdsResponse(expectedClaimedId, se);
427 //// return new MockIdentifier(opIdentifier, new ServiceEndpoint[] { se });