diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-12-15 22:17:20 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-12-15 22:17:20 -0800 |
commit | e12782c1a6727390b2107ff2e39d4ac6173d86fc (patch) | |
tree | 3be0ccda0a9425927263f5b6b9616ef8ba11ac08 /src/DotNetOpenId.Test/TestSupport.cs | |
parent | 078b1f350eb40ceee7423c25b1d833dd1f242da4 (diff) | |
parent | a545f7be2693596fa14540c359e43150a6a7cf88 (diff) | |
download | DotNetOpenAuth-origin/mono.zip DotNetOpenAuth-origin/mono.tar.gz DotNetOpenAuth-origin/mono.tar.bz2 |
Merge branch 'v2.5' into monoorigin/mono
Conflicts:
src/DotNetOpenId/Properties/AssemblyInfo.cs
src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs
Diffstat (limited to 'src/DotNetOpenId.Test/TestSupport.cs')
-rw-r--r-- | src/DotNetOpenId.Test/TestSupport.cs | 322 |
1 files changed, 298 insertions, 24 deletions
diff --git a/src/DotNetOpenId.Test/TestSupport.cs b/src/DotNetOpenId.Test/TestSupport.cs index be17494..66822eb 100644 --- a/src/DotNetOpenId.Test/TestSupport.cs +++ b/src/DotNetOpenId.Test/TestSupport.cs @@ -1,27 +1,39 @@ using System;
using System.Collections.Generic;
-using System.Text;
-using NUnit.Framework;
+using System.Collections.Specialized;
+using System.Diagnostics;
using System.IO;
-using System.Globalization;
-using DotNetOpenId.Test.Hosting;
+using System.Reflection;
+using System.Web;
using DotNetOpenId;
-using System.Net;
-using System.Collections.Specialized;
+using DotNetOpenId.Provider;
using DotNetOpenId.RelyingParty;
-using System.Diagnostics;
+using DotNetOpenId.Test.Mocks;
+using DotNetOpenId.Test.UI;
+using log4net;
+using NUnit.Framework;
+using IProviderAssociationStore = DotNetOpenId.IAssociationStore<DotNetOpenId.AssociationRelyingPartyType>;
+using ProviderMemoryStore = DotNetOpenId.AssociationMemoryStore<DotNetOpenId.AssociationRelyingPartyType>;
[SetUpFixture]
public class TestSupport {
public static readonly string TestWebDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), @"..\..\src\DotNetOpenId.TestWeb"));
public const string HostTestPage = "HostTest.aspx";
const string identityPage = "IdentityEndpoint.aspx";
+ const string directedIdentityPage = "DirectedIdentityEndpoint.aspx";
public const string ProviderPage = "ProviderEndpoint.aspx";
+ public const string DirectedProviderEndpoint = "DirectedProviderEndpoint.aspx";
public const string MobileConsumerPage = "RelyingPartyMobile.aspx";
public const string ConsumerPage = "RelyingParty.aspx";
+ public const string OPDefaultPage = "OPDefault.aspx";
+ public static Uri ReturnTo { get { return TestSupport.GetFullUrl(TestSupport.ConsumerPage); } }
+ public static Realm Realm { get { return new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri); } }
+ public readonly static ILog Logger = LogManager.GetLogger("DotNetOpenId.Test");
+
public enum Scenarios {
// Authentication test scenarios
AutoApproval,
+ AutoApprovalAddFragment,
ApproveOnSetup,
AlwaysDeny,
@@ -35,39 +47,278 @@ public class TestSupport { /// </summary>
ExtensionPartialCooperation,
}
+ internal static UriIdentifier GetOPIdentityUrl(Scenarios scenario, bool useSsl) {
+ var args = new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ };
+ return new UriIdentifier(GetFullUrl("/" + OPDefaultPage, args, useSsl));
+ }
internal static UriIdentifier GetIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion) {
- UriBuilder builder = new UriBuilder(Host.BaseUri);
- builder.Path = "/" + identityPage;
- builder.Query = "user=" + scenario + "&version=" + providerVersion;
- return new UriIdentifier(builder.Uri);
+ return GetIdentityUrl(scenario, providerVersion, false);
+ }
+ internal static UriIdentifier GetIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
+ return new UriIdentifier(GetFullUrl("/" + identityPage, new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ { "version", providerVersion.ToString() },
+ }, useSsl));
+ }
+ internal static UriIdentifier GetDirectedIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion) {
+ return GetDirectedIdentityUrl(scenario, providerVersion, false);
+ }
+ internal static UriIdentifier GetDirectedIdentityUrl(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
+ return new UriIdentifier(GetFullUrl("/" + directedIdentityPage, new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ { "version", providerVersion.ToString() },
+ }, useSsl));
}
public static Identifier GetDelegateUrl(Scenarios scenario) {
- return new UriIdentifier(new Uri(Host.BaseUri, "/" + scenario));
+ return GetDelegateUrl(scenario, false);
+ }
+ public static Identifier GetDelegateUrl(Scenarios scenario, bool useSsl) {
+ return new UriIdentifier(GetFullUrl("/" + scenario, null, useSsl));
+ }
+ internal static MockIdentifier GetMockIdentifier(Scenarios scenario, ProtocolVersion providerVersion) {
+ return GetMockIdentifier(scenario, providerVersion, false);
+ }
+ internal static MockIdentifier GetMockIdentifier(Scenarios scenario, ProtocolVersion providerVersion, bool useSsl) {
+ ServiceEndpoint se = GetServiceEndpoint(scenario, providerVersion, 10, useSsl);
+ return new MockIdentifier(GetIdentityUrl(scenario, providerVersion, useSsl), new ServiceEndpoint[] { se });
+ }
+ internal static ServiceEndpoint GetServiceEndpoint(Scenarios scenario, ProtocolVersion providerVersion, int servicePriority, bool useSsl) {
+ return ServiceEndpoint.CreateForClaimedIdentifier(
+ GetIdentityUrl(scenario, providerVersion, useSsl),
+ GetDelegateUrl(scenario, useSsl),
+ GetFullUrl("/" + ProviderPage, null, useSsl),
+ new string[] { Protocol.Lookup(providerVersion).ClaimedIdentifierServiceTypeURI },
+ servicePriority,
+ 10
+ );
+ }
+ internal static MockIdentifier GetMockOPIdentifier(Scenarios scenario, UriIdentifier expectedClaimedId) {
+ return GetMockOPIdentifier(scenario, expectedClaimedId, false, false);
+ }
+ internal static MockIdentifier GetMockOPIdentifier(Scenarios scenario, UriIdentifier expectedClaimedId, bool useSslOpIdentifier, bool useSslProviderEndpoint) {
+ var fields = new Dictionary<string, string> {
+ { "user", scenario.ToString() },
+ };
+ Uri opEndpoint = GetFullUrl(DirectedProviderEndpoint, fields, useSslProviderEndpoint);
+ Uri opIdentifier = GetOPIdentityUrl(scenario, useSslOpIdentifier);
+ ServiceEndpoint se = ServiceEndpoint.CreateForProviderIdentifier(
+ opIdentifier,
+ opEndpoint,
+ new string[] { Protocol.v20.OPIdentifierServiceTypeURI },
+ 10,
+ 10
+ );
+
+ // Register the Claimed Identifier that directed identity will choose so that RP
+ // discovery on that identifier can be mocked up.
+ MockHttpRequest.RegisterMockXrdsResponse(expectedClaimedId, se);
+
+ return new MockIdentifier(opIdentifier, new ServiceEndpoint[] { se });
}
public static Uri GetFullUrl(string url) {
- return GetFullUrl(url, null);
+ return GetFullUrl(url, null, false);
+ }
+ public static Uri GetFullUrl(string url, string key, object value) {
+ return GetFullUrl(url, new Dictionary<string, string> {
+ { key, value.ToString() },
+ }, false);
}
- public static Uri GetFullUrl(string url, IDictionary<string, string> args) {
- UriBuilder builder = new UriBuilder(new Uri(Host.BaseUri, url));
+ public static Uri GetFullUrl(string url, IDictionary<string, string> args, bool useSsl) {
+ Uri defaultUriBase = new Uri(useSsl ? "https://localhost/" : "http://localhost/");
+ Uri baseUri = UITestSupport.Host != null ? UITestSupport.Host.BaseUri : defaultUriBase;
+ UriBuilder builder = new UriBuilder(new Uri(baseUri, url));
UriUtil.AppendQueryArgs(builder, args);
return builder.Uri;
}
- internal static AspNetHost Host { get; private set; }
- internal static EncodingInterceptor Interceptor { get; private set; }
+ /// <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>
+ internal static string LoadEmbeddedFile(string path) {
+ if (!path.StartsWith("/")) path = "/" + path;
+ path = "DotNetOpenId.Test" + 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 IRelyingPartyApplicationStore RelyingPartyStore;
+ internal static IProviderAssociationStore ProviderStore;
+ /// <summary>
+ /// Generates a new, stateful <see cref="OpenIdRelyingParty"/> whose direct messages
+ /// will be automatically handled by an internal <see cref="OpenIdProvider"/>
+ /// that uses the shared <see cref="ProviderStore"/>.
+ /// </summary>
+ internal static OpenIdRelyingParty CreateRelyingParty(NameValueCollection fields) {
+ return CreateRelyingParty(RelyingPartyStore, null, fields);
+ }
+ internal static OpenIdRelyingParty CreateRelyingParty(IRelyingPartyApplicationStore store, NameValueCollection fields) {
+ return CreateRelyingParty(store, null, fields);
+ }
+ /// <summary>
+ /// Generates a new <see cref="OpenIdRelyingParty"/> whose direct messages
+ /// will be automatically handled by an internal <see cref="OpenIdProvider"/>
+ /// that uses the shared <see cref="ProviderStore"/>.
+ /// </summary>
+ internal static OpenIdRelyingParty CreateRelyingParty(IRelyingPartyApplicationStore store, Uri requestUrl, NameValueCollection fields) {
+ var rp = new OpenIdRelyingParty(store, requestUrl ?? GetFullUrl(ConsumerPage), fields ?? new NameValueCollection());
+ if (fields == null || fields.Count == 0) {
+ Assert.IsNull(rp.Response);
+ }
+ rp.DirectMessageChannel = new DirectMessageTestRedirector(ProviderStore);
+ return rp;
+ }
+ internal static DotNetOpenId.RelyingParty.IAuthenticationRequest CreateRelyingPartyRequest(bool stateless, Scenarios scenario, ProtocolVersion version, bool useSsl) {
+ // Publish RP discovery information
+ MockHttpRequest.RegisterMockRPDiscovery();
+
+ var rp = TestSupport.CreateRelyingParty(stateless ? null : RelyingPartyStore, null);
+ var rpReq = rp.CreateRequest(TestSupport.GetMockIdentifier(scenario, version, useSsl), Realm, ReturnTo);
+
+ {
+ // Sidetrack: verify URLs and other default properties
+ Assert.AreEqual(AuthenticationRequestMode.Setup, rpReq.Mode);
+ Assert.AreEqual(Realm, rpReq.Realm);
+ Assert.AreEqual(ReturnTo, rpReq.ReturnToUrl);
+ }
+
+ return rpReq;
+ }
+ /// <summary>
+ /// Generates a new <see cref="OpenIdRelyingParty"/> ready to process a
+ /// response from an <see cref="OpenIdProvider"/>.
+ /// </summary>
+ internal static IAuthenticationResponse CreateRelyingPartyResponse(IRelyingPartyApplicationStore store, IResponse providerResponse) {
+ return CreateRelyingPartyResponse(store, providerResponse, false);
+ }
+ internal static IAuthenticationResponse CreateRelyingPartyResponse(IRelyingPartyApplicationStore store, IResponse providerResponse, bool requireSsl) {
+ if (providerResponse == null) throw new ArgumentNullException("providerResponse");
+
+ var opAuthWebResponse = (Response)providerResponse;
+ var opAuthResponse = (EncodableResponse)opAuthWebResponse.EncodableMessage;
+ var rp = CreateRelyingParty(store, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ rp.Settings.RequireSsl = requireSsl;
+ // Get the response now, before trying the replay attack. The Response
+ // property is lazily-evaluated, so the replay attack can be evaluated first
+ // and pass, while this one that SUPPOSED to pass fails, if we don't force it now.
+ var response = rp.Response;
+
+ // Side-track to test for replay attack while we're at it.
+ // This simulates a network sniffing user who caught the
+ // authenticating query en route to either the user agent or
+ // the consumer, and tries the same query to the consumer in an
+ // attempt to spoof the identity of the authenticating user.
+ try {
+ Logger.Info("Attempting replay attack...");
+ var replayRP = CreateRelyingParty(store, opAuthResponse.RedirectUrl,
+ opAuthResponse.EncodedFields.ToNameValueCollection());
+ replayRP.Settings.RequireSsl = requireSsl;
+ Assert.AreNotEqual(AuthenticationStatus.Authenticated, replayRP.Response.Status, "Replay attack succeeded!");
+ } catch (OpenIdException) { // nonce already used
+ // another way to pass
+ }
+
+ // Return the result of the initial response (not the replay attack one).
+ return response;
+ }
+ /// <summary>
+ /// Generates a new <see cref="OpenIdProvider"/> that uses the shared
+ /// store in <see cref="ProviderStore"/>.
+ /// </summary>
+ internal static OpenIdProvider CreateProvider(NameValueCollection fields) {
+ return CreateProvider(fields, false);
+ }
+ internal static OpenIdProvider CreateProvider(NameValueCollection fields, bool useSsl) {
+ Protocol protocol = fields != null ? Protocol.Detect(fields.ToDictionary()) : Protocol.v20;
+ Uri opEndpoint = GetFullUrl(ProviderPage, null, useSsl);
+ var provider = new OpenIdProvider(ProviderStore, opEndpoint, opEndpoint, fields ?? new NameValueCollection());
+ return provider;
+ }
+ internal static OpenIdProvider CreateProviderForRequest(DotNetOpenId.RelyingParty.IAuthenticationRequest request) {
+ IResponse relyingPartyAuthenticationRequest = request.RedirectingResponse;
+ var rpWebMessageToOP = (Response)relyingPartyAuthenticationRequest;
+ var rpMessageToOP = (IndirectMessageRequest)rpWebMessageToOP.EncodableMessage;
+ var opEndpoint = (ServiceEndpoint)request.Provider;
+ var provider = new OpenIdProvider(ProviderStore, opEndpoint.ProviderEndpoint,
+ opEndpoint.ProviderEndpoint, rpMessageToOP.EncodedFields.ToNameValueCollection());
+ return provider;
+ }
+ internal static IResponse CreateProviderResponseToRequest(
+ DotNetOpenId.RelyingParty.IAuthenticationRequest request,
+ Action<DotNetOpenId.Provider.IAuthenticationRequest> prepareProviderResponse) {
+
+ {
+ // Sidetrack: Verify the return_to and realm URLs
+ var consumerToProviderQuery = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
+ Protocol protocol = Protocol.Detect(consumerToProviderQuery.ToDictionary());
+ Assert.IsTrue(consumerToProviderQuery[protocol.openid.return_to].StartsWith(request.ReturnToUrl.AbsoluteUri, StringComparison.Ordinal));
+ Assert.AreEqual(request.Realm.ToString(), consumerToProviderQuery[protocol.openid.Realm]);
+ }
+
+ var op = TestSupport.CreateProviderForRequest(request);
+ var opReq = (DotNetOpenId.Provider.IAuthenticationRequest)op.Request;
+ prepareProviderResponse(opReq);
+ Assert.IsTrue(opReq.IsResponseReady);
+ return opReq.Response;
+ }
+ internal static IAuthenticationResponse CreateRelyingPartyResponseThroughProvider(
+ DotNetOpenId.RelyingParty.IAuthenticationRequest request,
+ Action<DotNetOpenId.Provider.IAuthenticationRequest> providerAction) {
+
+ var rpReq = (AuthenticationRequest)request;
+ var opResponse = CreateProviderResponseToRequest(rpReq, providerAction);
+ // Be careful to use whatever store the original RP was using.
+ var rp = CreateRelyingPartyResponse(rpReq.RelyingParty.Store, opResponse,
+ ((AuthenticationRequest)request).RelyingParty.Settings.RequireSsl);
+ Assert.IsNotNull(rp);
+ return rp;
+ }
[SetUp]
public void SetUp() {
- Host = AspNetHost.CreateHost(TestSupport.TestWebDirectory);
- Host.MessageInterceptor = Interceptor = new EncodingInterceptor();
+ log4net.Config.XmlConfigurator.Configure(Assembly.GetExecutingAssembly().GetManifestResourceStream("DotNetOpenId.Test.Logging.config"));
+
+ ResetStores();
}
[TearDown]
public void TearDown() {
- Host.MessageInterceptor = null;
- if (Host != null) {
- Host.CloseHttp();
- Host = null;
+ log4net.LogManager.Shutdown();
+ }
+
+ internal static void ResetStores() {
+ RelyingPartyStore = new ApplicationMemoryStore();
+ ProviderStore = new ProviderMemoryStore();
+ }
+
+ internal static void SetAuthenticationFromScenario(Scenarios scenario, DotNetOpenId.Provider.IAuthenticationRequest request) {
+ Assert.IsTrue(request.IsReturnUrlDiscoverable);
+ switch (scenario) {
+ case TestSupport.Scenarios.ExtensionFullCooperation:
+ case TestSupport.Scenarios.ExtensionPartialCooperation:
+ case TestSupport.Scenarios.AutoApproval:
+ // immediately approve
+ request.IsAuthenticated = true;
+ break;
+ case TestSupport.Scenarios.AutoApprovalAddFragment:
+ request.SetClaimedIdentifierFragment("frag");
+ request.IsAuthenticated = true;
+ break;
+ case TestSupport.Scenarios.ApproveOnSetup:
+ request.IsAuthenticated = !request.Immediate;
+ break;
+ case TestSupport.Scenarios.AlwaysDeny:
+ request.IsAuthenticated = false;
+ break;
+ default:
+ throw new InvalidOperationException("Unrecognized scenario");
}
}
@@ -76,7 +327,7 @@ public class TestSupport { /// to simulate a Provider that deliberately sent a bad message in an attempt
/// to thwart RP security.
/// </summary>
- internal static void Resign(NameValueCollection nvc, ApplicationMemoryStore store) {
+ internal static void Resign(NameValueCollection nvc, IRelyingPartyApplicationStore store) {
Debug.Assert(nvc != null);
Debug.Assert(store != null);
var dict = Util.NameValueCollectionToDictionary(nvc);
@@ -84,6 +335,7 @@ public class TestSupport { Uri providerEndpoint = new Uri(nvc[protocol.openid.op_endpoint]);
string assoc_handle = nvc[protocol.openid.assoc_handle];
Association assoc = store.GetAssociation(providerEndpoint, assoc_handle);
+ Debug.Assert(assoc != null, "Association not found in RP's store. Maybe you're communicating with a hosted OP instead of the TestSupport one?");
IList<string> signed = nvc[protocol.openid.signed].Split(',');
var subsetDictionary = new Dictionary<string, string>();
foreach (string signedKey in signed) {
@@ -92,6 +344,12 @@ public class TestSupport { }
nvc[protocol.openid.sig] = Convert.ToBase64String(assoc.Sign(subsetDictionary, signed));
}
+
+ public static IAssociationStore<AssociationRelyingPartyType> ProviderStoreContext {
+ get {
+ return DotNetOpenId.Provider.OpenIdProvider.HttpApplicationStore;
+ }
+ }
}
static class TestExtensions {
@@ -105,4 +363,20 @@ static class TestExtensions { UriUtil.AppendQueryArgs(builder, encodable.EncodedFields);
return builder.Uri;
}
+
+ public static NameValueCollection ToNameValueCollection(this IDictionary<string, string> dictionary) {
+ NameValueCollection nvc = new NameValueCollection(dictionary.Count);
+ foreach (var pair in dictionary) {
+ nvc.Add(pair.Key, pair.Value);
+ }
+ return nvc;
+ }
+ public static IDictionary<string, string> ToDictionary(this NameValueCollection nvc) {
+ if (nvc == null) return null;
+ Dictionary<string, string> dict = new Dictionary<string, string>(nvc.Count);
+ foreach (string key in nvc) {
+ dict[key] = nvc[key];
+ }
+ return dict;
+ }
}
|