summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenId.Test/EndToEndTesting.cs12
-rw-r--r--src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs2
-rw-r--r--src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs7
-rw-r--r--src/DotNetOpenId.Test/Hosting/AspNetHost.cs2
-rw-r--r--src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs4
-rw-r--r--src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs8
-rw-r--r--src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs21
-rw-r--r--src/DotNetOpenId.Test/TestSupport.cs13
-rw-r--r--src/DotNetOpenId.Test/UtilTest.cs10
-rw-r--r--src/DotNetOpenId.sln4
-rw-r--r--src/DotNetOpenId/DotNetOpenId.csproj10
-rw-r--r--src/DotNetOpenId/IEncodable.cs (renamed from src/DotNetOpenId/Provider/IEncodable.cs)18
-rw-r--r--src/DotNetOpenId/IResponse.cs (renamed from src/DotNetOpenId/Provider/IResponse.cs)4
-rw-r--r--src/DotNetOpenId/MessageEncoder.cs106
-rw-r--r--src/DotNetOpenId/OpenIdException.cs4
-rw-r--r--src/DotNetOpenId/Provider/EncodableResponse.cs4
-rw-r--r--src/DotNetOpenId/Provider/Encoder.cs88
-rw-r--r--src/DotNetOpenId/Provider/OpenIdProvider.cs11
-rw-r--r--src/DotNetOpenId/Provider/SigningMessageEncoder.cs41
-rw-r--r--src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs37
-rw-r--r--src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs7
-rw-r--r--src/DotNetOpenId/RelyingParty/DirectRequest.cs9
-rw-r--r--src/DotNetOpenId/RelyingParty/IAuthenticationRequest.cs17
-rw-r--r--src/DotNetOpenId/RelyingParty/IndirectMessageRequest.cs25
-rw-r--r--src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs25
-rw-r--r--src/DotNetOpenId/RelyingParty/OpenIdTextBox.cs2
-rw-r--r--src/DotNetOpenId/Response.cs (renamed from src/DotNetOpenId/Provider/Response.cs)20
-rw-r--r--src/DotNetOpenId/Util.cs3
28 files changed, 324 insertions, 190 deletions
diff --git a/src/DotNetOpenId.Test/EndToEndTesting.cs b/src/DotNetOpenId.Test/EndToEndTesting.cs
index 8c2df0f..de1ed2a 100644
--- a/src/DotNetOpenId.Test/EndToEndTesting.cs
+++ b/src/DotNetOpenId.Test/EndToEndTesting.cs
@@ -36,7 +36,7 @@ namespace DotNetOpenId.Test {
Uri redirectToProviderUrl;
var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
- var consumer = new OpenIdRelyingParty(store, null);
+ var consumer = new OpenIdRelyingParty(store, null, null);
Assert.IsNull(consumer.Response);
var request = consumer.CreateRequest(identityUrl, realm, returnTo);
Protocol protocol = Protocol.Lookup(request.ProviderVersion);
@@ -49,11 +49,11 @@ namespace DotNetOpenId.Test {
request.Mode = requestMode;
// Verify the redirect URL
- Assert.IsNotNull(request.RedirectToProviderUrl);
- var consumerToProviderQuery = HttpUtility.ParseQueryString(request.RedirectToProviderUrl.Query);
+ Assert.IsNotNull(request.RedirectingResponse);
+ var consumerToProviderQuery = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
Assert.IsTrue(consumerToProviderQuery[protocol.openid.return_to].StartsWith(returnTo.AbsoluteUri, StringComparison.Ordinal));
Assert.AreEqual(realm.ToString(), consumerToProviderQuery[protocol.openid.Realm]);
- redirectToProviderUrl = request.RedirectToProviderUrl;
+ redirectToProviderUrl = request.RedirectingResponse.ExtractUrl();
HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(redirectToProviderUrl);
providerRequest.AllowAutoRedirect = false;
@@ -72,7 +72,7 @@ namespace DotNetOpenId.Test {
}
throw;
}
- consumer = new OpenIdRelyingParty(store, redirectUrl);
+ consumer = new OpenIdRelyingParty(store, redirectUrl, HttpUtility.ParseQueryString(redirectUrl.Query));
Assert.AreEqual(expectedResult, consumer.Response.Status);
Assert.AreEqual(identityUrl, consumer.Response.ClaimedIdentifier);
@@ -83,7 +83,7 @@ namespace DotNetOpenId.Test {
// the consumer, and tries the same query to the consumer in an
// attempt to spoof the identity of the authenticating user.
try {
- var replayAttackConsumer = new OpenIdRelyingParty(store, redirectUrl);
+ var replayAttackConsumer = new OpenIdRelyingParty(store, redirectUrl, HttpUtility.ParseQueryString(redirectUrl.Query));
Assert.AreNotEqual(AuthenticationStatus.Authenticated, replayAttackConsumer.Response.Status, "Replay attack");
} catch (OpenIdException) { // nonce already used
// another way to pass
diff --git a/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs b/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs
index 5f4fd26..62efbc2 100644
--- a/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs
+++ b/src/DotNetOpenId.Test/Extensions/AttributeExchangeTests.cs
@@ -95,7 +95,7 @@ namespace DotNetOpenId.Test.Extensions {
var identityUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.ExtensionFullCooperation, Version);
var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
- var consumer = new OpenIdRelyingParty(AppStore, null);
+ var consumer = new OpenIdRelyingParty(AppStore, null, null);
var request = consumer.CreateRequest(identityUrl, realm, returnTo);
request.AddExtension(new FetchRequest());
request.AddExtension(new StoreRequest());
diff --git a/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs b/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs
index ea3379c..825ef58 100644
--- a/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs
+++ b/src/DotNetOpenId.Test/Extensions/ExtensionTestBase.cs
@@ -8,6 +8,7 @@ using System.Net;
using DotNetOpenId.Extensions;
using System.IO;
using System.Diagnostics;
+using System.Web;
namespace DotNetOpenId.Test.Extensions {
public class ExtensionTestBase {
@@ -24,12 +25,12 @@ namespace DotNetOpenId.Test.Extensions {
Debug.Assert(identityUrl != null);
var returnTo = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
var realm = new Realm(TestSupport.GetFullUrl(TestSupport.ConsumerPage).AbsoluteUri);
- var consumer = new OpenIdRelyingParty(AppStore, null);
+ var consumer = new OpenIdRelyingParty(AppStore, null, null);
var request = consumer.CreateRequest(identityUrl, realm, returnTo);
if (extension != null)
request.AddExtension(extension);
- HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(request.RedirectToProviderUrl);
+ HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(request.RedirectingResponse.ExtractUrl());
providerRequest.AllowAutoRedirect = false;
Uri redirectUrl;
try {
@@ -46,7 +47,7 @@ namespace DotNetOpenId.Test.Extensions {
}
throw;
}
- consumer = new OpenIdRelyingParty(AppStore, redirectUrl);
+ consumer = new OpenIdRelyingParty(AppStore, redirectUrl, HttpUtility.ParseQueryString(redirectUrl.Query));
Assert.AreEqual(AuthenticationStatus.Authenticated, consumer.Response.Status);
Assert.AreEqual(identityUrl, consumer.Response.ClaimedIdentifier);
return consumer.Response.GetExtension<T>();
diff --git a/src/DotNetOpenId.Test/Hosting/AspNetHost.cs b/src/DotNetOpenId.Test/Hosting/AspNetHost.cs
index 4340404..844c040 100644
--- a/src/DotNetOpenId.Test/Hosting/AspNetHost.cs
+++ b/src/DotNetOpenId.Test/Hosting/AspNetHost.cs
@@ -21,7 +21,7 @@ namespace DotNetOpenId.Test.Hosting {
httpHost = HttpHost.CreateHost(this);
if (!UntrustedWebRequest.WhitelistHosts.Contains("localhost"))
UntrustedWebRequest.WhitelistHosts.Add("localhost");
- DotNetOpenId.Provider.SigningEncoder.Signing += (s, e) => {
+ DotNetOpenId.Provider.SigningMessageEncoder.Signing += (s, e) => {
if (MessageInterceptor != null) MessageInterceptor.OnSigningMessage(e.Message);
};
}
diff --git a/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs b/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs
index 42a572f..3ea7d9c 100644
--- a/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs
+++ b/src/DotNetOpenId.Test/Provider/IAuthenticationRequestTest.cs
@@ -20,9 +20,9 @@ namespace DotNetOpenId.Test.Provider {
Uri returnTo;
Realm realm;
getUnverifiableRP(out returnTo, out realm);
- var consumer = new OpenIdRelyingParty(new ApplicationMemoryStore(), null);
+ var consumer = new OpenIdRelyingParty(new ApplicationMemoryStore(), null, null);
var request = consumer.CreateRequest(TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20), realm, returnTo);
- WebRequest.Create(request.RedirectToProviderUrl).GetResponse(); // the OP should return 500, causing exception here.
+ WebRequest.Create(request.RedirectingResponse.ExtractUrl()).GetResponse(); // the OP should return 500, causing exception here.
}
static void getUnverifiableRP(out Uri returnTo, out Realm realm) {
diff --git a/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs b/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs
index a3e2e28..7dcb792 100644
--- a/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs
+++ b/src/DotNetOpenId.Test/RelyingParty/AuthenticationResponseTests.cs
@@ -35,10 +35,10 @@ namespace DotNetOpenId.Test.RelyingParty {
Uri getPositiveAssertion(ProtocolVersion version) {
try {
- OpenIdRelyingParty rp = new OpenIdRelyingParty(store, null);
+ OpenIdRelyingParty rp = new OpenIdRelyingParty(store, null, null);
Identifier id = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, version);
var request = rp.CreateRequest(id, realm, returnTo);
- HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(request.RedirectToProviderUrl);
+ HttpWebRequest providerRequest = (HttpWebRequest)WebRequest.Create(request.RedirectingResponse.ExtractUrl());
providerRequest.AllowAutoRedirect = false;
Uri redirectUrl;
try {
@@ -106,7 +106,7 @@ namespace DotNetOpenId.Test.RelyingParty {
// which should cause a failure because the return_to argument
// says that parameter is supposed to be there.
removeQueryParameter(ref assertion, returnToRemovableParameter);
- var response = new OpenIdRelyingParty(store, assertion).Response;
+ var response = new OpenIdRelyingParty(store, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
Assert.AreEqual(AuthenticationStatus.Failed, response.Status);
Assert.IsNotNull(response.Exception);
}
@@ -140,7 +140,7 @@ namespace DotNetOpenId.Test.RelyingParty {
resign(ref assertion); // resign changed URL to simulate a contrived OP for breaking into RPs.
// (triggers exception) "... you're in trouble up to your ears."
- var response = new OpenIdRelyingParty(store, assertion).Response;
+ var response = new OpenIdRelyingParty(store, assertion, HttpUtility.ParseQueryString(assertion.Query)).Response;
Assert.AreEqual(AuthenticationStatus.Failed, response.Status);
Assert.IsNotNull(response.Exception);
}
diff --git a/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs b/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs
index 63d6f8e..ddef8a3 100644
--- a/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs
+++ b/src/DotNetOpenId.Test/RelyingParty/OpenIdRelyingPartyTest.cs
@@ -3,6 +3,7 @@ using DotNetOpenId.RelyingParty;
using NUnit.Framework;
using ProviderMemoryStore = DotNetOpenId.AssociationMemoryStore<DotNetOpenId.AssociationRelyingPartyType>;
using System.Web;
+using System.Collections.Specialized;
namespace DotNetOpenId.Test.RelyingParty {
[TestFixture]
@@ -28,25 +29,25 @@ namespace DotNetOpenId.Test.RelyingParty {
[Test]
public void CtorWithNullRequestUri() {
- new OpenIdRelyingParty(store, null);
+ new OpenIdRelyingParty(store, null, null);
}
[Test]
public void CtorWithNullStore() {
- var consumer = new OpenIdRelyingParty(null, simpleNonOpenIdRequest);
+ var consumer = new OpenIdRelyingParty(null, simpleNonOpenIdRequest, new NameValueCollection());
}
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void CreateRequestWithoutContext1() {
- var consumer = new OpenIdRelyingParty(store, simpleNonOpenIdRequest);
+ var consumer = new OpenIdRelyingParty(store, simpleNonOpenIdRequest, new NameValueCollection());
consumer.CreateRequest(simpleOpenId);
}
[Test]
[ExpectedException(typeof(InvalidOperationException))]
public void CreateRequestWithoutContext2() {
- var consumer = new OpenIdRelyingParty(store, simpleNonOpenIdRequest);
+ var consumer = new OpenIdRelyingParty(store, simpleNonOpenIdRequest, new NameValueCollection());
consumer.CreateRequest(simpleOpenId, realm);
}
@@ -54,7 +55,7 @@ namespace DotNetOpenId.Test.RelyingParty {
public void AssociationCreationWithStore() {
var providerStore = new ProviderMemoryStore();
- OpenIdRelyingParty rp = new OpenIdRelyingParty(new ApplicationMemoryStore(), null);
+ OpenIdRelyingParty rp = new OpenIdRelyingParty(new ApplicationMemoryStore(), null, null);
var idUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
DotNetOpenId.RelyingParty.IAuthenticationRequest req;
@@ -72,7 +73,7 @@ namespace DotNetOpenId.Test.RelyingParty {
public void NoAssociationRequestWithoutStore() {
var providerStore = new ProviderMemoryStore();
- OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null);
+ OpenIdRelyingParty rp = new OpenIdRelyingParty(null, null, null);
var idUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
DotNetOpenId.RelyingParty.IAuthenticationRequest req;
@@ -113,10 +114,10 @@ namespace DotNetOpenId.Test.RelyingParty {
private static void testExplicitPortOnRealmAndReturnTo(Uri returnTo, Realm realm) {
var identityUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
- var consumer = new OpenIdRelyingParty(null, null);
+ var consumer = new OpenIdRelyingParty(null, null, null);
var request = consumer.CreateRequest(identityUrl, realm, returnTo);
Protocol protocol = Protocol.Lookup(request.ProviderVersion);
- var nvc = HttpUtility.ParseQueryString(request.RedirectToProviderUrl.Query);
+ var nvc = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
string realmString = nvc[protocol.openid.Realm];
string returnToString = nvc[protocol.openid.return_to];
bool realmPortExplicitlyGiven = realmString.Contains(":80");
@@ -133,11 +134,11 @@ namespace DotNetOpenId.Test.RelyingParty {
public void ReturnToUrlEncodingTest() {
Uri origin = TestSupport.GetFullUrl(TestSupport.ConsumerPage);
var identityUrl = TestSupport.GetIdentityUrl(TestSupport.Scenarios.AutoApproval, ProtocolVersion.V20);
- var consumer = new OpenIdRelyingParty(null, null);
+ var consumer = new OpenIdRelyingParty(null, null, null);
var request = consumer.CreateRequest(identityUrl, origin, origin);
Protocol protocol = Protocol.Lookup(request.ProviderVersion);
request.AddCallbackArguments("a+b", "c+d");
- var requestArgs = HttpUtility.ParseQueryString(request.RedirectToProviderUrl.Query);
+ var requestArgs = HttpUtility.ParseQueryString(request.RedirectingResponse.ExtractUrl().Query);
var returnToArgs = HttpUtility.ParseQueryString(requestArgs[protocol.openid.return_to]);
Assert.AreEqual("c+d", returnToArgs["a+b"]);
}
diff --git a/src/DotNetOpenId.Test/TestSupport.cs b/src/DotNetOpenId.Test/TestSupport.cs
index d45aad3..be17494 100644
--- a/src/DotNetOpenId.Test/TestSupport.cs
+++ b/src/DotNetOpenId.Test/TestSupport.cs
@@ -93,3 +93,16 @@ public class TestSupport {
nvc[protocol.openid.sig] = Convert.ToBase64String(assoc.Sign(subsetDictionary, signed));
}
}
+
+static class TestExtensions {
+ /// <summary>
+ /// Gets a URL that can be requested to send an indirect message.
+ /// </summary>
+ public static Uri ExtractUrl(this IResponse message) {
+ DotNetOpenId.Response response = (DotNetOpenId.Response)message;
+ IEncodable encodable = response.EncodableMessage;
+ UriBuilder builder = new UriBuilder(encodable.RedirectUrl);
+ UriUtil.AppendQueryArgs(builder, encodable.EncodedFields);
+ return builder.Uri;
+ }
+}
diff --git a/src/DotNetOpenId.Test/UtilTest.cs b/src/DotNetOpenId.Test/UtilTest.cs
index 2f995c5..f6a3dbe 100644
--- a/src/DotNetOpenId.Test/UtilTest.cs
+++ b/src/DotNetOpenId.Test/UtilTest.cs
@@ -24,5 +24,15 @@ namespace DotNetOpenId.Test {
IDictionary<string, string> dict = Util.NameValueCollectionToDictionary(nvc);
Assert.IsTrue(dict["a"] == "b");
}
+
+ [Test]
+ public void NameValueCollectionToDictionaryNull() {
+ Assert.IsNull(Util.NameValueCollectionToDictionary(null));
+ }
+
+ [Test]
+ public void DictionaryToNameValueCollectionNull() {
+ Assert.IsNull(Util.DictionaryToNameValueCollection(null));
+ }
}
}
diff --git a/src/DotNetOpenId.sln b/src/DotNetOpenId.sln
index c36d9d9..8cd73a7 100644
--- a/src/DotNetOpenId.sln
+++ b/src/DotNetOpenId.sln
@@ -3,10 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{14D00F8C-C7CB-49B3-A668-7D0C5A4A6D9F}"
ProjectSection(SolutionItems) = preProject
- ..\doc\openid-attribute-exchange-1_0.html = ..\doc\openid-attribute-exchange-1_0.html
- ..\doc\openid-authentication-1_1.html = ..\doc\openid-authentication-1_1.html
- ..\doc\openid-authentication-2_0.html = ..\doc\openid-authentication-2_0.html
- ..\doc\openid-simple-registration-extension-1_0.html = ..\doc\openid-simple-registration-extension-1_0.html
..\doc\README.html = ..\doc\README.html
..\doc\WebFarms.htm = ..\doc\WebFarms.htm
EndProjectSection
diff --git a/src/DotNetOpenId/DotNetOpenId.csproj b/src/DotNetOpenId/DotNetOpenId.csproj
index b4fea45..a908853 100644
--- a/src/DotNetOpenId/DotNetOpenId.csproj
+++ b/src/DotNetOpenId/DotNetOpenId.csproj
@@ -55,6 +55,8 @@
<Compile Include="Association.cs" />
<Compile Include="AssociationMemoryStore.cs" />
<Compile Include="Associations.cs" />
+ <Compile Include="Provider\SigningMessageEncoder.cs" />
+ <Compile Include="RelyingParty\IndirectMessageRequest.cs" />
<Compile Include="ExtensionArgumentsManager.cs" />
<Compile Include="Extensions\AliasManager.cs" />
<Compile Include="Extensions\AttributeExchange\Constants.cs" />
@@ -74,6 +76,7 @@
<Compile Include="Extensions\IExtension.cs" />
<Compile Include="HmacSha256Association.cs" />
<Compile Include="Identifier.cs" />
+ <Compile Include="IResponse.cs" />
<Compile Include="Protocol.cs" />
<Compile Include="Provider\AssertionMessage.cs" />
<Compile Include="Provider\RelyingPartyReceivingEndpoint.cs" />
@@ -105,16 +108,15 @@
<Compile Include="OpenIdException.cs" />
<Compile Include="ProtocolMessages.cs" />
<Compile Include="Provider\EncodableResponse.cs" />
- <Compile Include="Provider\Encoder.cs" />
+ <Compile Include="MessageEncoder.cs" />
<Compile Include="Provider\FaultyRequest.cs" />
<Compile Include="Provider\IAuthenticationRequest.cs" />
<Compile Include="Provider\IdentityEndpoint.cs" />
<Compile Include="Provider\IRequest.cs" />
- <Compile Include="Provider\IResponse.cs" />
<Compile Include="Provider\OpenIdProvider.cs" />
<Compile Include="Provider\ProviderSession.cs" />
<Compile Include="Provider\Request.cs" />
- <Compile Include="Provider\Response.cs" />
+ <Compile Include="Response.cs" />
<Compile Include="Provider\ProviderEndpoint.cs" />
<Compile Include="Extensions\SimpleRegistration\Gender.cs" />
<Compile Include="Provider\AssociatedRequest.cs" />
@@ -139,7 +141,7 @@
<Compile Include="Provider\AssociateRequest.cs" />
<Compile Include="Provider\CheckAuthRequest.cs" />
<Compile Include="Provider\CheckIdRequest.cs" />
- <Compile Include="Provider\IEncodable.cs" />
+ <Compile Include="IEncodable.cs" />
<Compile Include="Provider\Signatory.cs" />
<Compile Include="XrdsPublisher.cs" />
<Compile Include="Strings.Designer.cs">
diff --git a/src/DotNetOpenId/Provider/IEncodable.cs b/src/DotNetOpenId/IEncodable.cs
index 3a7a60d..ef5ab60 100644
--- a/src/DotNetOpenId/Provider/IEncodable.cs
+++ b/src/DotNetOpenId/IEncodable.cs
@@ -2,21 +2,21 @@ using System;
using System.Collections.Generic;
using System.Text;
-namespace DotNetOpenId.Provider {
+namespace DotNetOpenId {
internal enum EncodingType {
None,
/// <summary>
- /// Response data to be sent to the consumer web site by telling the
- /// browser to redirect back to the consumer web site with a querystring
- /// that contains our data.
+ /// Data to be sent to the OP or RP site by telling the user agent to
+ /// redirect GET or form POST to a special URL with a payload of arguments.
/// </summary>
- RedirectBrowserUrl,
+ IndirectMessage,
/// <summary>
- /// Response data to be sent directly to the consumer site,
- /// in response to a direct request initiated by the consumer site
- /// (not the client browser).
+ /// Provider response data to be sent directly to the Relying Party site,
+ /// in response to a direct request initiated by the RP
+ /// (not indirect via the user agent).
+ /// Key-Value Form encoding will be used.
/// </summary>
- ResponseBody
+ DirectResponse
}
/// <remarks>
diff --git a/src/DotNetOpenId/Provider/IResponse.cs b/src/DotNetOpenId/IResponse.cs
index 29a70ce..e023383 100644
--- a/src/DotNetOpenId/Provider/IResponse.cs
+++ b/src/DotNetOpenId/IResponse.cs
@@ -4,7 +4,7 @@ using System.Text;
using System.Net;
using System.Collections.Specialized;
-namespace DotNetOpenId.Provider {
+namespace DotNetOpenId {
/// <summary>
/// Represents a Provider's response to an OpenId authentication request.
/// </summary>
@@ -26,7 +26,7 @@ namespace DotNetOpenId.Provider {
/// Sends the response to the browser.
/// </summary>
/// <remarks>
- /// This requires an ASP.NET hosted web site.
+ /// This requires an ASP.NET HttpContext.
/// </remarks>
void Send();
}
diff --git a/src/DotNetOpenId/MessageEncoder.cs b/src/DotNetOpenId/MessageEncoder.cs
new file mode 100644
index 0000000..3d5f840
--- /dev/null
+++ b/src/DotNetOpenId/MessageEncoder.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Specialized;
+using System.Text;
+using System.Net;
+using System.Diagnostics;
+using DotNetOpenId.Provider;
+using System.IO;
+using System.Web;
+
+namespace DotNetOpenId {
+ /// <summary>
+ /// Encodes <see cref="IEncodable"/> messages into <see cref="Response"/> instances
+ /// that can be interpreted by the host web site.
+ /// </summary>
+ internal class MessageEncoder {
+ /// <summary>
+ /// The maximum allowable size for a 301 Redirect response before we send
+ /// a 200 OK response with a scripted form POST with the parameters instead
+ /// in order to ensure successfully sending a large payload to another server
+ /// that might have a maximum allowable size restriction on its GET request.
+ /// </summary>
+ internal static int GetToPostThreshold = 2 * 1024; // 2KB, recommended by OpenID group
+ // We are intentionally using " instead of the html single quote ' below because
+ // the HtmlEncode'd values that we inject will only escape the double quote, so
+ // only the double-quote used around these values is safe.
+ const string FormPostFormat = @"
+<html>
+<body onload=""var btn = document.getElementById('submit_button'); btn.disabled = true; btn.value = 'Login in progress'; document.getElementById('openid_message').submit()"">
+<form id=""openid_message"" action=""{0}"" method=""post"" accept-charset=""UTF-8"" enctype=""application/x-www-form-urlencoded"" onSubmit=""var btn = document.getElementById('submit_button'); btn.disabled = true; btn.value = 'Login in progress'; return true;"">
+{1}
+ <input id=""submit_button"" type=""submit"" value=""Continue"" />
+</form>
+</body>
+</html>
+";
+ /// <summary>
+ /// Encodes messages into <see cref="Response"/> instances.
+ /// </summary>
+ public virtual Response Encode(IEncodable message) {
+ EncodingType encode_as = message.EncodingType;
+ Response wr;
+
+ WebHeaderCollection headers = new WebHeaderCollection();
+ switch (encode_as) {
+ case EncodingType.DirectResponse:
+ HttpStatusCode code = (message is Exception) ?
+ HttpStatusCode.BadRequest : HttpStatusCode.OK;
+ wr = new Response(code, headers, ProtocolMessages.KeyValueForm.GetBytes(message.EncodedFields), message);
+ break;
+ case EncodingType.IndirectMessage:
+ // TODO: either redirect or do a form POST depending on payload size.
+ Debug.Assert(message.RedirectUrl != null);
+ if (getSizeOfPayload(message) <= GetToPostThreshold)
+ wr = Create301RedirectResponse(message);
+ else
+ wr = CreateFormPostResponse(message);
+ break;
+ default:
+ if (TraceUtil.Switch.TraceError) {
+ Trace.TraceError("Cannot encode response: {0}", message);
+ }
+ wr = new Response(HttpStatusCode.BadRequest, headers, new byte[0], message);
+ break;
+ }
+ return wr;
+ }
+
+ static int getSizeOfPayload(IEncodable message) {
+ Debug.Assert(message != null);
+ int size = 0;
+ foreach (var field in message.EncodedFields) {
+ size += field.Key.Length;
+ size += field.Value.Length;
+ }
+ return size;
+ }
+ protected virtual Response Create301RedirectResponse(IEncodable message) {
+ WebHeaderCollection headers = new WebHeaderCollection();
+ UriBuilder builder = new UriBuilder(message.RedirectUrl);
+ UriUtil.AppendQueryArgs(builder, message.EncodedFields);
+ headers.Add(HttpResponseHeader.Location, builder.Uri.AbsoluteUri);
+ return new Response(HttpStatusCode.Redirect, headers, new byte[0], message);
+ }
+ protected virtual Response CreateFormPostResponse(IEncodable message) {
+ WebHeaderCollection headers = new WebHeaderCollection();
+ MemoryStream body = new MemoryStream();
+ StreamWriter bodyWriter = new StreamWriter(body);
+ StringBuilder hiddenFields = new StringBuilder();
+ foreach (var field in message.EncodedFields) {
+ hiddenFields.AppendFormat("\t<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />\r\n",
+ HttpUtility.HtmlEncode(field.Key), HttpUtility.HtmlEncode(field.Value));
+ }
+ bodyWriter.WriteLine(FormPostFormat,
+ HttpUtility.HtmlEncode(message.RedirectUrl.AbsoluteUri), hiddenFields);
+ bodyWriter.Flush();
+ return new Response(HttpStatusCode.OK, headers, body.ToArray(), message);
+ }
+ }
+
+ internal class EncodeEventArgs : EventArgs {
+ public EncodeEventArgs(IEncodable encodable) {
+ Message = encodable;
+ }
+ public IEncodable Message { get; private set; }
+ }
+}
diff --git a/src/DotNetOpenId/OpenIdException.cs b/src/DotNetOpenId/OpenIdException.cs
index b2647bb..b523cff 100644
--- a/src/DotNetOpenId/OpenIdException.cs
+++ b/src/DotNetOpenId/OpenIdException.cs
@@ -83,14 +83,14 @@ namespace DotNetOpenId {
get {
Debug.Assert(Query != null, "An OpenId exception should always be provided with the query if it is to be encoded for transmittal to the RP.");
if (HasReturnTo)
- return EncodingType.RedirectBrowserUrl;
+ return EncodingType.IndirectMessage;
if (Query != null) {
string mode = Util.GetOptionalArg(Query, Protocol.openid.mode);
if (mode != null)
if (mode != Protocol.Args.Mode.checkid_setup &&
mode != Protocol.Args.Mode.checkid_immediate)
- return EncodingType.ResponseBody;
+ return EncodingType.DirectResponse;
}
// Notes from the original port
diff --git a/src/DotNetOpenId/Provider/EncodableResponse.cs b/src/DotNetOpenId/Provider/EncodableResponse.cs
index c7ebb4e..47bc1cd 100644
--- a/src/DotNetOpenId/Provider/EncodableResponse.cs
+++ b/src/DotNetOpenId/Provider/EncodableResponse.cs
@@ -45,7 +45,7 @@ namespace DotNetOpenId.Provider {
#region IEncodable Members
public EncodingType EncodingType {
- get { return RedirectUrl != null ? EncodingType.RedirectBrowserUrl : EncodingType.ResponseBody; }
+ get { return RedirectUrl != null ? EncodingType.IndirectMessage : EncodingType.DirectResponse; }
}
public IDictionary<string, string> EncodedFields {
@@ -53,7 +53,7 @@ namespace DotNetOpenId.Provider {
var nvc = new Dictionary<string, string>();
foreach (var pair in Fields) {
- if (EncodingType == EncodingType.RedirectBrowserUrl) {
+ if (EncodingType == EncodingType.IndirectMessage) {
nvc.Add(Protocol.openid.Prefix + pair.Key, pair.Value);
} else {
nvc.Add(pair.Key, pair.Value);
diff --git a/src/DotNetOpenId/Provider/Encoder.cs b/src/DotNetOpenId/Provider/Encoder.cs
deleted file mode 100644
index 57a5435..0000000
--- a/src/DotNetOpenId/Provider/Encoder.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-using System;
-using System.Collections.Specialized;
-using System.Text;
-using System.Net;
-using System.Diagnostics;
-
-namespace DotNetOpenId.Provider {
- /// <summary>
- /// Encodes responses in to <see cref="WebResponse"/>.
- /// </summary>
- internal class Encoder {
- /// <summary>
- /// Encodes responses in to WebResponses.
- /// </summary>
- public virtual Response Encode(IEncodable response) {
- EncodingType encode_as = response.EncodingType;
- Response wr;
-
- switch (encode_as) {
- case EncodingType.ResponseBody:
- HttpStatusCode code = (response is Exception) ?
- HttpStatusCode.BadRequest : HttpStatusCode.OK;
- wr = new Response(code, null, ProtocolMessages.KeyValueForm.GetBytes(response.EncodedFields));
- break;
- case EncodingType.RedirectBrowserUrl:
- Debug.Assert(response.RedirectUrl != null);
- WebHeaderCollection headers = new WebHeaderCollection();
-
- UriBuilder builder = new UriBuilder(response.RedirectUrl);
- UriUtil.AppendQueryArgs(builder, response.EncodedFields);
- headers.Add(HttpResponseHeader.Location, builder.Uri.AbsoluteUri);
-
- wr = new Response(HttpStatusCode.Redirect, headers, new byte[0]);
- break;
- default:
- if (TraceUtil.Switch.TraceError) {
- Trace.TraceError("Cannot encode response: {0}", response);
- }
- wr = new Response(HttpStatusCode.BadRequest, null, new byte[0]);
- break;
- }
- return wr;
- }
- }
-
- /// <summary>
- /// Encodes responses in to <see cref="WebResponse"/>, signing them when required.
- /// </summary>
- internal class SigningEncoder : Encoder {
- Signatory signatory;
-
- public SigningEncoder(Signatory signatory) {
- if (signatory == null)
- throw new ArgumentNullException("signatory", "Must have a store to sign this request");
-
- this.signatory = signatory;
- }
-
- public override Response Encode(IEncodable encodable) {
- OnSigning(encodable);
- var response = encodable as EncodableResponse;
- if (response != null) {
- if (response.NeedsSigning) {
- Debug.Assert(!response.Fields.ContainsKey(encodable.Protocol.openidnp.sig));
- signatory.Sign(response);
- }
- }
- return base.Encode(encodable);
- }
-
- /// <summary>
- /// Used for testing. Allows interception and modification of messages
- /// that are about to be returned to the RP.
- /// </summary>
- public static event EventHandler<EncodeEventArgs> Signing;
- protected virtual void OnSigning(IEncodable encodable) {
- if (Signing != null)
- Signing(this, new EncodeEventArgs(encodable));
- }
- }
-
- internal class EncodeEventArgs : EventArgs {
- public EncodeEventArgs(IEncodable encodable) {
- Message = encodable;
- }
- public IEncodable Message { get; private set;}
- }
-}
diff --git a/src/DotNetOpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenId/Provider/OpenIdProvider.cs
index f227f0c..e0b2afd 100644
--- a/src/DotNetOpenId/Provider/OpenIdProvider.cs
+++ b/src/DotNetOpenId/Provider/OpenIdProvider.cs
@@ -15,7 +15,7 @@ namespace DotNetOpenId.Provider {
[DebuggerDisplay("Endpoint: {Endpoint}, OpenId Request: {Query.ContainsKey(\"openid.mode\")}")]
public class OpenIdProvider {
internal Signatory Signatory { get; private set; }
- internal Encoder Encoder;
+ internal MessageEncoder Encoder;
/// <summary>
/// The incoming request's Url.
/// </summary>
@@ -55,8 +55,11 @@ namespace DotNetOpenId.Provider {
/// The Internet-facing URL that responds to OpenID requests.
/// </param>
/// <param name="requestUrl">The incoming request URL.</param>
- /// <param name="query">The name/value pairs that came in on the
- /// QueryString of a GET request or in the entity of a POST request.</param>
+ /// <param name="query">
+ /// The name/value pairs that came in on the
+ /// QueryString of a GET request or in the entity of a POST request.
+ /// For example: (Request.HttpMethod == "GET" ? Request.QueryString : Request.Form).
+ /// </param>
public OpenIdProvider(IProviderAssociationStore store, Uri providerEndpoint, Uri requestUrl, NameValueCollection query)
: this(store, providerEndpoint, requestUrl, Util.NameValueCollectionToDictionary(query)) { }
OpenIdProvider(IProviderAssociationStore store, Uri providerEndpoint, Uri requestUrl, IDictionary<string, string> query) {
@@ -68,7 +71,7 @@ namespace DotNetOpenId.Provider {
RequestUrl = requestUrl;
Query = query;
Signatory = new Signatory(store);
- Encoder = new SigningEncoder(Signatory);
+ Encoder = new SigningMessageEncoder(Signatory);
store.ClearExpiredAssociations(); // every so often we should do this.
}
diff --git a/src/DotNetOpenId/Provider/SigningMessageEncoder.cs b/src/DotNetOpenId/Provider/SigningMessageEncoder.cs
new file mode 100644
index 0000000..ea5a522
--- /dev/null
+++ b/src/DotNetOpenId/Provider/SigningMessageEncoder.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Diagnostics;
+
+namespace DotNetOpenId.Provider {
+ /// <summary>
+ /// Encodes responses in to <see cref="Response"/>, signing them when required.
+ /// </summary>
+ internal class SigningMessageEncoder : MessageEncoder {
+ Signatory signatory;
+
+ public SigningMessageEncoder(Signatory signatory) {
+ if (signatory == null)
+ throw new ArgumentNullException("signatory", "Must have a store to sign this request");
+
+ this.signatory = signatory;
+ }
+
+ public override Response Encode(IEncodable encodable) {
+ OnSigning(encodable);
+ var response = encodable as EncodableResponse;
+ if (response != null) {
+ if (response.NeedsSigning) {
+ Debug.Assert(!response.Fields.ContainsKey(encodable.Protocol.openidnp.sig));
+ signatory.Sign(response);
+ }
+ }
+ return base.Encode(encodable);
+ }
+
+ /// <summary>
+ /// Used for testing. Allows interception and modification of messages
+ /// that are about to be returned to the RP.
+ /// </summary>
+ public static event EventHandler<EncodeEventArgs> Signing;
+ protected virtual void OnSigning(IEncodable encodable) {
+ if (Signing != null)
+ Signing(this, new EncodeEventArgs(encodable));
+ }
+ }
+
+}
diff --git a/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs
index 37ec80f..cc9c3ae 100644
--- a/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs
+++ b/src/DotNetOpenId/RelyingParty/AuthenticationRequest.cs
@@ -30,15 +30,18 @@ namespace DotNetOpenId.RelyingParty {
class AuthenticationRequest : IAuthenticationRequest {
Association assoc;
ServiceEndpoint endpoint;
+ MessageEncoder encoder;
Protocol protocol { get { return endpoint.Protocol; } }
AuthenticationRequest(string token, Association assoc, ServiceEndpoint endpoint,
- Realm realm, Uri returnToUrl) {
+ Realm realm, Uri returnToUrl, MessageEncoder encoder) {
if (endpoint == null) throw new ArgumentNullException("endpoint");
if (realm == null) throw new ArgumentNullException("realm");
if (returnToUrl == null) throw new ArgumentNullException("returnToUrl");
+ if (encoder == null) throw new ArgumentNullException("encoder");
this.assoc = assoc;
this.endpoint = endpoint;
+ this.encoder = encoder;
Realm = realm;
ReturnToUrl = returnToUrl;
@@ -49,7 +52,7 @@ namespace DotNetOpenId.RelyingParty {
AddCallbackArguments(DotNetOpenId.RelyingParty.Token.TokenKey, token);
}
internal static AuthenticationRequest Create(Identifier userSuppliedIdentifier,
- Realm realm, Uri returnToUrl, IRelyingPartyApplicationStore store) {
+ Realm realm, Uri returnToUrl, IRelyingPartyApplicationStore store, MessageEncoder encoder) {
if (userSuppliedIdentifier == null) throw new ArgumentNullException("userSuppliedIdentifier");
if (realm == null) throw new ArgumentNullException("realm");
@@ -92,7 +95,7 @@ namespace DotNetOpenId.RelyingParty {
return new AuthenticationRequest(
new Token(endpoint).Serialize(store),
store != null ? getAssociation(endpoint, store) : null,
- endpoint, realm, returnToUrl);
+ endpoint, realm, returnToUrl, encoder);
}
static Association getAssociation(ServiceEndpoint provider, IRelyingPartyApplicationStore store) {
if (provider == null) throw new ArgumentNullException("provider");
@@ -147,7 +150,7 @@ namespace DotNetOpenId.RelyingParty {
/// Gets the URL the user agent should be redirected to to begin the
/// OpenID authentication process.
/// </summary>
- public Uri RedirectToProviderUrl {
+ public IResponse RedirectingResponse {
get {
UriBuilder returnToBuilder = new UriBuilder(ReturnToUrl);
UriUtil.AppendQueryArgs(returnToBuilder, this.ReturnToArgs);
@@ -168,16 +171,17 @@ namespace DotNetOpenId.RelyingParty {
if (this.assoc != null)
qsArgs.Add(protocol.openid.assoc_handle, this.assoc.Handle);
- UriBuilder redir = new UriBuilder(this.endpoint.ProviderEndpoint);
+ // Add on extension arguments
+ foreach(var pair in OutgoingExtensions.GetArgumentsToSend(true))
+ qsArgs.Add(pair.Key, pair.Value);
- UriUtil.AppendQueryArgs(redir, qsArgs);
- UriUtil.AppendQueryArgs(redir, OutgoingExtensions.GetArgumentsToSend(true));
-
- return redir.Uri;
+ var request = new IndirectMessageRequest(this.endpoint.ProviderEndpoint, qsArgs);
+ return this.encoder.Encode(request);
}
}
public void AddExtension(DotNetOpenId.Extensions.IExtensionRequest extension) {
+ if (extension == null) throw new ArgumentNullException("extension");
OutgoingExtensions.AddExtensionArguments(extension.TypeUri, extension.Serialize(this));
}
@@ -204,26 +208,15 @@ namespace DotNetOpenId.RelyingParty {
/// <summary>
/// Redirects the user agent to the provider for authentication.
+ /// Execution of the current page terminates after this call.
/// </summary>
/// <remarks>
/// This method requires an ASP.NET HttpContext.
/// </remarks>
public void RedirectToProvider() {
- RedirectToProvider(false);
- }
- /// <summary>
- /// Redirects the user agent to the provider for authentication.
- /// </summary>
- /// <param name="endResponse">
- /// Whether execution of this response should cease after this call.
- /// </param>
- /// <remarks>
- /// This method requires an ASP.NET HttpContext.
- /// </remarks>
- public void RedirectToProvider(bool endResponse) {
if (HttpContext.Current == null || HttpContext.Current.Response == null)
throw new InvalidOperationException(Strings.CurrentHttpContextRequired);
- HttpContext.Current.Response.Redirect(RedirectToProviderUrl.AbsoluteUri, endResponse);
+ RedirectingResponse.Send();
}
}
}
diff --git a/src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs b/src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs
index 978d521..127e90c 100644
--- a/src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs
+++ b/src/DotNetOpenId/RelyingParty/AuthenticationResponse.cs
@@ -111,7 +111,12 @@ namespace DotNetOpenId.RelyingParty {
if (query == null) throw new ArgumentNullException("query");
if (requestUrl == null) throw new ArgumentNullException("requestUrl");
ServiceEndpoint tokenEndpoint = null;
- string token = Util.GetOptionalArg(query, Token.TokenKey);
+ // The query parameter may be the POST query or the GET query,
+ // but the token parameter will always be in the GET query because
+ // it was added to the return_to parameter list.
+ IDictionary<string, string> requestUrlQuery = Util.NameValueCollectionToDictionary(
+ HttpUtility.ParseQueryString(requestUrl.Query));
+ string token = Util.GetOptionalArg(requestUrlQuery, Token.TokenKey);
if (token != null) {
tokenEndpoint = Token.Deserialize(token, store).Endpoint;
}
diff --git a/src/DotNetOpenId/RelyingParty/DirectRequest.cs b/src/DotNetOpenId/RelyingParty/DirectRequest.cs
index d9a8276..9b9d732 100644
--- a/src/DotNetOpenId/RelyingParty/DirectRequest.cs
+++ b/src/DotNetOpenId/RelyingParty/DirectRequest.cs
@@ -4,6 +4,7 @@ using System.Text;
using System.Net;
using System.Diagnostics;
using System.Globalization;
+using System.IO;
namespace DotNetOpenId.RelyingParty {
[DebuggerDisplay("OpenId: {Protocol.Version}")]
@@ -27,6 +28,14 @@ namespace DotNetOpenId.RelyingParty {
IDictionary<string, string> args = null;
try {
resp = UntrustedWebRequest.Request(Provider.ProviderEndpoint, body);
+ // If an internal server error occurred, there won't be any KV-form stream
+ // to read in. So instead, preserve whatever error the server did send back
+ // and throw it in the exception.
+ if (resp.StatusCode == HttpStatusCode.InternalServerError) {
+ string errorStream = new StreamReader(resp.ResponseStream).ReadToEnd();
+ throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
+ Strings.ProviderRespondedWithError, errorStream));
+ }
args = ProtocolMessages.KeyValueForm.GetDictionary(resp.ResponseStream);
} catch (ArgumentException e) {
throw new OpenIdException("Failure decoding Key-Value Form response from provider.", e);
diff --git a/src/DotNetOpenId/RelyingParty/IAuthenticationRequest.cs b/src/DotNetOpenId/RelyingParty/IAuthenticationRequest.cs
index 3297b64..0fdc4f1 100644
--- a/src/DotNetOpenId/RelyingParty/IAuthenticationRequest.cs
+++ b/src/DotNetOpenId/RelyingParty/IAuthenticationRequest.cs
@@ -26,30 +26,21 @@ namespace DotNetOpenId.RelyingParty {
void AddExtension(IExtensionRequest extension);
/// <summary>
/// Redirects the user agent to the provider for authentication.
+ /// Execution of the current page terminates after this call.
/// </summary>
/// <remarks>
/// This method requires an ASP.NET HttpContext.
/// </remarks>
void RedirectToProvider();
/// <summary>
- /// Redirects the user agent to the provider for authentication.
- /// </summary>
- /// <param name="endResponse">
- /// Whether execution of this response should cease after this call.
- /// </param>
- /// <remarks>
- /// This method requires an ASP.NET HttpContext.
- /// </remarks>
- void RedirectToProvider(bool endResponse);
- /// <summary>
/// Gets/sets the mode the Provider should use during authentication.
/// </summary>
AuthenticationRequestMode Mode { get; set; }
/// <summary>
- /// Gets the URL the user agent should be redirected to to begin the
- /// OpenID authentication process.
+ /// Gets the HTTP response the relying party should send to the user agent
+ /// to redirect it to the OpenID Provider to start the OpenID authentication process.
/// </summary>
- Uri RedirectToProviderUrl { get; }
+ IResponse RedirectingResponse { get; }
/// <summary>
/// Gets the URL that the user agent will return to after authentication
/// completes or fails at the Provider.
diff --git a/src/DotNetOpenId/RelyingParty/IndirectMessageRequest.cs b/src/DotNetOpenId/RelyingParty/IndirectMessageRequest.cs
new file mode 100644
index 0000000..8348374
--- /dev/null
+++ b/src/DotNetOpenId/RelyingParty/IndirectMessageRequest.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace DotNetOpenId.RelyingParty {
+ internal class IndirectMessageRequest : IEncodable {
+ public IndirectMessageRequest(Uri receivingUrl, IDictionary<string, string> fields) {
+ if (receivingUrl == null) throw new ArgumentNullException("receivingUrl");
+ if (fields == null) throw new ArgumentNullException("fields");
+ RedirectUrl = receivingUrl;
+ EncodedFields = fields;
+ }
+
+ #region IEncodable Members
+
+ public EncodingType EncodingType { get { return EncodingType.IndirectMessage ; } }
+ public IDictionary<string, string> EncodedFields { get; private set; }
+ public Uri RedirectUrl { get; private set; }
+ public Protocol Protocol {
+ get { throw new NotImplementedException(); }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs
index 5203966..f53b8f0 100644
--- a/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs
+++ b/src/DotNetOpenId/RelyingParty/OpenIdRelyingParty.cs
@@ -17,6 +17,7 @@ namespace DotNetOpenId.RelyingParty {
IRelyingPartyApplicationStore store;
Uri request;
IDictionary<string, string> query;
+ MessageEncoder encoder;
/// <summary>
/// Constructs an OpenId consumer that uses the current HttpContext request
@@ -25,7 +26,9 @@ namespace DotNetOpenId.RelyingParty {
/// <remarks>
/// This method requires a current ASP.NET HttpContext.
/// </remarks>
- public OpenIdRelyingParty() : this(HttpApplicationStore, Util.GetRequestUrlFromContext()) { }
+ public OpenIdRelyingParty()
+ : this(HttpApplicationStore,
+ Util.GetRequestUrlFromContext(), Util.GetQueryFromContext()) { }
/// <summary>
/// Constructs an OpenId consumer that uses a given querystring and IAssociationStore.
/// </summary>
@@ -39,6 +42,12 @@ namespace DotNetOpenId.RelyingParty {
/// Optional. The current incoming HTTP request that may contain an OpenId assertion.
/// If not included, any OpenId authentication assertions will not be processed.
/// </param>
+ /// <param name="query">
+ /// The name/value pairs that came in on the
+ /// QueryString of a GET request or in the entity of a POST request.
+ /// For example: (Request.HttpMethod == "GET" ? Request.QueryString : Request.Form).
+ /// This must be supplied if <paramref name="requestUrl"/> is supplied.
+ /// </param>
/// <remarks>
/// The IRelyingPartyApplicationStore must be shared across an entire web farm
/// because of the design of how nonces are stored/retrieved. Even if
@@ -47,15 +56,20 @@ namespace DotNetOpenId.RelyingParty {
/// which must therefore share the nonce information in the application
/// state store in order to stop the intruder.
/// </remarks>
- public OpenIdRelyingParty(IRelyingPartyApplicationStore store, Uri requestUrl) {
+ public OpenIdRelyingParty(IRelyingPartyApplicationStore store, Uri requestUrl, NameValueCollection query) :
+ this(store, requestUrl, Util.NameValueCollectionToDictionary(query)) {
+ }
+ OpenIdRelyingParty(IRelyingPartyApplicationStore store, Uri requestUrl, IDictionary<string, string> query) {
this.store = store;
if (store != null) {
store.ClearExpiredAssociations(); // every so often we should do this.
}
if (requestUrl != null) {
+ if (query == null) throw new ArgumentNullException("query");
this.request = requestUrl;
- this.query = Util.NameValueCollectionToDictionary(HttpUtility.ParseQueryString(requestUrl.Query));
+ this.query = query;
}
+ this.encoder = new MessageEncoder();
}
/// <summary>
@@ -79,7 +93,7 @@ namespace DotNetOpenId.RelyingParty {
/// send to the user agent to initiate the authentication.
/// </returns>
public IAuthenticationRequest CreateRequest(Identifier userSuppliedIdentifier, Realm realm, Uri returnToUrl) {
- return AuthenticationRequest.Create(userSuppliedIdentifier, realm, returnToUrl, store);
+ return AuthenticationRequest.Create(userSuppliedIdentifier, realm, returnToUrl, store, encoder);
}
/// <remarks>
@@ -138,9 +152,6 @@ namespace DotNetOpenId.RelyingParty {
if (!query.ContainsKey(protocol.openid.mode))
return false;
- if (HttpContext.Current != null && !HttpContext.Current.Request.RequestType.Equals("GET", StringComparison.Ordinal))
- return false;
-
return true;
}
}
diff --git a/src/DotNetOpenId/RelyingParty/OpenIdTextBox.cs b/src/DotNetOpenId/RelyingParty/OpenIdTextBox.cs
index d8f7e61..57a5fd4 100644
--- a/src/DotNetOpenId/RelyingParty/OpenIdTextBox.cs
+++ b/src/DotNetOpenId/RelyingParty/OpenIdTextBox.cs
@@ -552,7 +552,7 @@ namespace DotNetOpenId.RelyingParty
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
- if (!Enabled) return;
+ if (!Enabled || Page.IsPostBack) return;
var consumer = new OpenIdRelyingParty();
if (consumer.Response != null) {
switch (consumer.Response.Status) {
diff --git a/src/DotNetOpenId/Provider/Response.cs b/src/DotNetOpenId/Response.cs
index c8ca8b9..d4469ec 100644
--- a/src/DotNetOpenId/Provider/Response.cs
+++ b/src/DotNetOpenId/Response.cs
@@ -3,24 +3,37 @@ using System.Collections.Specialized;
using System.Text;
using System.Net;
using System.Web;
+using System.Diagnostics;
-namespace DotNetOpenId.Provider {
+namespace DotNetOpenId {
/// <summary>
- /// A response to an OpenID request in terms a web server understands.
+ /// A response to an OpenID request in terms the host web site can forward to the user agent.
/// </summary>
class Response : IResponse {
- internal Response(HttpStatusCode code, WebHeaderCollection headers, byte[] body) {
+ /// <param name="code">The HTTP status code.</param>
+ /// <param name="headers">The collection of any HTTP headers that should be included. Cannot be null, but can be an empty collection.</param>
+ /// <param name="body">The payload of the response, if any. Cannot be null, but can be an empty array.</param>
+ /// <param name="encodableMessage">
+ /// Used to assist testing to decipher the field contents of a Response.
+ /// </param>
+ internal Response(HttpStatusCode code, WebHeaderCollection headers, byte[] body, IEncodable encodableMessage) {
+ if (headers == null) throw new ArgumentNullException("headers");
+ if (body == null) throw new ArgumentNullException("body");
+ Debug.Assert(encodableMessage != null, "For testing, this is useful to have.");
Code = code;
Headers = headers ?? new WebHeaderCollection();
Body = body;
+ EncodableMessage = encodableMessage;
}
public HttpStatusCode Code { get; private set; }
public WebHeaderCollection Headers { get; private set; }
public byte[] Body { get; private set; }
+ internal IEncodable EncodableMessage { get; private set; }
/// <summary>
/// Sends this response to the user agent or OpenId consumer.
+ /// Execution of the current page terminates after this call.
/// </summary>
/// <remarks>
/// This method requires a current ASP.NET HttpContext.
@@ -36,6 +49,7 @@ namespace DotNetOpenId.Provider {
HttpContext.Current.Response.OutputStream.Flush();
}
HttpContext.Current.Response.OutputStream.Close();
+ HttpContext.Current.Response.End();
}
}
}
diff --git a/src/DotNetOpenId/Util.cs b/src/DotNetOpenId/Util.cs
index 82892b2..65bf3b0 100644
--- a/src/DotNetOpenId/Util.cs
+++ b/src/DotNetOpenId/Util.cs
@@ -88,7 +88,7 @@ namespace DotNetOpenId {
internal const string DefaultNamespace = "DotNetOpenId";
public static IDictionary<string, string> NameValueCollectionToDictionary(NameValueCollection nvc) {
- if (nvc == null) throw new ArgumentNullException("nvc");
+ if (nvc == null) return null;
var dict = new Dictionary<string, string>(nvc.Count);
for (int i = 0; i < nvc.Count; i++) {
string key = nvc.GetKey(i);
@@ -103,6 +103,7 @@ namespace DotNetOpenId {
return dict;
}
public static NameValueCollection DictionaryToNameValueCollection(IDictionary<string, string> dict) {
+ if (dict == null) return null;
NameValueCollection nvc = new NameValueCollection(dict.Count);
foreach (var pair in dict) {
nvc.Add(pair.Key, pair.Value);