summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--samples/OpenIdProviderWebForms/Code/Util.cs24
-rw-r--r--samples/OpenIdProviderWebForms/Provider.ashx.cs15
-rw-r--r--samples/OpenIdProviderWebForms/decide.aspx34
-rw-r--r--samples/OpenIdProviderWebForms/decide.aspx.cs72
-rw-r--r--samples/OpenIdProviderWebForms/decide.aspx.designer.cs11
-rw-r--r--samples/OpenIdProviderWebForms/server.aspx2
-rw-r--r--samples/OpenIdProviderWebForms/server.aspx.cs4
-rw-r--r--samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx41
-rw-r--r--samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.cs79
-rw-r--r--samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.designer.cs115
-rw-r--r--samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj8
-rw-r--r--samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs2
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx1
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.cs5
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs11
-rw-r--r--samples/OpenIdRelyingPartyWebForms/xrds.aspx1
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj6
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/NegativeAssertionResponse.cs7
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs9
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.resx3
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs74
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/AnonymousRequestEventArgs.cs32
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs88
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs131
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IAnonymousRequest.cs25
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs32
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs45
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs5
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs76
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs26
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationStatus.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs24
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs3
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdTextBox.cs7
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs273
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs223
37 files changed, 1120 insertions, 402 deletions
diff --git a/samples/OpenIdProviderWebForms/Code/Util.cs b/samples/OpenIdProviderWebForms/Code/Util.cs
index 84d3c63..8700dbd 100644
--- a/samples/OpenIdProviderWebForms/Code/Util.cs
+++ b/samples/OpenIdProviderWebForms/Code/Util.cs
@@ -6,10 +6,6 @@
namespace OpenIdProviderWebForms.Code {
using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Net;
- using System.Text;
using System.Web;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Provider;
@@ -51,6 +47,26 @@ namespace OpenIdProviderWebForms.Code {
// to know the answer.
idrequest.IsAuthenticated = userOwningOpenIdUrl == HttpContext.Current.User.Identity.Name;
}
+
+ if (idrequest.IsAuthenticated.Value) {
+ // add extension responses here.
+ }
+ } else {
+ HttpContext.Current.Response.Redirect("~/decide.aspx", true);
+ }
+ }
+
+ internal static void ProcessAnonymousRequest(IAnonymousRequest request) {
+ if (request.Immediate) {
+ // NOTE: in a production provider site, you may want to only
+ // respond affirmatively if the user has already authorized this consumer
+ // to know the answer.
+ request.IsApproved = HttpContext.Current.User.Identity.IsAuthenticated;
+
+ if (request.IsApproved.Value) {
+ // Add extension responses here.
+ // These would typically be filled in from a user database
+ }
} else {
HttpContext.Current.Response.Redirect("~/decide.aspx", true);
}
diff --git a/samples/OpenIdProviderWebForms/Provider.ashx.cs b/samples/OpenIdProviderWebForms/Provider.ashx.cs
index 40acc04..c8441cf 100644
--- a/samples/OpenIdProviderWebForms/Provider.ashx.cs
+++ b/samples/OpenIdProviderWebForms/Provider.ashx.cs
@@ -24,17 +24,20 @@
// But authentication requests cannot be responded to until something on
// this site decides whether to approve or disapprove the authentication.
if (!request.IsResponseReady) {
- var idrequest = (IAuthenticationRequest)request;
-
- // We store the authentication request in the user's session so that
+ // We store the request in the user's session so that
// redirects and user prompts can appear and eventually some page can decide
// to respond to the OpenID authentication request either affirmatively or
// negatively.
- ProviderEndpoint.PendingAuthenticationRequest = idrequest;
+ ProviderEndpoint.PendingAnonymousRequest = request as IAnonymousRequest;
+ ProviderEndpoint.PendingAuthenticationRequest = request as IAuthenticationRequest;
// We delegate that approval process to our utility method that we share
// with our other Provider sample page server.aspx.
- Code.Util.ProcessAuthenticationChallenge(idrequest);
+ if (ProviderEndpoint.PendingAuthenticationRequest != null) {
+ Code.Util.ProcessAuthenticationChallenge(ProviderEndpoint.PendingAuthenticationRequest);
+ } else if (ProviderEndpoint.PendingAnonymousRequest != null) {
+ Code.Util.ProcessAnonymousRequest(ProviderEndpoint.PendingAnonymousRequest);
+ }
// As part of authentication approval, the user may need to authenticate
// to this Provider and/or decide whether to allow the requesting RP site
@@ -52,7 +55,7 @@
ProviderEndpoint.Provider.SendResponse(request);
// Make sure that any PendingAuthenticationRequest that MAY be set is cleared.
- ProviderEndpoint.PendingAuthenticationRequest = null;
+ ProviderEndpoint.PendingRequest = null;
}
}
}
diff --git a/samples/OpenIdProviderWebForms/decide.aspx b/samples/OpenIdProviderWebForms/decide.aspx
index 54c2f01..4a6e2d8 100644
--- a/samples/OpenIdProviderWebForms/decide.aspx
+++ b/samples/OpenIdProviderWebForms/decide.aspx
@@ -1,34 +1,24 @@
-<%@ Page Language="C#" AutoEventWireup="true" Inherits="OpenIdProviderWebForms.decide" CodeBehind="decide.aspx.cs" MasterPageFile="~/Site.Master" %>
+<%@ Page Language="C#" AutoEventWireup="true" Inherits="OpenIdProviderWebForms.decide"
+ CodeBehind="decide.aspx.cs" MasterPageFile="~/Site.Master" %>
<%@ Register Src="ProfileFields.ascx" TagName="ProfileFields" TagPrefix="uc1" %>
<asp:Content runat="server" ContentPlaceHolderID="Main">
- <p>
- A site has asked to authenticate that you own the identifier below.&nbsp; You should
- only do this if you wish to log in to the site given by the Realm.</p>
- <p>
- This site
- <asp:Label ID="relyingPartyVerificationResultLabel" runat="server"
- Font-Bold="True" Text="failed" /> verification. </p>
+ <p><asp:Label ID="siteRequestLabel" runat="server" Text="A site has asked to authenticate that you own the identifier below." />
+ You should only do this if you wish to log in to the site given by the Realm.</p>
+ <p>This site <asp:Label ID="relyingPartyVerificationResultLabel" runat="server" Font-Bold="True"
+ Text="failed" /> verification. </p>
<table>
<tr>
- <td>
- Identifier: </td>
- <td>
- <asp:Label runat="server" ID='identityUrlLabel' />
- </td>
+ <td>Identifier: </td>
+ <td><asp:Label runat="server" ID='identityUrlLabel' /> </td>
</tr>
<tr>
- <td>
- Realm: </td>
- <td>
- <asp:Label runat="server" ID='realmLabel' />
- </td>
+ <td>Realm: </td>
+ <td><asp:Label runat="server" ID='realmLabel' /> </td>
</tr>
</table>
- <p>
- Allow this authentication to proceed?
- </p>
+ <p>Allow this to proceed? </p>
<uc1:ProfileFields ID="profileFields" runat="server" Visible="false" />
<asp:Button ID="yes_button" OnClick="Yes_Click" Text=" yes " runat="Server" />
<asp:Button ID="no_button" OnClick="No_Click" Text=" no " runat="Server" />
-</asp:Content> \ No newline at end of file
+</asp:Content>
diff --git a/samples/OpenIdProviderWebForms/decide.aspx.cs b/samples/OpenIdProviderWebForms/decide.aspx.cs
index 777a688..13f997f 100644
--- a/samples/OpenIdProviderWebForms/decide.aspx.cs
+++ b/samples/OpenIdProviderWebForms/decide.aspx.cs
@@ -12,61 +12,75 @@ namespace OpenIdProviderWebForms {
/// </summary>
public partial class decide : Page {
protected void Page_Load(object src, EventArgs e) {
- if (ProviderEndpoint.PendingAuthenticationRequest == null) {
+ if (ProviderEndpoint.PendingRequest == null) {
Response.Redirect("~/");
}
- if (ProviderEndpoint.PendingAuthenticationRequest.IsDirectedIdentity) {
- ProviderEndpoint.PendingAuthenticationRequest.LocalIdentifier = Code.Util.BuildIdentityUrl();
- }
this.relyingPartyVerificationResultLabel.Text =
- ProviderEndpoint.PendingAuthenticationRequest.IsReturnUrlDiscoverable(ProviderEndpoint.Provider.Channel.WebRequestHandler) ? "passed" : "failed";
+ ProviderEndpoint.PendingRequest.IsReturnUrlDiscoverable(ProviderEndpoint.Provider.Channel.WebRequestHandler) ? "passed" : "failed";
+
+ this.realmLabel.Text = ProviderEndpoint.PendingRequest.Realm.ToString();
- this.identityUrlLabel.Text = ProviderEndpoint.PendingAuthenticationRequest.LocalIdentifier.ToString();
- this.realmLabel.Text = ProviderEndpoint.PendingAuthenticationRequest.Realm.ToString();
+ if (ProviderEndpoint.PendingAuthenticationRequest != null) {
+ if (ProviderEndpoint.PendingAuthenticationRequest.IsDirectedIdentity) {
+ ProviderEndpoint.PendingAuthenticationRequest.LocalIdentifier = Code.Util.BuildIdentityUrl();
+ }
+ this.identityUrlLabel.Text = ProviderEndpoint.PendingAuthenticationRequest.LocalIdentifier.ToString();
- // check that the logged in user is the same as the user requesting authentication to the consumer. If not, then log them out.
- if (string.Equals(User.Identity.Name, Code.Util.ExtractUserName(ProviderEndpoint.PendingAuthenticationRequest.LocalIdentifier), StringComparison.OrdinalIgnoreCase)) {
- // if simple registration fields were used, then prompt the user for them
- var requestedFields = ProviderEndpoint.PendingAuthenticationRequest.GetExtension<ClaimsRequest>();
- if (requestedFields != null) {
- this.profileFields.Visible = true;
- this.profileFields.SetRequiredFieldsFromRequest(requestedFields);
- if (!IsPostBack) {
- var sregResponse = requestedFields.CreateResponse();
- sregResponse.Email = Membership.GetUser().Email;
- this.profileFields.SetOpenIdProfileFields(sregResponse);
- }
+ // check that the logged in user is the same as the user requesting authentication to the consumer. If not, then log them out.
+ if (!string.Equals(User.Identity.Name, Code.Util.ExtractUserName(ProviderEndpoint.PendingAuthenticationRequest.LocalIdentifier), StringComparison.OrdinalIgnoreCase)) {
+ FormsAuthentication.SignOut();
+ Response.Redirect(Request.Url.AbsoluteUri);
}
} else {
- FormsAuthentication.SignOut();
- Response.Redirect(Request.Url.AbsoluteUri);
+ this.identityUrlLabel.Text = "(not applicable)";
+ this.siteRequestLabel.Text = "A site has asked for information about you.";
+ }
+
+ // if simple registration fields were used, then prompt the user for them
+ var requestedFields = ProviderEndpoint.PendingRequest.GetExtension<ClaimsRequest>();
+ if (requestedFields != null) {
+ this.profileFields.Visible = true;
+ this.profileFields.SetRequiredFieldsFromRequest(requestedFields);
+ if (!IsPostBack) {
+ var sregResponse = requestedFields.CreateResponse();
+ sregResponse.Email = Membership.GetUser().Email;
+ this.profileFields.SetOpenIdProfileFields(sregResponse);
+ }
}
}
protected void Yes_Click(object sender, EventArgs e) {
- var sregRequest = ProviderEndpoint.PendingAuthenticationRequest.GetExtension<ClaimsRequest>();
+ var sregRequest = ProviderEndpoint.PendingRequest.GetExtension<ClaimsRequest>();
ClaimsResponse sregResponse = null;
if (sregRequest != null) {
sregResponse = this.profileFields.GetOpenIdProfileFields(sregRequest);
- ProviderEndpoint.PendingAuthenticationRequest.AddResponseExtension(sregResponse);
+ ProviderEndpoint.PendingRequest.AddResponseExtension(sregResponse);
}
- var papeRequest = ProviderEndpoint.PendingAuthenticationRequest.GetExtension<PolicyRequest>();
+ var papeRequest = ProviderEndpoint.PendingRequest.GetExtension<PolicyRequest>();
PolicyResponse papeResponse = null;
if (papeRequest != null) {
papeResponse = new PolicyResponse();
papeResponse.NistAssuranceLevel = NistAssuranceLevel.InsufficientForLevel1;
- ProviderEndpoint.PendingAuthenticationRequest.AddResponseExtension(papeResponse);
+ ProviderEndpoint.PendingRequest.AddResponseExtension(papeResponse);
}
- ProviderEndpoint.PendingAuthenticationRequest.IsAuthenticated = true;
- Debug.Assert(ProviderEndpoint.PendingAuthenticationRequest.IsResponseReady, "Setting authentication should be all that's necessary.");
+ if (ProviderEndpoint.PendingAuthenticationRequest != null) {
+ ProviderEndpoint.PendingAuthenticationRequest.IsAuthenticated = true;
+ } else {
+ ProviderEndpoint.PendingAnonymousRequest.IsApproved = true;
+ }
+ Debug.Assert(ProviderEndpoint.PendingRequest.IsResponseReady, "Setting authentication should be all that's necessary.");
ProviderEndpoint.SendResponse();
}
protected void No_Click(object sender, EventArgs e) {
- ProviderEndpoint.PendingAuthenticationRequest.IsAuthenticated = false;
- Debug.Assert(ProviderEndpoint.PendingAuthenticationRequest.IsResponseReady, "Setting authentication should be all that's necessary.");
+ if (ProviderEndpoint.PendingAuthenticationRequest != null) {
+ ProviderEndpoint.PendingAuthenticationRequest.IsAuthenticated = false;
+ } else {
+ ProviderEndpoint.PendingAnonymousRequest.IsApproved = false;
+ }
+ Debug.Assert(ProviderEndpoint.PendingRequest.IsResponseReady, "Setting authentication should be all that's necessary.");
ProviderEndpoint.SendResponse();
}
}
diff --git a/samples/OpenIdProviderWebForms/decide.aspx.designer.cs b/samples/OpenIdProviderWebForms/decide.aspx.designer.cs
index 795d1c7..05386cd 100644
--- a/samples/OpenIdProviderWebForms/decide.aspx.designer.cs
+++ b/samples/OpenIdProviderWebForms/decide.aspx.designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.3521
+// Runtime Version:2.0.50727.4918
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -14,6 +14,15 @@ namespace OpenIdProviderWebForms {
public partial class decide {
/// <summary>
+ /// siteRequestLabel control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label siteRequestLabel;
+
+ /// <summary>
/// relyingPartyVerificationResultLabel control.
/// </summary>
/// <remarks>
diff --git a/samples/OpenIdProviderWebForms/server.aspx b/samples/OpenIdProviderWebForms/server.aspx
index 10030a6..d3ce78d 100644
--- a/samples/OpenIdProviderWebForms/server.aspx
+++ b/samples/OpenIdProviderWebForms/server.aspx
@@ -14,7 +14,7 @@
This server.aspx page is the default provider endpoint to use. To switch to the .ashx handler,
change the user_xrds.aspx and op_xrds.aspx files to point to provider.ashx instead of server.aspx.
--%>
- <openid:ProviderEndpoint runat="server" OnAuthenticationChallenge="provider_AuthenticationChallenge" />
+ <openid:ProviderEndpoint runat="server" OnAuthenticationChallenge="provider_AuthenticationChallenge" OnAnonymousRequest="provider_AnonymousRequest" />
<p>
<asp:Label ID="serverEndpointUrl" runat="server" EnableViewState="false" />
is an OpenID server endpoint.
diff --git a/samples/OpenIdProviderWebForms/server.aspx.cs b/samples/OpenIdProviderWebForms/server.aspx.cs
index c0af0b4..89e14f4 100644
--- a/samples/OpenIdProviderWebForms/server.aspx.cs
+++ b/samples/OpenIdProviderWebForms/server.aspx.cs
@@ -14,5 +14,9 @@ namespace OpenIdProviderWebForms {
protected void provider_AuthenticationChallenge(object sender, AuthenticationChallengeEventArgs e) {
Code.Util.ProcessAuthenticationChallenge(e.Request);
}
+
+ protected void provider_AnonymousRequest(object sender, AnonymousRequestEventArgs e) {
+ Code.Util.ProcessAnonymousRequest(e.Request);
+ }
}
} \ No newline at end of file
diff --git a/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx b/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx
new file mode 100644
index 0000000..dc0c2bb
--- /dev/null
+++ b/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx
@@ -0,0 +1,41 @@
+<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="NoIdentityOpenId.aspx.cs"
+ MasterPageFile="~/Site.Master" Inherits="OpenIdRelyingPartyWebForms.NoIdentityOpenId" %>
+
+<asp:Content runat="server" ContentPlaceHolderID="Main">
+ <h2>No-login OpenID extension Page </h2>
+ <p>This demonstrates an RP sending an extension-only request to an OP that carries
+ extensions that request anonymous information about you. In this scenario, the OP
+ would still authenticate the user, but would not assert any OpenID Identifier back
+ to the RP, but might provide information regarding the user such as age or membership
+ in an organization. </p>
+ <p><b>Note: </b>At time of this writing, most OPs do not support this feature, although
+ it is documented in the OpenID 2.0 spec. </p>
+ <asp:Label ID="Label1" runat="server" Text="OpenID Identifier" /> <asp:TextBox ID="openIdBox"
+ runat="server" />
+ <asp:Button ID="beginButton" runat="server" Text="Begin" OnClick="beginButton_Click" />
+ <asp:CustomValidator runat="server" ID="openidValidator" ErrorMessage="Invalid OpenID Identifier"
+ ControlToValidate="openIdBox" EnableViewState="false" Display="Dynamic" OnServerValidate="openidValidator_ServerValidate" />
+ <asp:Label runat="server" EnableViewState="false" ID="resultMessage" />
+ <asp:Panel runat="server" ID="ExtensionResponsesPanel" EnableViewState="false" Visible="false">
+ <p>We have received a reasonable response from the Provider. Below is the Simple Registration
+ response we received, if any: </p>
+ <table id="profileFieldsTable" runat="server">
+ <tr>
+ <td>Gender </td>
+ <td><asp:Label runat="server" ID="genderLabel" /> </td>
+ </tr>
+ <tr>
+ <td>Post Code </td>
+ <td><asp:Label runat="server" ID="postalCodeLabel" /> </td>
+ </tr>
+ <tr>
+ <td>Country </td>
+ <td><asp:Label runat="server" ID="countryLabel" /> </td>
+ </tr>
+ <tr>
+ <td>Timezone </td>
+ <td><asp:Label runat="server" ID="timeZoneLabel" /> </td>
+ </tr>
+ </table>
+ </asp:Panel>
+</asp:Content>
diff --git a/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.cs b/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.cs
new file mode 100644
index 0000000..8b9ea78
--- /dev/null
+++ b/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.cs
@@ -0,0 +1,79 @@
+namespace OpenIdRelyingPartyWebForms {
+ using System;
+ using System.Web.UI.WebControls;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
+ using DotNetOpenAuth.OpenId.RelyingParty;
+
+ public partial class NoIdentityOpenId : System.Web.UI.Page {
+ protected void Page_Load(object sender, EventArgs e) {
+ openIdBox.Focus();
+ using (OpenIdRelyingParty rp = new OpenIdRelyingParty()) {
+ IAuthenticationResponse response = rp.GetResponse();
+ if (response != null) {
+ switch (response.Status) {
+ case AuthenticationStatus.ExtensionsOnly:
+ ExtensionResponsesPanel.Visible = true;
+
+ // This is the "success" status we get when no authentication was requested.
+ var sreg = response.GetExtension<ClaimsResponse>();
+ if (sreg != null) {
+ timeZoneLabel.Text = sreg.TimeZone;
+ postalCodeLabel.Text = sreg.PostalCode;
+ countryLabel.Text = sreg.Country;
+ if (sreg.Gender.HasValue) {
+ genderLabel.Text = sreg.Gender.Value.ToString();
+ }
+ }
+ break;
+ case AuthenticationStatus.Canceled:
+ resultMessage.Text = "Canceled at OP. This may be a sign that the OP doesn't support this message.";
+ break;
+ case AuthenticationStatus.Failed:
+ resultMessage.Text = "OP returned a failure: " + response.Exception;
+ break;
+ case AuthenticationStatus.SetupRequired:
+ case AuthenticationStatus.Authenticated:
+ default:
+ resultMessage.Text = "OP returned an unexpected response.";
+ break;
+ }
+ }
+ }
+ }
+
+ protected void beginButton_Click(object sender, EventArgs e) {
+ if (!this.Page.IsValid) {
+ return; // don't login if custom validation failed.
+ }
+ try {
+ using (OpenIdRelyingParty rp = new OpenIdRelyingParty()) {
+ var request = rp.CreateRequest(openIdBox.Text);
+ request.IsExtensionOnly = true;
+
+ // This is where you would add any OpenID extensions you wanted
+ // to include in the request.
+ request.AddExtension(new ClaimsRequest {
+ Country = DemandLevel.Request,
+ Gender = DemandLevel.Require,
+ PostalCode = DemandLevel.Require,
+ TimeZone = DemandLevel.Require,
+ });
+
+ request.RedirectToProvider();
+ }
+ } catch (ProtocolException ex) {
+ // The user probably entered an Identifier that
+ // was not a valid OpenID endpoint.
+ this.openidValidator.Text = ex.Message;
+ this.openidValidator.IsValid = false;
+ }
+ }
+
+ protected void openidValidator_ServerValidate(object source, ServerValidateEventArgs args) {
+ // This catches common typos that result in an invalid OpenID Identifier.
+ args.IsValid = Identifier.IsValid(args.Value);
+ }
+ }
+}
diff --git a/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.designer.cs b/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.designer.cs
new file mode 100644
index 0000000..fb959a3
--- /dev/null
+++ b/samples/OpenIdRelyingPartyWebForms/NoIdentityOpenId.aspx.designer.cs
@@ -0,0 +1,115 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.4918
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace OpenIdRelyingPartyWebForms {
+
+
+ public partial class NoIdentityOpenId {
+
+ /// <summary>
+ /// Label1 control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label Label1;
+
+ /// <summary>
+ /// openIdBox control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.TextBox openIdBox;
+
+ /// <summary>
+ /// beginButton control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Button beginButton;
+
+ /// <summary>
+ /// openidValidator control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.CustomValidator openidValidator;
+
+ /// <summary>
+ /// resultMessage control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label resultMessage;
+
+ /// <summary>
+ /// ExtensionResponsesPanel control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Panel ExtensionResponsesPanel;
+
+ /// <summary>
+ /// profileFieldsTable control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.HtmlControls.HtmlTable profileFieldsTable;
+
+ /// <summary>
+ /// genderLabel control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label genderLabel;
+
+ /// <summary>
+ /// postalCodeLabel control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label postalCodeLabel;
+
+ /// <summary>
+ /// countryLabel control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label countryLabel;
+
+ /// <summary>
+ /// timeZoneLabel control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.Label timeZoneLabel;
+ }
+}
diff --git a/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj b/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj
index c45f007..556dadf 100644
--- a/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj
+++ b/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj
@@ -139,6 +139,13 @@
<Compile Include="m\Login.aspx.designer.cs">
<DependentUpon>Login.aspx</DependentUpon>
</Compile>
+ <Compile Include="NoIdentityOpenId.aspx.cs">
+ <DependentUpon>NoIdentityOpenId.aspx</DependentUpon>
+ <SubType>ASPXCodeBehind</SubType>
+ </Compile>
+ <Compile Include="NoIdentityOpenId.aspx.designer.cs">
+ <DependentUpon>NoIdentityOpenId.aspx</DependentUpon>
+ </Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TracePage.aspx.cs">
<DependentUpon>TracePage.aspx</DependentUpon>
@@ -163,6 +170,7 @@
<Content Include="MembersOnly\DisplayGoogleContacts.aspx" />
<Content Include="MembersOnly\Web.config" />
<Content Include="m\Login.aspx" />
+ <Content Include="NoIdentityOpenId.aspx" />
</ItemGroup>
<ItemGroup>
<None Include="Code\CustomStoreDataSet.xsc">
diff --git a/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs b/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs
index 436ef7b..d175fc8 100644
--- a/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs
+++ b/samples/OpenIdRelyingPartyWebForms/login.aspx.designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.4912
+// Runtime Version:2.0.50727.4918
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
diff --git a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx
index a00eccd..78179f7 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx
+++ b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx
@@ -12,4 +12,5 @@
Visible="False" />
<asp:Label ID="loginCanceledLabel" runat="server" EnableViewState="False" Text="Login canceled"
Visible="False" />
+ <asp:CheckBox ID="noLoginCheckBox" runat="server" Text="Extensions only (no login) -- most OPs don't yet support this" />
</asp:Content> \ No newline at end of file
diff --git a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.cs b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.cs
index fe73b7e..ed11148 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.cs
+++ b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.cs
@@ -41,11 +41,6 @@
// was not a valid OpenID endpoint.
this.openidValidator.Text = ex.Message;
this.openidValidator.IsValid = false;
- } catch (WebException ex) {
- // The user probably entered an Identifier that
- // was not a valid OpenID endpoint.
- this.openidValidator.Text = ex.Message;
- this.openidValidator.IsValid = false;
}
}
diff --git a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs
index 0363be7..239d7b8 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs
+++ b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.4912
+// Runtime Version:2.0.50727.4918
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -66,5 +66,14 @@ namespace OpenIdRelyingPartyWebForms {
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label loginCanceledLabel;
+
+ /// <summary>
+ /// noLoginCheckBox control.
+ /// </summary>
+ /// <remarks>
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ /// </remarks>
+ protected global::System.Web.UI.WebControls.CheckBox noLoginCheckBox;
}
}
diff --git a/samples/OpenIdRelyingPartyWebForms/xrds.aspx b/samples/OpenIdRelyingPartyWebForms/xrds.aspx
index e169bc7..9e201d0 100644
--- a/samples/OpenIdRelyingPartyWebForms/xrds.aspx
+++ b/samples/OpenIdRelyingPartyWebForms/xrds.aspx
@@ -17,6 +17,7 @@ is default.aspx.
<URI priority="1"><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/login.aspx"))%></URI>
<URI priority="2"><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/loginProgrammatic.aspx"))%></URI>
<URI priority="3"><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/ajaxlogin.aspx"))%></URI>
+ <URI priority="3"><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/NoIdentityOpenId.aspx"))%></URI>
</Service>
</XRD>
</xrds:XRDS>
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index a6069b4..1f3df12 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -368,10 +368,15 @@
<Compile Include="OpenId\Messages\SignedResponseRequest.cs" />
<Compile Include="OpenId\NoDiscoveryIdentifier.cs" />
<Compile Include="OpenId\OpenIdUtilities.cs" />
+ <Compile Include="OpenId\Provider\AnonymousRequest.cs" />
+ <Compile Include="OpenId\Provider\AnonymousRequestEventArgs.cs" />
<Compile Include="OpenId\Provider\AuthenticationChallengeEventArgs.cs" />
<Compile Include="OpenId\Provider\AuthenticationRequest.cs" />
<Compile Include="OpenId\Provider\AutoResponsiveRequest.cs" />
+ <Compile Include="OpenId\Provider\HostProcessedRequest.cs" />
+ <Compile Include="OpenId\Provider\IAnonymousRequest.cs" />
<Compile Include="OpenId\Provider\IAuthenticationRequest.cs" />
+ <Compile Include="OpenId\Provider\IHostProcessedRequest.cs" />
<Compile Include="OpenId\Provider\IdentityEndpoint.cs" />
<Compile Include="OpenId\Provider\IdentityEndpointNormalizationEventArgs.cs" />
<Compile Include="OpenId\Provider\IErrorReporting.cs" />
@@ -418,6 +423,7 @@
<Compile Include="OpenId\RelyingParty\OpenIdLogin.cs" />
<Compile Include="OpenId\RelyingParty\OpenIdMobileTextBox.cs" />
<Compile Include="OpenId\RelyingParty\OpenIdTextBox.cs" />
+ <Compile Include="OpenId\RelyingParty\PositiveAnonymousResponse.cs" />
<Compile Include="OpenId\RelyingParty\PositiveAuthenticationResponse.cs" />
<Compile Include="OpenId\RelyingParty\AuthenticationStatus.cs" />
<Compile Include="OpenId\RelyingParty\FailedAuthenticationResponse.cs" />
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs
index c8ffae8..31a2da5 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdMessageFactory.cs
@@ -57,6 +57,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
if (fields.ContainsKey(protocol.openid.identity)) {
message = new CheckIdRequest(protocol.Version, recipient.Location, authMode);
} else {
+ ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent);
message = new SignedResponseRequest(protocol.Version, recipient.Location, authMode);
}
} else if (string.Equals(mode, protocol.Args.Mode.cancel) ||
@@ -66,6 +67,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
if (fields.ContainsKey(protocol.openid.identity)) {
message = new PositiveAssertionResponse(protocol.Version, recipient.Location);
} else {
+ ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent);
message = new IndirectSignedResponse(protocol.Version, recipient.Location);
}
} else if (string.Equals(mode, protocol.Args.Mode.check_authentication)) {
diff --git a/src/DotNetOpenAuth/OpenId/Messages/NegativeAssertionResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/NegativeAssertionResponse.cs
index f03422c..99a7c5a 100644
--- a/src/DotNetOpenAuth/OpenId/Messages/NegativeAssertionResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Messages/NegativeAssertionResponse.cs
@@ -31,12 +31,13 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// </summary>
/// <param name="request">The request that the relying party sent.</param>
/// <param name="channel">The channel to use to simulate construction of the user_setup_url, if applicable. May be null, but the user_setup_url will not be constructed.</param>
- internal NegativeAssertionResponse(CheckIdRequest request, Channel channel)
+ internal NegativeAssertionResponse(SignedResponseRequest request, Channel channel)
: base(request, GetMode(request)) {
// If appropriate, and when we're provided with a channel to do it,
// go ahead and construct the user_setup_url
if (this.Version.Major < 2 && request.Immediate && channel != null) {
- this.UserSetupUrl = ConstructUserSetupUrl(request, channel);
+ // All requests are CheckIdRequests in OpenID 1.x, so this cast should be safe.
+ this.UserSetupUrl = ConstructUserSetupUrl((CheckIdRequest)request, channel);
}
}
@@ -130,7 +131,7 @@ namespace DotNetOpenAuth.OpenId.Messages {
/// </summary>
/// <param name="request">The request that we're responding to.</param>
/// <returns>The value of the openid.mode parameter to use.</returns>
- private static string GetMode(CheckIdRequest request) {
+ private static string GetMode(SignedResponseRequest request) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
Protocol protocol = Protocol.Lookup(request.Version);
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
index a6e02fe..033ea54 100644
--- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
@@ -259,6 +259,15 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
+ /// Looks up a localized string similar to The openid.identity and openid.claimed_id parameters must either be both present or both absent from the message..
+ /// </summary>
+ internal static string IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent {
+ get {
+ return ResourceManager.GetString("IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The Provider requested association type &apos;{0}&apos; and session type &apos;{1}&apos;, which are not compatible with each other..
/// </summary>
internal static string IncompatibleAssociationAndSessionTypes {
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
index 95fe655..2b934f5 100644
--- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
+++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
@@ -301,4 +301,7 @@ Discovered endpoint info:
<data name="UnsupportedChannelConfiguration" xml:space="preserve">
<value>This feature is unavailable due to an unrecognized channel configuration.</value>
</data>
+ <data name="IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent" xml:space="preserve">
+ <value>The openid.identity and openid.claimed_id parameters must either be both present or both absent from the message.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs
new file mode 100644
index 0000000..546db9f
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs
@@ -0,0 +1,74 @@
+//-----------------------------------------------------------------------
+// <copyright file="AnonymousRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System.Diagnostics.Contracts;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+
+ /// <summary>
+ /// Provides access to a host Provider to read an incoming extension-only checkid request message,
+ /// and supply extension responses or a cancellation message to the RP.
+ /// </summary>
+ internal class AnonymousRequest : HostProcessedRequest, IAnonymousRequest {
+ /// <summary>
+ /// The extension-response message to send, if the host site chooses to send it.
+ /// </summary>
+ private readonly IndirectSignedResponse positiveResponse;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AnonymousRequest"/> class.
+ /// </summary>
+ /// <param name="provider">The provider that received the request.</param>
+ /// <param name="request">The incoming authentication request message.</param>
+ internal AnonymousRequest(OpenIdProvider provider, SignedResponseRequest request)
+ : base(provider, request) {
+ Contract.Requires(provider != null);
+ Contract.Requires(!(request is CheckIdRequest), "Instantiate " + typeof(AuthenticationRequest).Name + " to handle this kind of message.");
+ ErrorUtilities.VerifyInternal(!(request is CheckIdRequest), "Instantiate {0} to handle this kind of message.", typeof(AuthenticationRequest).Name);
+
+ this.positiveResponse = new IndirectSignedResponse(request);
+ }
+
+ #region IAnonymousRequest Members
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the user approved sending any data to the relying party.
+ /// </summary>
+ /// <value><c>true</c> if approved; otherwise, <c>false</c>.</value>
+ public bool? IsApproved { get; set; }
+
+ #endregion
+
+ #region Request members
+
+ /// <summary>
+ /// Gets a value indicating whether the response is ready to be sent to the user agent.
+ /// </summary>
+ /// <remarks>
+ /// This property returns false if there are properties that must be set on this
+ /// request instance before the response can be sent.
+ /// </remarks>
+ public override bool IsResponseReady {
+ get { return this.IsApproved.HasValue; }
+ }
+
+ /// <summary>
+ /// Gets the response message, once <see cref="IsResponseReady"/> is <c>true</c>.
+ /// </summary>
+ protected override IProtocolMessage ResponseMessage {
+ get {
+ if (this.IsApproved.HasValue) {
+ return this.IsApproved.Value ? (IProtocolMessage)this.positiveResponse : this.NegativeResponse;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequestEventArgs.cs b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequestEventArgs.cs
new file mode 100644
index 0000000..cdd5311
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequestEventArgs.cs
@@ -0,0 +1,32 @@
+//-----------------------------------------------------------------------
+// <copyright file="AnonymousRequestEventArgs.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
+ using System.Diagnostics.Contracts;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The event arguments that include details of the incoming request.
+ /// </summary>
+ public class AnonymousRequestEventArgs : EventArgs {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AnonymousRequestEventArgs"/> class.
+ /// </summary>
+ /// <param name="request">The incoming OpenID request.</param>
+ internal AnonymousRequestEventArgs(IAnonymousRequest request) {
+ Contract.Requires(request != null);
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+
+ this.Request = request;
+ }
+
+ /// <summary>
+ /// Gets the incoming OpenID request.
+ /// </summary>
+ public IAnonymousRequest Request { get; private set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs
index 34ade49..7a547dd 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs
@@ -6,10 +6,7 @@
namespace DotNetOpenAuth.OpenId.Provider {
using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Text;
+ using System.Diagnostics.Contracts;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Messages;
@@ -19,28 +16,23 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// requests.
/// </summary>
[Serializable]
- internal class AuthenticationRequest : Request, IAuthenticationRequest {
+ internal class AuthenticationRequest : HostProcessedRequest, IAuthenticationRequest {
/// <summary>
/// The positive assertion to send, if the host site chooses to send it.
/// </summary>
private readonly PositiveAssertionResponse positiveResponse;
/// <summary>
- /// The negative assertion to send, if the host site chooses to send it.
- /// </summary>
- private readonly NegativeAssertionResponse negativeResponse;
-
- /// <summary>
/// Initializes a new instance of the <see cref="AuthenticationRequest"/> class.
/// </summary>
/// <param name="provider">The provider that received the request.</param>
/// <param name="request">The incoming authentication request message.</param>
internal AuthenticationRequest(OpenIdProvider provider, CheckIdRequest request)
- : base(request) {
+ : base(provider, request) {
+ Contract.Requires(provider != null);
ErrorUtilities.VerifyArgumentNotNull(provider, "provider");
this.positiveResponse = new PositiveAssertionResponse(request);
- this.negativeResponse = new NegativeAssertionResponse(request, provider.Channel);
if (this.ClaimedIdentifier == Protocol.ClaimedIdentifierForOPIdentifier &&
Protocol.ClaimedIdentifierForOPIdentifier != null) {
@@ -71,29 +63,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
#region IAuthenticationRequest Properties
/// <summary>
- /// Gets the version of OpenID being used by the relying party that sent the request.
- /// </summary>
- public ProtocolVersion RelyingPartyVersion {
- get { return Protocol.Lookup(this.RequestMessage.Version).ProtocolVersion; }
- }
-
- /// <summary>
- /// Gets a value indicating whether the consumer demands an immediate response.
- /// If false, the consumer is willing to wait for the identity provider
- /// to authenticate the user.
- /// </summary>
- public bool Immediate {
- get { return this.RequestMessage.Immediate; }
- }
-
- /// <summary>
- /// Gets the URL the consumer site claims to use as its 'base' address.
- /// </summary>
- public Realm Realm {
- get { return this.RequestMessage.Realm; }
- }
-
- /// <summary>
/// Gets a value indicating whether the Provider should help the user
/// select a Claimed Identifier to send back to the relying party.
/// </summary>
@@ -197,7 +166,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
protected override IProtocolMessage ResponseMessage {
get {
if (this.IsAuthenticated.HasValue) {
- return this.IsAuthenticated.Value ? (IProtocolMessage)this.positiveResponse : this.negativeResponse;
+ return this.IsAuthenticated.Value ? (IProtocolMessage)this.positiveResponse : this.NegativeResponse;
} else {
return null;
}
@@ -231,53 +200,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
this.positiveResponse.ClaimedIdentifier = builder.Uri;
}
- /// <summary>
- /// Gets a value indicating whether verification of the return URL claimed by the Relying Party
- /// succeeded.
- /// </summary>
- /// <param name="requestHandler">The request handler to use to perform relying party discovery.</param>
- /// <returns>
- /// <c>true</c> if the Relying Party passed discovery verification; <c>false</c> otherwise.
- /// </returns>
- /// <remarks>
- /// Return URL verification is only attempted if this property is queried.
- /// The result of the verification is cached per request so calling this
- /// property getter multiple times in one request is not a performance hit.
- /// See OpenID Authentication 2.0 spec section 9.2.1.
- /// </remarks>
- public bool IsReturnUrlDiscoverable(IDirectWebRequestHandler requestHandler) {
- ErrorUtilities.VerifyArgumentNotNull(requestHandler, "requestHandler");
-
- ErrorUtilities.VerifyInternal(this.Realm != null, "Realm should have been read or derived by now.");
- try {
- foreach (var returnUrl in Realm.Discover(requestHandler, false)) {
- Realm discoveredReturnToUrl = returnUrl.ReturnToEndpoint;
-
- // The spec requires that the return_to URLs given in an RPs XRDS doc
- // do not contain wildcards.
- if (discoveredReturnToUrl.DomainWildcard) {
- Logger.Yadis.WarnFormat("Realm {0} contained return_to URL {1} which contains a wildcard, which is not allowed.", Realm, discoveredReturnToUrl);
- continue;
- }
-
- // Use the same rules as return_to/realm matching to check whether this
- // URL fits the return_to URL we were given.
- if (discoveredReturnToUrl.Contains(this.RequestMessage.ReturnTo)) {
- // no need to keep looking after we find a match
- return true;
- }
- }
- } catch (ProtocolException ex) {
- // Don't do anything else. We quietly fail at return_to verification and return false.
- Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex);
- } catch (WebException ex) {
- // Don't do anything else. We quietly fail at return_to verification and return false.
- Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex);
- }
-
- return false;
- }
-
#endregion
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs
new file mode 100644
index 0000000..f4f42a4
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs
@@ -0,0 +1,131 @@
+//-----------------------------------------------------------------------
+// <copyright file="HostProcessedRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+
+ /// <summary>
+ /// A base class from which identity and non-identity RP requests can derive.
+ /// </summary>
+ internal abstract class HostProcessedRequest : Request, IHostProcessedRequest {
+ /// <summary>
+ /// The negative assertion to send, if the host site chooses to send it.
+ /// </summary>
+ private readonly NegativeAssertionResponse negativeResponse;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="HostProcessedRequest"/> class.
+ /// </summary>
+ /// <param name="provider">The provider that received the request.</param>
+ /// <param name="request">The incoming request message.</param>
+ protected HostProcessedRequest(OpenIdProvider provider, SignedResponseRequest request)
+ : base(request) {
+ Contract.Requires(provider != null);
+
+ this.negativeResponse = new NegativeAssertionResponse(request, provider.Channel);
+ }
+
+ #region IHostProcessedRequest Properties
+
+ /// <summary>
+ /// Gets the version of OpenID being used by the relying party that sent the request.
+ /// </summary>
+ public ProtocolVersion RelyingPartyVersion {
+ get { return Protocol.Lookup(this.RequestMessage.Version).ProtocolVersion; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the consumer demands an immediate response.
+ /// If false, the consumer is willing to wait for the identity provider
+ /// to authenticate the user.
+ /// </summary>
+ public bool Immediate {
+ get { return this.RequestMessage.Immediate; }
+ }
+
+ /// <summary>
+ /// Gets the URL the consumer site claims to use as its 'base' address.
+ /// </summary>
+ public Realm Realm {
+ get { return this.RequestMessage.Realm; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets the negative response.
+ /// </summary>
+ protected NegativeAssertionResponse NegativeResponse {
+ get { return this.negativeResponse; }
+ }
+
+ /// <summary>
+ /// Gets the original request message.
+ /// </summary>
+ /// <value>This may be null in the case of an unrecognizable message.</value>
+ protected new SignedResponseRequest RequestMessage {
+ get { return (SignedResponseRequest)base.RequestMessage; }
+ }
+
+ #region IHostProcessedRequest Methods
+
+ /// <summary>
+ /// Gets a value indicating whether verification of the return URL claimed by the Relying Party
+ /// succeeded.
+ /// </summary>
+ /// <param name="requestHandler">The request handler to use to perform relying party discovery.</param>
+ /// <returns>
+ /// <c>true</c> if the Relying Party passed discovery verification; <c>false</c> otherwise.
+ /// </returns>
+ /// <remarks>
+ /// Return URL verification is only attempted if this property is queried.
+ /// The result of the verification is cached per request so calling this
+ /// property getter multiple times in one request is not a performance hit.
+ /// See OpenID Authentication 2.0 spec section 9.2.1.
+ /// </remarks>
+ public bool IsReturnUrlDiscoverable(IDirectWebRequestHandler requestHandler) {
+ ErrorUtilities.VerifyArgumentNotNull(requestHandler, "requestHandler");
+
+ ErrorUtilities.VerifyInternal(this.Realm != null, "Realm should have been read or derived by now.");
+ try {
+ foreach (var returnUrl in Realm.Discover(requestHandler, false)) {
+ Realm discoveredReturnToUrl = returnUrl.ReturnToEndpoint;
+
+ // The spec requires that the return_to URLs given in an RPs XRDS doc
+ // do not contain wildcards.
+ if (discoveredReturnToUrl.DomainWildcard) {
+ Logger.Yadis.WarnFormat("Realm {0} contained return_to URL {1} which contains a wildcard, which is not allowed.", Realm, discoveredReturnToUrl);
+ continue;
+ }
+
+ // Use the same rules as return_to/realm matching to check whether this
+ // URL fits the return_to URL we were given.
+ if (discoveredReturnToUrl.Contains(this.RequestMessage.ReturnTo)) {
+ // no need to keep looking after we find a match
+ return true;
+ }
+ }
+ } catch (ProtocolException ex) {
+ // Don't do anything else. We quietly fail at return_to verification and return false.
+ Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex);
+ } catch (WebException ex) {
+ // Don't do anything else. We quietly fail at return_to verification and return false.
+ Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex);
+ }
+
+ return false;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IAnonymousRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IAnonymousRequest.cs
new file mode 100644
index 0000000..ec2c175
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/IAnonymousRequest.cs
@@ -0,0 +1,25 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAnonymousRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+
+ /// <summary>
+ /// Instances of this interface represent incoming extension-only requests.
+ /// This interface provides the details of the request and allows setting
+ /// the response.
+ /// </summary>
+ public interface IAnonymousRequest : IHostProcessedRequest {
+ /// <summary>
+ /// Gets or sets a value indicating whether the user approved sending any data to the relying party.
+ /// </summary>
+ /// <value><c>true</c> if approved; otherwise, <c>false</c>.</value>
+ bool? IsApproved { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs
index b1ef269..bb837b5 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs
@@ -15,24 +15,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// This interface provides the details of the request and allows setting
/// the response.
/// </summary>
- public interface IAuthenticationRequest : IRequest {
- /// <summary>
- /// Gets the version of OpenID being used by the relying party that sent the request.
- /// </summary>
- ProtocolVersion RelyingPartyVersion { get; }
-
- /// <summary>
- /// Gets a value indicating whether the consumer demands an immediate response.
- /// If false, the consumer is willing to wait for the identity provider
- /// to authenticate the user.
- /// </summary>
- bool Immediate { get; }
-
- /// <summary>
- /// Gets the URL the consumer site claims to use as its 'base' address.
- /// </summary>
- Realm Realm { get; }
-
+ public interface IAuthenticationRequest : IHostProcessedRequest {
/// <summary>
/// Gets a value indicating whether the Provider should help the user
/// select a Claimed Identifier to send back to the relying party.
@@ -109,18 +92,5 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// request before the <see cref="ClaimedIdentifier"/> property is set.
/// </exception>
void SetClaimedIdentifierFragment(string fragment);
-
- /// <summary>
- /// Attempts to perform relying party discovery of the return URL claimed by the Relying Party.
- /// </summary>
- /// <param name="requestHandler">The request handler to use to perform relying party discovery.</param>
- /// <returns>
- /// <c>true</c> if the Relying Party passed discovery verification; <c>false</c> otherwise.
- /// </returns>
- /// <remarks>
- /// <para>Return URL verification is only attempted if this method is called.</para>
- /// <para>See OpenID Authentication 2.0 spec section 9.2.1.</para>
- /// </remarks>
- bool IsReturnUrlDiscoverable(IDirectWebRequestHandler requestHandler);
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs
new file mode 100644
index 0000000..31479a1
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/Provider/IHostProcessedRequest.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="IHostProcessedRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// Interface exposing incoming messages to the OpenID Provider that
+ /// require interaction with the host site.
+ /// </summary>
+ public interface IHostProcessedRequest : IRequest {
+ /// <summary>
+ /// Gets the version of OpenID being used by the relying party that sent the request.
+ /// </summary>
+ ProtocolVersion RelyingPartyVersion { get; }
+
+ /// <summary>
+ /// Gets the URL the consumer site claims to use as its 'base' address.
+ /// </summary>
+ Realm Realm { get; }
+
+ /// <summary>
+ /// Gets a value indicating whether the consumer demands an immediate response.
+ /// If false, the consumer is willing to wait for the identity provider
+ /// to authenticate the user.
+ /// </summary>
+ bool Immediate { get; }
+
+ /// <summary>
+ /// Attempts to perform relying party discovery of the return URL claimed by the Relying Party.
+ /// </summary>
+ /// <param name="requestHandler">The request handler to use to perform relying party discovery.</param>
+ /// <returns>
+ /// <c>true</c> if the Relying Party passed discovery verification; <c>false</c> otherwise.
+ /// </returns>
+ /// <remarks>
+ /// <para>Return URL verification is only attempted if this method is called.</para>
+ /// <para>See OpenID Authentication 2.0 spec section 9.2.1.</para>
+ /// </remarks>
+ bool IsReturnUrlDiscoverable(IDirectWebRequestHandler requestHandler);
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
index c3780a9..7bb404c 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs
@@ -204,6 +204,11 @@ namespace DotNetOpenAuth.OpenId.Provider {
return new AuthenticationRequest(this, checkIdMessage);
}
+ var extensionOnlyRequest = incomingMessage as SignedResponseRequest;
+ if (extensionOnlyRequest != null) {
+ return new AnonymousRequest(this, extensionOnlyRequest);
+ }
+
var checkAuthMessage = incomingMessage as CheckAuthenticationRequest;
if (checkAuthMessage != null) {
return new AutoResponsiveRequest(incomingMessage, new CheckAuthenticationResponse(checkAuthMessage, this));
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
index bec510b..91f10e6 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
@@ -27,7 +27,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <summary>
/// The key used to store the pending authentication request in the ASP.NET session.
/// </summary>
- private const string PendingAuthenticationRequestKey = "pendingAuthenticationRequestKey";
+ private const string PendingRequestKey = "pendingRequest";
/// <summary>
/// The default value for the <see cref="Enabled"/> property.
@@ -52,6 +52,12 @@ namespace DotNetOpenAuth.OpenId.Provider {
public event EventHandler<AuthenticationChallengeEventArgs> AuthenticationChallenge;
/// <summary>
+ /// Fired when an incoming OpenID message carries extension requests
+ /// but is not regarding any OpenID identifier.
+ /// </summary>
+ public event EventHandler<AnonymousRequestEventArgs> AnonymousRequest;
+
+ /// <summary>
/// Gets or sets the <see cref="OpenIdProvider"/> instance to use for all instances of this control.
/// </summary>
/// <value>The default value is an <see cref="OpenIdProvider"/> instance initialized according to the web.config file.</value>
@@ -76,8 +82,36 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// before responding to the relying party's authentication request.
/// </remarks>
public static IAuthenticationRequest PendingAuthenticationRequest {
- get { return HttpContext.Current.Session[PendingAuthenticationRequestKey] as IAuthenticationRequest; }
- set { HttpContext.Current.Session[PendingAuthenticationRequestKey] = value; }
+ get { return HttpContext.Current.Session[PendingRequestKey] as IAuthenticationRequest; }
+ set { HttpContext.Current.Session[PendingRequestKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets an incoming OpenID anonymous request that has not yet been responded to.
+ /// </summary>
+ /// <remarks>
+ /// This request is stored in the ASP.NET Session state, so it will survive across
+ /// redirects, postbacks, and transfers. This allows you to authenticate the user
+ /// yourself, and confirm his/her desire to provide data to the relying party site
+ /// before responding to the relying party's request.
+ /// </remarks>
+ public static IAnonymousRequest PendingAnonymousRequest {
+ get { return HttpContext.Current.Session[PendingRequestKey] as IAnonymousRequest; }
+ set { HttpContext.Current.Session[PendingRequestKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets an incoming OpenID request that has not yet been responded to.
+ /// </summary>
+ /// <remarks>
+ /// This request is stored in the ASP.NET Session state, so it will survive across
+ /// redirects, postbacks, and transfers. This allows you to authenticate the user
+ /// yourself, and confirm his/her desire to provide data to the relying party site
+ /// before responding to the relying party's request.
+ /// </remarks>
+ public static IHostProcessedRequest PendingRequest {
+ get { return HttpContext.Current.Session[PendingRequestKey] as IHostProcessedRequest; }
+ set { HttpContext.Current.Session[PendingRequestKey] = value; }
}
/// <summary>
@@ -100,8 +134,8 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// Sends the response for the <see cref="PendingAuthenticationRequest"/> and clears the property.
/// </summary>
public static void SendResponse() {
- Provider.SendResponse(PendingAuthenticationRequest);
- PendingAuthenticationRequest = null;
+ Provider.SendResponse(PendingRequest);
+ PendingRequest = null;
}
/// <summary>
@@ -125,13 +159,22 @@ namespace DotNetOpenAuth.OpenId.Provider {
// determine what incoming message was received
IRequest request = provider.GetRequest();
if (request != null) {
+ PendingRequest = null;
+
// process the incoming message appropriately and send the response
- if (!request.IsResponseReady) {
- var idrequest = (IAuthenticationRequest)request;
+ IAuthenticationRequest idrequest;
+ IAnonymousRequest anonRequest;
+ if ((idrequest = request as IAuthenticationRequest) != null) {
PendingAuthenticationRequest = idrequest;
this.OnAuthenticationChallenge(idrequest);
- } else {
- PendingAuthenticationRequest = null;
+ } else if ((anonRequest = request as IAnonymousRequest) != null) {
+ PendingAnonymousRequest = anonRequest;
+ if (!this.OnAnonymousRequest(anonRequest)) {
+ // This is a feature not supported by the OP, so
+ // go ahead and set disapproved so we can send a response.
+ Logger.OpenId.Warn("An incoming anonymous OpenID request message was detected, but the ProviderEndpoint.AnonymousRequest event is not handled, so returning cancellation message to relying party.");
+ anonRequest.IsApproved = false;
+ }
}
if (request.IsResponseReady) {
provider.SendResponse(request);
@@ -154,6 +197,21 @@ namespace DotNetOpenAuth.OpenId.Provider {
}
/// <summary>
+ /// Fires the <see cref="AnonymousRequest"/> event.
+ /// </summary>
+ /// <param name="request">The request to include in the event args.</param>
+ /// <returns><c>true</c> if there were any anonymous request handlers.</returns>
+ protected virtual bool OnAnonymousRequest(IAnonymousRequest request) {
+ var anonymousRequest = this.AnonymousRequest;
+ if (anonymousRequest != null) {
+ anonymousRequest(this, new AnonymousRequestEventArgs(request));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /// <summary>
/// Creates the default OpenIdProvider to use.
/// </summary>
/// <returns>The new instance of OpenIdProvider.</returns>
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
index 2e22aec..1f470b2 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
@@ -133,6 +133,16 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
}
/// <summary>
+ /// Gets or sets a value indicating whether this request only carries extensions
+ /// and is not a request to verify that the user controls some identifier.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this request is merely a carrier of extensions and is not
+ /// about an OpenID identifier; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsExtensionOnly { get; set; }
+
+ /// <summary>
/// Gets information about the OpenId Provider, as advertised by the
/// OpenId discovery documents found at the <see cref="ClaimedIdentifier"/>
/// location.
@@ -401,16 +411,22 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
}
/// <summary>
- /// Creates the authentication request message to send to the Provider,
+ /// Creates the request message to send to the Provider,
/// based on the properties in this instance.
/// </summary>
/// <returns>The message to send to the Provider.</returns>
- private CheckIdRequest CreateRequestMessage() {
+ private SignedResponseRequest CreateRequestMessage() {
Association association = this.GetAssociation();
- CheckIdRequest request = new CheckIdRequest(this.endpoint.Protocol.Version, this.endpoint.ProviderEndpoint, this.Mode);
- request.ClaimedIdentifier = this.endpoint.ClaimedIdentifier;
- request.LocalIdentifier = this.endpoint.ProviderLocalIdentifier;
+ SignedResponseRequest request;
+ if (!this.IsExtensionOnly) {
+ CheckIdRequest authRequest = new CheckIdRequest(this.endpoint.Protocol.Version, this.endpoint.ProviderEndpoint, this.Mode);
+ authRequest.ClaimedIdentifier = this.endpoint.ClaimedIdentifier;
+ authRequest.LocalIdentifier = this.endpoint.ProviderLocalIdentifier;
+ request = authRequest;
+ } else {
+ request = new SignedResponseRequest(this.endpoint.Protocol.Version, this.endpoint.ProviderEndpoint, this.Mode);
+ }
request.Realm = this.Realm;
request.ReturnTo = this.ReturnToUrl;
request.AssociationHandle = association != null ? association.Handle : null;
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationStatus.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationStatus.cs
index c67355d..d9e5d0a 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationStatus.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationStatus.cs
@@ -33,5 +33,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// Authentication is completed successfully.
/// </summary>
Authenticated,
+
+ /// <summary>
+ /// The Provider sent a message that did not contain an identity assertion,
+ /// but may carry OpenID extensions.
+ /// </summary>
+ ExtensionsOnly,
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs
index 4892092..0bfcaf5 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs
@@ -63,6 +63,30 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
bool IsDirectedIdentity { get; }
/// <summary>
+ /// Gets or sets a value indicating whether this request only carries extensions
+ /// and is not a request to verify that the user controls some identifier.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this request is merely a carrier of extensions and is not
+ /// about an OpenID identifier; otherwise, <c>false</c>.
+ /// </value>
+ /// <remarks>
+ /// <para>Although OpenID is first and primarily an authentication protocol, its extensions
+ /// can be interesting all by themselves. For instance, a relying party might want
+ /// to know that its user is over 21 years old, or perhaps a member of some organization.
+ /// OpenID extensions can provide this, without any need for asserting the identity of the user.</para>
+ /// <para>Constructing an OpenID request for only extensions can be done by calling
+ /// <see cref="OpenIdRelyingParty.CreateRequest(Identifier)"/> with any valid OpenID identifier
+ /// (claimed identifier or OP identifier). But once this property is set to <c>true</c>,
+ /// the claimed identifier value in the request is not included in the transmitted message.</para>
+ /// <para>It is anticipated that an RP would only issue these types of requests to OPs that
+ /// trusts to make assertions regarding the individual holding an account at that OP, so it
+ /// is not likely that the RP would allow the user to type in an arbitrary claimed identifier
+ /// without checking that it resolved to an OP endpoint the RP has on a trust whitelist.</para>
+ /// </remarks>
+ bool IsExtensionOnly { get; set; }
+
+ /// <summary>
/// Gets information about the OpenId Provider, as advertised by the
/// OpenId discovery documents found at the <see cref="ClaimedIdentifier"/>
/// location.
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
index 4bcaf10..3762602 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
@@ -342,8 +342,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
var message = this.Channel.ReadFromRequest(httpRequestInfo);
PositiveAssertionResponse positiveAssertion;
NegativeAssertionResponse negativeAssertion;
+ IndirectSignedResponse positiveExtensionOnly;
if ((positiveAssertion = message as PositiveAssertionResponse) != null) {
return new PositiveAuthenticationResponse(positiveAssertion, this);
+ } else if ((positiveExtensionOnly = message as IndirectSignedResponse) != null) {
+ return new PositiveAnonymousResponse(positiveExtensionOnly);
} else if ((negativeAssertion = message as NegativeAssertionResponse) != null) {
return new NegativeAuthenticationResponse(negativeAssertion);
} else if (message != null) {
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdTextBox.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdTextBox.cs
index c86647a..1eea315 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdTextBox.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdTextBox.cs
@@ -1033,8 +1033,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
case AuthenticationStatus.Failed:
this.OnFailed(response);
break;
+ case AuthenticationStatus.ExtensionsOnly:
default:
- throw new InvalidOperationException("Unexpected response status code.");
+ // The NotApplicable (extension-only assertion) is NOT one that we support
+ // in this control because that scenario is primarily interesting to RPs
+ // that are asking a specific OP, and it is not user-initiated as this textbox
+ // is designed for.
+ throw new InvalidOperationException(MessagingStrings.UnexpectedMessageReceivedOfMany);
}
}
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs
new file mode 100644
index 0000000..a28de12
--- /dev/null
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs
@@ -0,0 +1,273 @@
+//-----------------------------------------------------------------------
+// <copyright file="PositiveAnonymousResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.RelyingParty {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Web;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+
+ /// <summary>
+ /// Wraps an extension-only response from the OP in an <see cref="IAuthenticationResponse"/> instance
+ /// for public consumption by the host web site.
+ /// </summary>
+ internal class PositiveAnonymousResponse : IAuthenticationResponse {
+ /// <summary>
+ /// Backin field for the <see cref="Response"/> property.
+ /// </summary>
+ private readonly IndirectSignedResponse response;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PositiveAnonymousResponse"/> class.
+ /// </summary>
+ /// <param name="response">The response message.</param>
+ protected internal PositiveAnonymousResponse(IndirectSignedResponse response) {
+ Contract.Requires(response != null);
+ ErrorUtilities.VerifyArgumentNotNull(response, "response");
+
+ this.response = response;
+ }
+
+ #region IAuthenticationResponse Properties
+
+ /// <summary>
+ /// Gets the Identifier that the end user claims to own. For use with user database storage and lookup.
+ /// May be null for some failed authentications (i.e. failed directed identity authentications).
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// This is the secure identifier that should be used for database storage and lookup.
+ /// It is not always friendly (i.e. =Arnott becomes =!9B72.7DD1.50A9.5CCD), but it protects
+ /// user identities against spoofing and other attacks.
+ /// </para>
+ /// <para>
+ /// For user-friendly identifiers to display, use the
+ /// <see cref="FriendlyIdentifierForDisplay"/> property.
+ /// </para>
+ /// </remarks>
+ public virtual Identifier ClaimedIdentifier {
+ get { return null; }
+ }
+
+ /// <summary>
+ /// Gets a user-friendly OpenID Identifier for display purposes ONLY.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// <para>
+ /// This <i>should</i> be put through <see cref="HttpUtility.HtmlEncode(string)"/> before
+ /// sending to a browser to secure against javascript injection attacks.
+ /// </para>
+ /// <para>
+ /// This property retains some aspects of the user-supplied identifier that get lost
+ /// in the <see cref="ClaimedIdentifier"/>. For example, XRIs used as user-supplied
+ /// identifiers (i.e. =Arnott) become unfriendly unique strings (i.e. =!9B72.7DD1.50A9.5CCD).
+ /// For display purposes, such as text on a web page that says "You're logged in as ...",
+ /// this property serves to provide the =Arnott string, or whatever else is the most friendly
+ /// string close to what the user originally typed in.
+ /// </para>
+ /// <para>
+ /// If the user-supplied identifier is a URI, this property will be the URI after all
+ /// redirects, and with the protocol and fragment trimmed off.
+ /// If the user-supplied identifier is an XRI, this property will be the original XRI.
+ /// If the user-supplied identifier is an OpenID Provider identifier (i.e. yahoo.com),
+ /// this property will be the Claimed Identifier, with the protocol stripped if it is a URI.
+ /// </para>
+ /// <para>
+ /// It is <b>very</b> important that this property <i>never</i> be used for database storage
+ /// or lookup to avoid identity spoofing and other security risks. For database storage
+ /// and lookup please use the <see cref="ClaimedIdentifier"/> property.
+ /// </para>
+ /// </remarks>
+ public virtual string FriendlyIdentifierForDisplay {
+ get { return null; }
+ }
+
+ /// <summary>
+ /// Gets the detailed success or failure status of the authentication attempt.
+ /// </summary>
+ public virtual AuthenticationStatus Status {
+ get { return AuthenticationStatus.ExtensionsOnly; }
+ }
+
+ /// <summary>
+ /// Gets the details regarding a failed authentication attempt, if available.
+ /// This will be set if and only if <see cref="Status"/> is <see cref="AuthenticationStatus.Failed"/>.
+ /// </summary>
+ /// <value></value>
+ public Exception Exception {
+ get { return null; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets the positive extension-only message the Relying Party received that this instance wraps.
+ /// </summary>
+ protected internal IndirectSignedResponse Response {
+ get { return this.response; }
+ }
+
+ #region IAuthenticationResponse methods
+
+ /// <summary>
+ /// Gets a callback argument's value that was previously added using
+ /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.
+ /// </summary>
+ /// <param name="key">The name of the parameter whose value is sought.</param>
+ /// <returns>
+ /// The value of the argument, or null if the named parameter could not be found.
+ /// </returns>
+ /// <remarks>
+ /// Callback parameters are only available if they are complete and untampered with
+ /// since the original request message (as proven by a signature).
+ /// If the relying party is operating in stateless mode <c>null</c> is always
+ /// returned since the callback arguments could not be signed to protect against
+ /// tampering.
+ /// </remarks>
+ public string GetCallbackArgument(string key) {
+ if (this.response.ReturnToParametersSignatureValidated) {
+ return this.response.GetReturnToArgument(key);
+ } else {
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Gets all the callback arguments that were previously added using
+ /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/> or as a natural part
+ /// of the return_to URL.
+ /// </summary>
+ /// <returns>A name-value dictionary. Never null.</returns>
+ /// <remarks>
+ /// Callback parameters are only available if they are complete and untampered with
+ /// since the original request message (as proven by a signature).
+ /// If the relying party is operating in stateless mode an empty dictionary is always
+ /// returned since the callback arguments could not be signed to protect against
+ /// tampering.
+ /// </remarks>
+ public IDictionary<string, string> GetCallbackArguments() {
+ if (this.response.ReturnToParametersSignatureValidated) {
+ var args = new Dictionary<string, string>();
+
+ // Return all the return_to arguments, except for the OpenID-supporting ones.
+ // The only arguments that should be returned here are the ones that the host
+ // web site adds explicitly.
+ foreach (string key in this.response.GetReturnToParameterNames().Where(key => !OpenIdRelyingParty.IsOpenIdSupportingParameter(key))) {
+ args[key] = this.response.GetReturnToArgument(key);
+ }
+
+ return args;
+ } else {
+ return EmptyDictionary<string, string>.Instance;
+ }
+ }
+
+ /// <summary>
+ /// Tries to get an OpenID extension that may be present in the response.
+ /// </summary>
+ /// <typeparam name="T">The type of extension to look for in the response message.</typeparam>
+ /// <returns>
+ /// The extension, if it is found. Null otherwise.
+ /// </returns>
+ /// <remarks>
+ /// <para>Extensions are returned only if the Provider signed them.
+ /// Relying parties that do not care if the values were modified in
+ /// transit should use the <see cref="GetUntrustedExtension&lt;T&gt;"/> method
+ /// in order to allow the Provider to not sign the extension. </para>
+ /// <para>Unsigned extensions are completely unreliable and should be
+ /// used only to prefill user forms since the user or any other third
+ /// party may have tampered with the data carried by the extension.</para>
+ /// <para>Signed extensions are only reliable if the relying party
+ /// trusts the OpenID Provider that signed them. Signing does not mean
+ /// the relying party can trust the values -- it only means that the values
+ /// have not been tampered with since the Provider sent the message.</para>
+ /// </remarks>
+ public T GetExtension<T>() where T : IOpenIdMessageExtension {
+ return this.response.SignedExtensions.OfType<T>().FirstOrDefault();
+ }
+
+ /// <summary>
+ /// Tries to get an OpenID extension that may be present in the response.
+ /// </summary>
+ /// <param name="extensionType">Type of the extension to look for in the response.</param>
+ /// <returns>
+ /// The extension, if it is found. Null otherwise.
+ /// </returns>
+ /// <remarks>
+ /// <para>Extensions are returned only if the Provider signed them.
+ /// Relying parties that do not care if the values were modified in
+ /// transit should use the <see cref="GetUntrustedExtension"/> method
+ /// in order to allow the Provider to not sign the extension. </para>
+ /// <para>Unsigned extensions are completely unreliable and should be
+ /// used only to prefill user forms since the user or any other third
+ /// party may have tampered with the data carried by the extension.</para>
+ /// <para>Signed extensions are only reliable if the relying party
+ /// trusts the OpenID Provider that signed them. Signing does not mean
+ /// the relying party can trust the values -- it only means that the values
+ /// have not been tampered with since the Provider sent the message.</para>
+ /// </remarks>
+ public IOpenIdMessageExtension GetExtension(Type extensionType) {
+ ErrorUtilities.VerifyArgumentNotNull(extensionType, "extensionType");
+ return this.response.SignedExtensions.OfType<IOpenIdMessageExtension>().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault();
+ }
+
+ /// <summary>
+ /// Tries to get an OpenID extension that may be present in the response, without
+ /// requiring it to be signed by the Provider.
+ /// </summary>
+ /// <typeparam name="T">The type of extension to look for in the response message.</typeparam>
+ /// <returns>
+ /// The extension, if it is found. Null otherwise.
+ /// </returns>
+ /// <remarks>
+ /// <para>Extensions are returned whether they are signed or not.
+ /// Use the <see cref="GetExtension&lt;T&gt;"/> method to retrieve
+ /// extension responses only if they are signed by the Provider to
+ /// protect against tampering. </para>
+ /// <para>Unsigned extensions are completely unreliable and should be
+ /// used only to prefill user forms since the user or any other third
+ /// party may have tampered with the data carried by the extension.</para>
+ /// <para>Signed extensions are only reliable if the relying party
+ /// trusts the OpenID Provider that signed them. Signing does not mean
+ /// the relying party can trust the values -- it only means that the values
+ /// have not been tampered with since the Provider sent the message.</para>
+ /// </remarks>
+ public T GetUntrustedExtension<T>() where T : IOpenIdMessageExtension {
+ return this.response.Extensions.OfType<T>().FirstOrDefault();
+ }
+
+ /// <summary>
+ /// Tries to get an OpenID extension that may be present in the response.
+ /// </summary>
+ /// <param name="extensionType">Type of the extension to look for in the response.</param>
+ /// <returns>
+ /// The extension, if it is found. Null otherwise.
+ /// </returns>
+ /// <remarks>
+ /// <para>Extensions are returned whether they are signed or not.
+ /// Use the <see cref="GetExtension"/> method to retrieve
+ /// extension responses only if they are signed by the Provider to
+ /// protect against tampering. </para>
+ /// <para>Unsigned extensions are completely unreliable and should be
+ /// used only to prefill user forms since the user or any other third
+ /// party may have tampered with the data carried by the extension.</para>
+ /// <para>Signed extensions are only reliable if the relying party
+ /// trusts the OpenID Provider that signed them. Signing does not mean
+ /// the relying party can trust the values -- it only means that the values
+ /// have not been tampered with since the Provider sent the message.</para>
+ /// </remarks>
+ public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) {
+ ErrorUtilities.VerifyArgumentNotNull(extensionType, "extensionType");
+ return this.response.Extensions.OfType<IOpenIdMessageExtension>().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault();
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs
index 32980f5..e3740db 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs
@@ -5,14 +5,11 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OpenId.RelyingParty {
- using System;
- using System.Collections.Generic;
using System.Diagnostics;
+ using System.Diagnostics.Contracts;
using System.Linq;
- using System.Text;
using System.Web;
using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OpenId.Extensions;
using DotNetOpenAuth.OpenId.Messages;
/// <summary>
@@ -20,17 +17,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// for public consumption by the host web site.
/// </summary>
[DebuggerDisplay("Status: {Status}, ClaimedIdentifier: {ClaimedIdentifier}")]
- internal class PositiveAuthenticationResponse : IAuthenticationResponse {
- /// <summary>
- /// The positive assertion message the Relying Party received that this instance wraps.
- /// </summary>
- private readonly PositiveAssertionResponse response;
-
- /// <summary>
- /// The relying party that created this request object.
- /// </summary>
- private readonly OpenIdRelyingParty relyingParty;
-
+ internal class PositiveAuthenticationResponse : PositiveAnonymousResponse {
/// <summary>
/// The OpenID service endpoint reconstructed from the assertion message.
/// </summary>
@@ -47,22 +34,20 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// </summary>
/// <param name="response">The positive assertion response that was just received by the Relying Party.</param>
/// <param name="relyingParty">The relying party.</param>
- internal PositiveAuthenticationResponse(PositiveAssertionResponse response, OpenIdRelyingParty relyingParty) {
- ErrorUtilities.VerifyArgumentNotNull(response, "response");
+ internal PositiveAuthenticationResponse(PositiveAssertionResponse response, OpenIdRelyingParty relyingParty)
+ : base(response) {
+ Contract.Requires(relyingParty != null);
ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty");
- this.response = response;
- this.relyingParty = relyingParty;
-
this.endpoint = ServiceEndpoint.CreateForClaimedIdentifier(
- this.response.ClaimedIdentifier,
- this.response.GetReturnToArgument(AuthenticationRequest.UserSuppliedIdentifierParameterName),
- this.response.LocalIdentifier,
- new ProviderEndpointDescription(this.response.ProviderEndpoint, this.response.Version),
+ this.Response.ClaimedIdentifier,
+ this.Response.GetReturnToArgument(AuthenticationRequest.UserSuppliedIdentifierParameterName),
+ this.Response.LocalIdentifier,
+ new ProviderEndpointDescription(this.Response.ProviderEndpoint, this.Response.Version),
null,
null);
- this.VerifyDiscoveryMatchesAssertion();
+ this.VerifyDiscoveryMatchesAssertion(relyingParty);
}
#region IAuthenticationResponse Properties
@@ -83,14 +68,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <see cref="FriendlyIdentifierForDisplay"/> property.
/// </para>
/// </remarks>
- public Identifier ClaimedIdentifier {
+ public override Identifier ClaimedIdentifier {
get { return this.endpoint.ClaimedIdentifier; }
}
/// <summary>
/// Gets a user-friendly OpenID Identifier for display purposes ONLY.
/// </summary>
- /// <value></value>
/// <remarks>
/// <para>
/// This <i>should</i> be put through <see cref="HttpUtility.HtmlEncode(string)"/> before
@@ -117,203 +101,38 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// and lookup please use the <see cref="ClaimedIdentifier"/> property.
/// </para>
/// </remarks>
- public string FriendlyIdentifierForDisplay {
+ public override string FriendlyIdentifierForDisplay {
get { return this.endpoint.FriendlyIdentifierForDisplay; }
}
/// <summary>
/// Gets the detailed success or failure status of the authentication attempt.
/// </summary>
- /// <value></value>
- public AuthenticationStatus Status {
+ public override AuthenticationStatus Status {
get { return AuthenticationStatus.Authenticated; }
}
- /// <summary>
- /// Gets the details regarding a failed authentication attempt, if available.
- /// This will be set if and only if <see cref="Status"/> is <see cref="AuthenticationStatus.Failed"/>.
- /// </summary>
- /// <value></value>
- public Exception Exception {
- get { return null; }
- }
-
#endregion
/// <summary>
/// Gets the positive assertion response message.
/// </summary>
- internal PositiveAssertionResponse Response {
- get { return this.response; }
- }
-
- #region IAuthenticationResponse methods
-
- /// <summary>
- /// Gets a callback argument's value that was previously added using
- /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.
- /// </summary>
- /// <param name="key">The name of the parameter whose value is sought.</param>
- /// <returns>
- /// The value of the argument, or null if the named parameter could not be found.
- /// </returns>
- /// <remarks>
- /// Callback parameters are only available if they are complete and untampered with
- /// since the original request message (as proven by a signature).
- /// If the relying party is operating in stateless mode <c>null</c> is always
- /// returned since the callback arguments could not be signed to protect against
- /// tampering.
- /// </remarks>
- public string GetCallbackArgument(string key) {
- if (this.response.ReturnToParametersSignatureValidated) {
- return this.response.GetReturnToArgument(key);
- } else {
- return null;
- }
- }
-
- /// <summary>
- /// Gets all the callback arguments that were previously added using
- /// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/> or as a natural part
- /// of the return_to URL.
- /// </summary>
- /// <returns>A name-value dictionary. Never null.</returns>
- /// <remarks>
- /// Callback parameters are only available if they are complete and untampered with
- /// since the original request message (as proven by a signature).
- /// If the relying party is operating in stateless mode an empty dictionary is always
- /// returned since the callback arguments could not be signed to protect against
- /// tampering.
- /// </remarks>
- public IDictionary<string, string> GetCallbackArguments() {
- if (this.response.ReturnToParametersSignatureValidated) {
- var args = new Dictionary<string, string>();
-
- // Return all the return_to arguments, except for the OpenID-supporting ones.
- // The only arguments that should be returned here are the ones that the host
- // web site adds explicitly.
- foreach (string key in this.response.GetReturnToParameterNames().Where(key => !OpenIdRelyingParty.IsOpenIdSupportingParameter(key))) {
- args[key] = this.response.GetReturnToArgument(key);
- }
-
- return args;
- } else {
- return EmptyDictionary<string, string>.Instance;
- }
- }
-
- /// <summary>
- /// Tries to get an OpenID extension that may be present in the response.
- /// </summary>
- /// <typeparam name="T">The type of extension to look for in the response message.</typeparam>
- /// <returns>
- /// The extension, if it is found. Null otherwise.
- /// </returns>
- /// <remarks>
- /// <para>Extensions are returned only if the Provider signed them.
- /// Relying parties that do not care if the values were modified in
- /// transit should use the <see cref="GetUntrustedExtension&lt;T&gt;"/> method
- /// in order to allow the Provider to not sign the extension. </para>
- /// <para>Unsigned extensions are completely unreliable and should be
- /// used only to prefill user forms since the user or any other third
- /// party may have tampered with the data carried by the extension.</para>
- /// <para>Signed extensions are only reliable if the relying party
- /// trusts the OpenID Provider that signed them. Signing does not mean
- /// the relying party can trust the values -- it only means that the values
- /// have not been tampered with since the Provider sent the message.</para>
- /// </remarks>
- public T GetExtension<T>() where T : IOpenIdMessageExtension {
- return this.response.SignedExtensions.OfType<T>().FirstOrDefault();
- }
-
- /// <summary>
- /// Tries to get an OpenID extension that may be present in the response.
- /// </summary>
- /// <param name="extensionType">Type of the extension to look for in the response.</param>
- /// <returns>
- /// The extension, if it is found. Null otherwise.
- /// </returns>
- /// <remarks>
- /// <para>Extensions are returned only if the Provider signed them.
- /// Relying parties that do not care if the values were modified in
- /// transit should use the <see cref="GetUntrustedExtension"/> method
- /// in order to allow the Provider to not sign the extension. </para>
- /// <para>Unsigned extensions are completely unreliable and should be
- /// used only to prefill user forms since the user or any other third
- /// party may have tampered with the data carried by the extension.</para>
- /// <para>Signed extensions are only reliable if the relying party
- /// trusts the OpenID Provider that signed them. Signing does not mean
- /// the relying party can trust the values -- it only means that the values
- /// have not been tampered with since the Provider sent the message.</para>
- /// </remarks>
- public IOpenIdMessageExtension GetExtension(Type extensionType) {
- ErrorUtilities.VerifyArgumentNotNull(extensionType, "extensionType");
- return this.response.SignedExtensions.OfType<IOpenIdMessageExtension>().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault();
- }
-
- /// <summary>
- /// Tries to get an OpenID extension that may be present in the response, without
- /// requiring it to be signed by the Provider.
- /// </summary>
- /// <typeparam name="T">The type of extension to look for in the response message.</typeparam>
- /// <returns>
- /// The extension, if it is found. Null otherwise.
- /// </returns>
- /// <remarks>
- /// <para>Extensions are returned whether they are signed or not.
- /// Use the <see cref="GetExtension&lt;T&gt;"/> method to retrieve
- /// extension responses only if they are signed by the Provider to
- /// protect against tampering. </para>
- /// <para>Unsigned extensions are completely unreliable and should be
- /// used only to prefill user forms since the user or any other third
- /// party may have tampered with the data carried by the extension.</para>
- /// <para>Signed extensions are only reliable if the relying party
- /// trusts the OpenID Provider that signed them. Signing does not mean
- /// the relying party can trust the values -- it only means that the values
- /// have not been tampered with since the Provider sent the message.</para>
- /// </remarks>
- public T GetUntrustedExtension<T>() where T : IOpenIdMessageExtension {
- return this.response.Extensions.OfType<T>().FirstOrDefault();
- }
-
- /// <summary>
- /// Tries to get an OpenID extension that may be present in the response.
- /// </summary>
- /// <param name="extensionType">Type of the extension to look for in the response.</param>
- /// <returns>
- /// The extension, if it is found. Null otherwise.
- /// </returns>
- /// <remarks>
- /// <para>Extensions are returned whether they are signed or not.
- /// Use the <see cref="GetExtension"/> method to retrieve
- /// extension responses only if they are signed by the Provider to
- /// protect against tampering. </para>
- /// <para>Unsigned extensions are completely unreliable and should be
- /// used only to prefill user forms since the user or any other third
- /// party may have tampered with the data carried by the extension.</para>
- /// <para>Signed extensions are only reliable if the relying party
- /// trusts the OpenID Provider that signed them. Signing does not mean
- /// the relying party can trust the values -- it only means that the values
- /// have not been tampered with since the Provider sent the message.</para>
- /// </remarks>
- public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) {
- ErrorUtilities.VerifyArgumentNotNull(extensionType, "extensionType");
- return this.response.Extensions.OfType<IOpenIdMessageExtension>().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault();
+ protected internal new PositiveAssertionResponse Response {
+ get { return (PositiveAssertionResponse)base.Response; }
}
- #endregion
-
/// <summary>
/// Verifies that the positive assertion data matches the results of
/// discovery on the Claimed Identifier.
/// </summary>
+ /// <param name="relyingParty">The relying party.</param>
/// <exception cref="ProtocolException">
/// Thrown when the Provider is asserting that a user controls an Identifier
/// when discovery on that Identifier contradicts what the Provider says.
/// This would be an indication of either a misconfigured Provider or
/// an attempt by someone to spoof another user's identity with a rogue Provider.
/// </exception>
- private void VerifyDiscoveryMatchesAssertion() {
+ private void VerifyDiscoveryMatchesAssertion(OpenIdRelyingParty relyingParty) {
Logger.OpenId.Debug("Verifying assertion matches identifier discovery results...");
// While it LOOKS like we're performing discovery over HTTP again
@@ -325,8 +144,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
// is signed by the RP before it's considered reliable. In 1.x stateless mode, this RP
// doesn't (and can't) sign its own return_to URL, so its cached discovery information
// is merely a hint that must be verified by performing discovery again here.
- var discoveryResults = this.response.ClaimedIdentifier.Discover(this.relyingParty.WebRequestHandler);
- ErrorUtilities.VerifyProtocol(discoveryResults.Contains(this.endpoint), OpenIdStrings.IssuedAssertionFailsIdentifierDiscovery, this.endpoint, discoveryResults.ToStringDeferred(true));
+ var discoveryResults = this.Response.ClaimedIdentifier.Discover(relyingParty.WebRequestHandler);
+ ErrorUtilities.VerifyProtocol(
+ discoveryResults.Contains(this.endpoint),
+ OpenIdStrings.IssuedAssertionFailsIdentifierDiscovery,
+ this.endpoint,
+ discoveryResults.ToStringDeferred(true));
}
}
}