summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs')
-rw-r--r--src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs1054
1 files changed, 0 insertions, 1054 deletions
diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs
deleted file mode 100644
index 16ea839..0000000
--- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs
+++ /dev/null
@@ -1,1054 +0,0 @@
-//-----------------------------------------------------------------------
-// <copyright file="OpenIdRelyingPartyControlBase.cs" company="Andrew Arnott">
-// Copyright (c) Andrew Arnott. All rights reserved.
-// </copyright>
-//-----------------------------------------------------------------------
-
-[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdRelyingPartyControlBase.EmbeddedJavascriptResource, "text/javascript")]
-
-namespace DotNetOpenAuth.OpenId.RelyingParty {
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.ComponentModel;
- using System.Diagnostics.CodeAnalysis;
- using System.Diagnostics.Contracts;
- using System.Drawing.Design;
- using System.Globalization;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Web;
- using System.Web.Security;
- using System.Web.UI;
- using DotNetOpenAuth.ComponentModel;
- using DotNetOpenAuth.Configuration;
- using DotNetOpenAuth.Messaging;
- using DotNetOpenAuth.OpenId.Extensions;
- using DotNetOpenAuth.OpenId.Extensions.UI;
- using DotNetOpenAuth.OpenId.Messages;
-
- /// <summary>
- /// Methods of indicating to the rest of the web site that the user has logged in.
- /// </summary>
- [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "OnSite", Justification = "Two words intended.")]
- public enum LogOnSiteNotification {
- /// <summary>
- /// The rest of the web site is unaware that the user just completed an OpenID login.
- /// </summary>
- None,
-
- /// <summary>
- /// After the <see cref="OpenIdRelyingPartyControlBase.LoggedIn"/> event is fired
- /// the control automatically calls <see cref="System.Web.Security.FormsAuthentication.RedirectFromLoginPage(string, bool)"/>
- /// with the <see cref="IAuthenticationResponse.ClaimedIdentifier"/> as the username
- /// unless the <see cref="OpenIdRelyingPartyControlBase.LoggedIn"/> event handler sets
- /// <see cref="OpenIdEventArgs.Cancel"/> property to true.
- /// </summary>
- FormsAuthentication,
- }
-
- /// <summary>
- /// How an OpenID user session should be persisted across visits.
- /// </summary>
- public enum LogOnPersistence {
- /// <summary>
- /// The user should only be logged in as long as the browser window remains open.
- /// Nothing is persisted to help the user on a return visit. Public kiosk mode.
- /// </summary>
- Session,
-
- /// <summary>
- /// The user should only be logged in as long as the browser window remains open.
- /// The OpenID Identifier is persisted to help expedite re-authentication when
- /// the user visits the next time.
- /// </summary>
- SessionAndPersistentIdentifier,
-
- /// <summary>
- /// The user is issued a persistent authentication ticket so that no login is
- /// necessary on their return visit.
- /// </summary>
- PersistentAuthentication,
- }
-
- /// <summary>
- /// A common base class for OpenID Relying Party controls.
- /// </summary>
- [DefaultProperty("Identifier"), ValidationProperty("Identifier")]
- [ParseChildren(true), PersistChildren(false)]
- public abstract class OpenIdRelyingPartyControlBase : Control, IPostBackEventHandler, IDisposable {
- /// <summary>
- /// The manifest resource name of the javascript file to include on the hosting page.
- /// </summary>
- internal const string EmbeddedJavascriptResource = Util.DefaultNamespace + ".OpenId.RelyingParty.OpenIdRelyingPartyControlBase.js";
-
- /// <summary>
- /// The cookie used to persist the Identifier the user logged in with.
- /// </summary>
- internal const string PersistentIdentifierCookieName = OpenIdUtilities.CustomParameterPrefix + "OpenIDIdentifier";
-
- /// <summary>
- /// The callback parameter name to use to store which control initiated the auth request.
- /// </summary>
- internal const string ReturnToReceivingControlId = OpenIdUtilities.CustomParameterPrefix + "receiver";
-
- #region Protected internal callback parameter names
-
- /// <summary>
- /// The callback parameter to use for recognizing when the callback is in a popup window or hidden iframe.
- /// </summary>
- protected internal const string UIPopupCallbackKey = OpenIdUtilities.CustomParameterPrefix + "uipopup";
-
- /// <summary>
- /// The parameter name to include in the formulated auth request so that javascript can know whether
- /// the OP advertises support for the UI extension.
- /// </summary>
- protected internal const string PopupUISupportedJSHint = OpenIdUtilities.CustomParameterPrefix + "popupUISupported";
-
- #endregion
-
- #region Property category constants
-
- /// <summary>
- /// The "Appearance" category for properties.
- /// </summary>
- protected const string AppearanceCategory = "Appearance";
-
- /// <summary>
- /// The "Behavior" category for properties.
- /// </summary>
- protected const string BehaviorCategory = "Behavior";
-
- /// <summary>
- /// The "OpenID" category for properties and events.
- /// </summary>
- protected const string OpenIdCategory = "OpenID";
-
- #endregion
-
- #region Private callback parameter names
-
- /// <summary>
- /// The callback parameter for use with persisting the <see cref="UsePersistentCookie"/> property.
- /// </summary>
- private const string UsePersistentCookieCallbackKey = OpenIdUtilities.CustomParameterPrefix + "UsePersistentCookie";
-
- /// <summary>
- /// The callback parameter to use for recognizing when the callback is in the parent window.
- /// </summary>
- private const string UIPopupCallbackParentKey = OpenIdUtilities.CustomParameterPrefix + "uipopupParent";
-
- #endregion
-
- #region Property default values
-
- /// <summary>
- /// The default value for the <see cref="Stateless"/> property.
- /// </summary>
- private const bool StatelessDefault = false;
-
- /// <summary>
- /// The default value for the <see cref="ReturnToUrl"/> property.
- /// </summary>
- private const string ReturnToUrlDefault = "";
-
- /// <summary>
- /// Default value of <see cref="UsePersistentCookie"/>.
- /// </summary>
- private const LogOnPersistence UsePersistentCookieDefault = LogOnPersistence.Session;
-
- /// <summary>
- /// Default value of <see cref="LogOnMode"/>.
- /// </summary>
- private const LogOnSiteNotification LogOnModeDefault = LogOnSiteNotification.FormsAuthentication;
-
- /// <summary>
- /// The default value for the <see cref="RealmUrl"/> property.
- /// </summary>
- private const string RealmUrlDefault = "~/";
-
- /// <summary>
- /// The default value for the <see cref="Popup"/> property.
- /// </summary>
- private const PopupBehavior PopupDefault = PopupBehavior.Never;
-
- /// <summary>
- /// The default value for the <see cref="RequireSsl"/> property.
- /// </summary>
- private const bool RequireSslDefault = false;
-
- #endregion
-
- #region Property view state keys
-
- /// <summary>
- /// The viewstate key to use for storing the value of the <see cref="Extensions"/> property.
- /// </summary>
- private const string ExtensionsViewStateKey = "Extensions";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="Stateless"/> property.
- /// </summary>
- private const string StatelessViewStateKey = "Stateless";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="UsePersistentCookie"/> property.
- /// </summary>
- private const string UsePersistentCookieViewStateKey = "UsePersistentCookie";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="LogOnMode"/> property.
- /// </summary>
- private const string LogOnModeViewStateKey = "LogOnMode";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="RealmUrl"/> property.
- /// </summary>
- private const string RealmUrlViewStateKey = "RealmUrl";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="ReturnToUrl"/> property.
- /// </summary>
- private const string ReturnToUrlViewStateKey = "ReturnToUrl";
-
- /// <summary>
- /// The key under which the value for the <see cref="Identifier"/> property will be stored.
- /// </summary>
- private const string IdentifierViewStateKey = "Identifier";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="Popup"/> property.
- /// </summary>
- private const string PopupViewStateKey = "Popup";
-
- /// <summary>
- /// The viewstate key to use for the <see cref="RequireSsl"/> property.
- /// </summary>
- private const string RequireSslViewStateKey = "RequireSsl";
-
- #endregion
-
- /// <summary>
- /// The lifetime of the cookie used to persist the Identifier the user logged in with.
- /// </summary>
- private static readonly TimeSpan PersistentIdentifierTimeToLiveDefault = TimeSpan.FromDays(14);
-
- /// <summary>
- /// Backing field for the <see cref="RelyingParty"/> property.
- /// </summary>
- private OpenIdRelyingParty relyingParty;
-
- /// <summary>
- /// A value indicating whether the <see cref="relyingParty"/> field contains
- /// an instance that we own and should Dispose.
- /// </summary>
- private bool relyingPartyOwned;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="OpenIdRelyingPartyControlBase"/> class.
- /// </summary>
- protected OpenIdRelyingPartyControlBase() {
- Reporting.RecordFeatureUse(this);
- }
-
- #region Events
-
- /// <summary>
- /// Fired when the user has typed in their identifier, discovery was successful
- /// and a login attempt is about to begin.
- /// </summary>
- [Description("Fired when the user has typed in their identifier, discovery was successful and a login attempt is about to begin."), Category(OpenIdCategory)]
- public event EventHandler<OpenIdEventArgs> LoggingIn;
-
- /// <summary>
- /// Fired upon completion of a successful login.
- /// </summary>
- [Description("Fired upon completion of a successful login."), Category(OpenIdCategory)]
- public event EventHandler<OpenIdEventArgs> LoggedIn;
-
- /// <summary>
- /// Fired when a login attempt fails.
- /// </summary>
- [Description("Fired when a login attempt fails."), Category(OpenIdCategory)]
- public event EventHandler<OpenIdEventArgs> Failed;
-
- /// <summary>
- /// Fired when an authentication attempt is canceled at the OpenID Provider.
- /// </summary>
- [Description("Fired when an authentication attempt is canceled at the OpenID Provider."), Category(OpenIdCategory)]
- public event EventHandler<OpenIdEventArgs> Canceled;
-
- /// <summary>
- /// Occurs when the <see cref="Identifier"/> property is changed.
- /// </summary>
- protected event EventHandler IdentifierChanged;
-
- #endregion
-
- /// <summary>
- /// Gets or sets the <see cref="OpenIdRelyingParty"/> instance to use.
- /// </summary>
- /// <value>The default value is an <see cref="OpenIdRelyingParty"/> instance initialized according to the web.config file.</value>
- /// <remarks>
- /// A performance optimization would be to store off the
- /// instance as a static member in your web site and set it
- /// to this property in your <see cref="Control.Load">Page.Load</see>
- /// event since instantiating these instances can be expensive on
- /// heavily trafficked web pages.
- /// </remarks>
- [Browsable(false)]
- public virtual OpenIdRelyingParty RelyingParty {
- get {
- if (this.relyingParty == null) {
- this.relyingParty = this.CreateRelyingParty();
- this.ConfigureRelyingParty(this.relyingParty);
- this.relyingPartyOwned = true;
- }
- return this.relyingParty;
- }
-
- set {
- if (this.relyingPartyOwned && this.relyingParty != null) {
- this.relyingParty.Dispose();
- }
-
- this.relyingParty = value;
- this.relyingPartyOwned = false;
- }
- }
-
- /// <summary>
- /// Gets the collection of extension requests this selector should include in generated requests.
- /// </summary>
- [PersistenceMode(PersistenceMode.InnerProperty)]
- public Collection<IOpenIdMessageExtension> Extensions {
- get {
- if (this.ViewState[ExtensionsViewStateKey] == null) {
- var extensions = new Collection<IOpenIdMessageExtension>();
- this.ViewState[ExtensionsViewStateKey] = extensions;
- return extensions;
- } else {
- return (Collection<IOpenIdMessageExtension>)this.ViewState[ExtensionsViewStateKey];
- }
- }
- }
-
- /// <summary>
- /// Gets or sets a value indicating whether stateless mode is used.
- /// </summary>
- [Bindable(true), DefaultValue(StatelessDefault), Category(OpenIdCategory)]
- [Description("Controls whether stateless mode is used.")]
- public bool Stateless {
- get { return (bool)(ViewState[StatelessViewStateKey] ?? StatelessDefault); }
- set { ViewState[StatelessViewStateKey] = value; }
- }
-
- /// <summary>
- /// Gets or sets the OpenID <see cref="Realm"/> of the relying party web site.
- /// </summary>
- [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Uri", Justification = "Using Uri.ctor for validation.")]
- [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "DotNetOpenAuth.OpenId.Realm", Justification = "Using ctor for validation.")]
- [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Bindable property must be simple type")]
- [Bindable(true), DefaultValue(RealmUrlDefault), Category(OpenIdCategory)]
- [Description("The OpenID Realm of the relying party web site.")]
- [UrlProperty, Editor("System.Web.UI.Design.UrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
- public string RealmUrl {
- get {
- return (string)(ViewState[RealmUrlViewStateKey] ?? RealmUrlDefault);
- }
-
- set {
- Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(value));
-
- if (Page != null && !DesignMode) {
- // Validate new value by trying to construct a Realm object based on it.
- new Realm(OpenIdUtilities.GetResolvedRealm(this.Page, value, this.RelyingParty.Channel.GetRequestFromContext())); // throws an exception on failure.
- } else {
- // We can't fully test it, but it should start with either ~/ or a protocol.
- if (Regex.IsMatch(value, @"^https?://")) {
- new Uri(value.Replace("*.", string.Empty)); // make sure it's fully-qualified, but ignore wildcards
- } else if (value.StartsWith("~/", StringComparison.Ordinal)) {
- // this is valid too
- } else {
- throw new UriFormatException();
- }
- }
- ViewState[RealmUrlViewStateKey] = value;
- }
- }
-
- /// <summary>
- /// Gets or sets the OpenID ReturnTo of the relying party web site.
- /// </summary>
- [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "Bindable property must be simple type")]
- [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Uri", Justification = "Using Uri.ctor for validation.")]
- [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Bindable property must be simple type")]
- [Bindable(true), DefaultValue(ReturnToUrlDefault), Category(OpenIdCategory)]
- [Description("The OpenID ReturnTo of the relying party web site.")]
- [UrlProperty, Editor("System.Web.UI.Design.UrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
- public string ReturnToUrl {
- get {
- return (string)(this.ViewState[ReturnToUrlViewStateKey] ?? ReturnToUrlDefault);
- }
-
- set {
- if (this.Page != null && !this.DesignMode) {
- // Validate new value by trying to construct a Uri based on it.
- new Uri(this.RelyingParty.Channel.GetRequestFromContext().UrlBeforeRewriting, this.Page.ResolveUrl(value)); // throws an exception on failure.
- } else {
- // We can't fully test it, but it should start with either ~/ or a protocol.
- if (Regex.IsMatch(value, @"^https?://")) {
- new Uri(value); // make sure it's fully-qualified, but ignore wildcards
- } else if (value.StartsWith("~/", StringComparison.Ordinal)) {
- // this is valid too
- } else {
- throw new UriFormatException();
- }
- }
-
- this.ViewState[ReturnToUrlViewStateKey] = value;
- }
- }
-
- /// <summary>
- /// Gets or sets a value indicating whether to send a persistent cookie upon successful
- /// login so the user does not have to log in upon returning to this site.
- /// </summary>
- [Bindable(true), DefaultValue(UsePersistentCookieDefault), Category(BehaviorCategory)]
- [Description("Whether to send a persistent cookie upon successful " +
- "login so the user does not have to log in upon returning to this site.")]
- public virtual LogOnPersistence UsePersistentCookie {
- get { return (LogOnPersistence)(this.ViewState[UsePersistentCookieViewStateKey] ?? UsePersistentCookieDefault); }
- set { this.ViewState[UsePersistentCookieViewStateKey] = value; }
- }
-
- /// <summary>
- /// Gets or sets the way a completed login is communicated to the rest of the web site.
- /// </summary>
- [Bindable(true), DefaultValue(LogOnModeDefault), Category(BehaviorCategory)]
- [Description("The way a completed login is communicated to the rest of the web site.")]
- public virtual LogOnSiteNotification LogOnMode {
- get { return (LogOnSiteNotification)(this.ViewState[LogOnModeViewStateKey] ?? LogOnModeDefault); }
- set { this.ViewState[LogOnModeViewStateKey] = value; }
- }
-
- /// <summary>
- /// Gets or sets a value indicating when to use a popup window to complete the login experience.
- /// </summary>
- /// <value>The default value is <see cref="PopupBehavior.Never"/>.</value>
- [Bindable(true), DefaultValue(PopupDefault), Category(BehaviorCategory)]
- [Description("When to use a popup window to complete the login experience.")]
- public virtual PopupBehavior Popup {
- get { return (PopupBehavior)(ViewState[PopupViewStateKey] ?? PopupDefault); }
- set { ViewState[PopupViewStateKey] = value; }
- }
-
- /// <summary>
- /// Gets or sets a value indicating whether to enforce on high security mode,
- /// which requires the full authentication pipeline to be protected by SSL.
- /// </summary>
- [Bindable(true), DefaultValue(RequireSslDefault), Category(OpenIdCategory)]
- [Description("Turns on high security mode, requiring the full authentication pipeline to be protected by SSL.")]
- public bool RequireSsl {
- get { return (bool)(ViewState[RequireSslViewStateKey] ?? RequireSslDefault); }
- set { ViewState[RequireSslViewStateKey] = value; }
- }
-
- /// <summary>
- /// Gets or sets the Identifier that will be used to initiate login.
- /// </summary>
- [Bindable(true), Category(OpenIdCategory)]
- [Description("The OpenID Identifier that this button will use to initiate login.")]
- [TypeConverter(typeof(IdentifierConverter))]
- public virtual Identifier Identifier {
- get {
- return (Identifier)ViewState[IdentifierViewStateKey];
- }
-
- set {
- ViewState[IdentifierViewStateKey] = value;
- this.OnIdentifierChanged();
- }
- }
-
- /// <summary>
- /// Gets or sets the default association preference to set on authentication requests.
- /// </summary>
- internal AssociationPreference AssociationPreference { get; set; }
-
- /// <summary>
- /// Gets ancestor controls, starting with the immediate parent, and progressing to more distant ancestors.
- /// </summary>
- protected IEnumerable<Control> ParentControls {
- get {
- Control parent = this;
- while ((parent = parent.Parent) != null) {
- yield return parent;
- }
- }
- }
-
- /// <summary>
- /// Gets a value indicating whether this control is a child control of a composite OpenID control.
- /// </summary>
- /// <value>
- /// <c>true</c> if this instance is embedded in parent OpenID control; otherwise, <c>false</c>.
- /// </value>
- protected bool IsEmbeddedInParentOpenIdControl {
- get { return this.ParentControls.OfType<OpenIdRelyingPartyControlBase>().Any(); }
- }
-
- /// <summary>
- /// Clears any cookie set by this control to help the user on a returning visit next time.
- /// </summary>
- public static void LogOff() {
- HttpContext.Current.Response.SetCookie(CreateIdentifierPersistingCookie(null));
- }
-
- /// <summary>
- /// Immediately redirects to the OpenID Provider to verify the Identifier
- /// provided in the text box.
- /// </summary>
- public void LogOn() {
- IAuthenticationRequest request = this.CreateRequests().FirstOrDefault();
- ErrorUtilities.VerifyProtocol(request != null, OpenIdStrings.OpenIdEndpointNotFound);
- this.LogOn(request);
- }
-
- /// <summary>
- /// Immediately redirects to the OpenID Provider to verify the Identifier
- /// provided in the text box.
- /// </summary>
- /// <param name="request">The request.</param>
- public void LogOn(IAuthenticationRequest request) {
- Contract.Requires<ArgumentNullException>(request != null);
-
- if (this.IsPopupAppropriate(request)) {
- this.ScriptPopupWindow(request);
- } else {
- request.RedirectToProvider();
- }
- }
-
- #region IPostBackEventHandler Members
-
- /// <summary>
- /// When implemented by a class, enables a server control to process an event raised when a form is posted to the server.
- /// </summary>
- /// <param name="eventArgument">A <see cref="T:System.String"/> that represents an optional event argument to be passed to the event handler.</param>
- void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
- this.RaisePostBackEvent(eventArgument);
- }
-
- #endregion
-
- /// <summary>
- /// Enables a server control to perform final clean up before it is released from memory.
- /// </summary>
- [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Unavoidable because base class does not expose a protected virtual Dispose(bool) method."), SuppressMessage("Microsoft.Design", "CA1063:ImplementIDisposableCorrectly", Justification = "Base class doesn't implement virtual Dispose(bool), so we must call its Dispose() method.")]
- public sealed override void Dispose() {
- this.Dispose(true);
- base.Dispose();
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Creates the authentication requests for a given user-supplied Identifier.
- /// </summary>
- /// <param name="identifier">The identifier to create a request for.</param>
- /// <returns>
- /// A sequence of authentication requests, any one of which may be
- /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>.
- /// </returns>
- protected internal virtual IEnumerable<IAuthenticationRequest> CreateRequests(Identifier identifier) {
- Contract.Requires<ArgumentNullException>(identifier != null);
-
- // If this control is actually a member of another OpenID RP control,
- // delegate creation of requests to the parent control.
- var parentOwner = this.ParentControls.OfType<OpenIdRelyingPartyControlBase>().FirstOrDefault();
- if (parentOwner != null) {
- return parentOwner.CreateRequests(identifier);
- } else {
- // Delegate to a private method to keep 'yield return' and Code Contract separate.
- return this.CreateRequestsCore(identifier);
- }
- }
-
- /// <summary>
- /// Releases unmanaged and - optionally - managed resources
- /// </summary>
- /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
- protected virtual void Dispose(bool disposing) {
- if (disposing) {
- if (this.relyingPartyOwned && this.relyingParty != null) {
- this.relyingParty.Dispose();
- this.relyingParty = null;
- }
- }
- }
-
- /// <summary>
- /// When implemented by a class, enables a server control to process an event raised when a form is posted to the server.
- /// </summary>
- /// <param name="eventArgument">A <see cref="T:System.String"/> that represents an optional event argument to be passed to the event handler.</param>
- [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = "Predefined signature.")]
- protected virtual void RaisePostBackEvent(string eventArgument) {
- }
-
- /// <summary>
- /// Creates the authentication requests for the value set in the <see cref="Identifier"/> property.
- /// </summary>
- /// <returns>
- /// A sequence of authentication requests, any one of which may be
- /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>.
- /// </returns>
- protected IEnumerable<IAuthenticationRequest> CreateRequests() {
- Contract.Requires<InvalidOperationException>(this.Identifier != null, OpenIdStrings.NoIdentifierSet);
- return this.CreateRequests(this.Identifier);
- }
-
- /// <summary>
- /// Raises the <see cref="E:Load"/> event.
- /// </summary>
- /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
- protected override void OnLoad(EventArgs e) {
- base.OnLoad(e);
-
- if (Page.IsPostBack) {
- // OpenID responses NEVER come in the form of a postback.
- return;
- }
-
- if (this.Identifier == null) {
- this.TryPresetIdentifierWithCookie();
- }
-
- // Take an unreliable sneek peek to see if we're in a popup and an OpenID
- // assertion is coming in. We shouldn't process assertions in a popup window.
- if (this.Page.Request.QueryString[UIPopupCallbackKey] == "1" && this.Page.Request.QueryString[UIPopupCallbackParentKey] == null) {
- // We're in a popup window. We need to close it and pass the
- // message back to the parent window for processing.
- this.ScriptClosingPopupOrIFrame();
- return; // don't do any more processing on it now
- }
-
- // Only sniff for an OpenID response if it is targeted at this control.
- // Note that Stateless mode causes no receiver to be indicated, and
- // we want to handle that, but only if there isn't a parent control that
- // will be handling that.
- string receiver = this.Page.Request.QueryString[ReturnToReceivingControlId] ?? this.Page.Request.Form[ReturnToReceivingControlId];
- if (receiver == this.ClientID || (receiver == null && !this.IsEmbeddedInParentOpenIdControl)) {
- var response = this.RelyingParty.GetResponse();
- Logger.Controls.DebugFormat(
- "The {0} control checked for an authentication response and found: {1}",
- this.ID,
- response != null ? response.Status.ToString() : "nothing");
- this.ProcessResponse(response);
- }
- }
-
- /// <summary>
- /// Notifies the user agent via an AJAX response of a completed authentication attempt.
- /// </summary>
- protected virtual void ScriptClosingPopupOrIFrame() {
- this.RelyingParty.ProcessResponseFromPopup();
- }
-
- /// <summary>
- /// Called when the <see cref="Identifier"/> property is changed.
- /// </summary>
- protected virtual void OnIdentifierChanged() {
- var identifierChanged = this.IdentifierChanged;
- if (identifierChanged != null) {
- identifierChanged(this, EventArgs.Empty);
- }
- }
-
- /// <summary>
- /// Processes the response.
- /// </summary>
- /// <param name="response">The response.</param>
- protected virtual void ProcessResponse(IAuthenticationResponse response) {
- if (response == null) {
- return;
- }
- string persistentString = response.GetUntrustedCallbackArgument(UsePersistentCookieCallbackKey);
- if (persistentString != null) {
- this.UsePersistentCookie = (LogOnPersistence)Enum.Parse(typeof(LogOnPersistence), persistentString);
- }
-
- switch (response.Status) {
- case AuthenticationStatus.Authenticated:
- this.OnLoggedIn(response);
- break;
- case AuthenticationStatus.Canceled:
- this.OnCanceled(response);
- break;
- case AuthenticationStatus.Failed:
- this.OnFailed(response);
- break;
- case AuthenticationStatus.SetupRequired:
- case AuthenticationStatus.ExtensionsOnly:
- default:
- // 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);
- }
- }
-
- /// <summary>
- /// Raises the <see cref="E:System.Web.UI.Control.PreRender"/> event.
- /// </summary>
- /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
- protected override void OnPreRender(EventArgs e) {
- base.OnPreRender(e);
-
- this.Page.ClientScript.RegisterClientScriptResource(typeof(OpenIdRelyingPartyControlBase), EmbeddedJavascriptResource);
- }
-
- /// <summary>
- /// Fires the <see cref="LoggedIn"/> event.
- /// </summary>
- /// <param name="response">The response.</param>
- protected virtual void OnLoggedIn(IAuthenticationResponse response) {
- Contract.Requires<ArgumentNullException>(response != null);
- Contract.Requires<ArgumentException>(response.Status == AuthenticationStatus.Authenticated);
-
- var loggedIn = this.LoggedIn;
- OpenIdEventArgs args = new OpenIdEventArgs(response);
- if (loggedIn != null) {
- loggedIn(this, args);
- }
-
- if (!args.Cancel) {
- if (this.UsePersistentCookie == LogOnPersistence.SessionAndPersistentIdentifier) {
- Page.Response.SetCookie(CreateIdentifierPersistingCookie(response));
- }
-
- switch (this.LogOnMode) {
- case LogOnSiteNotification.FormsAuthentication:
- FormsAuthentication.RedirectFromLoginPage(response.ClaimedIdentifier, this.UsePersistentCookie == LogOnPersistence.PersistentAuthentication);
- break;
- case LogOnSiteNotification.None:
- default:
- break;
- }
- }
- }
-
- /// <summary>
- /// Fires the <see cref="LoggingIn"/> event.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>
- /// Returns whether the login should proceed. False if some event handler canceled the request.
- /// </returns>
- protected virtual bool OnLoggingIn(IAuthenticationRequest request) {
- Contract.Requires<ArgumentNullException>(request != null);
-
- EventHandler<OpenIdEventArgs> loggingIn = this.LoggingIn;
-
- OpenIdEventArgs args = new OpenIdEventArgs(request);
- if (loggingIn != null) {
- loggingIn(this, args);
- }
-
- return !args.Cancel;
- }
-
- /// <summary>
- /// Fires the <see cref="Canceled"/> event.
- /// </summary>
- /// <param name="response">The response.</param>
- protected virtual void OnCanceled(IAuthenticationResponse response) {
- Contract.Requires<ArgumentNullException>(response != null);
- Contract.Requires<ArgumentException>(response.Status == AuthenticationStatus.Canceled);
-
- var canceled = this.Canceled;
- if (canceled != null) {
- canceled(this, new OpenIdEventArgs(response));
- }
- }
-
- /// <summary>
- /// Fires the <see cref="Failed"/> event.
- /// </summary>
- /// <param name="response">The response.</param>
- protected virtual void OnFailed(IAuthenticationResponse response) {
- Contract.Requires<ArgumentNullException>(response != null);
- Contract.Requires<ArgumentException>(response.Status == AuthenticationStatus.Failed);
-
- var failed = this.Failed;
- if (failed != null) {
- failed(this, new OpenIdEventArgs(response));
- }
- }
-
- /// <summary>
- /// Creates the relying party instance used to generate authentication requests.
- /// </summary>
- /// <returns>The instantiated relying party.</returns>
- protected OpenIdRelyingParty CreateRelyingParty() {
- IOpenIdApplicationStore store = this.Stateless ? null : OpenIdElement.Configuration.RelyingParty.ApplicationStore.CreateInstance(OpenIdRelyingParty.HttpApplicationStore);
- return this.CreateRelyingParty(store);
- }
-
- /// <summary>
- /// Creates the relying party instance used to generate authentication requests.
- /// </summary>
- /// <param name="store">The store to pass to the relying party constructor.</param>
- /// <returns>The instantiated relying party.</returns>
- protected virtual OpenIdRelyingParty CreateRelyingParty(IOpenIdApplicationStore store) {
- return new OpenIdRelyingParty(store);
- }
-
- /// <summary>
- /// Configures the relying party.
- /// </summary>
- /// <param name="relyingParty">The relying party.</param>
- [SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "relyingParty", Justification = "This makes it possible for overrides to see the value before it is set on a field.")]
- protected virtual void ConfigureRelyingParty(OpenIdRelyingParty relyingParty) {
- Contract.Requires<ArgumentNullException>(relyingParty != null);
-
- // Only set RequireSsl to true, as we don't want to override
- // a .config setting of true with false.
- if (this.RequireSsl) {
- relyingParty.SecuritySettings.RequireSsl = true;
- }
- }
-
- /// <summary>
- /// Detects whether a popup window should be used to show the Provider's UI.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>
- /// <c>true</c> if a popup should be used; <c>false</c> otherwise.
- /// </returns>
- protected virtual bool IsPopupAppropriate(IAuthenticationRequest request) {
- Contract.Requires<ArgumentNullException>(request != null);
-
- switch (this.Popup) {
- case PopupBehavior.Never:
- return false;
- case PopupBehavior.Always:
- return true;
- case PopupBehavior.IfProviderSupported:
- return request.DiscoveryResult.IsExtensionSupported<UIRequest>();
- default:
- throw ErrorUtilities.ThrowInternal("Unexpected value for Popup property.");
- }
- }
-
- /// <summary>
- /// Adds attributes to an HTML &lt;A&gt; tag that will be written by the caller using
- /// <see cref="HtmlTextWriter.RenderBeginTag(HtmlTextWriterTag)"/> after this method.
- /// </summary>
- /// <param name="writer">The HTML writer.</param>
- /// <param name="request">The outgoing authentication request.</param>
- /// <param name="windowStatus">The text to try to display in the status bar on mouse hover.</param>
- protected void RenderOpenIdMessageTransmissionAsAnchorAttributes(HtmlTextWriter writer, IAuthenticationRequest request, string windowStatus) {
- Contract.Requires<ArgumentNullException>(writer != null);
- Contract.Requires<ArgumentNullException>(request != null);
-
- // We render a standard HREF attribute for non-javascript browsers.
- writer.AddAttribute(HtmlTextWriterAttribute.Href, request.RedirectingResponse.GetDirectUriRequest(this.RelyingParty.Channel).AbsoluteUri);
-
- // And for the Javascript ones we do the extra work to use form POST where necessary.
- writer.AddAttribute(HtmlTextWriterAttribute.Onclick, this.CreateGetOrPostAHrefValue(request) + " return false;");
-
- writer.AddStyleAttribute(HtmlTextWriterStyle.Cursor, "pointer");
- if (!string.IsNullOrEmpty(windowStatus)) {
- writer.AddAttribute("onMouseOver", "window.status = " + MessagingUtilities.GetSafeJavascriptValue(windowStatus));
- writer.AddAttribute("onMouseOut", "window.status = null");
- }
- }
-
- /// <summary>
- /// Creates the identifier-persisting cookie, either for saving or deleting.
- /// </summary>
- /// <param name="response">The positive authentication response; or <c>null</c> to clear the cookie.</param>
- /// <returns>An persistent cookie.</returns>
- private static HttpCookie CreateIdentifierPersistingCookie(IAuthenticationResponse response) {
- HttpCookie cookie = new HttpCookie(PersistentIdentifierCookieName);
- bool clearingCookie = false;
-
- // We'll try to store whatever it was the user originally typed in, but fallback
- // to the final claimed_id.
- if (response != null && response.Status == AuthenticationStatus.Authenticated) {
- var positiveResponse = (PositiveAuthenticationResponse)response;
-
- // We must escape the value because XRIs start with =, and any leading '=' gets dropped (by ASP.NET?)
- cookie.Value = Uri.EscapeDataString(positiveResponse.Endpoint.UserSuppliedIdentifier ?? response.ClaimedIdentifier);
- } else {
- clearingCookie = true;
- cookie.Value = string.Empty;
- if (HttpContext.Current.Request.Browser["supportsEmptyStringInCookieValue"] == "false") {
- cookie.Value = "NoCookie";
- }
- }
-
- if (clearingCookie) {
- // mark the cookie has having already expired to cause the user agent to delete
- // the old persisted cookie.
- cookie.Expires = DateTime.Now.Subtract(TimeSpan.FromDays(1));
- } else {
- // Make the cookie persistent by setting an expiration date
- cookie.Expires = DateTime.Now + PersistentIdentifierTimeToLiveDefault;
- }
-
- return cookie;
- }
-
- /// <summary>
- /// Creates the authentication requests for a given user-supplied Identifier.
- /// </summary>
- /// <param name="identifier">The identifier to create a request for.</param>
- /// <returns>
- /// A sequence of authentication requests, any one of which may be
- /// used to determine the user's control of the <see cref="IAuthenticationRequest.ClaimedIdentifier"/>.
- /// </returns>
- private IEnumerable<IAuthenticationRequest> CreateRequestsCore(Identifier identifier) {
- ErrorUtilities.VerifyArgumentNotNull(identifier, "identifier"); // NO CODE CONTRACTS! (yield return used here)
- IEnumerable<IAuthenticationRequest> requests;
-
- // Approximate the returnTo (either based on the customize property or the page URL)
- // so we can use it to help with Realm resolution.
- Uri returnToApproximation;
- if (this.ReturnToUrl != null) {
- string returnToResolvedPath = this.ResolveUrl(this.ReturnToUrl);
- returnToApproximation = new Uri(this.RelyingParty.Channel.GetRequestFromContext().UrlBeforeRewriting, returnToResolvedPath);
- } else {
- returnToApproximation = this.Page.Request.Url;
- }
-
- // Resolve the trust root, and swap out the scheme and port if necessary to match the
- // return_to URL, since this match is required by OpenID, and the consumer app
- // may be using HTTP at some times and HTTPS at others.
- UriBuilder realm = OpenIdUtilities.GetResolvedRealm(this.Page, this.RealmUrl, this.RelyingParty.Channel.GetRequestFromContext());
- realm.Scheme = returnToApproximation.Scheme;
- realm.Port = returnToApproximation.Port;
-
- // Initiate OpenID request
- // We use TryParse here to avoid throwing an exception which
- // might slip through our validator control if it is disabled.
- Realm typedRealm = new Realm(realm);
- if (string.IsNullOrEmpty(this.ReturnToUrl)) {
- requests = this.RelyingParty.CreateRequests(identifier, typedRealm);
- } else {
- // Since the user actually gave us a return_to value,
- // the "approximation" is exactly what we want.
- requests = this.RelyingParty.CreateRequests(identifier, typedRealm, returnToApproximation);
- }
-
- // Some OPs may be listed multiple times (one with HTTPS and the other with HTTP, for example).
- // Since we're gathering OPs to try one after the other, just take the first choice of each OP
- // and don't try it multiple times.
- requests = requests.Distinct(DuplicateRequestedHostsComparer.Instance);
-
- // Configure each generated request.
- foreach (var req in requests) {
- if (this.IsPopupAppropriate(req)) {
- // Inform ourselves in return_to that we're in a popup.
- req.SetUntrustedCallbackArgument(UIPopupCallbackKey, "1");
-
- if (req.DiscoveryResult.IsExtensionSupported<UIRequest>()) {
- // Inform the OP that we'll be using a popup window consistent with the UI extension.
- // But beware that the extension MAY have already been added if we're using
- // the OpenIdAjaxRelyingParty class.
- if (!((AuthenticationRequest)req).Extensions.OfType<UIRequest>().Any()) {
- req.AddExtension(new UIRequest());
- }
-
- // Provide a hint for the client javascript about whether the OP supports the UI extension.
- // This is so the window can be made the correct size for the extension.
- // If the OP doesn't advertise support for the extension, the javascript will use
- // a bigger popup window.
- req.SetUntrustedCallbackArgument(PopupUISupportedJSHint, "1");
- }
- }
-
- // Add the extensions injected into the control.
- foreach (var extension in this.Extensions) {
- req.AddExtension(extension);
- }
-
- // Add state that needs to survive across the redirect, but at this point
- // only save those properties that are not expected to be changed by a
- // LoggingIn event handler.
- req.SetUntrustedCallbackArgument(ReturnToReceivingControlId, this.ClientID);
-
- // Apply the control's association preference to this auth request, but only if
- // it is less demanding (greater ordinal value) than the existing one.
- // That way, we protect against retrying an association that was already attempted.
- var authReq = ((AuthenticationRequest)req);
- if (authReq.AssociationPreference < this.AssociationPreference) {
- authReq.AssociationPreference = this.AssociationPreference;
- }
-
- if (this.OnLoggingIn(req)) {
- // We save this property after firing OnLoggingIn so that the host page can
- // change its value and have that value saved.
- req.SetUntrustedCallbackArgument(UsePersistentCookieCallbackKey, this.UsePersistentCookie.ToString());
-
- yield return req;
- }
- }
- }
-
- /// <summary>
- /// Gets the javascript to executee to redirect or POST an OpenID message to a remote party.
- /// </summary>
- /// <param name="request">The authentication request to send.</param>
- /// <returns>The javascript that should execute.</returns>
- private string CreateGetOrPostAHrefValue(IAuthenticationRequest request) {
- Contract.Requires<ArgumentNullException>(request != null);
-
- Uri directUri = request.RedirectingResponse.GetDirectUriRequest(this.RelyingParty.Channel);
- return "window.dnoa_internal.GetOrPost(" + MessagingUtilities.GetSafeJavascriptValue(directUri.AbsoluteUri) + ");";
- }
-
- /// <summary>
- /// Wires the return page to immediately display a popup window with the Provider in it.
- /// </summary>
- /// <param name="request">The request.</param>
- private void ScriptPopupWindow(IAuthenticationRequest request) {
- Contract.Requires<ArgumentNullException>(request != null);
- Contract.Requires<InvalidOperationException>(this.RelyingParty != null);
-
- StringBuilder startupScript = new StringBuilder();
-
- // Add a callback function that the popup window can call on this, the
- // parent window, to pass back the authentication result.
- startupScript.AppendLine("window.dnoa_internal = {};");
- startupScript.AppendLine("window.dnoa_internal.processAuthorizationResult = function(uri) { window.location = uri; };");
- startupScript.AppendLine("window.dnoa_internal.popupWindow = function() {");
- startupScript.AppendFormat(
- @"\tvar openidPopup = {0}",
- UIUtilities.GetWindowPopupScript(this.RelyingParty, request, "openidPopup"));
- startupScript.AppendLine("};");
-
- this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "loginPopup", startupScript.ToString(), true);
- }
-
- /// <summary>
- /// Tries to preset the <see cref="Identifier"/> property based on a persistent
- /// cookie on the browser.
- /// </summary>
- /// <returns>
- /// A value indicating whether the <see cref="Identifier"/> property was
- /// successfully preset to some non-empty value.
- /// </returns>
- private bool TryPresetIdentifierWithCookie() {
- HttpCookie cookie = this.Page.Request.Cookies[PersistentIdentifierCookieName];
- if (cookie != null) {
- this.Identifier = Uri.UnescapeDataString(cookie.Value);
- return true;
- }
-
- return false;
- }
- }
-}