diff options
author | Andrew Arnott <andrewarnott@gmail.com> | 2009-12-26 07:04:33 -0800 |
---|---|---|
committer | Andrew Arnott <andrewarnott@gmail.com> | 2009-12-26 07:04:33 -0800 |
commit | 8a677d2d2320e96e4b70e994e978804a5cc358fc (patch) | |
tree | 25353095c2f3d5bbb940d47e8f612cafcdd4aa44 /src | |
parent | ce37861c9507e338fc81314898b3a30888310b55 (diff) | |
parent | 72f5ee12a341eaca93075fb0f4705bec7cc84631 (diff) | |
download | DotNetOpenAuth-8a677d2d2320e96e4b70e994e978804a5cc358fc.zip DotNetOpenAuth-8a677d2d2320e96e4b70e994e978804a5cc358fc.tar.gz DotNetOpenAuth-8a677d2d2320e96e4b70e994e978804a5cc358fc.tar.bz2 |
Merge branch 'reports' into v3.3
Conflicts:
projecttemplates/WebFormsRelyingParty/Web.config
src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs
Diffstat (limited to 'src')
20 files changed, 206 insertions, 62 deletions
diff --git a/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs b/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs index 691df20..51fcee4 100644 --- a/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs +++ b/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs @@ -81,5 +81,32 @@ namespace DotNetOpenAuth.BuildTasks { return true; } + + /// <summary> + /// Tests whether a file is up to date with respect to another, + /// based on existence, last write time and file size. + /// </summary> + /// <param name="sourcePath">The source path.</param> + /// <param name="destPath">The dest path.</param> + /// <returns><c>true</c> if the files are the same; <c>false</c> if the files are different</returns> + internal static bool FastFileEqualityCheck(string sourcePath, string destPath) { + FileInfo sourceInfo = new FileInfo(sourcePath); + FileInfo destInfo = new FileInfo(destPath); + + if (sourceInfo.Exists ^ destInfo.Exists) { + // Either the source file or the destination file is missing. + return false; + } + + if (!sourceInfo.Exists) { + // Neither file exists. + return true; + } + + // We'll say the files are the same if their modification date and length are the same. + return + sourceInfo.LastWriteTimeUtc == destInfo.LastWriteTimeUtc && + sourceInfo.Length == destInfo.Length; + } } } diff --git a/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs b/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs index 3b81978..e17d8f2 100644 --- a/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs +++ b/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs @@ -18,15 +18,6 @@ namespace DotNetOpenAuth.BuildTasks { /// </summary> public class CopyWithTokenSubstitution : Task { /// <summary> - /// Gets or sets a value indicating whether the task should - /// skip the copying of files that are unchanged between the source and destination. - /// </summary> - /// <value> - /// <c>true</c> to skip copying files where the destination files are newer than the source files; otherwise, <c>false</c> to copy all files. - /// </value> - public bool SkipUnchangedFiles { get; set; } - - /// <summary> /// Gets or sets the files to copy. /// </summary> /// <value>The files to copy.</value> @@ -65,8 +56,11 @@ namespace DotNetOpenAuth.BuildTasks { for (int i = 0; i < this.SourceFiles.Length; i++) { string sourcePath = this.SourceFiles[i].ItemSpec; string destPath = this.DestinationFiles[i].ItemSpec; + bool skipUnchangedFiles = bool.Parse(this.SourceFiles[i].GetMetadata("SkipUnchangedFiles")); - if (this.SkipUnchangedFiles && File.GetLastWriteTimeUtc(sourcePath) < File.GetLastWriteTimeUtc(destPath)) { + // We deliberably consider newer destination files to be up-to-date rather than + // requiring equality because this task modifies the destination file while copying. + if (skipUnchangedFiles && File.GetLastWriteTimeUtc(sourcePath) < File.GetLastWriteTimeUtc(destPath)) { Log.LogMessage(MessageImportance.Low, "Skipping \"{0}\" -> \"{1}\" because the destination is up to date.", sourcePath, destPath); continue; } diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln index 3233865..569a7bc 100644 --- a/src/DotNetOpenAuth.sln +++ b/src/DotNetOpenAuth.sln @@ -7,6 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetOpenAuth.Test", "DotN EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{20B5E173-C3C4-49F8-BD25-E69044075B4D}" ProjectSection(SolutionItems) = preProject + ..\build.proj = ..\build.proj DotNetOpenAuth.vsmdi = DotNetOpenAuth.vsmdi ..\LICENSE.txt = ..\LICENSE.txt LocalTestRun.testrunconfig = LocalTestRun.testrunconfig @@ -169,6 +170,11 @@ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebFormsRelyingParty", "..\projecttemplates\WebFormsRelyingParty\WebFormsRelyingParty.csproj", "{A78F8FC6-7B03-4230-BE41-761E400D6810}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelyingPartyLogic", "..\projecttemplates\RelyingPartyLogic\RelyingPartyLogic.csproj", "{17932639-1F50-48AF-B0A5-E2BF832F82CC}" + ProjectSection(ProjectDependencies) = postProject + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D} = {2B4261AC-25AC-4B8D-B459-1C42B6B1401D} + EndProjectSection +EndProject +Project("{C8D11400-126E-41CD-887F-60BD40844F9E}") = "RelyingPartyDatabase", "..\projecttemplates\RelyingPartyDatabase\RelyingPartyDatabase.dbproj", "{2B4261AC-25AC-4B8D-B459-1C42B6B1401D}" EndProject Global GlobalSection(TestCaseManagementSettings) = postSolution @@ -276,6 +282,15 @@ Global {17932639-1F50-48AF-B0A5-E2BF832F82CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {17932639-1F50-48AF-B0A5-E2BF832F82CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {17932639-1F50-48AF-B0A5-E2BF832F82CC}.Release|Any CPU.Build.0 = Release|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.CodeAnalysis|Any CPU.ActiveCfg = Debug|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.CodeAnalysis|Any CPU.Build.0 = Debug|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.CodeAnalysis|Any CPU.Deploy.0 = Debug|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Release|Any CPU.Build.0 = Release|Any CPU + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Release|Any CPU.Deploy.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -298,5 +313,6 @@ Global {5C65603B-235F-47E6-B536-06385C60DE7F} = {E9ED920D-1F83-48C0-9A4B-09CCE505FE6D} {A78F8FC6-7B03-4230-BE41-761E400D6810} = {B9EB8729-4B54-4453-B089-FE6761BA3057} {17932639-1F50-48AF-B0A5-E2BF832F82CC} = {B9EB8729-4B54-4453-B089-FE6761BA3057} + {2B4261AC-25AC-4B8D-B459-1C42B6B1401D} = {B9EB8729-4B54-4453-B089-FE6761BA3057} EndGlobalSection EndGlobal diff --git a/src/DotNetOpenAuth/Logger.cs b/src/DotNetOpenAuth/Logger.cs index a9dbef2..48007ed 100644 --- a/src/DotNetOpenAuth/Logger.cs +++ b/src/DotNetOpenAuth/Logger.cs @@ -60,6 +60,11 @@ namespace DotNetOpenAuth { private static readonly ILog http = Create("DotNetOpenAuth.Http"); /// <summary> + /// Backing field for the <see cref="Controls"/> property. + /// </summary> + private static readonly ILog controls = Create("DotNetOpenAuth.Controls"); + + /// <summary> /// Backing field for the <see cref="OpenId"/> property. /// </summary> private static readonly ILog openId = Create("DotNetOpenAuth.OpenId"); @@ -110,6 +115,11 @@ namespace DotNetOpenAuth { internal static ILog Http { get { return http; } } /// <summary> + /// Gets the logger for events logged by ASP.NET controls. + /// </summary> + internal static ILog Controls { get { return controls; } } + + /// <summary> /// Gets the logger for high-level OpenID events. /// </summary> internal static ILog OpenId { get { return openId; } } diff --git a/src/DotNetOpenAuth/Messaging/Bindings/StandardReplayProtectionBindingElement.cs b/src/DotNetOpenAuth/Messaging/Bindings/StandardReplayProtectionBindingElement.cs index 0a7ddbd..bb56cfd 100644 --- a/src/DotNetOpenAuth/Messaging/Bindings/StandardReplayProtectionBindingElement.cs +++ b/src/DotNetOpenAuth/Messaging/Bindings/StandardReplayProtectionBindingElement.cs @@ -125,6 +125,7 @@ namespace DotNetOpenAuth.Messaging.Bindings { ErrorUtilities.VerifyProtocol(nonceMessage.Nonce.Length > 0 || this.AllowZeroLengthNonce, MessagingStrings.InvalidNonceReceived); if (!this.nonceStore.StoreNonce(nonceMessage.NonceContext, nonceMessage.Nonce, nonceMessage.UtcCreationDate)) { + Logger.OpenId.ErrorFormat("Replayed nonce detected ({0} {1}). Rejecting message.", nonceMessage.Nonce, nonceMessage.UtcCreationDate); throw new ReplayedMessageException(message); } diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs index 1c20f1d..4fa70a0 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs @@ -223,7 +223,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { yield return extension; } } else { - Logger.OpenId.WarnFormat("Extension with type URI '{0}' ignored because it is not a recognized extension.", typeUri); + Logger.OpenId.DebugFormat("Extension with type URI '{0}' ignored because it is not a recognized extension.", typeUri); } } } diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs index 9040404..817407c 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs @@ -187,6 +187,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { IReplayProtectedProtocolMessage replayResponse = response; if (!this.nonceStore.StoreNonce(replayResponse.NonceContext, nonce.RandomPartAsString, nonce.CreationDateUtc)) { + Logger.OpenId.ErrorFormat("Replayed nonce detected ({0} {1}). Rejecting message.", replayResponse.Nonce, replayResponse.UtcCreationDate); throw new ReplayedMessageException(message); } diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs index cd7575e..9d3f576 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs @@ -47,12 +47,12 @@ namespace DotNetOpenAuth.OpenId.Extensions { var req = (RelyingParty.AuthenticationRequest)request; var sreg = req.AppliedExtensions.OfType<ClaimsRequest>().SingleOrDefault(); if (sreg == null) { - Logger.OpenId.Warn("No Simple Registration (ClaimsRequest) extension present in the request to spread to AX."); + Logger.OpenId.Debug("No Simple Registration (ClaimsRequest) extension present in the request to spread to AX."); return; } if (req.Provider.IsExtensionSupported<ClaimsRequest>()) { - Logger.OpenId.Info("Skipping generation of AX request because the Identifier advertises the Provider supports the Sreg extension."); + Logger.OpenId.Debug("Skipping generation of AX request because the Identifier advertises the Provider supports the Sreg extension."); return; } @@ -65,11 +65,11 @@ namespace DotNetOpenAuth.OpenId.Extensions { // Try to use just one AX Type URI format if we can figure out which type the OP accepts. AXAttributeFormats detectedFormat; if (TryDetectOPAttributeFormat(request, out detectedFormat)) { - Logger.OpenId.Info("Detected OP support for AX but not for Sreg. Removing Sreg extension request and using AX instead."); + Logger.OpenId.Debug("Detected OP support for AX but not for Sreg. Removing Sreg extension request and using AX instead."); attributeFormats = detectedFormat; req.Extensions.Remove(sreg); } else { - Logger.OpenId.Info("Could not determine whether OP supported Sreg or AX. Using both extensions."); + Logger.OpenId.Debug("Could not determine whether OP supported Sreg or AX. Using both extensions."); } foreach (AXAttributeFormats format in ForEachFormat(attributeFormats)) { diff --git a/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs b/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs index 7085e72..f33a655 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs @@ -122,7 +122,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// </summary> /// <param name="context">The context, or namespace, within which the <paramref name="nonce"/> must be unique.</param> /// <param name="nonce">A series of random characters.</param> - /// <param name="timestamp">The timestamp that together with the nonce string make it unique. + /// <param name="timestampUtc">The timestamp that together with the nonce string make it unique. /// The timestamp may also be used by the data store to clear out old nonces.</param> /// <returns> /// True if the nonce+timestamp (combination) was not previously in the database. @@ -135,8 +135,8 @@ namespace DotNetOpenAuth.OpenId.Provider { /// is retrieved or set using the /// <see cref="StandardExpirationBindingElement.MaximumMessageAge"/> property. /// </remarks> - public bool StoreNonce(string context, string nonce, DateTime timestamp) { - return this.nonceStore.StoreNonce(context, nonce, timestamp); + public bool StoreNonce(string context, string nonce, DateTime timestampUtc) { + return this.nonceStore.StoreNonce(context, nonce, timestampUtc); } #endregion diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs index f1851a0..a317b95 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs @@ -416,7 +416,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { var failedAssociationEndpoints = new List<ServiceEndpoint>(0); foreach (var endpoint in endpoints) { - Logger.OpenId.InfoFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); + Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); // The strategy here is to prefer endpoints with whom we can create associations. Association association = null; @@ -446,10 +446,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { if (relyingParty.SecuritySettings.RequireAssociation) { Logger.OpenId.Warn("Associations could not be formed with some Providers. Security settings require shared associations for authentication requests so these will be skipped."); } else { - Logger.OpenId.WarnFormat("Now generating requests for Provider endpoints that failed initial association attempts."); + Logger.OpenId.Debug("Now generating requests for Provider endpoints that failed initial association attempts."); foreach (var endpoint in failedAssociationEndpoints) { - Logger.OpenId.WarnFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); + Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0} at endpoint: {1}", userSuppliedIdentifier, endpoint.ProviderEndpoint.AbsoluteUri); // Create the auth request, but prevent it from attempting to create an association // because we've already tried. Let's not have it waste time trying again. diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs index 4249834..f646599 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs @@ -704,6 +704,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); + if (!this.Visible) { + return; + } + if (this.DownloadYahooUILibrary) { // Although we'll add the <script> tag to download the YAHOO component, // a download failure may have occurred, so protect ourselves from a diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs index 44a5b41..0254346 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs @@ -174,6 +174,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { }; this.authenticationResponse = this.RelyingParty.GetResponse(clientResponseInfo); + Logger.Controls.DebugFormat( + "The {0} control checked for an authentication response and found: {1}", + this.ID, + this.authenticationResponse.Status); this.AuthenticationProcessedAlready = false; // Save out the authentication response to viewstate so we can find it on @@ -416,10 +420,14 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Notifies the user agent via an AJAX response of a completed authentication attempt. /// </summary> protected override void ScriptClosingPopupOrIFrame() { - Logger.OpenId.InfoFormat("AJAX (iframe) callback from OP: {0}", this.Page.Request.Url); + Logger.OpenId.DebugFormat("AJAX (iframe) callback from OP: {0}", this.Page.Request.Url); string extensionsJson = null; var authResponse = RelyingPartyNonVerifying.GetResponse(); + Logger.Controls.DebugFormat( + "The {0} control checked for an authentication response from a popup window or iframe using a non-verifying RP and found: {1}", + this.ID, + authResponse.Status); if (authResponse.Status == AuthenticationStatus.Authenticated) { this.OnUnconfirmedPositiveAssertion(); // event handler will fill the clientScriptExtensions collection. var extensionsDictionary = new Dictionary<string, string>(); @@ -613,7 +621,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="methodCall">The method to call on the OpenIdAjaxTextBox, including /// parameters. (i.e. "callback('arg1', 2)"). No escaping is done by this method.</param> private void CallbackUserAgentMethod(string methodCall) { - Logger.OpenId.InfoFormat("Sending Javascript callback: {0}", methodCall); + Logger.OpenId.DebugFormat("Sending Javascript callback: {0}", methodCall); Page.Response.Write(@"<html><body><script language='javascript'> var inPopup = !window.frameElement; var objSrc = inPopup ? window.opener : window.frameElement; diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs index 538e9f2..2420fd6 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs @@ -482,6 +482,16 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <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() { @@ -608,11 +618,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { 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. + // 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 == null || receiver == this.ClientID) { + 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); } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.cs index ed83412..e93383d 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.cs @@ -81,6 +81,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private HiddenField positiveAssertionField; /// <summary> + /// A field to store the value to set on the <see cref="textBox"/> control after it's created. + /// </summary> + private bool downloadYuiLibrary = OpenIdAjaxTextBox.DownloadYahooUILibraryDefault; + + /// <summary> /// Initializes a new instance of the <see cref="OpenIdSelector"/> class. /// </summary> public OpenIdSelector() { @@ -121,13 +126,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { [Description("Whether a split button will be used for the \"log in\" when the user provides an identifier that delegates to more than one Provider.")] public bool DownloadYahooUILibrary { get { - this.EnsureChildControls(); - return this.textBox.DownloadYahooUILibrary; + return this.textBox != null ? this.textBox.DownloadYahooUILibrary : this.downloadYuiLibrary; } set { - this.EnsureChildControls(); - this.textBox.DownloadYahooUILibrary = value; + // We don't just call EnsureChildControls() and then set the property on + // this.textBox itself because (apparently) setting this property in the ASPX + // page and thus calling this EnsureID() via EnsureChildControls() this early + // results in no ID. + if (this.textBox != null) { + this.textBox.DownloadYahooUILibrary = value; + } else { + this.downloadYuiLibrary = value; + } } } @@ -171,6 +182,14 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> + /// Gets a value indicating whether some button in the selector will want + /// to display the <see cref="OpenIdAjaxTextBox"/> control. + /// </summary> + protected virtual bool OpenIdTextBoxVisible { + get { return this.Buttons.OfType<SelectorOpenIdButton>().Any(); } + } + + /// <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> @@ -190,6 +209,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { protected override void CreateChildControls() { base.CreateChildControls(); this.EnsureID(); + ErrorUtilities.VerifyInternal(!string.IsNullOrEmpty(this.UniqueID), "Control.EnsureID() failed to give us a unique ID. Try setting an ID on the OpenIdSelector control. But please also file this bug with the project owners."); var selectorButton = this.Buttons.OfType<SelectorInfoCardButton>().FirstOrDefault(); if (selectorButton != null) { @@ -205,6 +225,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.textBox.ID = "openid_identifier"; this.textBox.HookFormSubmit = false; this.textBox.ShowLogOnPostBackButton = true; + this.textBox.DownloadYahooUILibrary = this.downloadYuiLibrary; this.Controls.Add(this.textBox); this.positiveAssertionField = new HiddenField(); @@ -259,6 +280,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Postback", script, true); this.PreloadDiscovery(this.Buttons.OfType<SelectorProviderButton>().Select(op => op.OPIdentifier).Where(id => id != null)); + this.textBox.Visible = this.OpenIdTextBoxVisible; } /// <summary> @@ -295,13 +317,15 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { writer.RenderEndTag(); // </ul> - writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none"); - writer.AddAttribute(HtmlTextWriterAttribute.Id, "OpenIDForm"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); + if (this.textBox.Visible) { + writer.AddStyleAttribute(HtmlTextWriterStyle.Display, "none"); + writer.AddAttribute(HtmlTextWriterAttribute.Id, "OpenIDForm"); + writer.RenderBeginTag(HtmlTextWriterTag.Div); - this.textBox.RenderControl(writer); + this.textBox.RenderControl(writer); - writer.RenderEndTag(); // </div> + writer.RenderEndTag(); // </div> + } this.positiveAssertionField.RenderControl(writer); } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.js b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.js index 6271952..c58e06e 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.js +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdSelector.js @@ -10,7 +10,7 @@ $(function() { var hint = $.cookie('openid_identifier') || ''; var ajaxbox = document.getElementsByName('openid_identifier')[0]; - if (hint != 'infocard') { + if (ajaxbox && hint != 'infocard') { ajaxbox.setValue(hint); } @@ -31,12 +31,18 @@ $(function() { } }); if (!matchFound) { - $('#OpenIDButton') - .removeClass('grayedOut') - .addClass('focused'); - $('#OpenIDForm').show('slow', function() { - ajaxbox.focus(); - }); + if (ajaxbox) { + $('#OpenIDButton') + .removeClass('grayedOut') + .addClass('focused'); + $('#OpenIDForm').show('slow', function() { + ajaxbox.focus(); + }); + } else { + // No OP button matched the last identifier, and there is no text box, + // so just un-gray all buttons. + ops.removeClass('grayedOut'); + } } } @@ -65,13 +71,15 @@ $(function() { } }); - ajaxbox.onStateChanged = function(state) { - if (state == "authenticated") { - showLoginSuccess('OpenIDButton', true); - } else { - showLoginSuccess('OpenIDButton', false); // hide checkmark - } - }; + if (ajaxbox) { + ajaxbox.onStateChanged = function(state) { + if (state == "authenticated") { + showLoginSuccess('OpenIDButton', true); + } else { + showLoginSuccess('OpenIDButton', false); // hide checkmark + } + }; + } function checkidSetup(identifier, timerBased) { var openid = new window.OpenIdIdentifier(identifier); @@ -88,8 +96,10 @@ $(function() { window.postLoginAssertion(respondingEndpoint.response.toString(), window.parent.location.href); } - // take over how the text box does postbacks. - ajaxbox.dnoi_internal.postback = doLogin; + if (ajaxbox) { + // take over how the text box does postbacks. + ajaxbox.dnoi_internal.postback = doLogin; + } // This FrameManager will be used for background logins for the OP buttons // and the last used identifier. It is NOT the frame manager used by the @@ -138,7 +148,7 @@ $(function() { // Don't immediately login if the user clicked OpenID and he can't see the identifier box. if ($(this)[0].id != 'OpenIDButton') { relevantUserSuppliedIdentifier = $(this)[0].id; - } else if ($('#OpenIDForm').is(':visible')) { + } else if (ajaxbox && $('#OpenIDForm').is(':visible')) { relevantUserSuppliedIdentifier = ajaxbox.value; } @@ -157,16 +167,18 @@ $(function() { $('img', this)[0].click(); } }); - $('#OpenIDButton').click(function() { - // Be careful to only try to select the text box once it is available. - if ($('#OpenIDForm').is(':hidden')) { - $('#OpenIDForm').show('slow', function() { + if (ajaxbox) { + $('#OpenIDButton').click(function() { + // Be careful to only try to select the text box once it is available. + if ($('#OpenIDForm').is(':hidden')) { + $('#OpenIDForm').show('slow', function() { + ajaxbox.focus(); + }); + } else { ajaxbox.focus(); - }); - } else { - ajaxbox.focus(); - } - }); + } + }); + } // Make popup window close on escape (the dialog style is already taken care of) $(document).keydown(function(e) { diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs index 7338b1a..7a1fbbf 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs @@ -40,6 +40,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.provider = new ProviderEndpointDescription(response.ProviderEndpoint, response.Version); } + // Derived types of this are responsible to log an appropriate message for themselves. + if (Logger.OpenId.IsInfoEnabled && this.GetType() == typeof(PositiveAnonymousResponse)) { + Logger.OpenId.Info("Received anonymous (identity-less) positive assertion."); + } + Reporting.RecordEventOccurrence(this, response.ProviderEndpoint.AbsoluteUri); } @@ -130,6 +135,16 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { #endregion /// <summary> + /// Gets a value indicating whether trusted callback arguments are available. + /// </summary> + /// <remarks> + /// We use this internally to avoid logging a warning during a standard snapshot creation. + /// </remarks> + internal bool TrustedCallbackArgumentsAvailable { + get { return this.response.ReturnToParametersSignatureValidated; } + } + + /// <summary> /// Gets the positive extension-only message the Relying Party received that this instance wraps. /// </summary> protected internal IndirectSignedResponse Response { diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs index e809205..0fd034c 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs @@ -37,6 +37,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { null); this.VerifyDiscoveryMatchesAssertion(relyingParty); + + Logger.OpenId.InfoFormat("Received identity assertion for {0} via {1}.", this.ClaimedIdentifier, this.Provider.Uri); } #region IAuthenticationResponse Properties diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs index 32c8af9..80b424a 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponseSnapshot.cs @@ -39,8 +39,15 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.FriendlyIdentifierForDisplay = copyFrom.FriendlyIdentifierForDisplay; this.Status = copyFrom.Status; this.Provider = copyFrom.Provider; - this.callbackArguments = copyFrom.GetCallbackArguments(); this.untrustedCallbackArguments = copyFrom.GetUntrustedCallbackArguments(); + + // Do this special check to avoid logging a warning for trying to clone a dictionary. + var anonResponse = copyFrom as PositiveAnonymousResponse; + if (anonResponse == null || anonResponse.TrustedCallbackArgumentsAvailable) { + this.callbackArguments = copyFrom.GetCallbackArguments(); + } else { + this.callbackArguments = EmptyDictionary<string, string>.Instance; + } } #region IAuthenticationResponse Members diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorOpenIdButton.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorOpenIdButton.cs index 0b11695..15b6ca7 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorOpenIdButton.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorOpenIdButton.cs @@ -5,7 +5,9 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId.RelyingParty { + using System.ComponentModel; using System.Diagnostics.Contracts; + using System.Drawing.Design; using System.Web.UI; using DotNetOpenAuth.Messaging; @@ -25,6 +27,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Gets or sets the path to the image to display on the button's surface. /// </summary> /// <value>The virtual path to the image.</value> + [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))] + [UrlProperty] public string Image { get; set; } /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorProviderButton.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorProviderButton.cs index 1d4dcf2..3a05287 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorProviderButton.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/SelectorProviderButton.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.ComponentModel; using System.Diagnostics.Contracts; + using System.Drawing.Design; using System.Web.UI; using DotNetOpenAuth.ComponentModel; using DotNetOpenAuth.Messaging; @@ -27,6 +28,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Gets or sets the path to the image to display on the button's surface. /// </summary> /// <value>The virtual path to the image.</value> + [Editor("System.Web.UI.Design.ImageUrlEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))] + [UrlProperty] public string Image { get; set; } /// <summary> |