//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId.Extensions.UI { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.Linq; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; using DotNetOpenAuth.Xrds; /// /// OpenID User Interface extension 1.0 request message. /// /// /// Implements the extension described by: http://wiki.openid.net/f/openid_ui_extension_draft01.html /// This extension only applies to checkid_setup requests, since checkid_immediate requests display /// no UI to the user. /// For rules about how the popup window should be displayed, please see the documentation of /// . /// An RP may determine whether an arbitrary OP supports this extension (and thereby determine /// whether to use a standard full window redirect or a popup) via the /// method. /// [Serializable] public class UIRequest : IOpenIdMessageExtension, IMessageWithEvents { /// /// The factory method that may be used in deserialization of this message. /// internal static readonly StandardOpenIdExtensionFactory.CreateDelegate Factory = (typeUri, data, baseMessage, isProviderRole) => { if (typeUri == UIConstants.UITypeUri && isProviderRole) { return new UIRequest(); } return null; }; /// /// Additional type URIs that this extension is sometimes known by remote parties. /// private static readonly string[] additionalTypeUris = new string[] { UIConstants.LangPrefSupported, UIConstants.PopupSupported, UIConstants.IconSupported, }; /// /// Backing store for . /// private Dictionary extraData = new Dictionary(); /// /// Initializes a new instance of the class. /// public UIRequest() { this.LanguagePreference = new[] { CultureInfo.CurrentUICulture }; this.Mode = UIModes.Popup; } /// /// Gets or sets the list of user's preferred languages, sorted in decreasing preferred order. /// /// The default is the of the thread that created this instance. /// /// The user's preferred languages as a [BCP 47] language priority list, represented as a comma-separated list of BCP 47 basic language ranges in descending priority order. For instance, the value "fr-CA,fr-FR,en-CA" represents the preference for French spoken in Canada, French spoken in France, followed by English spoken in Canada. /// [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "By design.")] [MessagePart("lang", AllowEmpty = false)] public CultureInfo[] LanguagePreference { get; set; } /// /// Gets or sets the style of UI that the RP is hosting the OP's authentication page in. /// /// Some value from the class. Defaults to . [MessagePart("mode", AllowEmpty = false, IsRequired = true)] public string Mode { get; set; } /// /// Gets or sets a value indicating whether the Relying Party has an icon /// it would like the Provider to display to the user while asking them /// whether they would like to log in. /// /// true if the Provider should display an icon; otherwise, false. /// /// By default, the Provider displays the relying party's favicon.ico. /// [MessagePart("icon", AllowEmpty = false, IsRequired = false)] public bool? Icon { get; set; } #region IOpenIdMessageExtension Members /// /// Gets the TypeURI the extension uses in the OpenID protocol and in XRDS advertisements. /// /// public string TypeUri { get { return UIConstants.UITypeUri; } } /// /// Gets the additional TypeURIs that are supported by this extension, in preferred order. /// May be empty if none other than is supported, but /// should not be null. /// /// /// Useful for reading in messages with an older version of an extension. /// The value in the property is always checked before /// trying this list. /// If you do support multiple versions of an extension using this method, /// consider adding a CreateResponse method to your request extension class /// so that the response can have the context it needs to remain compatible /// given the version of the extension in the request message. /// The for an example. /// public IEnumerable AdditionalSupportedTypeUris { get { return additionalTypeUris; } } /// /// Gets or sets a value indicating whether this extension was /// signed by the sender. /// /// /// true if this instance is signed by the sender; otherwise, false. /// public bool IsSignedByRemoteParty { get; set; } #endregion #region IMessage Properties /// /// Gets the version of the protocol or extension this message is prepared to implement. /// /// The value 1.0. /// /// Implementations of this interface should ensure that this property never returns null. /// public Version Version { get { return new Version(1, 0); } } /// /// Gets the extra, non-standard Protocol parameters included in the message. /// /// /// Implementations of this interface should ensure that this property never returns null. /// public IDictionary ExtraData { get { return this.extraData; } } #endregion #region IMessage methods /// /// Checks the message state for conformity to the protocol specification /// and throws an exception if the message is invalid. /// /// /// Some messages have required fields, or combinations of fields that must relate to each other /// in specialized ways. After deserializing a message, this method checks the state of the /// message to see if it conforms to the protocol. /// Note that this property should not check signatures or perform any state checks /// outside this scope of this particular message. /// /// Thrown if the message is invalid. public void EnsureValidMessage() { } #endregion #region IMessageWithEvents Members /// /// Called when the message is about to be transmitted, /// before it passes through the channel binding elements. /// public void OnSending() { } /// /// Called when the message has been received, /// after it passes through the channel binding elements. /// public void OnReceiving() { if (this.LanguagePreference != null) { // TODO: see if we can change the CultureInfo.CurrentUICulture somehow } } #endregion } }