summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-01-29 14:32:45 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2012-01-29 14:32:45 -0800
commit5fec515095ee10b522f414a03e78f282aaf520dc (patch)
tree204c75486639c23cdda2ef38b34d7e5050a1a2e3 /src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs
parentf1a4155398635a4fd9f485eec817152627682704 (diff)
parent8f4165ee515728aca3faaa26e8354a40612e85e4 (diff)
downloadDotNetOpenAuth-5fec515095ee10b522f414a03e78f282aaf520dc.zip
DotNetOpenAuth-5fec515095ee10b522f414a03e78f282aaf520dc.tar.gz
DotNetOpenAuth-5fec515095ee10b522f414a03e78f282aaf520dc.tar.bz2
Merge branch 'splitDlls'.
DNOA now builds and (in some cases) ships as many distinct assemblies.
Diffstat (limited to 'src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs')
-rw-r--r--src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs708
1 files changed, 708 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs
new file mode 100644
index 0000000..1dea39a
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/OpenIdTextBox.cs
@@ -0,0 +1,708 @@
+//-----------------------------------------------------------------------
+// <copyright file="OpenIdTextBox.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdTextBox.EmbeddedLogoResourceName, "image/png")]
+
+#pragma warning disable 0809 // marking inherited, unsupported properties as obsolete to discourage their use
+
+namespace DotNetOpenAuth.OpenId.RelyingParty {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Specialized;
+ using System.ComponentModel;
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Diagnostics.Contracts;
+ using System.Drawing.Design;
+ using System.Globalization;
+ using System.Net;
+ using System.Text;
+ using System.Text.RegularExpressions;
+ using System.Web;
+ using System.Web.Security;
+ using System.Web.UI;
+ using System.Web.UI.WebControls;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
+ using DotNetOpenAuth.OpenId.Extensions.UI;
+
+ /// <summary>
+ /// An ASP.NET control that provides a minimal text box that is OpenID-aware.
+ /// </summary>
+ /// <remarks>
+ /// This control offers greater UI flexibility than the <see cref="OpenIdLogin"/>
+ /// control, but requires more work to be done by the hosting web site to
+ /// assemble a complete login experience.
+ /// </remarks>
+ [DefaultProperty("Text"), ValidationProperty("Text")]
+ [ToolboxData("<{0}:OpenIdTextBox runat=\"server\" />")]
+ public class OpenIdTextBox : OpenIdRelyingPartyControlBase, IEditableTextControl, ITextControl, IPostBackDataHandler {
+ /// <summary>
+ /// The name of the manifest stream containing the
+ /// OpenID logo that is placed inside the text box.
+ /// </summary>
+ internal const string EmbeddedLogoResourceName = Util.DefaultNamespace + ".OpenId.RelyingParty.openid_login.png";
+
+ /// <summary>
+ /// Default value for <see cref="TabIndex"/> property.
+ /// </summary>
+ protected const short TabIndexDefault = 0;
+
+ #region Property category constants
+
+ /// <summary>
+ /// The "Simple Registration" category for properties.
+ /// </summary>
+ private const string ProfileCategory = "Simple Registration";
+
+ #endregion
+
+ #region Property viewstate keys
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestEmail"/> property.
+ /// </summary>
+ private const string RequestEmailViewStateKey = "RequestEmail";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestNickname"/> property.
+ /// </summary>
+ private const string RequestNicknameViewStateKey = "RequestNickname";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestPostalCode"/> property.
+ /// </summary>
+ private const string RequestPostalCodeViewStateKey = "RequestPostalCode";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestCountry"/> property.
+ /// </summary>
+ private const string RequestCountryViewStateKey = "RequestCountry";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestLanguage"/> property.
+ /// </summary>
+ private const string RequestLanguageViewStateKey = "RequestLanguage";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestTimeZone"/> property.
+ /// </summary>
+ private const string RequestTimeZoneViewStateKey = "RequestTimeZone";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="EnableRequestProfile"/> property.
+ /// </summary>
+ private const string EnableRequestProfileViewStateKey = "EnableRequestProfile";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="PolicyUrl"/> property.
+ /// </summary>
+ private const string PolicyUrlViewStateKey = "PolicyUrl";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestFullName"/> property.
+ /// </summary>
+ private const string RequestFullNameViewStateKey = "RequestFullName";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="PresetBorder"/> property.
+ /// </summary>
+ private const string PresetBorderViewStateKey = "PresetBorder";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="ShowLogo"/> property.
+ /// </summary>
+ private const string ShowLogoViewStateKey = "ShowLogo";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestGender"/> property.
+ /// </summary>
+ private const string RequestGenderViewStateKey = "RequestGender";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="RequestBirthDate"/> property.
+ /// </summary>
+ private const string RequestBirthDateViewStateKey = "RequestBirthDate";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="CssClass"/> property.
+ /// </summary>
+ private const string CssClassViewStateKey = "CssClass";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="MaxLength"/> property.
+ /// </summary>
+ private const string MaxLengthViewStateKey = "MaxLength";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="Columns"/> property.
+ /// </summary>
+ private const string ColumnsViewStateKey = "Columns";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="TabIndex"/> property.
+ /// </summary>
+ private const string TabIndexViewStateKey = "TabIndex";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="Enabled"/> property.
+ /// </summary>
+ private const string EnabledViewStateKey = "Enabled";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="Name"/> property.
+ /// </summary>
+ private const string NameViewStateKey = "Name";
+
+ /// <summary>
+ /// The viewstate key to use for the <see cref="Text"/> property.
+ /// </summary>
+ private const string TextViewStateKey = "Text";
+
+ #endregion
+
+ #region Property defaults
+
+ /// <summary>
+ /// The default value for the <see cref="Columns"/> property.
+ /// </summary>
+ private const int ColumnsDefault = 40;
+
+ /// <summary>
+ /// The default value for the <see cref="MaxLength"/> property.
+ /// </summary>
+ private const int MaxLengthDefault = 40;
+
+ /// <summary>
+ /// The default value for the <see cref="Name"/> property.
+ /// </summary>
+ private const string NameDefault = "openid_identifier";
+
+ /// <summary>
+ /// The default value for the <see cref="EnableRequestProfile"/> property.
+ /// </summary>
+ private const bool EnableRequestProfileDefault = true;
+
+ /// <summary>
+ /// The default value for the <see cref="ShowLogo"/> property.
+ /// </summary>
+ private const bool ShowLogoDefault = true;
+
+ /// <summary>
+ /// The default value for the <see cref="PresetBorder"/> property.
+ /// </summary>
+ private const bool PresetBorderDefault = true;
+
+ /// <summary>
+ /// The default value for the <see cref="PolicyUrl"/> property.
+ /// </summary>
+ private const string PolicyUrlDefault = "";
+
+ /// <summary>
+ /// The default value for the <see cref="CssClass"/> property.
+ /// </summary>
+ private const string CssClassDefault = "openid";
+
+ /// <summary>
+ /// The default value for the <see cref="Text"/> property.
+ /// </summary>
+ private const string TextDefault = "";
+
+ /// <summary>
+ /// The default value for the <see cref="RequestEmail"/> property.
+ /// </summary>
+ private const DemandLevel RequestEmailDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestPostalCode"/> property.
+ /// </summary>
+ private const DemandLevel RequestPostalCodeDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestCountry"/> property.
+ /// </summary>
+ private const DemandLevel RequestCountryDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestLanguage"/> property.
+ /// </summary>
+ private const DemandLevel RequestLanguageDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestTimeZone"/> property.
+ /// </summary>
+ private const DemandLevel RequestTimeZoneDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestNickname"/> property.
+ /// </summary>
+ private const DemandLevel RequestNicknameDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestFullName"/> property.
+ /// </summary>
+ private const DemandLevel RequestFullNameDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestBirthDate"/> property.
+ /// </summary>
+ private const DemandLevel RequestBirthDateDefault = DemandLevel.NoRequest;
+
+ /// <summary>
+ /// The default value for the <see cref="RequestGender"/> property.
+ /// </summary>
+ private const DemandLevel RequestGenderDefault = DemandLevel.NoRequest;
+
+ #endregion
+
+ /// <summary>
+ /// An empty sreg request, used to compare with others to see if they too are empty.
+ /// </summary>
+ private static readonly ClaimsRequest EmptyClaimsRequest = new ClaimsRequest();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdTextBox"/> class.
+ /// </summary>
+ public OpenIdTextBox() {
+ }
+
+ #region IEditableTextControl Members
+
+ /// <summary>
+ /// Occurs when the content of the text changes between posts to the server.
+ /// </summary>
+ public event EventHandler TextChanged;
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// Gets or sets the content of the text box.
+ /// </summary>
+ [Bindable(true), DefaultValue(""), Category(AppearanceCategory)]
+ [Description("The content of the text box.")]
+ public string Text {
+ get {
+ return this.Identifier != null ? this.Identifier.OriginalString : (this.ViewState[TextViewStateKey] as string ?? string.Empty);
+ }
+
+ set {
+ // Try to store it as a validated identifier,
+ // but failing that at least store the text.
+ Identifier id;
+ if (Identifier.TryParse(value, out id)) {
+ this.Identifier = id;
+ } else {
+ // Be sure to set the viewstate AFTER setting the Identifier,
+ // since setting the Identifier clears the viewstate in OnIdentifierChanged.
+ this.Identifier = null;
+ this.ViewState[TextViewStateKey] = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets the form name to use for this input field.
+ /// </summary>
+ [Bindable(true), DefaultValue(NameDefault), Category(BehaviorCategory)]
+ [Description("The form name of this input field.")]
+ public string Name {
+ get { return (string)(this.ViewState[NameViewStateKey] ?? NameDefault); }
+ set { this.ViewState[NameViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the CSS class assigned to the text box.
+ /// </summary>
+ [Bindable(true), DefaultValue(CssClassDefault), Category(AppearanceCategory)]
+ [Description("The CSS class assigned to the text box.")]
+ public string CssClass {
+ get { return (string)this.ViewState[CssClassViewStateKey]; }
+ set { this.ViewState[CssClassViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to show the OpenID logo in the text box.
+ /// </summary>
+ [Bindable(true), DefaultValue(ShowLogoDefault), Category(AppearanceCategory)]
+ [Description("The visibility of the OpenID logo in the text box.")]
+ public bool ShowLogo {
+ get { return (bool)(this.ViewState[ShowLogoViewStateKey] ?? ShowLogoDefault); }
+ set { this.ViewState[ShowLogoViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to use inline styling to force a solid gray border.
+ /// </summary>
+ [Bindable(true), DefaultValue(PresetBorderDefault), Category(AppearanceCategory)]
+ [Description("Whether to use inline styling to force a solid gray border.")]
+ public bool PresetBorder {
+ get { return (bool)(this.ViewState[PresetBorderViewStateKey] ?? PresetBorderDefault); }
+ set { this.ViewState[PresetBorderViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the width of the text box in characters.
+ /// </summary>
+ [Bindable(true), DefaultValue(ColumnsDefault), Category(AppearanceCategory)]
+ [Description("The width of the text box in characters.")]
+ public int Columns {
+ get { return (int)(this.ViewState[ColumnsViewStateKey] ?? ColumnsDefault); }
+ set { this.ViewState[ColumnsViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the maximum number of characters the browser should allow
+ /// </summary>
+ [Bindable(true), DefaultValue(MaxLengthDefault), Category(AppearanceCategory)]
+ [Description("The maximum number of characters the browser should allow.")]
+ public int MaxLength {
+ get { return (int)(this.ViewState[MaxLengthViewStateKey] ?? MaxLengthDefault); }
+ set { this.ViewState[MaxLengthViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the tab index of the Web server control.
+ /// </summary>
+ /// <value></value>
+ /// <returns>
+ /// The tab index of the Web server control. The default is 0, which indicates that this property is not set.
+ /// </returns>
+ /// <exception cref="T:System.ArgumentOutOfRangeException">
+ /// The specified tab index is not between -32768 and 32767.
+ /// </exception>
+ [Bindable(true), DefaultValue(TabIndexDefault), Category(BehaviorCategory)]
+ [Description("The tab index of the text box control.")]
+ public virtual short TabIndex {
+ get { return (short)(this.ViewState[TabIndexViewStateKey] ?? TabIndexDefault); }
+ set { this.ViewState[TabIndexViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="OpenIdTextBox"/> is enabled
+ /// in the browser for editing and will respond to incoming OpenID messages.
+ /// </summary>
+ /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value>
+ [Bindable(true), DefaultValue(true), Category(BehaviorCategory)]
+ [Description("Whether the control is editable in the browser and will respond to OpenID messages.")]
+ public bool Enabled {
+ get { return (bool)(this.ViewState[EnabledViewStateKey] ?? true); }
+ set { this.ViewState[EnabledViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's nickname from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestNicknameDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's nickname from the Provider.")]
+ public DemandLevel RequestNickname {
+ get { return (DemandLevel)(ViewState[RequestNicknameViewStateKey] ?? RequestNicknameDefault); }
+ set { ViewState[RequestNicknameViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's email address from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestEmailDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's email address from the Provider.")]
+ public DemandLevel RequestEmail {
+ get { return (DemandLevel)(ViewState[RequestEmailViewStateKey] ?? RequestEmailDefault); }
+ set { ViewState[RequestEmailViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's full name from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestFullNameDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's full name from the Provider")]
+ public DemandLevel RequestFullName {
+ get { return (DemandLevel)(ViewState[RequestFullNameViewStateKey] ?? RequestFullNameDefault); }
+ set { ViewState[RequestFullNameViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's birthdate from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestBirthDateDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's birthdate from the Provider.")]
+ public DemandLevel RequestBirthDate {
+ get { return (DemandLevel)(ViewState[RequestBirthDateViewStateKey] ?? RequestBirthDateDefault); }
+ set { ViewState[RequestBirthDateViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's gender from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestGenderDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's gender from the Provider.")]
+ public DemandLevel RequestGender {
+ get { return (DemandLevel)(ViewState[RequestGenderViewStateKey] ?? RequestGenderDefault); }
+ set { ViewState[RequestGenderViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's postal code from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestPostalCodeDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's postal code from the Provider.")]
+ public DemandLevel RequestPostalCode {
+ get { return (DemandLevel)(ViewState[RequestPostalCodeViewStateKey] ?? RequestPostalCodeDefault); }
+ set { ViewState[RequestPostalCodeViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's country from the Provider.
+ /// </summary>
+ [Bindable(true)]
+ [Category(ProfileCategory)]
+ [DefaultValue(RequestCountryDefault)]
+ [Description("Your level of interest in receiving the user's country from the Provider.")]
+ public DemandLevel RequestCountry {
+ get { return (DemandLevel)(ViewState[RequestCountryViewStateKey] ?? RequestCountryDefault); }
+ set { ViewState[RequestCountryViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's preferred language from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestLanguageDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's preferred language from the Provider.")]
+ public DemandLevel RequestLanguage {
+ get { return (DemandLevel)(ViewState[RequestLanguageViewStateKey] ?? RequestLanguageDefault); }
+ set { ViewState[RequestLanguageViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets your level of interest in receiving the user's time zone from the Provider.
+ /// </summary>
+ [Bindable(true), DefaultValue(RequestTimeZoneDefault), Category(ProfileCategory)]
+ [Description("Your level of interest in receiving the user's time zone from the Provider.")]
+ public DemandLevel RequestTimeZone {
+ get { return (DemandLevel)(ViewState[RequestTimeZoneViewStateKey] ?? RequestTimeZoneDefault); }
+ set { ViewState[RequestTimeZoneViewStateKey] = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the URL to your privacy policy page that describes how
+ /// claims will be used and/or shared.
+ /// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification = "Bindable property must be simple type")]
+ [Bindable(true), DefaultValue(PolicyUrlDefault), Category(ProfileCategory)]
+ [Description("The URL to your privacy policy page that describes how claims will be used and/or shared.")]
+ [UrlProperty, Editor("System.Web.UI.Design.UrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
+ public string PolicyUrl {
+ get {
+ return (string)ViewState[PolicyUrlViewStateKey] ?? PolicyUrlDefault;
+ }
+
+ set {
+ UriUtil.ValidateResolvableUrl(Page, DesignMode, value);
+ ViewState[PolicyUrlViewStateKey] = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether to use OpenID extensions
+ /// to retrieve profile data of the authenticating user.
+ /// </summary>
+ [Bindable(true), DefaultValue(EnableRequestProfileDefault), Category(ProfileCategory)]
+ [Description("Turns the entire Simple Registration extension on or off.")]
+ public bool EnableRequestProfile {
+ get { return (bool)(ViewState[EnableRequestProfileViewStateKey] ?? EnableRequestProfileDefault); }
+ set { ViewState[EnableRequestProfileViewStateKey] = value; }
+ }
+
+ #endregion
+
+ #region IPostBackDataHandler Members
+
+ /// <summary>
+ /// When implemented by a class, processes postback data for an ASP.NET server control.
+ /// </summary>
+ /// <param name="postDataKey">The key identifier for the control.</param>
+ /// <param name="postCollection">The collection of all incoming name values.</param>
+ /// <returns>
+ /// true if the server control's state changes as a result of the postback; otherwise, false.
+ /// </returns>
+ bool IPostBackDataHandler.LoadPostData(string postDataKey, NameValueCollection postCollection) {
+ return this.LoadPostData(postDataKey, postCollection);
+ }
+
+ /// <summary>
+ /// When implemented by a class, signals the server control to notify the ASP.NET application that the state of the control has changed.
+ /// </summary>
+ void IPostBackDataHandler.RaisePostDataChangedEvent() {
+ this.RaisePostDataChangedEvent();
+ }
+
+ #endregion
+
+ /// <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 override IEnumerable<IAuthenticationRequest> CreateRequests(Identifier identifier) {
+ ErrorUtilities.VerifyArgumentNotNull(identifier, "identifier");
+
+ // We delegate all our logic to another method, since invoking base. methods
+ // within an iterator method results in unverifiable code.
+ return this.CreateRequestsCore(base.CreateRequests(identifier));
+ }
+
+ /// <summary>
+ /// Checks for incoming OpenID authentication responses and fires appropriate events.
+ /// </summary>
+ /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
+ protected override void OnLoad(EventArgs e) {
+ if (!this.Enabled) {
+ return;
+ }
+
+ this.Page.RegisterRequiresPostBack(this);
+ base.OnLoad(e);
+ }
+
+ /// <summary>
+ /// Called when the <see cref="Identifier"/> property is changed.
+ /// </summary>
+ protected override void OnIdentifierChanged() {
+ this.ViewState.Remove(TextViewStateKey);
+ base.OnIdentifierChanged();
+ }
+
+ /// <summary>
+ /// Sends server control content to a provided <see cref="T:System.Web.UI.HtmlTextWriter"/> object, which writes the content to be rendered on the client.
+ /// </summary>
+ /// <param name="writer">The <see cref="T:System.Web.UI.HtmlTextWriter"/> object that receives the server control content.</param>
+ protected override void Render(HtmlTextWriter writer) {
+ Contract.Assume(writer != null, "Missing contract.");
+
+ if (this.ShowLogo) {
+ string logoUrl = Page.ClientScript.GetWebResourceUrl(
+ typeof(OpenIdTextBox), EmbeddedLogoResourceName);
+ writer.AddStyleAttribute(
+ HtmlTextWriterStyle.BackgroundImage,
+ string.Format(CultureInfo.InvariantCulture, "url({0})", HttpUtility.HtmlEncode(logoUrl)));
+ writer.AddStyleAttribute("background-repeat", "no-repeat");
+ writer.AddStyleAttribute("background-position", "0 50%");
+ writer.AddStyleAttribute(HtmlTextWriterStyle.PaddingLeft, "18px");
+ }
+
+ if (this.PresetBorder) {
+ writer.AddStyleAttribute(HtmlTextWriterStyle.BorderStyle, "solid");
+ writer.AddStyleAttribute(HtmlTextWriterStyle.BorderWidth, "1px");
+ writer.AddStyleAttribute(HtmlTextWriterStyle.BorderColor, "lightgray");
+ }
+
+ if (!string.IsNullOrEmpty(this.CssClass)) {
+ writer.AddAttribute(HtmlTextWriterAttribute.Class, this.CssClass);
+ }
+
+ writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
+ writer.AddAttribute(HtmlTextWriterAttribute.Name, HttpUtility.HtmlEncode(this.Name));
+ writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
+ writer.AddAttribute(HtmlTextWriterAttribute.Size, this.Columns.ToString(CultureInfo.InvariantCulture));
+ writer.AddAttribute(HtmlTextWriterAttribute.Value, HttpUtility.HtmlEncode(this.Text));
+ writer.AddAttribute(HtmlTextWriterAttribute.Tabindex, this.TabIndex.ToString(CultureInfo.CurrentCulture));
+
+ writer.RenderBeginTag(HtmlTextWriterTag.Input);
+ writer.RenderEndTag();
+ }
+
+ /// <summary>
+ /// When implemented by a class, processes postback data for an ASP.NET server control.
+ /// </summary>
+ /// <param name="postDataKey">The key identifier for the control.</param>
+ /// <param name="postCollection">The collection of all incoming name values.</param>
+ /// <returns>
+ /// true if the server control's state changes as a result of the postback; otherwise, false.
+ /// </returns>
+ protected virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection) {
+ Contract.Assume(postCollection != null, "Missing contract");
+
+ // If the control was temporarily hidden, it won't be in the Form data,
+ // and we'll just implicitly keep the last Text setting.
+ if (postCollection[this.Name] != null) {
+ this.Text = postCollection[this.Name];
+ return true;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// When implemented by a class, signals the server control to notify the ASP.NET application that the state of the control has changed.
+ /// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = "Preserve signature of interface we're implementing.")]
+ protected virtual void RaisePostDataChangedEvent() {
+ this.OnTextChanged();
+ }
+
+ /// <summary>
+ /// Called on a postback when the Text property has changed.
+ /// </summary>
+ protected virtual void OnTextChanged() {
+ EventHandler textChanged = this.TextChanged;
+ if (textChanged != null) {
+ textChanged(this, EventArgs.Empty);
+ }
+ }
+
+ /// <summary>
+ /// Creates the authentication requests for a given user-supplied Identifier.
+ /// </summary>
+ /// <param name="requests">The authentication requests to prepare.</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(IEnumerable<IAuthenticationRequest> requests) {
+ Contract.Requires(requests != null);
+
+ foreach (var request in requests) {
+ if (this.EnableRequestProfile) {
+ this.AddProfileArgs(request);
+ }
+
+ yield return request;
+ }
+ }
+
+ /// <summary>
+ /// Adds extensions to a given authentication request to ask the Provider
+ /// for user profile data.
+ /// </summary>
+ /// <param name="request">The authentication request to add the extensions to.</param>
+ private void AddProfileArgs(IAuthenticationRequest request) {
+ Requires.NotNull(request, "request");
+
+ var sreg = new ClaimsRequest() {
+ Nickname = this.RequestNickname,
+ Email = this.RequestEmail,
+ FullName = this.RequestFullName,
+ BirthDate = this.RequestBirthDate,
+ Gender = this.RequestGender,
+ PostalCode = this.RequestPostalCode,
+ Country = this.RequestCountry,
+ Language = this.RequestLanguage,
+ TimeZone = this.RequestTimeZone,
+ PolicyUrl = string.IsNullOrEmpty(this.PolicyUrl) ?
+ null : new Uri(this.RelyingParty.Channel.GetRequestFromContext().UrlBeforeRewriting, this.Page.ResolveUrl(this.PolicyUrl)),
+ };
+
+ // Only actually add the extension request if fields are actually being requested.
+ if (!sreg.Equals(EmptyClaimsRequest)) {
+ request.AddExtension(sreg);
+ }
+ }
+ }
+}