1 //-----------------------------------------------------------------------
2 // <copyright file="OpenIdTextBox.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
5 //-----------------------------------------------------------------------
7 [assembly
: System
.Web
.UI
.WebResource(DotNetOpenAuth
.OpenId
.RelyingParty
.OpenIdTextBox
.EmbeddedLogoResourceName
, "image/gif")]
9 #pragma warning disable 0809 // marking inherited, unsupported properties as obsolete to discourage their use
11 namespace DotNetOpenAuth
.OpenId
.RelyingParty
{
13 using System
.Collections
.Generic
;
14 using System
.Collections
.Specialized
;
15 using System
.ComponentModel
;
16 using System
.Diagnostics
;
17 using System
.Diagnostics
.CodeAnalysis
;
18 using System
.Globalization
;
20 using System
.Text
.RegularExpressions
;
22 using System
.Web
.Security
;
24 using System
.Web
.UI
.WebControls
;
25 using DotNetOpenAuth
.Configuration
;
26 using DotNetOpenAuth
.Messaging
;
27 using DotNetOpenAuth
.OpenId
.Extensions
.SimpleRegistration
;
30 /// An ASP.NET control that provides a minimal text box that is OpenID-aware.
33 /// This control offers greater UI flexibility than the <see cref="OpenIdLogin"/>
34 /// control, but requires more work to be done by the hosting web site to
35 /// assemble a complete login experience.
37 [DefaultProperty("Text"), ValidationProperty("Text")]
38 [ToolboxData("<{0}:OpenIdTextBox runat=\"server\" />")]
39 public class OpenIdTextBox
: CompositeControl
, IEditableTextControl
, ITextControl
{
41 /// The name of the manifest stream containing the
42 /// OpenID logo that is placed inside the text box.
44 internal const string EmbeddedLogoResourceName
= Util
.DefaultNamespace
+ ".OpenId.RelyingParty.openid_login.gif";
47 /// Default value for <see cref="TabIndex"/> property.
49 protected const short TabIndexDefault
= 0;
52 /// Default value of <see cref="UsePersistentCookie"/>.
54 protected const bool UsePersistentCookieDefault
= false;
56 #region Property category constants
59 /// The "Appearance" category for properties.
61 private const string AppearanceCategory
= "Appearance";
64 /// The "Simple Registration" category for properties.
66 private const string ProfileCategory
= "Simple Registration";
69 /// The "Behavior" category for properties.
71 private const string BehaviorCategory
= "Behavior";
75 #region Property viewstate keys
78 /// The viewstate key to use for the <see cref="RequestEmail"/> property.
80 private const string RequestEmailViewStateKey
= "RequestEmail";
83 /// The viewstate key to use for the <see cref="RequestNickname"/> property.
85 private const string RequestNicknameViewStateKey
= "RequestNickname";
88 /// The viewstate key to use for the <see cref="RequestPostalCode"/> property.
90 private const string RequestPostalCodeViewStateKey
= "RequestPostalCode";
93 /// The viewstate key to use for the <see cref="RequestCountry"/> property.
95 private const string RequestCountryViewStateKey
= "RequestCountry";
98 /// The viewstate key to use for the <see cref="RequireSsl"/> property.
100 private const string RequireSslViewStateKey
= "RequireSsl";
103 /// The viewstate key to use for the <see cref="RequestLanguage"/> property.
105 private const string RequestLanguageViewStateKey
= "RequestLanguage";
108 /// The viewstate key to use for the <see cref="RequestTimeZone"/> property.
110 private const string RequestTimeZoneViewStateKey
= "RequestTimeZone";
113 /// The viewstate key to use for the <see cref="EnableRequestProfile"/> property.
115 private const string EnableRequestProfileViewStateKey
= "EnableRequestProfile";
118 /// The viewstate key to use for the <see cref="PolicyUrl"/> property.
120 private const string PolicyUrlViewStateKey
= "PolicyUrl";
123 /// The viewstate key to use for the <see cref="RequestFullName"/> property.
125 private const string RequestFullNameViewStateKey
= "RequestFullName";
128 /// The viewstate key to use for the <see cref="PresetBorder"/> property.
130 private const string PresetBorderViewStateKey
= "PresetBorder";
133 /// The viewstate key to use for the <see cref="ShowLogo"/> property.
135 private const string ShowLogoViewStateKey
= "ShowLogo";
138 /// The viewstate key to use for the <see cref="UsePersistentCookie"/> property.
140 private const string UsePersistentCookieViewStateKey
= "UsePersistentCookie";
143 /// The viewstate key to use for the <see cref="RequestGender"/> property.
145 private const string RequestGenderViewStateKey
= "RequestGender";
148 /// The viewstate key to use for the <see cref="ReturnToUrl"/> property.
150 private const string ReturnToUrlViewStateKey
= "ReturnToUrl";
153 /// The viewstate key to use for the <see cref="Stateless"/> property.
155 private const string StatelessViewStateKey
= "Stateless";
158 /// The viewstate key to use for the <see cref="ImmediateMode"/> property.
160 private const string ImmediateModeViewStateKey
= "ImmediateMode";
163 /// The viewstate key to use for the <see cref="RequestBirthDate"/> property.
165 private const string RequestBirthDateViewStateKey
= "RequestBirthDate";
168 /// The viewstate key to use for the <see cref="RealmUrl"/> property.
170 private const string RealmUrlViewStateKey
= "RealmUrl";
174 #region Property defaults
177 /// The default value for the <see cref="Columns"/> property.
179 private const int ColumnsDefault
= 40;
182 /// The default value for the <see cref="MaxLength"/> property.
184 private const int MaxLengthDefault
= 40;
187 /// The default value for the <see cref="EnableRequestProfile"/> property.
189 private const bool EnableRequestProfileDefault
= true;
192 /// The default value for the <see cref="RequireSsl"/> property.
194 private const bool RequireSslDefault
= false;
197 /// The default value for the <see cref="ImmediateMode"/> property.
199 private const bool ImmediateModeDefault
= false;
202 /// The default value for the <see cref="Stateless"/> property.
204 private const bool StatelessDefault
= false;
207 /// The default value for the <see cref="ShowLogo"/> property.
209 private const bool ShowLogoDefault
= true;
212 /// The default value for the <see cref="PresetBorder"/> property.
214 private const bool PresetBorderDefault
= true;
217 /// The default value for the <see cref="PolicyUrl"/> property.
219 private const string PolicyUrlDefault
= "";
222 /// The default value for the <see cref="CssClass"/> property.
224 private const string CssClassDefault
= "openid";
227 /// The default value for the <see cref="ReturnToUrl"/> property.
229 private const string ReturnToUrlDefault
= "";
232 /// The default value for the <see cref="Text"/> property.
234 private const string TextDefault
= "";
237 /// The default value for the <see cref="RealmUrl"/> property.
239 private const string RealmUrlDefault
= "~/";
242 /// The default value for the <see cref="RequestEmail"/> property.
244 private const DemandLevel RequestEmailDefault
= DemandLevel
.NoRequest
;
247 /// The default value for the <see cref="RequestPostalCode"/> property.
249 private const DemandLevel RequestPostalCodeDefault
= DemandLevel
.NoRequest
;
252 /// The default value for the <see cref="RequestCountry"/> property.
254 private const DemandLevel RequestCountryDefault
= DemandLevel
.NoRequest
;
257 /// The default value for the <see cref="RequestLanguage"/> property.
259 private const DemandLevel RequestLanguageDefault
= DemandLevel
.NoRequest
;
262 /// The default value for the <see cref="RequestTimeZone"/> property.
264 private const DemandLevel RequestTimeZoneDefault
= DemandLevel
.NoRequest
;
267 /// The default value for the <see cref="RequestNickname"/> property.
269 private const DemandLevel RequestNicknameDefault
= DemandLevel
.NoRequest
;
272 /// The default value for the <see cref="RequestFullName"/> property.
274 private const DemandLevel RequestFullNameDefault
= DemandLevel
.NoRequest
;
277 /// The default value for the <see cref="RequestBirthDate"/> property.
279 private const DemandLevel RequestBirthDateDefault
= DemandLevel
.NoRequest
;
282 /// The default value for the <see cref="RequestGender"/> property.
284 private const DemandLevel RequestGenderDefault
= DemandLevel
.NoRequest
;
289 /// The callback parameter for use with persisting the <see cref="UsePersistentCookie"/> property.
291 private const string UsePersistentCookieCallbackKey
= "OpenIdTextBox_UsePersistentCookie";
294 /// The text in the text box before the text box is instantiated.
296 private string text
= TextDefault
;
299 /// The text box itself.
301 private TextBox wrappedTextBox
;
304 /// Initializes a new instance of the <see cref="OpenIdTextBox"/> class.
306 public OpenIdTextBox() {
307 this.InitializeControls();
313 /// Fired upon completion of a successful login.
315 [Description("Fired upon completion of a successful login.")]
316 public event EventHandler
<OpenIdEventArgs
> LoggedIn
;
319 /// Fired when a login attempt fails.
321 [Description("Fired when a login attempt fails.")]
322 public event EventHandler
<OpenIdEventArgs
> Failed
;
325 /// Fired when an authentication attempt is canceled at the OpenID Provider.
327 [Description("Fired when an authentication attempt is canceled at the OpenID Provider.")]
328 public event EventHandler
<OpenIdEventArgs
> Canceled
;
331 /// Fired when an Immediate authentication attempt fails, and the Provider suggests using non-Immediate mode.
333 [Description("Fired when an Immediate authentication attempt fails, and the Provider suggests using non-Immediate mode.")]
334 public event EventHandler
<OpenIdEventArgs
> SetupRequired
;
337 #region IEditableTextControl Members
340 /// Occurs when the content of the text changes between posts to the server.
342 public event EventHandler TextChanged
{
343 add { this.WrappedTextBox.TextChanged += value; }
344 remove { this.WrappedTextBox.TextChanged -= value; }
352 /// Gets or sets the content of the text box.
354 [Bindable(true), DefaultValue(""), Category(AppearanceCategory
)]
355 [Description("The content of the text box.")]
358 return this.WrappedTextBox
!= null ? this.WrappedTextBox
.Text
: this.text
;
363 if (this.WrappedTextBox
!= null) {
364 this.WrappedTextBox
.Text
= value;
370 /// Gets or sets the OpenID <see cref="Realm"/> of the relying party web site.
372 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId
= "System.Uri", Justification
= "Using Uri.ctor for validation.")]
373 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId
= "DotNetOpenAuth.OpenId.Realm", Justification
= "Using ctor for validation.")]
374 [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification
= "Bindable property must be simple type")]
375 [Bindable(true), DefaultValue(RealmUrlDefault
), Category(BehaviorCategory
)]
376 [Description("The OpenID Realm of the relying party web site.")]
377 public string RealmUrl
{
379 return (string)(ViewState
[RealmUrlViewStateKey
] ?? RealmUrlDefault
);
383 if (Page
!= null && !DesignMode
) {
384 // Validate new value by trying to construct a Realm object based on it.
385 new Realm(OpenIdUtilities
.GetResolvedRealm(Page
, value)); // throws an exception on failure.
387 // We can't fully test it, but it should start with either ~/ or a protocol.
388 if (Regex
.IsMatch(value, @"^https?://")) {
389 new Uri(value.Replace("*.", string.Empty
)); // make sure it's fully-qualified, but ignore wildcards
390 } else if (value.StartsWith("~/", StringComparison
.Ordinal
)) {
393 throw new UriFormatException();
396 ViewState
[RealmUrlViewStateKey
] = value;
401 /// Gets or sets the OpenID ReturnTo of the relying party web site.
403 [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings")]
404 [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId
= "System.Uri", Justification
= "Using Uri.ctor for validation.")]
405 [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification
= "Bindable property must be simple type")]
406 [Bindable(true), DefaultValue(ReturnToUrlDefault
), Category(BehaviorCategory
)]
407 [Description("The OpenID ReturnTo of the relying party web site.")]
408 public string ReturnToUrl
{
410 return (string)(this.ViewState
[ReturnToUrlViewStateKey
] ?? ReturnToUrlDefault
);
414 if (this.Page
!= null && !this.DesignMode
) {
415 // Validate new value by trying to construct a Uri based on it.
416 new Uri(MessagingUtilities
.GetRequestUrlFromContext(), this.Page
.ResolveUrl(value)); // throws an exception on failure.
418 // We can't fully test it, but it should start with either ~/ or a protocol.
419 if (Regex
.IsMatch(value, @"^https?://")) {
420 new Uri(value); // make sure it's fully-qualified, but ignore wildcards
421 } else if (value.StartsWith("~/", StringComparison
.Ordinal
)) {
424 throw new UriFormatException();
428 this.ViewState
[ReturnToUrlViewStateKey
] = value;
433 /// Gets or sets a value indicating whether to use immediate mode in the
437 /// True if a Provider should reply immediately to the authentication request
438 /// without interacting with the user. False if the Provider can take time
439 /// to authenticate the user in order to complete an authentication attempt.
442 /// Setting this to true is sometimes useful in AJAX scenarios. Setting this to
443 /// true can cause failed authentications when the user truly controls an
444 /// Identifier, but must complete an authentication step with the Provider before
445 /// the Provider will approve the login from this relying party.
447 [Bindable(true), DefaultValue(ImmediateModeDefault
), Category(BehaviorCategory
)]
448 [Description("Whether the Provider should respond immediately to an authentication attempt without interacting with the user.")]
449 public bool ImmediateMode
{
450 get { return (bool)(ViewState[ImmediateModeViewStateKey] ?? ImmediateModeDefault); }
451 set { ViewState[ImmediateModeViewStateKey] = value; }
455 /// Gets or sets a value indicating whether stateless mode is used.
457 [Bindable(true), DefaultValue(StatelessDefault
), Category(BehaviorCategory
)]
458 [Description("Controls whether stateless mode is used.")]
459 public bool Stateless
{
460 get { return (bool)(ViewState[StatelessViewStateKey] ?? StatelessDefault); }
461 set { ViewState[StatelessViewStateKey] = value; }
465 /// Gets or sets the CSS class assigned to the text box.
467 [Bindable(true), DefaultValue(CssClassDefault
), Category(AppearanceCategory
)]
468 [Description("The CSS class assigned to the text box.")]
469 public override string CssClass
{
470 get { return this.WrappedTextBox.CssClass; }
471 set { this.WrappedTextBox.CssClass = value; }
475 /// Gets or sets a value indicating whether to show the OpenID logo in the text box.
477 [Bindable(true), DefaultValue(ShowLogoDefault
), Category(AppearanceCategory
)]
478 [Description("The visibility of the OpenID logo in the text box.")]
479 public bool ShowLogo
{
480 get { return (bool)(this.ViewState[ShowLogoViewStateKey] ?? ShowLogoDefault); }
481 set { this.ViewState[ShowLogoViewStateKey] = value; }
485 /// Gets or sets a value indicating whether to use inline styling to force a solid gray border.
487 [Bindable(true), DefaultValue(PresetBorderDefault
), Category(AppearanceCategory
)]
488 [Description("Whether to use inline styling to force a solid gray border.")]
489 public bool PresetBorder
{
490 get { return (bool)(this.ViewState[PresetBorderViewStateKey] ?? PresetBorderDefault); }
491 set { this.ViewState[PresetBorderViewStateKey] = value; }
495 /// Gets or sets a value indicating whether to send a persistent cookie upon successful
496 /// login so the user does not have to log in upon returning to this site.
498 [Bindable(true), DefaultValue(UsePersistentCookieDefault
), Category(BehaviorCategory
)]
499 [Description("Whether to send a persistent cookie upon successful " +
500 "login so the user does not have to log in upon returning to this site.")]
501 public virtual bool UsePersistentCookie
{
502 get { return (bool)(this.ViewState[UsePersistentCookieViewStateKey] ?? UsePersistentCookieDefault); }
503 set { this.ViewState[UsePersistentCookieViewStateKey] = value; }
507 /// Gets or sets the width of the text box in characters.
509 [Bindable(true), DefaultValue(ColumnsDefault
), Category(AppearanceCategory
)]
510 [Description("The width of the text box in characters.")]
512 get { return this.WrappedTextBox.Columns; }
513 set { this.WrappedTextBox.Columns = value; }
517 /// Gets or sets the maximum number of characters the browser should allow
519 [Bindable(true), DefaultValue(MaxLengthDefault
), Category(AppearanceCategory
)]
520 [Description("The maximum number of characters the browser should allow.")]
521 public int MaxLength
{
522 get { return this.WrappedTextBox.MaxLength; }
523 set { this.WrappedTextBox.MaxLength = value; }
527 /// Gets or sets the tab index of the Web server control.
531 /// The tab index of the Web server control. The default is 0, which indicates that this property is not set.
533 /// <exception cref="T:System.ArgumentOutOfRangeException">
534 /// The specified tab index is not between -32768 and 32767.
536 [Bindable(true), DefaultValue(TabIndexDefault
), Category(BehaviorCategory
)]
537 [Description("The tab index of the text box control.")]
538 public override short TabIndex
{
539 get { return this.WrappedTextBox.TabIndex; }
540 set { this.WrappedTextBox.TabIndex = value; }
544 /// Gets or sets your level of interest in receiving the user's nickname from the Provider.
546 [Bindable(true), DefaultValue(RequestNicknameDefault
), Category(ProfileCategory
)]
547 [Description("Your level of interest in receiving the user's nickname from the Provider.")]
548 public DemandLevel RequestNickname
{
549 get { return (DemandLevel)(ViewState[RequestNicknameViewStateKey] ?? RequestNicknameDefault); }
550 set { ViewState[RequestNicknameViewStateKey] = value; }
554 /// Gets or sets your level of interest in receiving the user's email address from the Provider.
556 [Bindable(true), DefaultValue(RequestEmailDefault
), Category(ProfileCategory
)]
557 [Description("Your level of interest in receiving the user's email address from the Provider.")]
558 public DemandLevel RequestEmail
{
559 get { return (DemandLevel)(ViewState[RequestEmailViewStateKey] ?? RequestEmailDefault); }
560 set { ViewState[RequestEmailViewStateKey] = value; }
564 /// Gets or sets your level of interest in receiving the user's full name from the Provider.
566 [Bindable(true), DefaultValue(RequestFullNameDefault
), Category(ProfileCategory
)]
567 [Description("Your level of interest in receiving the user's full name from the Provider")]
568 public DemandLevel RequestFullName
{
569 get { return (DemandLevel)(ViewState[RequestFullNameViewStateKey] ?? RequestFullNameDefault); }
570 set { ViewState[RequestFullNameViewStateKey] = value; }
574 /// Gets or sets your level of interest in receiving the user's birthdate from the Provider.
576 [Bindable(true), DefaultValue(RequestBirthDateDefault
), Category(ProfileCategory
)]
577 [Description("Your level of interest in receiving the user's birthdate from the Provider.")]
578 public DemandLevel RequestBirthDate
{
579 get { return (DemandLevel)(ViewState[RequestBirthDateViewStateKey] ?? RequestBirthDateDefault); }
580 set { ViewState[RequestBirthDateViewStateKey] = value; }
584 /// Gets or sets your level of interest in receiving the user's gender from the Provider.
586 [Bindable(true), DefaultValue(RequestGenderDefault
), Category(ProfileCategory
)]
587 [Description("Your level of interest in receiving the user's gender from the Provider.")]
588 public DemandLevel RequestGender
{
589 get { return (DemandLevel)(ViewState[RequestGenderViewStateKey] ?? RequestGenderDefault); }
590 set { ViewState[RequestGenderViewStateKey] = value; }
594 /// Gets or sets your level of interest in receiving the user's postal code from the Provider.
596 [Bindable(true), DefaultValue(RequestPostalCodeDefault
), Category(ProfileCategory
)]
597 [Description("Your level of interest in receiving the user's postal code from the Provider.")]
598 public DemandLevel RequestPostalCode
{
599 get { return (DemandLevel)(ViewState[RequestPostalCodeViewStateKey] ?? RequestPostalCodeDefault); }
600 set { ViewState[RequestPostalCodeViewStateKey] = value; }
604 /// Gets or sets your level of interest in receiving the user's country from the Provider.
607 [Category(ProfileCategory
)]
608 [DefaultValue(RequestCountryDefault
)]
609 [Description("Your level of interest in receiving the user's country from the Provider.")]
610 public DemandLevel RequestCountry
{
611 get { return (DemandLevel)(ViewState[RequestCountryViewStateKey] ?? RequestCountryDefault); }
612 set { ViewState[RequestCountryViewStateKey] = value; }
616 /// Gets or sets your level of interest in receiving the user's preferred language from the Provider.
618 [Bindable(true), DefaultValue(RequestLanguageDefault
), Category(ProfileCategory
)]
619 [Description("Your level of interest in receiving the user's preferred language from the Provider.")]
620 public DemandLevel RequestLanguage
{
621 get { return (DemandLevel)(ViewState[RequestLanguageViewStateKey] ?? RequestLanguageDefault); }
622 set { ViewState[RequestLanguageViewStateKey] = value; }
626 /// Gets or sets your level of interest in receiving the user's time zone from the Provider.
628 [Bindable(true), DefaultValue(RequestTimeZoneDefault
), Category(ProfileCategory
)]
629 [Description("Your level of interest in receiving the user's time zone from the Provider.")]
630 public DemandLevel RequestTimeZone
{
631 get { return (DemandLevel)(ViewState[RequestTimeZoneViewStateKey] ?? RequestTimeZoneDefault); }
632 set { ViewState[RequestTimeZoneViewStateKey] = value; }
636 /// Gets or sets the URL to your privacy policy page that describes how
637 /// claims will be used and/or shared.
639 [SuppressMessage("Microsoft.Design", "CA1056:UriPropertiesShouldNotBeStrings", Justification
= "Bindable property must be simple type")]
640 [Bindable(true), DefaultValue(PolicyUrlDefault
), Category(ProfileCategory
)]
641 [Description("The URL to your privacy policy page that describes how claims will be used and/or shared.")]
642 public string PolicyUrl
{
644 return (string)ViewState
[PolicyUrlViewStateKey
] ?? PolicyUrlDefault
;
648 UriUtil
.ValidateResolvableUrl(Page
, DesignMode
, value);
649 ViewState
[PolicyUrlViewStateKey
] = value;
654 /// Gets or sets a value indicating whether to use OpenID extensions
655 /// to retrieve profile data of the authenticating user.
657 [Bindable(true), DefaultValue(EnableRequestProfileDefault
), Category(ProfileCategory
)]
658 [Description("Turns the entire Simple Registration extension on or off.")]
659 public bool EnableRequestProfile
{
660 get { return (bool)(ViewState[EnableRequestProfileViewStateKey] ?? EnableRequestProfileDefault); }
661 set { ViewState[EnableRequestProfileViewStateKey] = value; }
665 /// Gets or sets a value indicating whether to enforce on high security mode,
666 /// which requires the full authentication pipeline to be protected by SSL.
668 [Bindable(true), DefaultValue(RequireSslDefault
), Category(BehaviorCategory
)]
669 [Description("Turns on high security mode, requiring the full authentication pipeline to be protected by SSL.")]
670 public bool RequireSsl
{
671 get { return (bool)(ViewState[RequireSslViewStateKey] ?? RequireSslDefault); }
672 set { ViewState[RequireSslViewStateKey] = value; }
676 /// Gets or sets the type of the custom application store to use, or <c>null</c> to use the default.
679 /// If set, this property must be set in each Page Load event
680 /// as it is not persisted across postbacks.
682 public IRelyingPartyApplicationStore CustomApplicationStore { get; set; }
686 #region Properties to hide
689 /// Gets or sets the foreground color (typically the color of the text) of the Web server control.
692 /// A <see cref="T:System.Drawing.Color"/> that represents the foreground color of the control. The default is <see cref="F:System.Drawing.Color.Empty"/>.
694 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
695 public override System
.Drawing
.Color ForeColor
{
696 get { throw new NotSupportedException(); }
697 set { throw new NotSupportedException(); }
701 /// Gets or sets the background color of the Web server control.
704 /// A <see cref="T:System.Drawing.Color"/> that represents the background color of the control. The default is <see cref="F:System.Drawing.Color.Empty"/>, which indicates that this property is not set.
706 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
707 public override System
.Drawing
.Color BackColor
{
708 get { throw new NotSupportedException(); }
709 set { throw new NotSupportedException(); }
713 /// Gets or sets the border color of the Web control.
716 /// A <see cref="T:System.Drawing.Color"/> that represents the border color of the control. The default is <see cref="F:System.Drawing.Color.Empty"/>, which indicates that this property is not set.
718 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
719 public override System
.Drawing
.Color BorderColor
{
720 get { throw new NotSupportedException(); }
721 set { throw new NotSupportedException(); }
725 /// Gets or sets the border width of the Web server control.
728 /// A <see cref="T:System.Web.UI.WebControls.Unit"/> that represents the border width of a Web server control. The default value is <see cref="F:System.Web.UI.WebControls.Unit.Empty"/>, which indicates that this property is not set.
730 /// <exception cref="T:System.ArgumentException">
731 /// The specified border width is a negative value.
733 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
734 public override Unit BorderWidth
{
735 get { return Unit.Empty; }
736 set { throw new NotSupportedException(); }
740 /// Gets or sets the border style of the Web server control.
743 /// One of the <see cref="T:System.Web.UI.WebControls.BorderStyle"/> enumeration values. The default is NotSet.
745 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
746 public override BorderStyle BorderStyle
{
747 get { return BorderStyle.None; }
748 set { throw new NotSupportedException(); }
752 /// Gets the font properties associated with the Web server control.
755 /// A <see cref="T:System.Web.UI.WebControls.FontInfo"/> that represents the font properties of the Web server control.
757 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
758 public override FontInfo Font
{
763 /// Gets or sets the height of the Web server control.
766 /// A <see cref="T:System.Web.UI.WebControls.Unit"/> that represents the height of the control. The default is <see cref="F:System.Web.UI.WebControls.Unit.Empty"/>.
768 /// <exception cref="T:System.ArgumentException">
769 /// The height was set to a negative value.
771 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
772 public override Unit Height
{
773 get { return Unit.Empty; }
774 set { throw new NotSupportedException(); }
778 /// Gets or sets the width of the Web server control.
781 /// A <see cref="T:System.Web.UI.WebControls.Unit"/> that represents the width of the control. The default is <see cref="F:System.Web.UI.WebControls.Unit.Empty"/>.
783 /// <exception cref="T:System.ArgumentException">
784 /// The width of the Web server control was set to a negative value.
786 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
787 public override Unit Width
{
788 get { return Unit.Empty; }
789 set { throw new NotSupportedException(); }
793 /// Gets or sets the text displayed when the mouse pointer hovers over the Web server control.
796 /// The text displayed when the mouse pointer hovers over the Web server control. The default is <see cref="F:System.String.Empty"/>.
798 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
799 public override string ToolTip
{
800 get { return string.Empty; }
801 set { throw new NotSupportedException(); }
805 /// Gets or sets the skin to apply to the control.
808 /// The name of the skin to apply to the control. The default is <see cref="F:System.String.Empty"/>.
810 /// <exception cref="T:System.ArgumentException">
811 /// The skin specified in the <see cref="P:System.Web.UI.WebControls.WebControl.SkinID"/> property does not exist in the theme.
813 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
814 public override string SkinID
{
815 get { return string.Empty; }
816 set { throw new NotSupportedException(); }
820 /// Gets or sets a value indicating whether themes apply to this control.
822 /// <returns>true to use themes; otherwise, false. The default is false.
824 [Obsolete("This property does not do anything."), Browsable(false), Bindable(false)]
825 public override bool EnableTheming
{
826 get { return false; }
827 set { throw new NotSupportedException(); }
833 /// Gets the <see cref="TextBox"/> control that this control wraps.
835 protected TextBox WrappedTextBox
{
836 get { return this.wrappedTextBox; }
840 /// Gets or sets a value indicating whether the text box should
841 /// receive input focus when the web page appears.
843 protected bool ShouldBeFocused { get; set; }
846 /// Gets or sets the OpenID authentication request that is about to be sent.
848 protected IAuthenticationRequest Request { get; set; }
851 /// Sets the input focus to start on the text box when the page appears
852 /// in the user's browser.
854 public override void Focus() {
855 if (Controls
.Count
== 0) {
856 this.ShouldBeFocused
= true;
858 this.WrappedTextBox
.Focus();
863 /// Constructs the authentication request and returns it.
865 /// <returns>The instantiated authentication request.</returns>
867 /// <para>This method need not be called before calling the <see cref="LogOn"/> method,
868 /// but is offered in the event that adding extensions to the request is desired.</para>
869 /// <para>The Simple Registration extension arguments are added to the request
870 /// before returning if <see cref="EnableRequestProfile"/> is set to true.</para>
872 public IAuthenticationRequest
CreateRequest() {
873 ErrorUtilities
.VerifyOperation(this.Request
== null, OpenIdStrings
.CreateRequestAlreadyCalled
);
874 ErrorUtilities
.VerifyOperation(!string.IsNullOrEmpty(this.Text
), OpenIdStrings
.OpenIdTextBoxEmpty
);
877 var consumer
= this.CreateRelyingParty();
879 // Resolve the trust root, and swap out the scheme and port if necessary to match the
880 // return_to URL, since this match is required by OpenId, and the consumer app
881 // may be using HTTP at some times and HTTPS at others.
882 UriBuilder realm
= OpenIdUtilities
.GetResolvedRealm(this.Page
, this.RealmUrl
);
883 realm
.Scheme
= Page
.Request
.Url
.Scheme
;
884 realm
.Port
= Page
.Request
.Url
.Port
;
886 // Initiate openid request
887 // We use TryParse here to avoid throwing an exception which
888 // might slip through our validator control if it is disabled.
889 Identifier userSuppliedIdentifier
;
890 if (Identifier
.TryParse(this.Text
, out userSuppliedIdentifier
)) {
891 Realm typedRealm
= new Realm(realm
);
892 if (string.IsNullOrEmpty(this.ReturnToUrl
)) {
893 this.Request
= consumer
.CreateRequest(userSuppliedIdentifier
, typedRealm
);
895 Uri returnTo
= new Uri(MessagingUtilities
.GetRequestUrlFromContext(), this.ReturnToUrl
);
896 this.Request
= consumer
.CreateRequest(userSuppliedIdentifier
, typedRealm
, returnTo
);
898 this.Request
.Mode
= this.ImmediateMode
? AuthenticationRequestMode
.Immediate
: AuthenticationRequestMode
.Setup
;
899 if (this.EnableRequestProfile
) {
900 this.AddProfileArgs(this.Request
);
903 // Add state that needs to survive across the redirect.
904 this.Request
.AddCallbackArguments(UsePersistentCookieCallbackKey
, this.UsePersistentCookie
.ToString(CultureInfo
.InvariantCulture
));
906 Logger
.WarnFormat("An invalid identifier was entered ({0}), but not caught by any validation routine.", this.Text
);
909 } catch (ProtocolException ex
) {
910 this.OnFailed(new FailedAuthenticationResponse(ex
));
917 /// Immediately redirects to the OpenID Provider to verify the Identifier
918 /// provided in the text box.
920 public void LogOn() {
921 if (this.Request
== null) {
922 this.CreateRequest(); // sets this.Request
925 if (this.Request
!= null) {
926 this.Request
.RedirectToProvider();
931 /// Creates the text box control.
933 protected override void CreateChildControls() {
934 base.CreateChildControls();
936 this.Controls
.Add(this.wrappedTextBox
);
937 if (this.ShouldBeFocused
) {
938 this.WrappedTextBox
.Focus();
943 /// Initializes the text box control.
945 protected virtual void InitializeControls() {
946 this.wrappedTextBox
= new TextBox();
947 this.wrappedTextBox
.ID
= "wrappedTextBox";
948 this.wrappedTextBox
.CssClass
= CssClassDefault
;
949 this.wrappedTextBox
.Columns
= ColumnsDefault
;
950 this.wrappedTextBox
.Text
= this.text
;
951 this.wrappedTextBox
.TabIndex
= TabIndexDefault
;
955 /// Checks for incoming OpenID authentication responses and fires appropriate events.
957 /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
958 protected override void OnLoad(EventArgs e
) {
961 if (!Enabled
|| Page
.IsPostBack
) {
965 var rp
= this.CreateRelyingParty();
966 var response
= rp
.GetResponse();
967 if (response
!= null) {
968 string persistentString
= response
.GetCallbackArgument(UsePersistentCookieCallbackKey
);
970 if (persistentString
!= null && bool.TryParse(persistentString
, out persistentBool
)) {
971 this.UsePersistentCookie
= persistentBool
;
974 switch (response
.Status
) {
975 case AuthenticationStatus
.Canceled
:
976 this.OnCanceled(response
);
978 case AuthenticationStatus
.Authenticated
:
979 this.OnLoggedIn(response
);
981 case AuthenticationStatus
.SetupRequired
:
982 this.OnSetupRequired(response
);
984 case AuthenticationStatus
.Failed
:
985 this.OnFailed(response
);
988 throw new InvalidOperationException("Unexpected response status code.");
994 /// Prepares the text box to be rendered.
996 /// <param name="e">An <see cref="T:System.EventArgs"/> object that contains the event data.</param>
997 protected override void OnPreRender(EventArgs e
) {
1000 if (this.ShowLogo
) {
1001 string logoUrl
= Page
.ClientScript
.GetWebResourceUrl(
1002 typeof(OpenIdTextBox
), EmbeddedLogoResourceName
);
1003 this.WrappedTextBox
.Style
[HtmlTextWriterStyle
.BackgroundImage
] = string.Format(
1004 CultureInfo
.InvariantCulture
, "url({0})", HttpUtility
.HtmlEncode(logoUrl
));
1005 this.WrappedTextBox
.Style
["background-repeat"] = "no-repeat";
1006 this.WrappedTextBox
.Style
["background-position"] = "0 50%";
1007 this.WrappedTextBox
.Style
[HtmlTextWriterStyle
.PaddingLeft
] = "18px";
1010 if (this.PresetBorder
) {
1011 this.WrappedTextBox
.Style
[HtmlTextWriterStyle
.BorderStyle
] = "solid";
1012 this.WrappedTextBox
.Style
[HtmlTextWriterStyle
.BorderWidth
] = "1px";
1013 this.WrappedTextBox
.Style
[HtmlTextWriterStyle
.BorderColor
] = "lightgray";
1020 /// Fires the <see cref="LoggedIn"/> event.
1022 /// <param name="response">The response.</param>
1023 protected virtual void OnLoggedIn(IAuthenticationResponse response
) {
1024 ErrorUtilities
.VerifyArgumentNotNull(response
, "response");
1025 ErrorUtilities
.VerifyInternal(response
.Status
== AuthenticationStatus
.Authenticated
, "Firing OnLoggedIn event without an authenticated response.");
1027 var loggedIn
= this.LoggedIn
;
1028 OpenIdEventArgs args
= new OpenIdEventArgs(response
);
1029 if (loggedIn
!= null) {
1030 loggedIn(this, args
);
1034 FormsAuthentication
.RedirectFromLoginPage(response
.ClaimedIdentifier
, this.UsePersistentCookie
);
1039 /// Fires the <see cref="Failed"/> event.
1041 /// <param name="response">The response.</param>
1042 protected virtual void OnFailed(IAuthenticationResponse response
) {
1043 ErrorUtilities
.VerifyArgumentNotNull(response
, "response");
1044 ErrorUtilities
.VerifyInternal(response
.Status
== AuthenticationStatus
.Failed
, "Firing Failed event for the wrong response type.");
1046 var failed
= this.Failed
;
1047 if (failed
!= null) {
1048 failed(this, new OpenIdEventArgs(response
));
1053 /// Fires the <see cref="Canceled"/> event.
1055 /// <param name="response">The response.</param>
1056 protected virtual void OnCanceled(IAuthenticationResponse response
) {
1057 ErrorUtilities
.VerifyArgumentNotNull(response
, "response");
1058 ErrorUtilities
.VerifyInternal(response
.Status
== AuthenticationStatus
.Canceled
, "Firing Canceled event for the wrong response type.");
1060 var canceled
= this.Canceled
;
1061 if (canceled
!= null) {
1062 canceled(this, new OpenIdEventArgs(response
));
1067 /// Fires the <see cref="SetupRequired"/> event.
1069 /// <param name="response">The response.</param>
1070 protected virtual void OnSetupRequired(IAuthenticationResponse response
) {
1071 ErrorUtilities
.VerifyArgumentNotNull(response
, "response");
1072 ErrorUtilities
.VerifyInternal(response
.Status
== AuthenticationStatus
.SetupRequired
, "Firing SetupRequired event for the wrong response type.");
1074 // Why are we firing Failed when we're OnSetupRequired? Backward compatibility.
1075 var setupRequired
= this.SetupRequired
;
1076 if (setupRequired
!= null) {
1077 setupRequired(this, new OpenIdEventArgs(response
));
1084 /// Adds extensions to a given authentication request to ask the Provider
1085 /// for user profile data.
1087 /// <param name="request">The authentication request to add the extensions to.</param>
1088 private void AddProfileArgs(IAuthenticationRequest request
) {
1089 ErrorUtilities
.VerifyArgumentNotNull(request
, "request");
1091 request
.AddExtension(new ClaimsRequest() {
1092 Nickname
= this.RequestNickname
,
1093 Email
= this.RequestEmail
,
1094 FullName
= this.RequestFullName
,
1095 BirthDate
= this.RequestBirthDate
,
1096 Gender
= this.RequestGender
,
1097 PostalCode
= this.RequestPostalCode
,
1098 Country
= this.RequestCountry
,
1099 Language
= this.RequestLanguage
,
1100 TimeZone
= this.RequestTimeZone
,
1101 PolicyUrl
= string.IsNullOrEmpty(this.PolicyUrl
) ?
1102 null : new Uri(MessagingUtilities
.GetRequestUrlFromContext(), this.Page
.ResolveUrl(this.PolicyUrl
)),
1107 /// Creates the relying party instance used to generate authentication requests.
1109 /// <returns>The instantiated relying party.</returns>
1110 private OpenIdRelyingParty
CreateRelyingParty() {
1111 // If we're in stateful mode, first use the explicitly given one on this control if there
1112 // is one. Then try the configuration file specified one. Finally, use the default
1113 // in-memory one that's built into OpenIdRelyingParty.
1114 IRelyingPartyApplicationStore store
= this.Stateless
? null :
1115 (this.CustomApplicationStore
?? DotNetOpenAuthSection
.Configuration
.OpenId
.RelyingParty
.ApplicationStore
.CreateInstance(OpenIdRelyingParty
.HttpApplicationStore
));
1116 var rp
= new OpenIdRelyingParty(store
);
1118 // Only set RequireSsl to true, as we don't want to override
1119 // a .config setting of true with false.
1120 if (this.RequireSsl
) {
1121 rp
.SecuritySettings
.RequireSsl
= true;