diff options
Diffstat (limited to 'src/DotNetOpenAuth')
45 files changed, 456 insertions, 44 deletions
diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd new file mode 100644 index 0000000..ea32f4c --- /dev/null +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd @@ -0,0 +1,269 @@ +<?xml version="1.0" encoding="utf-8"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:vs="http://schemas.microsoft.com/Visual-Studio-Intellisense" + elementFormDefault="qualified" + attributeFormDefault="unqualified"> + <xs:element name="dotNetOpenAuth"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="messaging"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="untrustedWebRequest"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="whitelistHosts"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="whitelistHostsRegex"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="blacklistHosts"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="blacklistHostsRegex"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="timeout" type="xs:string" /> + <xs:attribute name="readWriteTimeout" type="xs:string" /> + <xs:attribute name="maximumBytesToRead" type="xs:int" /> + <xs:attribute name="maximumRedirections" type="xs:int" /> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="lifetime" type="xs:string" /> + <xs:attribute name="clockSkew" type="xs:string" /> + </xs:complexType> + </xs:element> + <xs:element name="openid"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="relyingParty"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="security"> + <xs:complexType> + <xs:attribute name="requireSsl" type="xs:boolean" default="false" /> + <xs:attribute name="minimumRequiredOpenIdVersion"> + <xs:simpleType> + <xs:restriction base="xs:NMTOKEN"> + <xs:enumeration value="V10" /> + <xs:enumeration value="V11" /> + <xs:enumeration value="V20" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="minimumHashBitLength" type="xs:int" /> + <xs:attribute name="maximumHashBitLength" type="xs:int" /> + <xs:attribute name="privateSecretMaximumAge" type="xs:string" /> + <xs:attribute name="requireDirectedIdentity" type="xs:boolean" /> + <xs:attribute name="requireAssociation" type="xs:boolean" /> + <xs:attribute name="rejectUnsolicitedAssertions" type="xs:boolean" /> + <xs:attribute name="rejectDelegatingIdentifiers" type="xs:boolean" /> + <xs:attribute name="ignoreUnsignedExtensions" type="xs:boolean" /> + </xs:complexType> + </xs:element> + <xs:element name="behaviors"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="optional" /> + <xs:attribute name="xaml" type="xs:string" use="optional" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="store"> + <xs:complexType> + <xs:attribute name="type" type="xs:string"/> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="provider"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="security"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="associations"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="required" /> + <xs:attribute name="lifetime" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="requireSsl" type="xs:boolean" default="false" /> + <xs:attribute name="protectDownlevelReplayAttacks" type="xs:boolean" /> + <xs:attribute name="minimumHashBitLength" type="xs:int" /> + <xs:attribute name="maximumHashBitLength" type="xs:int" /> + </xs:complexType> + </xs:element> + <xs:element name="behaviors"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="optional" /> + <xs:attribute name="xaml" type="xs:string" use="optional" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="store"> + <xs:complexType> + <xs:attribute name="type" type="xs:string"/> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="extensionFactories"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="optional" /> + <xs:attribute name="xaml" type="xs:string" use="optional" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="type" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> + <xs:element name="xriResolver"> + <xs:complexType> + <xs:attribute name="enabled" type="xs:boolean" /> + <xs:attribute name="proxy" type="xs:string" /> + </xs:complexType> + </xs:element> + </xs:choice> + <xs:attribute name="maxAuthenticationTime" type="xs:string" /> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> +</xs:schema> diff --git a/src/DotNetOpenAuth/Configuration/OAuthConsumerSecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/OAuthConsumerSecuritySettingsElement.cs index 5e75390..38a183a 100644 --- a/src/DotNetOpenAuth/Configuration/OAuthConsumerSecuritySettingsElement.cs +++ b/src/DotNetOpenAuth/Configuration/OAuthConsumerSecuritySettingsElement.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Configuration { using System; using System.Collections.Generic; using System.Configuration; + using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using DotNetOpenAuth.OAuth; @@ -26,6 +27,7 @@ namespace DotNetOpenAuth.Configuration { /// Initializes a programmatically manipulatable bag of these security settings with the settings from the config file. /// </summary> /// <returns>The newly created security settings object.</returns> + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "By design")] internal ConsumerSecuritySettings CreateSecuritySettings() { return new ConsumerSecuritySettings(); } diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index cabdb6a..aba573d 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -393,6 +393,7 @@ <Compile Include="OpenId\Extensions\SimpleRegistration\Constants.cs" /> <Compile Include="OpenId\Extensions\SimpleRegistration\DemandLevel.cs" /> <Compile Include="OpenId\Extensions\SimpleRegistration\Gender.cs" /> + <Compile Include="OpenId\Extensions\UI\UIConstants.cs" /> <Compile Include="OpenId\Extensions\UI\UIUtilities.cs" /> <Compile Include="OpenId\Extensions\UI\UIModes.cs" /> <Compile Include="OpenId\Extensions\UI\UIRequest.cs" /> @@ -540,6 +541,7 @@ <Compile Include="Yadis\Yadis.cs" /> </ItemGroup> <ItemGroup> + <None Include="Configuration\DotNetOpenAuth.xsd" /> <None Include="OAuth\ClassDiagram.cd" /> <None Include="OAuth\Messages\OAuth Messages.cd" /> <None Include="Messaging\Bindings\Bindings.cd" /> @@ -611,4 +613,4 @@ </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/DotNetOpenAuth/GlobalSuppressions.cs b/src/DotNetOpenAuth/GlobalSuppressions.cs index 8be62f8..07fabc3 100644 --- a/src/DotNetOpenAuth/GlobalSuppressions.cs +++ b/src/DotNetOpenAuth/GlobalSuppressions.cs @@ -43,3 +43,4 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "DotNetOpenAuth.OpenId.Extensions.OAuth")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "DotNetOpenAuth.OpenId.Extensions.UI")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "DotNetOpenAuth.Messaging.Reflection")] +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "oauthverifier", Scope = "resource", Target = "DotNetOpenAuth.OAuth.OAuthStrings.resources")] diff --git a/src/DotNetOpenAuth/Loggers/Log4NetLogger.cs b/src/DotNetOpenAuth/Loggers/Log4NetLogger.cs index 30d93ae..dd71a05 100644 --- a/src/DotNetOpenAuth/Loggers/Log4NetLogger.cs +++ b/src/DotNetOpenAuth/Loggers/Log4NetLogger.cs @@ -197,7 +197,11 @@ namespace DotNetOpenAuth.Loggers { /// </summary> /// <returns>The created <see cref="ILog"/> instance.</returns> internal static ILog Initialize(string name) { - return IsLog4NetPresent ? CreateLogger(name) : null; + try { + return IsLog4NetPresent ? CreateLogger(name) : null; + } catch (FileLoadException) { // wrong log4net.dll version + return null; + } } /// <summary> diff --git a/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs b/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs index 1d4d28e..3d624a6 100644 --- a/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs +++ b/src/DotNetOpenAuth/Messaging/Bindings/NonceMemoryStore.cs @@ -73,7 +73,7 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// <see cref="StandardExpirationBindingElement.MaximumMessageAge"/> property. /// </remarks> public bool StoreNonce(string context, string nonce, DateTime timestamp) { - if (timestamp.ToUniversalTime() + this.maximumMessageAge < DateTime.UtcNow) { + if (timestamp.ToUniversalTimeSafe() + this.maximumMessageAge < DateTime.UtcNow) { // The expiration binding element should have taken care of this, but perhaps // it's at the boundary case. We should fail just to be safe. return false; @@ -115,7 +115,7 @@ namespace DotNetOpenAuth.Messaging.Bindings { /// </summary> public void ClearExpiredNonces() { lock (this.nonceLock) { - var oldNonceLists = this.usedNonces.Keys.Where(time => time.ToUniversalTime() + this.maximumMessageAge < DateTime.UtcNow).ToList(); + var oldNonceLists = this.usedNonces.Keys.Where(time => time.ToUniversalTimeSafe() + this.maximumMessageAge < DateTime.UtcNow).ToList(); foreach (DateTime time in oldNonceLists) { this.usedNonces.Remove(time); } diff --git a/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs b/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs index 5fcf4bd..7b00e34 100644 --- a/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs +++ b/src/DotNetOpenAuth/Messaging/Bindings/StandardExpirationBindingElement.cs @@ -87,7 +87,7 @@ namespace DotNetOpenAuth.Messaging.Bindings { if (expiringMessage != null) { // Yes the UtcCreationDate is supposed to always be in UTC already, // but just in case a given message failed to guarantee that, we do it here. - DateTime expirationDate = expiringMessage.UtcCreationDate.ToUniversalTime() + MaximumMessageAge; + DateTime expirationDate = expiringMessage.UtcCreationDate.ToUniversalTimeSafe() + MaximumMessageAge; if (expirationDate < DateTime.UtcNow) { throw new ExpiredMessageException(expirationDate, expiringMessage); } diff --git a/src/DotNetOpenAuth/Messaging/Channel.cs b/src/DotNetOpenAuth/Messaging/Channel.cs index 0f307b5..2e0f1a8 100644 --- a/src/DotNetOpenAuth/Messaging/Channel.cs +++ b/src/DotNetOpenAuth/Messaging/Channel.cs @@ -67,7 +67,9 @@ namespace DotNetOpenAuth.Messaging { /// </remarks> private const string IndirectMessageFormPostFormat = @" <html> -<body onload=""var btn = document.getElementById('submit_button'); btn.disabled = true; btn.value = 'Login in progress'; document.getElementById('openid_message').submit()""> +<head> +</head> +<body onload=""document.body.style.display = 'none'; var btn = document.getElementById('submit_button'); btn.disabled = true; btn.value = 'Login in progress'; document.getElementById('openid_message').submit()""> <form id=""openid_message"" action=""{0}"" method=""post"" accept-charset=""UTF-8"" enctype=""application/x-www-form-urlencoded"" onSubmit=""var btn = document.getElementById('submit_button'); btn.disabled = true; btn.value = 'Login in progress'; return true;""> {1} <input id=""submit_button"" type=""submit"" value=""Continue"" /> @@ -675,6 +677,7 @@ namespace DotNetOpenAuth.Messaging { ErrorUtilities.VerifyArgumentNotNull(fields, "fields"); WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add(HttpResponseHeader.ContentType, "text/html"); StringWriter bodyWriter = new StringWriter(CultureInfo.InvariantCulture); StringBuilder hiddenFields = new StringBuilder(); foreach (var field in fields) { diff --git a/src/DotNetOpenAuth/Messaging/HostErrorException.cs b/src/DotNetOpenAuth/Messaging/HostErrorException.cs index 0ab9e51..81691b0 100644 --- a/src/DotNetOpenAuth/Messaging/HostErrorException.cs +++ b/src/DotNetOpenAuth/Messaging/HostErrorException.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.Messaging { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; @@ -20,6 +21,7 @@ namespace DotNetOpenAuth.Messaging { /// or its configuration.</para> /// <para>It is an internal exception to assist in making it uncatchable.</para> /// </remarks> + [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic", Justification = "We don't want this exception to be catchable.")] [Serializable] internal class HostErrorException : Exception { /// <summary> diff --git a/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs b/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs index e532e99..79a1107 100644 --- a/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs +++ b/src/DotNetOpenAuth/Messaging/MessageReceivingEndpoint.cs @@ -12,6 +12,7 @@ namespace DotNetOpenAuth.Messaging { /// An immutable description of a URL that receives messages. /// </summary> [DebuggerDisplay("{AllowedMethods} {Location}")] + [Serializable] public class MessageReceivingEndpoint { /// <summary> /// Initializes a new instance of the <see cref="MessageReceivingEndpoint"/> class. diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs index b5d535c..7d89b4e 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs @@ -776,6 +776,32 @@ namespace DotNetOpenAuth.Messaging { } /// <summary> + /// Ensures that UTC times are converted to local times. Unspecified kinds are unchanged. + /// </summary> + /// <param name="value">The date-time to convert.</param> + /// <returns>The date-time in local time.</returns> + internal static DateTime ToLocalTimeSafe(this DateTime value) { + if (value.Kind == DateTimeKind.Unspecified) { + return value; + } + + return value.ToLocalTime(); + } + + /// <summary> + /// Ensures that local times are converted to UTC times. Unspecified kinds are unchanged. + /// </summary> + /// <param name="value">The date-time to convert.</param> + /// <returns>The date-time in UTC time.</returns> + internal static DateTime ToUniversalTimeSafe(this DateTime value) { + if (value.Kind == DateTimeKind.Unspecified) { + return value; + } + + return value.ToUniversalTime(); + } + + /// <summary> /// A class to convert a <see cref="Comparison<T>"/> into an <see cref="IComparer<T>"/>. /// </summary> /// <typeparam name="T">The type of objects being compared.</typeparam> diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs index 329ac4d..35ba52d 100644 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs +++ b/src/DotNetOpenAuth/OAuth/ChannelElements/IServiceProviderAccessToken.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; @@ -31,6 +32,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <value> /// The name of the user who authorized the OAuth request token originally. /// </value> + [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Username", Justification = "Breaking change.")] string Username { get; } /// <summary> @@ -40,6 +42,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// The roles that the user belongs to, or a subset of these according to the rights /// granted when the user authorized the request token. /// </value> + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "By design.")] string[] Roles { get; } } } diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs index 123582a..a1939dd 100644 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs +++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs @@ -307,7 +307,6 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <para>This method implements OAuth 1.0 section 5.2, item #1 (described in section 5.4).</para> /// </remarks> private HttpWebRequest InitializeRequestAsAuthHeader(IDirectedProtocolMessage requestMessage) { - var protocol = Protocol.Lookup(requestMessage.Version); var dictionary = this.MessageDescriptions.GetAccessor(requestMessage); // copy so as to not modify original diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthIdentity.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthIdentity.cs index 0de2c15..bd57012 100644 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthIdentity.cs +++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthIdentity.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { using System; + using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Runtime.InteropServices; using System.Security.Principal; @@ -14,6 +15,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <summary> /// Represents an OAuth consumer that is impersonating a known user on the system. /// </summary> + [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")] [Serializable] [ComVisible(true)] public class OAuthIdentity : IIdentity { diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthPrincipal.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthPrincipal.cs index 689c388..a9f363a 100644 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthPrincipal.cs +++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthPrincipal.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Linq; using System.Runtime.InteropServices; @@ -15,6 +16,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <summary> /// Represents an OAuth consumer that is impersonating a known user on the system. /// </summary> + [SuppressMessage("Microsoft.Interoperability", "CA1409:ComVisibleTypesShouldBeCreatable", Justification = "Not cocreatable.")] [Serializable] [ComVisible(true)] public class OAuthPrincipal : IPrincipal { diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs index ce7bb98..3e75e7b 100644 --- a/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs +++ b/src/DotNetOpenAuth/OAuth/ChannelElements/TokenHandlingBindingElement.cs @@ -146,7 +146,7 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { try { IServiceProviderAccessToken token = this.tokenManager.GetAccessToken(message.AccessToken); - if (token.ExpirationDate.HasValue && DateTime.Now >= token.ExpirationDate.Value.ToLocalTime()) { + if (token.ExpirationDate.HasValue && DateTime.Now >= token.ExpirationDate.Value.ToLocalTimeSafe()) { Logger.OAuth.ErrorFormat( "OAuth access token {0} rejected because it expired at {1}, and it is now {2}.", token.Token, @@ -166,14 +166,14 @@ namespace DotNetOpenAuth.OAuth.ChannelElements { /// <exception cref="ProtocolException">Thrown when the token in the message has expired.</exception> private void VerifyThrowTokenTimeToLive(ITokenContainingMessage message) { ErrorUtilities.VerifyInternal(!(message is AccessProtectedResourceRequest), "We shouldn't be verifying TTL on access tokens."); - if (message == null) { + if (message == null || string.IsNullOrEmpty(message.Token)) { return; } try { IServiceProviderRequestToken token = this.tokenManager.GetRequestToken(message.Token); TimeSpan ttl = DotNetOpenAuthSection.Configuration.OAuth.ServiceProvider.SecuritySettings.MaximumRequestTokenTimeToLive; - if (DateTime.Now >= token.CreatedOn.ToLocalTime() + ttl) { + if (DateTime.Now >= token.CreatedOn.ToLocalTimeSafe() + ttl) { Logger.OAuth.ErrorFormat( "OAuth request token {0} rejected because it was originally issued at {1}, expired at {2}, and it is now {3}.", token.Token, diff --git a/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs b/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs index 89e0276..944bc5c 100644 --- a/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs +++ b/src/DotNetOpenAuth/OAuth/Messages/MessageBase.cs @@ -17,6 +17,7 @@ namespace DotNetOpenAuth.OAuth.Messages { /// <summary> /// A base class for all OAuth messages. /// </summary> + [Serializable] public abstract class MessageBase : IDirectedProtocolMessage, IDirectResponseProtocolMessage { /// <summary> /// A store for extra name/value data pairs that are attached to this message. diff --git a/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs b/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs index 8ccd8e3..ce09213 100644 --- a/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs +++ b/src/DotNetOpenAuth/OAuth/Messages/UnauthorizedTokenResponse.cs @@ -89,6 +89,8 @@ namespace DotNetOpenAuth.OAuth.Messages { /// <summary> /// Gets a value indicating whether the Service Provider recognized the callback parameter in the request. /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Message serialization invoked.")] + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Message parts must be instance members.")] [MessagePart("oauth_callback_confirmed", IsRequired = true, MinVersion = Protocol.V10aVersion)] private bool CallbackConfirmed { get { return true; } diff --git a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs index 099729e..a5823bb 100644 --- a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs +++ b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationRequest.cs @@ -15,6 +15,7 @@ namespace DotNetOpenAuth.OAuth.Messages { /// so the Service Provider can ask the user to authorize the Consumer's access to some /// protected resource(s). /// </summary> + [Serializable] public class UserAuthorizationRequest : MessageBase, ITokenContainingMessage { /// <summary> /// Initializes a new instance of the <see cref="UserAuthorizationRequest"/> class. diff --git a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs index 69a327c..73fddc7 100644 --- a/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs +++ b/src/DotNetOpenAuth/OAuth/Messages/UserAuthorizationResponse.cs @@ -14,6 +14,7 @@ namespace DotNetOpenAuth.OAuth.Messages { /// <remarks> /// The class is sealed because extra parameters are determined by the callback URI provided by the Consumer. /// </remarks> + [Serializable] public sealed class UserAuthorizationResponse : MessageBase, ITokenContainingMessage { /// <summary> /// Initializes a new instance of the <see cref="UserAuthorizationResponse"/> class. diff --git a/src/DotNetOpenAuth/OAuth/Protocol.cs b/src/DotNetOpenAuth/OAuth/Protocol.cs index f535b10..cd4e486 100644 --- a/src/DotNetOpenAuth/OAuth/Protocol.cs +++ b/src/DotNetOpenAuth/OAuth/Protocol.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OAuth { using System; using System.Collections.Generic; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using DotNetOpenAuth.Messaging; @@ -24,6 +25,7 @@ namespace DotNetOpenAuth.OAuth { /// <summary> /// OAuth 1.0a specification /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "a", Justification = "By design.")] V10a, } diff --git a/src/DotNetOpenAuth/OAuth/VerificationCodeFormat.cs b/src/DotNetOpenAuth/OAuth/VerificationCodeFormat.cs index d25c988..3afd44e 100644 --- a/src/DotNetOpenAuth/OAuth/VerificationCodeFormat.cs +++ b/src/DotNetOpenAuth/OAuth/VerificationCodeFormat.cs @@ -5,6 +5,8 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.OAuth { + using System.Diagnostics.CodeAnalysis; + /// <summary> /// The different formats a user authorization verifier code can take /// in order to be as secure as possible while being compatible with @@ -33,6 +35,8 @@ namespace DotNetOpenAuth.OAuth { /// Some letters and numbers will be skipped where they are visually similar /// enough that they can be difficult to distinguish when displayed with most fonts. /// </remarks> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Alikes", Justification = "Breaking change of existing API")] + [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "AlphaNumeric", Justification = "Breaking change of existing API")] AlphaNumericNoLookAlikes, /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/Association.cs b/src/DotNetOpenAuth/OpenId/Association.cs index eb7c880..ce129bb 100644 --- a/src/DotNetOpenAuth/OpenId/Association.cs +++ b/src/DotNetOpenAuth/OpenId/Association.cs @@ -149,7 +149,7 @@ namespace DotNetOpenAuth.OpenId { if (privateData == null) { throw new ArgumentNullException("privateData"); } - expires = expires.ToUniversalTime(); + expires = expires.ToUniversalTimeSafe(); TimeSpan remainingLifeLength = expires - DateTime.UtcNow; byte[] secret = privateData; // the whole of privateData is the secret key for now. // We figure out what derived type to instantiate based on the length of the secret. diff --git a/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs b/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs index 1c124d8..d7dca9a 100644 --- a/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs +++ b/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.Behaviors { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text; using DotNetOpenAuth.Messaging; @@ -21,6 +22,7 @@ namespace DotNetOpenAuth.OpenId.Behaviors { /// requests look like Simple Registration requests, and to convert the response /// to the originally requested extension and format. /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sreg", Justification = "Abbreviation")] public class AXFetchAsSregTransform : IRelyingPartyBehavior, IProviderBehavior { /// <summary> /// Initializes static members of the <see cref="AXFetchAsSregTransform"/> class. diff --git a/src/DotNetOpenAuth/OpenId/Behaviors/PpidGeneration.cs b/src/DotNetOpenAuth/OpenId/Behaviors/PpidGeneration.cs index b9a3dfc..f09e886 100644 --- a/src/DotNetOpenAuth/OpenId/Behaviors/PpidGeneration.cs +++ b/src/DotNetOpenAuth/OpenId/Behaviors/PpidGeneration.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.OpenId.Behaviors { using System; + using System.Diagnostics.CodeAnalysis; using System.Linq; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy; @@ -23,10 +24,12 @@ namespace DotNetOpenAuth.OpenId.Behaviors { /// <c>Application_Start</c> method in the global.asax.cs file.</para> /// </remarks> [Serializable] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ppid", Justification = "Abbreviation")] public sealed class PpidGeneration : IProviderBehavior { /// <summary> /// Gets or sets the provider for generating PPID identifiers. /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ppid", Justification = "Abbreviation")] public static IDirectedIdentityIdentifierProvider PpidIdentifierProvider { get; set; } #region IProviderBehavior Members diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs index 63f7809..8b6f7ef 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs @@ -23,11 +23,6 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// </summary> internal class ExtensionsBindingElement : IChannelBindingElement { /// <summary> - /// The security settings that apply to this binding element. - /// </summary> - private readonly SecuritySettings securitySettings; - - /// <summary> /// The security settings that apply to this relying party, if it is a relying party. /// </summary> private readonly RelyingPartySecuritySettings relyingPartySecuritySettings; @@ -42,7 +37,6 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { ErrorUtilities.VerifyArgumentNotNull(securitySettings, "securitySettings"); this.ExtensionFactory = extensionFactory; - this.securitySettings = securitySettings; this.relyingPartySecuritySettings = securitySettings as RelyingPartySecuritySettings; } diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AXAttributeFormats.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AXAttributeFormats.cs index 7e4ed73..decd296 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AXAttributeFormats.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AXAttributeFormats.cs @@ -35,7 +35,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange { /// <summary> /// All known schemas. /// </summary> - All = 0xff, + All = AXSchemaOrg | SchemaOpenIdNet | OpenIdNetSchema, /// <summary> /// The most common schemas. diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs index 6522d2e..36358a7 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Linq; using DotNetOpenAuth.Messaging; @@ -39,6 +40,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// <para>If the request does not carry an sreg extension, the method logs a warning but /// otherwise quietly returns doing nothing.</para> /// </remarks> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sreg", Justification = "Abbreviation")] public static void SpreadSregToAX(this RelyingParty.IAuthenticationRequest request, AXAttributeFormats attributeFormats) { Contract.Requires(request != null); ErrorUtilities.VerifyArgumentNotNull(request, "request"); @@ -95,6 +97,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// or a fabricated one based on the Attribute Exchange extension if found, /// or just an empty <see cref="ClaimsResponse"/> if there was no data. /// Never <c>null</c>.</returns> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sreg", Justification = "Abbreviation")] public static ClaimsResponse UnifyExtensionsAsSreg(this RelyingParty.IAuthenticationResponse response, bool allowUnsigned) { Contract.Requires(response != null); ErrorUtilities.VerifyArgumentNotNull(response, "response"); diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/DateTimeEncoder.cs b/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/DateTimeEncoder.cs index 82297d0..9dc0574 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/DateTimeEncoder.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/DateTimeEncoder.cs @@ -7,6 +7,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy { using System; using System.Globalization; + using DotNetOpenAuth.Messaging; using DotNetOpenAuth.Messaging.Reflection; /// <summary> @@ -39,7 +40,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy { public string Encode(object value) { DateTime? dateTime = value as DateTime?; if (dateTime.HasValue) { - return dateTime.Value.ToUniversalTime().ToString(PermissibleDateTimeFormats[0], CultureInfo.InvariantCulture); + return dateTime.Value.ToUniversalTimeSafe().ToString(PermissibleDateTimeFormats[0], CultureInfo.InvariantCulture); } else { return null; } diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs b/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs index 4b2bcc9..b476cf7 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/PolicyResponse.cs @@ -90,7 +90,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy { // Convert to UTC and cut to the second, since the protocol only allows for // that level of precision. - this.authenticationTimeUtc = OpenIdUtilities.CutToSecond(value.Value.ToUniversalTime()); + this.authenticationTimeUtc = OpenIdUtilities.CutToSecond(value.Value.ToUniversalTimeSafe()); } else { this.authenticationTimeUtc = null; } diff --git a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIConstants.cs b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIConstants.cs new file mode 100644 index 0000000..963b301 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIConstants.cs @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------- +// <copyright file="UIConstants.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Extensions.UI { + /// <summary> + /// Constants used to support the UI extension. + /// </summary> + internal static class UIConstants { + /// <summary> + /// The type URI associated with this extension. + /// </summary> + internal const string UITypeUri = "http://specs.openid.net/extensions/ui/1.0"; + + /// <summary> + /// The Type URI that appears in an XRDS document when the OP supports popups through the UI extension. + /// </summary> + internal const string PopupSupported = "http://specs.openid.net/extensions/ui/1.0/mode/popup"; + + /// <summary> + /// The Type URI that appears in an XRDS document when the OP supports the RP + /// specifying the user's preferred language through the UI extension. + /// </summary> + internal const string LangPrefSupported = "http://specs.openid.net/extensions/ui/1.0/lang-pref"; + } +} diff --git a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs index 476b4ad..d67d932 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs @@ -33,7 +33,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI { /// The factory method that may be used in deserialization of this message. /// </summary> internal static readonly StandardOpenIdExtensionFactory.CreateDelegate Factory = (typeUri, data, baseMessage, isProviderRole) => { - if (typeUri == UITypeUri && isProviderRole) { + if (typeUri == UIConstants.UITypeUri && isProviderRole) { return new UIRequest(); } @@ -41,9 +41,12 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI { }; /// <summary> - /// The type URI associated with this extension. + /// Additional type URIs that this extension is sometimes known by remote parties. /// </summary> - private const string UITypeUri = "http://specs.openid.net/extensions/ui/1.0"; + private static readonly string[] additionalTypeUris = new string[] { + UIConstants.LangPrefSupported, + UIConstants.PopupSupported, + }; /// <summary> /// Backing store for <see cref="ExtraData"/>. @@ -75,13 +78,25 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI { [MessagePart("mode", AllowEmpty = false, IsRequired = true)] public string Mode { get { return UIModes.Popup; } } + /// <summary> + /// 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. + /// </summary> + /// <value><c>true</c> if the Provider should display an icon; otherwise, <c>false</c>.</value> + /// <remarks> + /// By default, the Provider displays the relying party's favicon.ico. + /// </remarks> + [MessagePart("popup", AllowEmpty = false, IsRequired = false)] + public bool? Icon { get; set; } + #region IOpenIdMessageExtension Members /// <summary> /// Gets the TypeURI the extension uses in the OpenID protocol and in XRDS advertisements. /// </summary> /// <value></value> - public string TypeUri { get { return UITypeUri; } } + public string TypeUri { get { return UIConstants.UITypeUri; } } /// <summary> /// Gets the additional TypeURIs that are supported by this extension, in preferred order. @@ -98,7 +113,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI { /// given the version of the extension in the request message. /// The <see cref="Extensions.SimpleRegistration.ClaimsRequest.CreateResponse"/> for an example. /// </remarks> - public IEnumerable<string> AdditionalSupportedTypeUris { get { return Enumerable.Empty<string>(); } } + public IEnumerable<string> AdditionalSupportedTypeUris { get { return additionalTypeUris; } } /// <summary> /// Gets or sets a value indicating whether this extension was diff --git a/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs b/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs index d44809f..41c4e21 100644 --- a/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs +++ b/src/DotNetOpenAuth/OpenId/Interop/OpenIdRelyingPartyShim.cs @@ -87,6 +87,19 @@ namespace DotNetOpenAuth.OpenId.Interop { [ClassInterface(ClassInterfaceType.None)] public sealed class OpenIdRelyingPartyShim : IOpenIdRelyingParty { /// <summary> + /// The OpenIdRelyingParty instance to use for requests. + /// </summary> + private static OpenIdRelyingParty relyingParty; + + /// <summary> + /// Initializes static members of the <see cref="OpenIdRelyingPartyShim"/> class. + /// </summary> + static OpenIdRelyingPartyShim() { + relyingParty = new OpenIdRelyingParty(null); + relyingParty.Behaviors.Add(new Behaviors.AXFetchAsSregTransform()); + } + + /// <summary> /// Creates an authentication request to verify that a user controls /// some given Identifier. /// </summary> @@ -109,9 +122,8 @@ namespace DotNetOpenAuth.OpenId.Interop { /// <exception cref="ProtocolException">Thrown if no OpenID endpoint could be found.</exception> [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "COM requires primitive types")] public string CreateRequest(string userSuppliedIdentifier, string realm, string returnToUrl) { - OpenIdRelyingParty rp = new OpenIdRelyingParty(null); - var request = rp.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)); - return request.RedirectingResponse.GetDirectUriRequest(rp.Channel).AbsoluteUri; + var request = relyingParty.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)); + return request.RedirectingResponse.GetDirectUriRequest(relyingParty.Channel).AbsoluteUri; } /// <summary> @@ -133,8 +145,7 @@ namespace DotNetOpenAuth.OpenId.Interop { /// <exception cref="ProtocolException">Thrown if no OpenID endpoint could be found.</exception> [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "COM requires primitive types")] public string CreateRequestWithSimpleRegistration(string userSuppliedIdentifier, string realm, string returnToUrl, string optionalSreg, string requiredSreg) { - OpenIdRelyingParty rp = new OpenIdRelyingParty(null); - var request = rp.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)); + var request = relyingParty.CreateRequest(userSuppliedIdentifier, realm, new Uri(returnToUrl)); ClaimsRequest sreg = new ClaimsRequest(); if (!string.IsNullOrEmpty(optionalSreg)) { @@ -144,7 +155,7 @@ namespace DotNetOpenAuth.OpenId.Interop { sreg.SetProfileRequestFromList(requiredSreg.Split(','), DemandLevel.Require); } request.AddExtension(sreg); - return request.RedirectingResponse.GetDirectUriRequest(rp.Channel).AbsoluteUri; + return request.RedirectingResponse.GetDirectUriRequest(relyingParty.Channel).AbsoluteUri; } /// <summary> @@ -155,14 +166,13 @@ namespace DotNetOpenAuth.OpenId.Interop { /// <param name="form">The form data that may have been included in the case of a POST request.</param> /// <returns>The Provider's response to a previous authentication request, or null if no response is present.</returns> public AuthenticationResponseShim ProcessAuthentication(string url, string form) { - OpenIdRelyingParty rp = new OpenIdRelyingParty(null); HttpRequestInfo requestInfo = new HttpRequestInfo { UrlBeforeRewriting = new Uri(url) }; if (!string.IsNullOrEmpty(form)) { requestInfo.HttpMethod = "POST"; requestInfo.InputStream = new MemoryStream(Encoding.Unicode.GetBytes(form)); } - var response = rp.GetResponse(requestInfo); + var response = relyingParty.GetResponse(requestInfo); if (response != null) { return new AuthenticationResponseShim(response); } diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs index 0d105ad..9462d21 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs @@ -201,7 +201,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// </exception> DateTime IExpiringProtocolMessage.UtcCreationDate { get { return this.creationDateUtc; } - set { this.creationDateUtc = value.ToUniversalTime(); } + set { this.creationDateUtc = value.ToUniversalTimeSafe(); } } /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs index 27dacfd..5b5017d 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs @@ -524,6 +524,15 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> + /// Looks up a localized string similar to Sorry. This site only accepts OpenIDs that are HTTPS-secured, but {0} is not a secure Identifier.. + /// </summary> + internal static string RequireSslNotSatisfiedByAssertedClaimedId { + get { + return ResourceManager.GetString("RequireSslNotSatisfiedByAssertedClaimedId", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to The response is not ready. Use IsResponseReady to check whether a response is ready first.. /// </summary> internal static string ResponseNotReady { diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx index bca813b..142438d 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx @@ -334,4 +334,7 @@ Discovered endpoint info: <data name="ArgumentIsPpidIdentifier" xml:space="preserve"> <value>This is already a PPID Identifier.</value> </data> -</root>
\ No newline at end of file + <data name="RequireSslNotSatisfiedByAssertedClaimedId" xml:space="preserve"> + <value>Sorry. This site only accepts OpenIDs that are HTTPS-secured, but {0} is not a secure Identifier.</value> + </data> +</root> diff --git a/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs index e38952a..b53e1f6 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/AnonymousRequest.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.OpenId.Provider { using System; + using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; @@ -26,6 +27,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// </summary> /// <param name="provider">The provider that received the request.</param> /// <param name="request">The incoming authentication request message.</param> + [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Code contracts require it.")] internal AnonymousRequest(OpenIdProvider provider, SignedResponseRequest request) : base(provider, request) { Contract.Requires(provider != null); diff --git a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs index 4bb7d28..6e61376 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/HostProcessedRequest.cs @@ -105,7 +105,6 @@ namespace DotNetOpenAuth.OpenId.Provider { /// See OpenID Authentication 2.0 spec section 9.2.1. /// </remarks> public RelyingPartyDiscoveryResult IsReturnUrlDiscoverable(OpenIdProvider provider) { - Contract.Requires(provider != null); ErrorUtilities.VerifyArgumentNotNull(provider, "provider"); if (!this.realmDiscoveryResult.HasValue) { diff --git a/src/DotNetOpenAuth/OpenId/Provider/IDirectedIdentityIdentifierProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/IDirectedIdentityIdentifierProvider.cs index de24f74..00a3267 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/IDirectedIdentityIdentifierProvider.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/IDirectedIdentityIdentifierProvider.cs @@ -71,9 +71,8 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <returns> /// <c>true</c> if the given identifier is the valid, unique identifier for some uesr (and NOT a PPID); otherwise, <c>false</c>. /// </returns> - public bool IsUserLocalIdentifier(Identifier identifier) { + bool IDirectedIdentityIdentifierProvider.IsUserLocalIdentifier(Identifier identifier) { Contract.Requires(identifier != null); - throw new NotImplementedException(); } diff --git a/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs b/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs index 64d2908..399a84f 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs @@ -34,7 +34,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// Initializes a new instance of the <see cref="PrivatePersonalIdentifierProviderBase"/> class. /// </summary> /// <param name="baseIdentifier">The base URI on which to append the anonymous part.</param> - public PrivatePersonalIdentifierProviderBase(Uri baseIdentifier) { + protected PrivatePersonalIdentifierProviderBase(Uri baseIdentifier) { Contract.Requires(baseIdentifier != null); ErrorUtilities.VerifyArgumentNotNull(baseIdentifier, "baseIdentifier"); @@ -47,6 +47,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <summary> /// A granularity description for who wide of an audience sees the same generated PPID. /// </summary> + [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Breaking change")] public enum AudienceScope { /// <summary> /// A unique Identifier is generated for every realm. This is the highest security setting. @@ -78,6 +79,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// for the authenticating uesr. /// </summary> /// <value>The default value is <see cref="AudienceScope.Realm"/>.</value> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Pairwise", Justification = "Meaningful word")] public AudienceScope PairwiseUnique { get; set; } /// <summary> @@ -183,6 +185,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// </summary> /// <param name="uriHash">The unique part of the Identifier to append to the common first part.</param> /// <returns>The full PPID Identifier.</returns> + [SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "NOT equivalent overload. The recommended one breaks on relative URIs.")] protected virtual Uri AppendIdentifiers(string uriHash) { Contract.Requires(!String.IsNullOrEmpty(uriHash)); ErrorUtilities.VerifyNonZeroLength(uriHash, "uriHash"); diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdButton.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdButton.cs index b367944..8b517b4 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdButton.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdButton.cs @@ -92,6 +92,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Gets or sets a value indicating whether to pre-discover the identifier so /// the user agent has an immediate redirect. /// </summary> + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Precreate", Justification = "Breaking change to public API")] [Bindable(true), Category(OpenIdCategory), DefaultValue(PrecreateRequestDefault)] [Description("Whether to pre-discover the identifier so the user agent has an immediate redirect.")] public bool PrecreateRequest { diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs index 5ab8053..da2a9ae 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs @@ -151,7 +151,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <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 override IEnumerable<IAuthenticationRequest> CreateRequests() { - Contract.Requires(this.Identifier != null, OpenIdStrings.NoIdentifierSet); ErrorUtilities.VerifyOperation(this.Identifier != null, OpenIdStrings.NoIdentifierSet); // We delegate all our logic to another method, since invoking base. methods diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs index e3740db..69a6eaa 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs @@ -135,6 +135,15 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private void VerifyDiscoveryMatchesAssertion(OpenIdRelyingParty relyingParty) { Logger.OpenId.Debug("Verifying assertion matches identifier discovery results..."); + // Ensure that we abide by the RP's rules regarding RequireSsl for this discovery step. + Identifier claimedId = this.Response.ClaimedIdentifier; + if (relyingParty.SecuritySettings.RequireSsl) { + if (!claimedId.TryRequireSsl(out claimedId)) { + Logger.OpenId.ErrorFormat("This site is configured to accept only SSL-protected OpenIDs, but {0} was asserted and must be rejected.", this.Response.ClaimedIdentifier); + ErrorUtilities.ThrowProtocol(OpenIdStrings.RequireSslNotSatisfiedByAssertedClaimedId, this.Response.ClaimedIdentifier); + } + } + // While it LOOKS like we're performing discovery over HTTP again // Yadis.IdentifierDiscoveryCachePolicy is set to HttpRequestCacheLevel.CacheIfAvailable // which means that the .NET runtime is caching our discoveries for us. This turns out @@ -144,7 +153,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // is signed by the RP before it's considered reliable. In 1.x stateless mode, this RP // doesn't (and can't) sign its own return_to URL, so its cached discovery information // is merely a hint that must be verified by performing discovery again here. - var discoveryResults = this.Response.ClaimedIdentifier.Discover(relyingParty.WebRequestHandler); + var discoveryResults = claimedId.Discover(relyingParty.WebRequestHandler); ErrorUtilities.VerifyProtocol( discoveryResults.Contains(this.endpoint), OpenIdStrings.IssuedAssertionFailsIdentifierDiscovery, diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs index 3e0c8db..8499178 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs @@ -48,12 +48,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Gets the best association (the one with the longest remaining life) for a given key. /// </summary> /// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param> - /// <param name="securitySettings">The security settings.</param> + /// <param name="securityRequirements">The security settings.</param> /// <returns> /// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key. /// </returns> - public Association GetAssociation(Uri distinguishingFactor, SecuritySettings securitySettings) { - return this.associationStore.GetAssociation(distinguishingFactor, securitySettings); + public Association GetAssociation(Uri distinguishingFactor, SecuritySettings securityRequirements) { + return this.associationStore.GetAssociation(distinguishingFactor, securityRequirements); } /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/WellKnownProviders.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/WellKnownProviders.cs index bd45842..2e2ab61 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/WellKnownProviders.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/WellKnownProviders.cs @@ -5,6 +5,8 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.OpenId.RelyingParty { + using System.Diagnostics.CodeAnalysis; + /// <summary> /// Common OpenID Provider Identifiers. /// </summary> @@ -12,16 +14,19 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// The Yahoo OP Identifier. /// </summary> + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "Immutable type")] public static readonly Identifier Yahoo = "https://me.yahoo.com/"; /// <summary> /// The Google OP Identifier. /// </summary> + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "Immutable type")] public static readonly Identifier Google = "https://www.google.com/accounts/o8/id"; /// <summary> /// The MyOpenID OP Identifier. /// </summary> + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "Immutable type")] public static readonly Identifier MyOpenId = "https://www.myopenid.com/"; /// <summary> |