diff options
27 files changed, 1601 insertions, 1029 deletions
diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj index 6c6a42e..8a4b8af 100644 --- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj +++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj @@ -1,180 +1,183 @@ -<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <PropertyGroup> - <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> - <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> - <ProductVersion>9.0.30729</ProductVersion> - <SchemaVersion>2.0</SchemaVersion> - <ProjectGuid>{4376ECC9-C346-4A99-B13C-FA93C0FBD2C9}</ProjectGuid> - <OutputType>Library</OutputType> - <AppDesignerFolder>Properties</AppDesignerFolder> - <RootNamespace>DotNetOpenAuth.Test</RootNamespace> - <AssemblyName>DotNetOpenAuth.Test</AssemblyName> - <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> - <FileAlignment>512</FileAlignment> - <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> - <DebugSymbols>true</DebugSymbols> - <DebugType>full</DebugType> - <Optimize>false</Optimize> - <OutputPath>..\..\bin\Debug\</OutputPath> - <DefineConstants>DEBUG;TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> - <DebugType>pdbonly</DebugType> - <Optimize>true</Optimize> - <OutputPath>..\..\bin\Release\</OutputPath> - <DefineConstants>TRACE</DefineConstants> - <ErrorReport>prompt</ErrorReport> - <WarningLevel>4</WarningLevel> - </PropertyGroup> - <PropertyGroup Condition=" '$(Sign)' == 'true' "> - <SignAssembly>true</SignAssembly> - <AssemblyOriginatorKeyFile>..\official-build-key.pfx</AssemblyOriginatorKeyFile> - </PropertyGroup> - <ItemGroup> - <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL"> - <SpecificVersion>False</SpecificVersion> - <HintPath>..\..\lib\log4net.dll</HintPath> - </Reference> - <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" /> - <Reference Include="System" /> - <Reference Include="System.configuration" /> - <Reference Include="System.Core"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Data" /> - <Reference Include="System.Data.DataSetExtensions"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - <Reference Include="System.Runtime.Serialization"> - <RequiredTargetFramework>3.0</RequiredTargetFramework> - </Reference> - <Reference Include="System.Web" /> - <Reference Include="System.Xml" /> - <Reference Include="System.Xml.Linq"> - <RequiredTargetFramework>3.5</RequiredTargetFramework> - </Reference> - </ItemGroup> - <ItemGroup> - <Compile Include="CoordinatorBase.cs" /> - <Compile Include="Hosting\AspNetHost.cs" /> - <Compile Include="Hosting\HttpHost.cs" /> - <Compile Include="Hosting\TestingWorkerRequest.cs" /> - <Compile Include="Messaging\CollectionAssert.cs" /> - <Compile Include="Messaging\ErrorUtilitiesTests.cs" /> - <Compile Include="Messaging\MessageSerializerTests.cs" /> - <Compile Include="Messaging\Reflection\MessageDescriptionTests.cs" /> - <Compile Include="Messaging\Reflection\MessageDictionaryTests.cs" /> - <Compile Include="Messaging\MessagingTestBase.cs" /> - <Compile Include="Messaging\MessagingUtilitiesTests.cs" /> - <Compile Include="Messaging\ChannelTests.cs" /> - <Compile Include="Messaging\HttpRequestInfoTests.cs" /> - <Compile Include="Messaging\ProtocolExceptionTests.cs" /> - <Compile Include="Messaging\Bindings\StandardExpirationBindingElementTests.cs" /> - <Compile Include="Messaging\Reflection\MessagePartTests.cs" /> - <Compile Include="Messaging\Reflection\ValueMappingTests.cs" /> - <Compile Include="Mocks\CoordinatingChannel.cs" /> - <Compile Include="Mocks\InMemoryTokenManager.cs" /> - <Compile Include="Mocks\MockHttpRequest.cs" /> - <Compile Include="Mocks\MockIdentifier.cs" /> - <Compile Include="Mocks\MockTransformationBindingElement.cs" /> - <Compile Include="Mocks\MockReplayProtectionBindingElement.cs" /> - <Compile Include="Mocks\TestBaseMessage.cs" /> - <Compile Include="Mocks\TestDerivedMessage.cs" /> - <Compile Include="Mocks\TestReplayProtectedMessage.cs" /> - <Compile Include="Mocks\TestDirectedMessage.cs" /> - <Compile Include="Mocks\TestBadChannel.cs" /> - <Compile Include="Mocks\TestExpiringMessage.cs" /> - <Compile Include="Mocks\TestSignedDirectedMessage.cs" /> - <Compile Include="Mocks\MockSigningBindingElement.cs" /> - <Compile Include="Mocks\TestWebRequestHandler.cs" /> - <Compile Include="Mocks\TestChannel.cs" /> - <Compile Include="Mocks\TestMessage.cs" /> - <Compile Include="Mocks\TestMessageFactory.cs" /> - <Compile Include="OAuth\ChannelElements\HmacSha1SigningBindingElementTests.cs" /> - <Compile Include="OAuth\ChannelElements\OAuthChannelTests.cs" /> - <Compile Include="OAuth\ChannelElements\PlaintextSigningBindingElementTest.cs" /> - <Compile Include="OAuth\ChannelElements\SigningBindingElementBaseTests.cs" /> - <Compile Include="OAuth\ConsumerDescription.cs" /> - <Compile Include="OAuth\ProtocolTests.cs" /> - <Compile Include="OAuth\ServiceProviderDescriptionTests.cs" /> - <Compile Include="OpenId\AssociationsTests.cs" /> - <Compile Include="OpenId\AssociationTests.cs" /> - <Compile Include="OpenId\AuthenticationTests.cs" /> - <Compile Include="OpenId\ChannelElements\KeyValueFormEncodingTests.cs" /> - <Compile Include="Messaging\Bindings\StandardReplayProtectionBindingElementTests.cs" /> - <Compile Include="OpenId\IdentifierTests.cs" /> - <Compile Include="OpenId\Messages\AssociateDiffieHellmanRequestTests.cs" /> - <Compile Include="OpenId\Messages\AssociateRequestTests.cs" /> - <Compile Include="OpenId\Messages\AssociateUnsuccessfulResponseTests.cs" /> - <Compile Include="OpenId\Messages\AssociateUnencryptedResponseTests.cs" /> - <Compile Include="OpenId\ChannelElements\OpenIdChannelTests.cs" /> - <Compile Include="OpenId\Messages\CheckIdRequestTests.cs" /> - <Compile Include="OpenId\Messages\CheckAuthenticationResponseTests.cs" /> - <Compile Include="OpenId\Messages\CheckAuthenticationRequestTests.cs" /> - <Compile Include="OpenId\Messages\IndirectSignedResponseTests.cs" /> - <Compile Include="OpenId\Messages\NegativeAssertionResponseTests.cs" /> - <Compile Include="OpenId\Messages\DirectErrorResponseTests.cs" /> - <Compile Include="OpenId\Messages\IndirectErrorResponseTests.cs" /> - <Compile Include="OpenId\Messages\PositiveAssertionResponseTests.cs" /> - <Compile Include="OpenId\Messages\SignedResponseRequestTests.cs" /> - <Compile Include="OpenId\OpenIdCoordinator.cs" /> - <Compile Include="OpenId\AssociationHandshakeTests.cs" /> - <Compile Include="OpenId\OpenIdTestBase.cs" /> - <Compile Include="OpenId\RealmTests.cs" /> - <Compile Include="OpenId\RelyingParty\OpenIdRelyingPartyTests.cs" /> - <Compile Include="OpenId\RelyingParty\RelyingPartySecuritySettingsTests.cs" /> - <Compile Include="OpenId\TestSupport.cs" /> - <Compile Include="OpenId\UI\UITestSupport.cs" /> - <Compile Include="OpenId\UriIdentifierTests.cs" /> - <Compile Include="OpenId\XriIdentifierTests.cs" /> - <Compile Include="Properties\AssemblyInfo.cs" /> - <Compile Include="Messaging\ResponseTests.cs" /> - <Compile Include="OAuth\AppendixScenarios.cs" /> - <Compile Include="Mocks\CoordinatingOAuthChannel.cs" /> - <Compile Include="OAuth\OAuthCoordinator.cs" /> - <Compile Include="TestBase.cs" /> - <Compile Include="TestUtilities.cs" /> - <Compile Include="UriUtilTests.cs" /> - </ItemGroup> - <ItemGroup> - <ProjectReference Include="..\DotNetOpenAuth\DotNetOpenAuth.csproj"> - <Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project> - <Name>DotNetOpenAuth</Name> - </ProjectReference> - </ItemGroup> - <ItemGroup> - <EmbeddedResource Include="Logging.config" /> - </ItemGroup> - <ItemGroup> - <Shadow Include="Test References\DotNetOpenAuth.accessor" /> - </ItemGroup> - <ItemGroup> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html1020.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html10both.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html10del.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html10prov.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010combinedA.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010combinedB.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010combinedC.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20both.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20del.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20prov.html" /> - <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20relative.html" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds-irrelevant.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds10.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds1020.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds11.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds20.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds2010a.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds2010b.xml" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\XrdsReferencedInHead.html" /> - <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\XrdsReferencedInHttpHeader.html" /> - </ItemGroup> - <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> - <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" /> +<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.30729</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4376ECC9-C346-4A99-B13C-FA93C0FBD2C9}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>DotNetOpenAuth.Test</RootNamespace>
+ <AssemblyName>DotNetOpenAuth.Test</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Sign)' == 'true' ">
+ <SignAssembly>true</SignAssembly>
+ <AssemblyOriginatorKeyFile>..\official-build-key.pfx</AssemblyOriginatorKeyFile>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\lib\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Runtime.Serialization">
+ <RequiredTargetFramework>3.0</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Web" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="CoordinatorBase.cs" />
+ <Compile Include="Hosting\AspNetHost.cs" />
+ <Compile Include="Hosting\HttpHost.cs" />
+ <Compile Include="Hosting\TestingWorkerRequest.cs" />
+ <Compile Include="Messaging\CollectionAssert.cs" />
+ <Compile Include="Messaging\ErrorUtilitiesTests.cs" />
+ <Compile Include="Messaging\MessageSerializerTests.cs" />
+ <Compile Include="Messaging\Reflection\MessageDescriptionTests.cs" />
+ <Compile Include="Messaging\Reflection\MessageDictionaryTests.cs" />
+ <Compile Include="Messaging\MessagingTestBase.cs" />
+ <Compile Include="Messaging\MessagingUtilitiesTests.cs" />
+ <Compile Include="Messaging\ChannelTests.cs" />
+ <Compile Include="Messaging\HttpRequestInfoTests.cs" />
+ <Compile Include="Messaging\ProtocolExceptionTests.cs" />
+ <Compile Include="Messaging\Bindings\StandardExpirationBindingElementTests.cs" />
+ <Compile Include="Messaging\Reflection\MessagePartTests.cs" />
+ <Compile Include="Messaging\Reflection\ValueMappingTests.cs" />
+ <Compile Include="Mocks\CoordinatingChannel.cs" />
+ <Compile Include="Mocks\InMemoryTokenManager.cs" />
+ <Compile Include="Mocks\MockHttpRequest.cs" />
+ <Compile Include="Mocks\MockIdentifier.cs" />
+ <Compile Include="Mocks\MockTransformationBindingElement.cs" />
+ <Compile Include="Mocks\MockReplayProtectionBindingElement.cs" />
+ <Compile Include="Mocks\TestBaseMessage.cs" />
+ <Compile Include="Mocks\TestDerivedMessage.cs" />
+ <Compile Include="Mocks\TestReplayProtectedMessage.cs" />
+ <Compile Include="Mocks\TestDirectedMessage.cs" />
+ <Compile Include="Mocks\TestBadChannel.cs" />
+ <Compile Include="Mocks\TestExpiringMessage.cs" />
+ <Compile Include="Mocks\TestSignedDirectedMessage.cs" />
+ <Compile Include="Mocks\MockSigningBindingElement.cs" />
+ <Compile Include="Mocks\TestWebRequestHandler.cs" />
+ <Compile Include="Mocks\TestChannel.cs" />
+ <Compile Include="Mocks\TestMessage.cs" />
+ <Compile Include="Mocks\TestMessageFactory.cs" />
+ <Compile Include="OAuth\ChannelElements\HmacSha1SigningBindingElementTests.cs" />
+ <Compile Include="OAuth\ChannelElements\OAuthChannelTests.cs" />
+ <Compile Include="OAuth\ChannelElements\PlaintextSigningBindingElementTest.cs" />
+ <Compile Include="OAuth\ChannelElements\SigningBindingElementBaseTests.cs" />
+ <Compile Include="OAuth\ConsumerDescription.cs" />
+ <Compile Include="OAuth\ProtocolTests.cs" />
+ <Compile Include="OAuth\ServiceProviderDescriptionTests.cs" />
+ <Compile Include="OpenId\AssociationsTests.cs" />
+ <Compile Include="OpenId\AssociationTests.cs" />
+ <Compile Include="OpenId\AuthenticationTests.cs" />
+ <Compile Include="OpenId\ChannelElements\KeyValueFormEncodingTests.cs" />
+ <Compile Include="Messaging\Bindings\StandardReplayProtectionBindingElementTests.cs" />
+ <None Include="OpenId\Extensions\ClaimsResponseTests.cs" />
+ <Compile Include="OpenId\Extensions\ExtensionTestBase.cs" />
+ <Compile Include="OpenId\Extensions\SimpleRegistrationTests.cs" />
+ <Compile Include="OpenId\IdentifierTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateDiffieHellmanRequestTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateRequestTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateUnsuccessfulResponseTests.cs" />
+ <Compile Include="OpenId\Messages\AssociateUnencryptedResponseTests.cs" />
+ <Compile Include="OpenId\ChannelElements\OpenIdChannelTests.cs" />
+ <Compile Include="OpenId\Messages\CheckIdRequestTests.cs" />
+ <Compile Include="OpenId\Messages\CheckAuthenticationResponseTests.cs" />
+ <Compile Include="OpenId\Messages\CheckAuthenticationRequestTests.cs" />
+ <Compile Include="OpenId\Messages\IndirectSignedResponseTests.cs" />
+ <Compile Include="OpenId\Messages\NegativeAssertionResponseTests.cs" />
+ <Compile Include="OpenId\Messages\DirectErrorResponseTests.cs" />
+ <Compile Include="OpenId\Messages\IndirectErrorResponseTests.cs" />
+ <Compile Include="OpenId\Messages\PositiveAssertionResponseTests.cs" />
+ <Compile Include="OpenId\Messages\SignedResponseRequestTests.cs" />
+ <Compile Include="OpenId\OpenIdCoordinator.cs" />
+ <Compile Include="OpenId\AssociationHandshakeTests.cs" />
+ <Compile Include="OpenId\OpenIdTestBase.cs" />
+ <Compile Include="OpenId\RealmTests.cs" />
+ <Compile Include="OpenId\RelyingParty\OpenIdRelyingPartyTests.cs" />
+ <Compile Include="OpenId\RelyingParty\RelyingPartySecuritySettingsTests.cs" />
+ <Compile Include="OpenId\TestSupport.cs" />
+ <Compile Include="OpenId\UI\UITestSupport.cs" />
+ <Compile Include="OpenId\UriIdentifierTests.cs" />
+ <Compile Include="OpenId\XriIdentifierTests.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Messaging\ResponseTests.cs" />
+ <Compile Include="OAuth\AppendixScenarios.cs" />
+ <Compile Include="Mocks\CoordinatingOAuthChannel.cs" />
+ <Compile Include="OAuth\OAuthCoordinator.cs" />
+ <Compile Include="TestBase.cs" />
+ <Compile Include="TestUtilities.cs" />
+ <Compile Include="UriUtilTests.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\DotNetOpenAuth\DotNetOpenAuth.csproj">
+ <Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project>
+ <Name>DotNetOpenAuth</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="Logging.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <Shadow Include="Test References\DotNetOpenAuth.accessor" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html1020.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html10both.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html10del.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html10prov.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010combinedA.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010combinedB.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html2010combinedC.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20both.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20del.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20prov.html" />
+ <EmbeddedResource Include="OpenId\Discovery\htmldiscovery\html20relative.html" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds-irrelevant.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds10.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds1020.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds11.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds20.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds2010a.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds2010b.xml" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\XrdsReferencedInHead.html" />
+ <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\XrdsReferencedInHttpHeader.html" />
+ </ItemGroup>
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+ <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" />
</Project>
\ No newline at end of file diff --git a/src/DotNetOpenAuth.Test/Messaging/CollectionAssert.cs b/src/DotNetOpenAuth.Test/Messaging/CollectionAssert.cs index d06ef62..1cdefdb 100644 --- a/src/DotNetOpenAuth.Test/Messaging/CollectionAssert.cs +++ b/src/DotNetOpenAuth.Test/Messaging/CollectionAssert.cs @@ -1,19 +1,26 @@ -//----------------------------------------------------------------------- -// <copyright file="CollectionAssert.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.Test.Messaging { - using System.Collections; - using System.Collections.Generic; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - internal class CollectionAssert<T> { - internal static void AreEquivalent(ICollection<T> expected, ICollection<T> actual) { - ICollection expectedNonGeneric = new List<T>(expected); - ICollection actualNonGeneric = new List<T>(actual); - CollectionAssert.AreEquivalent(expectedNonGeneric, actualNonGeneric); - } - } -} +//-----------------------------------------------------------------------
+// <copyright file="CollectionAssert.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.Messaging {
+ using System.Collections;
+ using System.Collections.Generic;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+ internal class CollectionAssert<T> {
+ internal static void AreEquivalent(ICollection<T> expected, ICollection<T> actual) {
+ ICollection expectedNonGeneric = new List<T>(expected);
+ ICollection actualNonGeneric = new List<T>(actual);
+ CollectionAssert.AreEquivalent(expectedNonGeneric, actualNonGeneric);
+ }
+
+ internal static void AreEquivalentByEquality(ICollection<T> expected, ICollection<T> actual) {
+ Assert.AreEqual(expected.Count, actual.Count);
+ foreach (T value in expected) {
+ Assert.IsTrue(actual.Contains(value));
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ClaimsResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ClaimsResponseTests.cs new file mode 100644 index 0000000..2e18b58 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ClaimsResponseTests.cs @@ -0,0 +1,142 @@ +//-----------------------------------------------------------------------
+// <copyright file="ClaimsResponseTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.Extensions {
+ using System;
+ using System.Collections.Generic;
+ using System.Text;
+ using System.Runtime.Serialization;
+ using System.Runtime.Serialization.Formatters.Binary;
+ using System.Xml.Serialization;
+ using System.IO;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
+
+ [TestClass]
+ public class ClaimsResponseTests {
+ private ClaimsResponse getFilledData() {
+ return new ClaimsResponse(Constants.sreg_ns) {
+ BirthDate = new DateTime(2005, 2, 3),
+ Culture = new System.Globalization.CultureInfo("en-US"),
+ Email = "a@b.com",
+ FullName = "Jimmy buffet",
+ Gender = Gender.Male,
+ Nickname = "Jimbo",
+ PostalCode = "12345",
+ TimeZone = "PST",
+ };
+ }
+
+ [TestMethod]
+ public void EmptyMailAddress() {
+ ClaimsResponse response = new ClaimsResponse(Constants.sreg_ns);
+ response.Email = "";
+ Assert.IsNull(response.MailAddress);
+ }
+
+ [TestMethod]
+ public void BinarySerialization() {
+ ClaimsResponse fields = getFilledData();
+ MemoryStream ms = new MemoryStream();
+ IFormatter formatter = new BinaryFormatter();
+ formatter.Serialize(ms, fields);
+
+ ms.Position = 0;
+ ClaimsResponse fields2 = (ClaimsResponse)formatter.Deserialize(ms);
+ Assert.AreEqual(fields, fields2);
+ }
+
+ [TestMethod]
+ public void XmlSerialization() {
+ ClaimsResponse fields = getFilledData();
+ MemoryStream ms = new MemoryStream();
+ XmlSerializer xs = new XmlSerializer(typeof(ClaimsResponse));
+ xs.Serialize(ms, fields);
+
+ ms.Position = 0;
+ ClaimsResponse fields2 = (ClaimsResponse)xs.Deserialize(ms);
+ Assert.AreEqual(fields, fields2);
+ }
+
+ [TestMethod]
+ public void TestEquals() {
+ ClaimsResponse fields1 = getFilledData();
+
+ Assert.AreNotEqual(fields1, null);
+ Assert.AreNotEqual(fields1, "string");
+
+ ClaimsResponse fields2 = getFilledData();
+ Assert.AreNotSame(fields1, fields2, "Test sanity check.");
+ Assert.AreEqual(fields1, fields2);
+
+ // go through each property and change it slightly and make sure it causes inequality.
+ fields2.Email += "q";
+ Assert.AreNotEqual(fields1, fields2);
+ fields1.Email = fields2.Email;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.BirthDate = DateTime.Now;
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.BirthDate = fields1.BirthDate;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.Country += "q";
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.Country = fields1.Country;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.FullName += "q";
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.FullName = fields1.FullName;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.Gender = Gender.Female;
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.Gender = fields1.Gender;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.Language = "gb";
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.Language = fields1.Language;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.Nickname += "q";
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.Nickname = fields1.Nickname;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.PostalCode += "q";
+ Assert.AreNotEqual(fields1, fields2);
+ fields2.PostalCode = fields1.PostalCode;
+ Assert.AreEqual(fields1, fields2, "Test sanity check.");
+ fields2.TimeZone += "q";
+ Assert.AreNotEqual(fields1, fields2);
+ }
+
+ void parameterizedPreserveVersionFromRequest(string versionTypeUri) {
+ Dictionary<string, string> fields = new Dictionary<string, string>{
+ {"optional", "nickname"},
+ };
+ var req = new ClaimsRequest();
+ Assert.IsTrue(((IExtensionRequest)req).Deserialize(fields, null, versionTypeUri));
+ Assert.AreEqual(DemandLevel.Request, req.Nickname);
+ ClaimsResponse resp = req.CreateResponse();
+ Assert.AreEqual(versionTypeUri, ((IExtensionResponse)resp).TypeUri);
+ }
+
+ [TestMethod]
+ public void PreserveVersionFromRequest() {
+ // some unofficial type URIs...
+ parameterizedPreserveVersionFromRequest("http://openid.net/sreg/1.0");
+ parameterizedPreserveVersionFromRequest("http://openid.net/sreg/1.1");
+ // and the official one.
+ parameterizedPreserveVersionFromRequest("http://openid.net/extensions/sreg/1.1");
+ }
+
+ //[TestMethod]
+ public void AddToResponse() {
+ // TODO
+ }
+
+ //[TestMethod]
+ public void ReadFromResponse() {
+ // TODO
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestBase.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestBase.cs new file mode 100644 index 0000000..4da8dfe --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestBase.cs @@ -0,0 +1,67 @@ +//-----------------------------------------------------------------------
+// <copyright file="ExtensionTestBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OpenId.Extensions {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using DotNetOpenId.Extensions;
+ using DotNetOpenAuth.OpenId;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using DotNetOpenAuth.OpenId.Messages;
+ using System.Collections.ObjectModel;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Test.Messaging;
+
+ public class ExtensionTestBase : OpenIdTestBase {
+ protected const ProtocolVersion Version = ProtocolVersion.V20;
+
+ [TestInitialize]
+ public virtual void Setup() {
+ base.SetUp();
+ }
+
+ internal void Roundtrip(
+ Protocol protocol,
+ IEnumerable<IOpenIdMessageExtension> requests,
+ IEnumerable<IOpenIdMessageExtension> responses) {
+ Association association = HmacShaAssociation.Create(protocol, protocol.Args.SignatureAlgorithm.Best, AssociationRelyingPartyType.Smart);
+ var coordinator = new OpenIdCoordinator(
+ rp => {
+ var requestBase = new CheckIdRequest(protocol.Version, ProviderUri, true);
+ rp.AssociationStore.StoreAssociation(ProviderUri, association);
+ requestBase.AssociationHandle = association.Handle;
+ requestBase.ClaimedIdentifier = "http://claimedid";
+ requestBase.LocalIdentifier = "http://localid";
+ requestBase.ReturnTo = RPUri;
+
+ foreach (IOpenIdMessageExtension extension in requests) {
+ requestBase.Extensions.Add(extension);
+ }
+
+ rp.Channel.Send(requestBase);
+ var response = rp.Channel.ReadFromRequest<PositiveAssertionResponse>();
+
+ var receivedResponses = response.Extensions.Cast<IOpenIdMessageExtension>();
+ CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(responses.ToArray(), receivedResponses.ToArray());
+ },
+ op => {
+ op.AssociationStore.StoreAssociation(AssociationRelyingPartyType.Smart, association);
+ var request = op.Channel.ReadFromRequest<CheckIdRequest>();
+ var response = new PositiveAssertionResponse(request);
+ var receivedRequests = request.Extensions.Cast<IOpenIdMessageExtension>();
+ CollectionAssert<IOpenIdMessageExtension>.AreEquivalentByEquality(requests.ToArray(), receivedRequests.ToArray());
+
+ foreach (var extensionResponse in responses) {
+ response.Extensions.Add(extensionResponse);
+ }
+
+ op.Channel.Send(response); + });
+ coordinator.Run();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/SimpleRegistrationTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/SimpleRegistrationTests.cs new file mode 100644 index 0000000..7f2592e --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/SimpleRegistrationTests.cs @@ -0,0 +1,83 @@ +namespace DotNetOpenAuth.Test.OpenId.Extensions {
+ using System;
+ using System.Collections.Generic;
+ using System.Globalization;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using DotNetOpenAuth.OpenId;
+
+ [TestClass]
+ public class SimpleRegistrationTests : ExtensionTestBase {
+ [TestMethod]
+ public void Simple() {
+ Roundtrip(Protocol.Default,
+ new[] { new ClaimsRequest() { Nickname = DemandLevel.Request } },
+ new[] { new ClaimsResponse() { Nickname = "Andrew" } });
+ }
+
+ ////[TestMethod]
+ ////public void None() {
+ //// var response = ParameterizedTest<ClaimsResponse>(
+ //// TestSupport.Scenarios.ExtensionFullCooperation, Version, null);
+ //// Assert.IsNull(response);
+ ////}
+
+ ////[TestMethod]
+ ////public void Full() {
+ //// var request = new ClaimsRequest();
+ //// request.FullName = DemandLevel.Request;
+ //// request.Email = DemandLevel.Require;
+ //// var response = ParameterizedTest<ClaimsResponse>(
+ //// TestSupport.Scenarios.ExtensionFullCooperation, Version, request);
+ //// Assert.AreEqual("Andrew Arnott", response.FullName);
+ //// Assert.AreEqual("andrewarnott@gmail.com", response.Email);
+ ////}
+ ////[TestMethod]
+ ////public void Partial() {
+ //// var request = new ClaimsRequest();
+ //// request.FullName = DemandLevel.Request;
+ //// request.Email = DemandLevel.Require;
+ //// var response = ParameterizedTest<ClaimsResponse>(
+ //// TestSupport.Scenarios.ExtensionPartialCooperation, Version, request);
+ //// Assert.IsNull(response.FullName);
+ //// Assert.AreEqual("andrewarnott@gmail.com", response.Email);
+ ////}
+
+ ////[TestMethod]
+ ////public void Birthdates() {
+ //// var response = new ClaimsResponse();
+ //// // Verify that they both start out as null
+ //// Assert.IsNull(response.BirthDateRaw);
+ //// Assert.IsFalse(response.BirthDate.HasValue);
+
+ //// // Verify that null can be set.
+ //// response.BirthDate = null;
+ //// response.BirthDateRaw = null;
+ //// Assert.IsNull(response.BirthDateRaw);
+ //// Assert.IsFalse(response.BirthDate.HasValue);
+
+ //// // Verify that the strong-typed BirthDate property can be set and that it affects the raw property.
+ //// response.BirthDate = DateTime.Parse("April 4, 1984");
+ //// Assert.AreEqual(4, response.BirthDate.Value.Month);
+ //// Assert.AreEqual("1984-04-04", response.BirthDateRaw);
+
+ //// // Verify that the raw property can be set with a complete birthdate and that it affects the strong-typed property.
+ //// response.BirthDateRaw = "1998-05-08";
+ //// Assert.AreEqual("1998-05-08", response.BirthDateRaw);
+ //// Assert.AreEqual(DateTime.Parse("May 8, 1998", CultureInfo.InvariantCulture), response.BirthDate);
+
+ //// // Verify that an partial raw birthdate works, and sets the strong-typed property to null since it cannot be represented.
+ //// response.BirthDateRaw = "2000-00-00";
+ //// Assert.AreEqual("2000-00-00", response.BirthDateRaw);
+ //// Assert.IsFalse(response.BirthDate.HasValue);
+ ////}
+
+ ////[TestMethod, ExpectedException(typeof(ArgumentException))]
+ ////public void InvalidRawBirthdate() {
+ //// var response = new ClaimsResponse();
+ //// response.BirthDateRaw = "2008";
+ ////}
+ }
+}
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index c8644c5..a0c8e2e 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -164,6 +164,7 @@ <Compile Include="OpenId\AssociationMemoryStore.cs" />
<Compile Include="OpenId\Associations.cs" />
<Compile Include="OpenId\ChannelElements\ExtensionsBindingElement.cs" />
+ <Compile Include="OpenId\ChannelElements\IOpenIdExtensionFactory.cs" />
<Compile Include="OpenId\ChannelElements\ITamperResistantOpenIdMessage.cs" />
<Compile Include="OpenId\ChannelElements\OriginalStringUriEncoder.cs" />
<Compile Include="OpenId\ChannelElements\SigningBindingElement.cs" />
@@ -177,6 +178,7 @@ <Compile Include="OpenId\Extensions\ExtensionArgumentsManager.cs" />
<None Include="OpenId\Extensions\IExtension.cs" />
<Compile Include="OpenId\Extensions\IIncomingExtensions.cs" />
+ <Compile Include="OpenId\Extensions\OpenIdExtensionFactory.cs" />
<Compile Include="OpenId\Extensions\SimpleRegistration\ClaimsRequest.cs" />
<Compile Include="OpenId\Extensions\SimpleRegistration\ClaimsResponse.cs" />
<Compile Include="OpenId\Extensions\SimpleRegistration\Constants.cs" />
@@ -188,7 +190,7 @@ <Compile Include="OpenId\Messages\CheckIdRequest.cs" />
<Compile Include="OpenId\Messages\IndirectResponseBase.cs" />
<Compile Include="OpenId\Messages\IndirectSignedResponse.cs" />
- <Compile Include="OpenId\Messages\IOpenIdProtocolMessageExtension.cs" />
+ <Compile Include="OpenId\Messages\IOpenIdMessageExtension.cs" />
<Compile Include="OpenId\Messages\NegativeAssertionResponse.cs" />
<Compile Include="OpenId\Messages\PositiveAssertionResponse.cs" />
<Compile Include="OpenId\Messages\SignedResponseRequest.cs" />
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs index 2916c6e..e10311f 100644 --- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs +++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs @@ -40,11 +40,11 @@ namespace DotNetOpenAuth.Messaging.Reflection { private MessageDescription(MessageTypeAndVersion messageTypeAndVersion) { ErrorUtilities.VerifyArgumentNotNull(messageTypeAndVersion, "messageTypeAndVersion"); - if (!typeof(IProtocolMessage).IsAssignableFrom(messageTypeAndVersion.Type)) { + if (!typeof(IMessage).IsAssignableFrom(messageTypeAndVersion.Type)) { throw new ArgumentException(string.Format( CultureInfo.CurrentCulture, MessagingStrings.UnexpectedType, - typeof(IProtocolMessage), + typeof(IMessage), messageTypeAndVersion.Type)); } @@ -64,7 +64,7 @@ namespace DotNetOpenAuth.Messaging.Reflection { /// Gets a <see cref="MessageDescription"/> instance prepared for the /// given message type. /// </summary> - /// <param name="messageType">A type that implements <see cref="IProtocolMessage"/>.</param> + /// <param name="messageType">A type that implements <see cref="IMessage"/>.</param> /// <param name="messageVersion">The protocol version of the message.</param> /// <returns>A <see cref="MessageDescription"/> instance.</returns> internal static MessageDescription Get(Type messageType, Version messageVersion) { @@ -86,7 +86,7 @@ namespace DotNetOpenAuth.Messaging.Reflection { } /// <summary> - /// Reflects over some <see cref="IProtocolMessage"/>-implementing type + /// Reflects over some <see cref="IMessage"/>-implementing type /// and prepares to serialize/deserialize instances of that type. /// </summary> internal void ReflectMessageType() { diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs index e28f2aa..abb7705 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs @@ -15,6 +15,13 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { using DotNetOpenAuth.OpenId.Messages;
internal class ExtensionsBindingElement : IChannelBindingElement {
+ private readonly IOpenIdExtensionFactory extensionFactory;
+
+ internal ExtensionsBindingElement(IOpenIdExtensionFactory extensionFactory) {
+ ErrorUtilities.VerifyArgumentNotNull(extensionFactory, "extensionFactory");
+ this.extensionFactory = extensionFactory;
+ }
+
#region IChannelBindingElement Members
/// <summary>
@@ -56,12 +63,12 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { // all the extensions, their aliases, and their parameters.
var extensionManager = ExtensionArgumentsManager.CreateOutgoingExtensions(protocol);
foreach (IExtensionMessage protocolExtension in extendableMessage.Extensions) {
- var extension = protocolExtension as IOpenIdProtocolMessageExtension;
+ var extension = protocolExtension as IOpenIdMessageExtension;
if (extension != null) {
var extensionDictionary = new MessageDictionary(extension);
extensionManager.AddExtensionArguments(extension.TypeUri, extensionDictionary);
} else {
- Logger.WarnFormat("Unexpected extension type {0} did not implement {1}.", protocolExtension.GetType(), typeof(IOpenIdProtocolMessageExtension).Name);
+ Logger.WarnFormat("Unexpected extension type {0} did not implement {1}.", protocolExtension.GetType(), typeof(IOpenIdMessageExtension).Name);
}
}
@@ -99,9 +106,26 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { public bool PrepareMessageForReceiving(IProtocolMessage message) {
var extendableMessage = message as IProtocolMessageWithExtensions;
if (extendableMessage != null) {
- // TODO: Implement this
- throw new NotImplementedException();
- ////return true;
+ Protocol protocol = Protocol.Lookup(message.Version);
+ MessageDictionary baseMessageDictionary = new MessageDictionary(message);
+
+ // We have a helper class that will do all the heavy-lifting of organizing
+ // all the extensions, their aliases, and their parameters.
+ var extensionManager = ExtensionArgumentsManager.CreateIncomingExtensions(baseMessageDictionary);
+ foreach (string typeUri in extensionManager.GetExtensionTypeUris()) {
+ var extensionData = extensionManager.GetExtensionArguments(typeUri);
+
+ // Initialize this particular extension.
+ IOpenIdMessageExtension extension = extensionFactory.Create(typeUri, extensionData, extendableMessage);
+ MessageDictionary extensionDictionary = new MessageDictionary(extension);
+ foreach (var pair in extensionData) {
+ extensionDictionary[pair.Key] = pair.Value;
+ }
+
+ extendableMessage.Extensions.Add(extension);
+ }
+
+ return true;
}
return false;
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/IOpenIdExtensionFactory.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/IOpenIdExtensionFactory.cs new file mode 100644 index 0000000..9fa3d06 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/IOpenIdExtensionFactory.cs @@ -0,0 +1,32 @@ +//-----------------------------------------------------------------------
+// <copyright file="IOpenIdExtensionFactory.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.ChannelElements {
+ using System.Collections.Generic;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+
+ /// <summary>
+ /// OpenID extension factory class for creating extensions based on received Type URIs.
+ /// </summary>
+ internal interface IOpenIdExtensionFactory {
+ /// <summary>
+ /// Creates a new instance of some extension based on the received extension parameters.
+ /// </summary>
+ /// <param name="typeUri">The type URI of the extension.</param>
+ /// <param name="data">The parameters associated specifically with this extension.</param>
+ /// <param name="baseMessage">The OpenID message carrying this extension.</param>
+ /// <returns>
+ /// An instance of <see cref="IOpenIdMessageExtension"/> if the factory recognizes
+ /// the extension described in the input parameters; <c>null</c> otherwise.
+ /// </returns>
+ /// <remarks>
+ /// This factory method need only initialize properties in the instantiated extension object
+ /// that are not bound using <see cref="MessagePartAttribute"/>.
+ /// </remarks>
+ IOpenIdMessageExtension Create(string typeUri, IDictionary<string, string> data, IProtocolMessageWithExtensions baseMessage);
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs index f669a2b..95ca6b1 100644 --- a/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs +++ b/src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs @@ -1,173 +1,180 @@ -//----------------------------------------------------------------------- -// <copyright file="OpenIdChannel.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.ChannelElements { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net; - using System.Text; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.Messaging.Bindings; - using DotNetOpenAuth.OpenId.Messages; - - /// <summary> - /// A channel that knows how to send and receive OpenID messages. - /// </summary> - internal class OpenIdChannel : Channel { - /// <summary> - /// The HTTP Content-Type to use in Key-Value Form responses. - /// </summary> - /// <remarks> - /// OpenID 2.0 section 5.1.2 says this SHOULD be text/plain. But this value - /// does not prevent free hosters like GoDaddy from tacking on their ads - /// to the end of the direct response, corrupting the data. So we deviate - /// from the spec a bit here to improve the story for free Providers. - /// </remarks> - private const string KeyValueFormContentType = "application/x-openid-kvf"; - - /// <summary> - /// The encoder that understands how to read and write Key-Value Form. - /// </summary> - private KeyValueFormEncoding keyValueForm = new KeyValueFormEncoding(); - - /// <summary> - /// Initializes a new instance of the <see cref="OpenIdChannel"/> class - /// for use by a Relying Party. - /// </summary> - /// <param name="associationStore">The association store to use.</param> - /// <param name="nonceStore">The nonce store to use.</param> - internal OpenIdChannel(IAssociationStore<Uri> associationStore, INonceStore nonceStore) - : this(associationStore, nonceStore, new OpenIdMessageFactory()) { - } - - /// <summary> - /// Initializes a new instance of the <see cref="OpenIdChannel"/> class - /// for use by a Provider. - /// </summary> - /// <param name="associationStore">The association store to use.</param> - /// <param name="nonceStore">The nonce store to use.</param> - internal OpenIdChannel(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore) - : this(associationStore, nonceStore, new OpenIdMessageFactory()) { - } - - /// <summary> - /// Initializes a new instance of the <see cref="OpenIdChannel"/> class - /// for use by a Relying Party. - /// </summary> - /// <param name="associationStore">The association store to use.</param> - /// <param name="nonceStore">The nonce store to use.</param> - /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param> - private OpenIdChannel(IAssociationStore<Uri> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider) : - base(messageTypeProvider, InitializeBindingElements(new SigningBindingElement(associationStore), nonceStore)) { - } - - /// <summary> - /// Initializes a new instance of the <see cref="OpenIdChannel"/> class - /// for use by a Provider. - /// </summary> - /// <param name="associationStore">The association store to use.</param> - /// <param name="nonceStore">The nonce store to use.</param> - /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param> - private OpenIdChannel(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider) : - base(messageTypeProvider, InitializeBindingElements(new SigningBindingElement(associationStore), nonceStore)) { - } - - /// <summary> - /// Verifies the integrity and applicability of an incoming message. - /// </summary> - /// <param name="message">The message just received.</param> - /// <exception cref="ProtocolException"> - /// Thrown when the message is somehow invalid, except for check_authentication messages. - /// This can be due to tampering, replay attack or expiration, among other things. - /// </exception> - protected override void VerifyMessageAfterReceiving(IProtocolMessage message) { - var checkAuthRequest = message as CheckAuthenticationRequest; - if (checkAuthRequest != null) { - IndirectSignedResponse originalResponse = new IndirectSignedResponse(checkAuthRequest); - try { - base.VerifyMessageAfterReceiving(originalResponse); - checkAuthRequest.IsValid = true; - } catch (ProtocolException) { - checkAuthRequest.IsValid = false; - } - } else { - base.VerifyMessageAfterReceiving(message); - } - } - - /// <summary> - /// Prepares an HTTP request that carries a given message. - /// </summary> - /// <param name="request">The message to send.</param> - /// <returns> - /// The <see cref="HttpWebRequest"/> prepared to send the request. - /// </returns> - protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) { - return this.InitializeRequestAsPost(request); - } - - /// <summary> - /// Gets the protocol message that may be in the given HTTP response. - /// </summary> - /// <param name="response">The response that is anticipated to contain an protocol message.</param> - /// <returns> - /// The deserialized message parts, if found. Null otherwise. - /// </returns> - protected override IDictionary<string, string> ReadFromResponseInternal(DirectWebResponse response) { - if (response == null) { - throw new ArgumentNullException("response"); - } - - return this.keyValueForm.GetDictionary(response.ResponseStream); - } - - /// <summary> - /// Queues a message for sending in the response stream where the fields - /// are sent in the response stream in querystring style. - /// </summary> - /// <param name="response">The message to send as a response.</param> - /// <returns> - /// The pending user agent redirect based message to be sent as an HttpResponse. - /// </returns> - /// <remarks> - /// This method implements spec V1.0 section 5.3. - /// </remarks> - protected override UserAgentResponse SendDirectMessageResponse(IProtocolMessage response) { - if (response == null) { - throw new ArgumentNullException("response"); - } - - var serializer = MessageSerializer.Get(response.GetType()); - var fields = serializer.Serialize(response); - byte[] keyValueEncoding = KeyValueFormEncoding.GetBytes(fields); - - UserAgentResponse preparedResponse = new UserAgentResponse(); - preparedResponse.Headers.Add(HttpResponseHeader.ContentType, KeyValueFormContentType); - preparedResponse.OriginalMessage = response; - preparedResponse.ResponseStream = new MemoryStream(keyValueEncoding); - - return preparedResponse; - } - - /// <summary> - /// Initializes the binding elements. - /// </summary> - /// <param name="signingElement">The signing element, previously constructed.</param> - /// <param name="nonceStore">The nonce store to use.</param> - /// <returns>An array of binding elements which may be used to construct the channel.</returns> - private static IChannelBindingElement[] InitializeBindingElements(SigningBindingElement signingElement, INonceStore nonceStore) { - ErrorUtilities.VerifyArgumentNotNull(signingElement, "signingElement"); - - List<IChannelBindingElement> elements = new List<IChannelBindingElement>(3); - elements.Add(signingElement); - elements.Add(new StandardReplayProtectionBindingElement(nonceStore, true)); - elements.Add(new StandardExpirationBindingElement()); - return elements.ToArray(); - } - } -} +//-----------------------------------------------------------------------
+// <copyright file="OpenIdChannel.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Net;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OpenId.Messages;
+ using DotNetOpenAuth.OpenId.Extensions;
+
+ /// <summary>
+ /// A channel that knows how to send and receive OpenID messages.
+ /// </summary>
+ internal class OpenIdChannel : Channel {
+ /// <summary>
+ /// The HTTP Content-Type to use in Key-Value Form responses.
+ /// </summary>
+ /// <remarks>
+ /// OpenID 2.0 section 5.1.2 says this SHOULD be text/plain. But this value
+ /// does not prevent free hosters like GoDaddy from tacking on their ads
+ /// to the end of the direct response, corrupting the data. So we deviate
+ /// from the spec a bit here to improve the story for free Providers.
+ /// </remarks>
+ private const string KeyValueFormContentType = "application/x-openid-kvf";
+
+ /// <summary>
+ /// The encoder that understands how to read and write Key-Value Form.
+ /// </summary>
+ private KeyValueFormEncoding keyValueForm = new KeyValueFormEncoding();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
+ /// for use by a Relying Party.
+ /// </summary>
+ /// <param name="associationStore">The association store to use.</param>
+ /// <param name="nonceStore">The nonce store to use.</param>
+ internal OpenIdChannel(IAssociationStore<Uri> associationStore, INonceStore nonceStore)
+ : this(associationStore, nonceStore, new OpenIdMessageFactory()) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
+ /// for use by a Provider.
+ /// </summary>
+ /// <param name="associationStore">The association store to use.</param>
+ /// <param name="nonceStore">The nonce store to use.</param>
+ internal OpenIdChannel(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore)
+ : this(associationStore, nonceStore, new OpenIdMessageFactory()) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
+ /// for use by a Relying Party.
+ /// </summary>
+ /// <param name="associationStore">The association store to use.</param>
+ /// <param name="nonceStore">The nonce store to use.</param>
+ /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
+ private OpenIdChannel(IAssociationStore<Uri> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider) :
+ base(messageTypeProvider, InitializeBindingElements(new SigningBindingElement(associationStore), nonceStore)) {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdChannel"/> class
+ /// for use by a Provider.
+ /// </summary>
+ /// <param name="associationStore">The association store to use.</param>
+ /// <param name="nonceStore">The nonce store to use.</param>
+ /// <param name="messageTypeProvider">An object that knows how to distinguish the various OpenID message types for deserialization purposes.</param>
+ private OpenIdChannel(IAssociationStore<AssociationRelyingPartyType> associationStore, INonceStore nonceStore, IMessageFactory messageTypeProvider) :
+ base(messageTypeProvider, InitializeBindingElements(new SigningBindingElement(associationStore), nonceStore)) {
+ }
+
+ /// <summary>
+ /// Gets the extension factory that can be used to register OpenID extensions.
+ /// </summary>
+ internal OpenIdExtensionFactory Extensions { get; private set; }
+
+ /// <summary>
+ /// Verifies the integrity and applicability of an incoming message.
+ /// </summary>
+ /// <param name="message">The message just received.</param>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the message is somehow invalid, except for check_authentication messages.
+ /// This can be due to tampering, replay attack or expiration, among other things.
+ /// </exception>
+ protected override void VerifyMessageAfterReceiving(IProtocolMessage message) {
+ var checkAuthRequest = message as CheckAuthenticationRequest;
+ if (checkAuthRequest != null) {
+ IndirectSignedResponse originalResponse = new IndirectSignedResponse(checkAuthRequest);
+ try {
+ base.VerifyMessageAfterReceiving(originalResponse);
+ checkAuthRequest.IsValid = true;
+ } catch (ProtocolException) {
+ checkAuthRequest.IsValid = false;
+ }
+ } else {
+ base.VerifyMessageAfterReceiving(message);
+ }
+ }
+
+ /// <summary>
+ /// Prepares an HTTP request that carries a given message.
+ /// </summary>
+ /// <param name="request">The message to send.</param>
+ /// <returns>
+ /// The <see cref="HttpWebRequest"/> prepared to send the request.
+ /// </returns>
+ protected override HttpWebRequest CreateHttpRequest(IDirectedProtocolMessage request) {
+ return this.InitializeRequestAsPost(request);
+ }
+
+ /// <summary>
+ /// Gets the protocol message that may be in the given HTTP response.
+ /// </summary>
+ /// <param name="response">The response that is anticipated to contain an protocol message.</param>
+ /// <returns>
+ /// The deserialized message parts, if found. Null otherwise.
+ /// </returns>
+ protected override IDictionary<string, string> ReadFromResponseInternal(DirectWebResponse response) {
+ if (response == null) {
+ throw new ArgumentNullException("response");
+ }
+
+ return this.keyValueForm.GetDictionary(response.ResponseStream);
+ }
+
+ /// <summary>
+ /// Queues a message for sending in the response stream where the fields
+ /// are sent in the response stream in querystring style.
+ /// </summary>
+ /// <param name="response">The message to send as a response.</param>
+ /// <returns>
+ /// The pending user agent redirect based message to be sent as an HttpResponse.
+ /// </returns>
+ /// <remarks>
+ /// This method implements spec V1.0 section 5.3.
+ /// </remarks>
+ protected override UserAgentResponse SendDirectMessageResponse(IProtocolMessage response) {
+ if (response == null) {
+ throw new ArgumentNullException("response");
+ }
+
+ var serializer = MessageSerializer.Get(response.GetType());
+ var fields = serializer.Serialize(response);
+ byte[] keyValueEncoding = KeyValueFormEncoding.GetBytes(fields);
+
+ UserAgentResponse preparedResponse = new UserAgentResponse();
+ preparedResponse.Headers.Add(HttpResponseHeader.ContentType, KeyValueFormContentType);
+ preparedResponse.OriginalMessage = response;
+ preparedResponse.ResponseStream = new MemoryStream(keyValueEncoding);
+
+ return preparedResponse;
+ }
+
+ /// <summary>
+ /// Initializes the binding elements.
+ /// </summary>
+ /// <param name="signingElement">The signing element, previously constructed.</param>
+ /// <param name="nonceStore">The nonce store to use.</param>
+ /// <returns>An array of binding elements which may be used to construct the channel.</returns>
+ private static IChannelBindingElement[] InitializeBindingElements(SigningBindingElement signingElement, INonceStore nonceStore) {
+ ErrorUtilities.VerifyArgumentNotNull(signingElement, "signingElement");
+
+ List<IChannelBindingElement> elements = new List<IChannelBindingElement>(3);
+ elements.Add(signingElement);
+ elements.Add(new StandardReplayProtectionBindingElement(nonceStore, true));
+ elements.Add(new StandardExpirationBindingElement());
+ elements.Add(new ExtensionsBindingElement(new OpenIdExtensionFactory()));
+ return elements.ToArray();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionArgumentsManager.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionArgumentsManager.cs index d41d1e4..3da1383 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionArgumentsManager.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionArgumentsManager.cs @@ -90,12 +90,16 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// where type URI, alias, and actual key/values are all defined.
/// </summary>
public IDictionary<string, string> GetArgumentsToSend(bool includeOpenIdPrefix) {
- if (isReadMode) throw new InvalidOperationException();
+ if (isReadMode) {
+ throw new InvalidOperationException();
+ }
Dictionary<string, string> args = new Dictionary<string, string>();
foreach (var typeUriAndExtension in extensions) {
string typeUri = typeUriAndExtension.Key;
var extensionArgs = typeUriAndExtension.Value;
- if (extensionArgs.Count == 0) continue;
+ if (extensionArgs.Count == 0) {
+ continue;
+ }
string alias = aliasManager.GetAlias(typeUri);
// send out the alias declaration
string openidPrefix = includeOpenIdPrefix ? protocol.openid.Prefix : string.Empty;
@@ -120,7 +124,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { IDictionary<string, string> extensionArgs;
if (!extensions.TryGetValue(extensionTypeUri, out extensionArgs)) {
- extensions.Add(extensionTypeUri, extensionArgs = new Dictionary<string, string>());
+ extensions.Add(extensionTypeUri, extensionArgs = new Dictionary<string, string>(arguments.Count));
}
ErrorUtilities.VerifyProtocol(extensionArgs.Count == 0, OpenIdStrings.ExtensionAlreadyAddedWithSameTypeURI, extensionTypeUri);
@@ -134,8 +138,11 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// </summary>
/// <returns>The fields included in the given extension, or null if the extension is not present.</returns>
public IDictionary<string, string> GetExtensionArguments(string extensionTypeUri) {
- if (!isReadMode) throw new InvalidOperationException();
- if (string.IsNullOrEmpty(extensionTypeUri)) throw new ArgumentNullException("extensionTypeUri");
+ ErrorUtilities.VerifyNonZeroLength(extensionTypeUri, "extensionTypeUri");
+ if (!isReadMode) {
+ throw new InvalidOperationException();
+ }
+
IDictionary<string, string> extensionArgs;
extensions.TryGetValue(extensionTypeUri, out extensionArgs);
return extensionArgs;
@@ -145,5 +152,9 @@ namespace DotNetOpenAuth.OpenId.Extensions { if (!isReadMode) throw new InvalidOperationException();
return extensions.ContainsKey(extensionTypeUri);
}
+
+ public IEnumerable<string> GetExtensionTypeUris() {
+ return this.extensions.Keys;
+ }
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs index e44bd55..53b72c8 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs @@ -12,7 +12,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { using DotNetOpenAuth.OpenId.Messages;
using DotNetOpenAuth.Messaging;
- public class ExtensionBase : IOpenIdProtocolMessageExtension {
+ public class ExtensionBase : IOpenIdMessageExtension {
/// <summary>
/// Backing store for the <see cref="IOpenIdProtocolMessageExtension.TypeUri"/> property.
/// </summary>
@@ -45,7 +45,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// <summary>
/// Gets the TypeURI the extension uses in the OpenID protocol and in XRDS advertisements.
/// </summary>
- string IOpenIdProtocolMessageExtension.TypeUri {
+ string IOpenIdMessageExtension.TypeUri {
get { return typeUri; }
}
@@ -65,7 +65,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// given the version of the extension in the request message.
/// The <see cref="SimpleRegistration.ClaimsRequest.CreateResponse"/> for an example.
/// </remarks>
- IEnumerable<string> IOpenIdProtocolMessageExtension.AdditionalSupportedTypeUris {
+ IEnumerable<string> IOpenIdMessageExtension.AdditionalSupportedTypeUris {
get { return this.additionalSupportedTypeUris; }
}
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/OpenIdExtensionFactory.cs b/src/DotNetOpenAuth/OpenId/Extensions/OpenIdExtensionFactory.cs new file mode 100644 index 0000000..88749d6 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/Extensions/OpenIdExtensionFactory.cs @@ -0,0 +1,73 @@ +//-----------------------------------------------------------------------
+// <copyright file="OpenIdExtensionFactory.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Extensions {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OpenId.ChannelElements;
+ using DotNetOpenAuth.OpenId.Messages;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
+
+ internal class OpenIdExtensionFactory : IOpenIdExtensionFactory {
+ /// <summary>
+ /// A delegate that individual extensions may register with this factory.
+ /// </summary>
+ internal delegate IOpenIdMessageExtension CreateDelegate(string typeUri, IDictionary<string, string> data, IProtocolMessageWithExtensions baseMessage);
+
+ /// <summary>
+ /// A collection of the registered OpenID extensions.
+ /// </summary>
+ private List<CreateDelegate> registeredExtensions = new List<CreateDelegate>();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="OpenIdExtensionFactory"/> class.
+ /// </summary>
+ internal OpenIdExtensionFactory() {
+ this.RegisterExtension(ClaimsRequest.Factory);
+ this.RegisterExtension(ClaimsResponse.Factory);
+ }
+
+ #region IOpenIdExtensionFactory Members
+
+ /// <summary>
+ /// Creates a new instance of some extension based on the received extension parameters.
+ /// </summary>
+ /// <param name="typeUri">The type URI of the extension.</param>
+ /// <param name="data">The parameters associated specifically with this extension.</param>
+ /// <param name="baseMessage">The OpenID message carrying this extension.</param>
+ /// <returns>
+ /// An instance of <see cref="IOpenIdMessageExtension"/> if the factory recognizes
+ /// the extension described in the input parameters; <c>null</c> otherwise.
+ /// </returns>
+ /// <remarks>
+ /// This factory method need only initialize properties in the instantiated extension object
+ /// that are not bound using <see cref="MessagePartAttribute"/>.
+ /// </remarks>
+ public IOpenIdMessageExtension Create(string typeUri, IDictionary<string, string> data, IProtocolMessageWithExtensions baseMessage) {
+ foreach (var factoryMethod in registeredExtensions) {
+ IOpenIdMessageExtension result = factoryMethod(typeUri, data, baseMessage);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Registers a new extension delegate.
+ /// </summary>
+ /// <param name="creator">The factory method that can create the extension.</param>
+ internal void RegisterExtension(CreateDelegate creator) {
+ this.registeredExtensions.Add(creator);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs index 79d35fb..afa72f6 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs @@ -25,6 +25,14 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration { Constants.sreg_ns11other,
};
+ internal static readonly OpenIdExtensionFactory.CreateDelegate Factory = (typeUri, data, baseMessage) => {
+ if (typeUri == Constants.sreg_ns && baseMessage is SignedResponseRequest) {
+ return new ClaimsRequest();
+ }
+
+ return null;
+ };
+
/// <summary>
/// Initializes a new instance of the <see cref="ClaimsRequest"/> class.
/// </summary>
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs index 2305cea..01527a6 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs @@ -14,6 +14,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration { using DotNetOpenAuth.OpenId.Messages;
using System.Diagnostics.CodeAnalysis;
using DotNetOpenAuth.Messaging;
+ using System.Text.RegularExpressions;
#pragma warning disable 0659, 0661
/// <summary>
@@ -22,6 +23,22 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration { /// </summary>
[SuppressMessage("Microsoft.Usage", "CA2218:OverrideGetHashCodeOnOverridingEquals"), Serializable()]
public sealed class ClaimsResponse : ExtensionBase {
+ internal static readonly OpenIdExtensionFactory.CreateDelegate Factory = (typeUri, data, baseMessage) => {
+ if (typeUri == Constants.sreg_ns && baseMessage is IndirectSignedResponse) {
+ return new ClaimsResponse();
+ }
+
+ return null;
+ };
+
+ /// <summary>
+ /// Storage for the raw string birthdate value.
+ /// </summary>
+ private string birthDateRaw;
+ private DateTime? birthDate;
+
+ private static readonly Regex birthDateValidator = new Regex(@"^\d\d\d\d-\d\d-\d\d$");
+
/// <summary>
/// The TypeURI that must be used in the response, based on the one used in the request.
/// </summary>
@@ -74,8 +91,51 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration { /// <summary>
/// The user's birthdate.
/// </summary>
+ public DateTime? BirthDate {
+ get {
+ return this.birthDate;
+ }
+
+ set {
+ this.birthDate = value;
+ // Don't use property accessor for peer property to avoid infinite loop between the two proeprty accessors.
+ if (value.HasValue) {
+ this.birthDateRaw = value.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
+ } else {
+ this.birthDateRaw = null;
+ }
+ }
+ }
+
[MessagePart(Constants.dob)]
- public DateTime? BirthDate { get; set; }
+ public string BirthDateRaw {
+ get {
+ return this.birthDateRaw;
+ }
+
+ set {
+ if (value != null) {
+ if (!birthDateValidator.IsMatch(value)) {
+ throw new ArgumentException(OpenIdStrings.SregInvalidBirthdate, "value");
+ }
+ // Update the BirthDate property, if possible.
+ // Don't use property accessor for peer property to avoid infinite loop between the two proeprty accessors.
+ // Some valid sreg dob values like "2000-00-00" will not work as a DateTime struct,
+ // in which case we null it out, but don't show any error.
+ DateTime newBirthDate;
+ if (DateTime.TryParse(value, out newBirthDate)) {
+ this.birthDate = newBirthDate;
+ } else {
+ Logger.WarnFormat("Simple Registration birthdate '{0}' could not be parsed into a DateTime and may not include month and/or day information. Setting BirthDate property to null.", value);
+ this.birthDate = null;
+ }
+ } else {
+ this.birthDate = null;
+ }
+
+ this.birthDateRaw = value;
+ }
+ }
/// <summary>
/// The gender of the user.
@@ -208,7 +268,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.SimpleRegistration { if (other == null) return false;
return
- this.BirthDate.Equals(other.BirthDate) &&
+ this.BirthDateRaw.EqualsNullSafe(other.BirthDateRaw) &&
this.Country.EqualsNullSafe(other.Country) &&
this.Language.EqualsNullSafe(other.Language) &&
this.Email.EqualsNullSafe(other.Email) &&
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs index c4ac4f1..aaaa221 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs @@ -16,7 +16,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary>
/// An OpenID direct request from Relying Party to Provider to initiate an association.
/// </summary>
- [DebuggerDisplay("OpenID {ProtocolVersion} {Mode} {AssociationType} {SessionType}")]
+ [DebuggerDisplay("OpenID {Version} {Mode} {AssociationType} {SessionType}")]
internal abstract class AssociateRequest : RequestBase {
/// <summary>
/// Initializes a new instance of the <see cref="AssociateRequest"/> class.
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs index 6486fce..dc891d9 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs @@ -1,120 +1,120 @@ -//----------------------------------------------------------------------- -// <copyright file="AssociateSuccessfulResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Messages { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Text; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// The base class that all successful association response messages derive from. - /// </summary> - /// <remarks> - /// Association response messages are described in OpenID 2.0 section 8.2. This type covers section 8.2.1. - /// </remarks> - [DebuggerDisplay("OpenID {ProtocolVersion} associate response {AssociationHandle} {AssociationType} {SessionType}")] - internal abstract class AssociateSuccessfulResponse : DirectResponseBase { - /// <summary> - /// A flag indicating whether an association has already been created. - /// </summary> - private bool associationCreated; - - /// <summary> - /// Initializes a new instance of the <see cref="AssociateSuccessfulResponse"/> class. - /// </summary> - /// <param name="originatingRequest">The originating request.</param> - internal AssociateSuccessfulResponse(AssociateRequest originatingRequest) - : base(originatingRequest) { - } - - /// <summary> - /// Gets or sets the association handle is used as a key to refer to this association in subsequent messages. - /// </summary> - /// <value>A string 255 characters or less in length. It MUST consist only of ASCII characters in the range 33-126 inclusive (printable non-whitespace characters). </value> - [MessagePart("assoc_handle", IsRequired = true, AllowEmpty = false)] - internal string AssociationHandle { get; set; } - - /// <summary> - /// Gets or sets the preferred association type. The association type defines the algorithm to be used to sign subsequent messages. - /// </summary> - /// <value>Value: A valid association type from Section 8.3.</value> - [MessagePart("assoc_type", IsRequired = true, AllowEmpty = false)] - internal string AssociationType { get; set; } - - /// <summary> - /// Gets or sets the value of the "openid.session_type" parameter from the request. - /// If the OP is unwilling or unable to support this association type, it MUST return an - /// unsuccessful response (Unsuccessful Response Parameters). - /// </summary> - /// <value>Value: A valid association session type from Section 8.4 (Association Session Types). </value> - /// <remarks>Note: Unless using transport layer encryption, "no-encryption" MUST NOT be used. </remarks> - [MessagePart("session_type", IsRequired = true, AllowEmpty = true)] - [MessagePart("session_type", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")] - internal string SessionType { get; set; } - - /// <summary> - /// Gets or sets the lifetime, in seconds, of this association. The Relying Party MUST NOT use the association after this time has passed. - /// </summary> - /// <value>An integer, represented in base 10 ASCII. </value> - [MessagePart("expires_in", IsRequired = true)] - internal long ExpiresIn { get; set; } - - /// <summary> - /// Called to create the Association based on a request previously given by the Relying Party. - /// </summary> - /// <param name="request">The prior request for an association.</param> - /// <returns>The created association.</returns> - /// <remarks> - /// <para>The response message is updated to include the details of the created association by this method, - /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para> - /// <para>This method is called by both the Provider and the Relying Party, but actually performs - /// quite different operations in either scenario.</para> - /// </remarks> - internal Association CreateAssociation(AssociateRequest request) { - ErrorUtilities.VerifyArgumentNotNull(request, "request"); - ErrorUtilities.VerifyInternal(!this.associationCreated, "The association has already been created."); - Association association; - - // If this message is outgoing, then we need to initialize some common - // properties based on the created association. - if (this.Incoming) { - association = this.CreateAssociationAtRelyingParty(request); - } else { - association = this.CreateAssociationAtProvider(request); - this.ExpiresIn = association.SecondsTillExpiration; - this.AssociationHandle = association.Handle; - } - - this.associationCreated = true; - - return association; - } - - /// <summary> - /// Called to create the Association based on a request previously given by the Relying Party. - /// </summary> - /// <param name="request">The prior request for an association.</param> - /// <returns>The created association.</returns> - /// <remarks> - /// <para>The caller will update this message's <see cref="ExpiresIn"/> and <see cref="AssociationHandle"/> - /// properties based on the <see cref="Association"/> returned by this method, but any other - /// association type specific properties must be set by this method.</para> - /// <para>The response message is updated to include the details of the created association by this method, - /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para> - /// </remarks> - protected abstract Association CreateAssociationAtProvider(AssociateRequest request); - - /// <summary> - /// Called to create the Association based on a request previously given by the Relying Party. - /// </summary> - /// <param name="request">The prior request for an association.</param> - /// <returns>The created association.</returns> - protected abstract Association CreateAssociationAtRelyingParty(AssociateRequest request); - } -} +//-----------------------------------------------------------------------
+// <copyright file="AssociateSuccessfulResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The base class that all successful association response messages derive from.
+ /// </summary>
+ /// <remarks>
+ /// Association response messages are described in OpenID 2.0 section 8.2. This type covers section 8.2.1.
+ /// </remarks>
+ [DebuggerDisplay("OpenID {Version} associate response {AssociationHandle} {AssociationType} {SessionType}")]
+ internal abstract class AssociateSuccessfulResponse : DirectResponseBase {
+ /// <summary>
+ /// A flag indicating whether an association has already been created.
+ /// </summary>
+ private bool associationCreated;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AssociateSuccessfulResponse"/> class.
+ /// </summary>
+ /// <param name="originatingRequest">The originating request.</param>
+ internal AssociateSuccessfulResponse(AssociateRequest originatingRequest)
+ : base(originatingRequest) {
+ }
+
+ /// <summary>
+ /// Gets or sets the association handle is used as a key to refer to this association in subsequent messages.
+ /// </summary>
+ /// <value>A string 255 characters or less in length. It MUST consist only of ASCII characters in the range 33-126 inclusive (printable non-whitespace characters). </value>
+ [MessagePart("assoc_handle", IsRequired = true, AllowEmpty = false)]
+ internal string AssociationHandle { get; set; }
+
+ /// <summary>
+ /// Gets or sets the preferred association type. The association type defines the algorithm to be used to sign subsequent messages.
+ /// </summary>
+ /// <value>Value: A valid association type from Section 8.3.</value>
+ [MessagePart("assoc_type", IsRequired = true, AllowEmpty = false)]
+ internal string AssociationType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the value of the "openid.session_type" parameter from the request.
+ /// If the OP is unwilling or unable to support this association type, it MUST return an
+ /// unsuccessful response (Unsuccessful Response Parameters).
+ /// </summary>
+ /// <value>Value: A valid association session type from Section 8.4 (Association Session Types). </value>
+ /// <remarks>Note: Unless using transport layer encryption, "no-encryption" MUST NOT be used. </remarks>
+ [MessagePart("session_type", IsRequired = true, AllowEmpty = true)]
+ [MessagePart("session_type", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")]
+ internal string SessionType { get; set; }
+
+ /// <summary>
+ /// Gets or sets the lifetime, in seconds, of this association. The Relying Party MUST NOT use the association after this time has passed.
+ /// </summary>
+ /// <value>An integer, represented in base 10 ASCII. </value>
+ [MessagePart("expires_in", IsRequired = true)]
+ internal long ExpiresIn { get; set; }
+
+ /// <summary>
+ /// Called to create the Association based on a request previously given by the Relying Party.
+ /// </summary>
+ /// <param name="request">The prior request for an association.</param>
+ /// <returns>The created association.</returns>
+ /// <remarks>
+ /// <para>The response message is updated to include the details of the created association by this method,
+ /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
+ /// <para>This method is called by both the Provider and the Relying Party, but actually performs
+ /// quite different operations in either scenario.</para>
+ /// </remarks>
+ internal Association CreateAssociation(AssociateRequest request) {
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ ErrorUtilities.VerifyInternal(!this.associationCreated, "The association has already been created.");
+ Association association;
+
+ // If this message is outgoing, then we need to initialize some common
+ // properties based on the created association.
+ if (this.Incoming) {
+ association = this.CreateAssociationAtRelyingParty(request);
+ } else {
+ association = this.CreateAssociationAtProvider(request);
+ this.ExpiresIn = association.SecondsTillExpiration;
+ this.AssociationHandle = association.Handle;
+ }
+
+ this.associationCreated = true;
+
+ return association;
+ }
+
+ /// <summary>
+ /// Called to create the Association based on a request previously given by the Relying Party.
+ /// </summary>
+ /// <param name="request">The prior request for an association.</param>
+ /// <returns>The created association.</returns>
+ /// <remarks>
+ /// <para>The caller will update this message's <see cref="ExpiresIn"/> and <see cref="AssociationHandle"/>
+ /// properties based on the <see cref="Association"/> returned by this method, but any other
+ /// association type specific properties must be set by this method.</para>
+ /// <para>The response message is updated to include the details of the created association by this method,
+ /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para>
+ /// </remarks>
+ protected abstract Association CreateAssociationAtProvider(AssociateRequest request);
+
+ /// <summary>
+ /// Called to create the Association based on a request previously given by the Relying Party.
+ /// </summary>
+ /// <param name="request">The prior request for an association.</param>
+ /// <returns>The created association.</returns>
+ protected abstract Association CreateAssociationAtRelyingParty(AssociateRequest request);
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs index 44b3eb5..fd5a66b 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs @@ -1,50 +1,50 @@ -//----------------------------------------------------------------------- -// <copyright file="AssociateUnsuccessfulResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Messages { - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// The Provider's response to a Relying Party that requested an association that the Provider does not support. - /// </summary> - /// <remarks> - /// This message type described in OpenID 2.0 section 8.2.4. - /// </remarks> - [DebuggerDisplay("OpenID {ProtocolVersion} associate (failed) response")] - internal class AssociateUnsuccessfulResponse : DirectErrorResponse { - /// <summary> - /// A hard-coded string indicating an error occurred. - /// </summary> - /// <value>"unsupported-type" </value> - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Read by reflection")] - [MessagePart("error_code", IsRequired = true, AllowEmpty = false)] -#pragma warning disable 0414 // read by reflection - private readonly string Error = "unsupported-type"; -#pragma warning restore 0414 - - /// <summary> - /// Initializes a new instance of the <see cref="AssociateUnsuccessfulResponse"/> class. - /// </summary> - /// <param name="originatingRequest">The originating request.</param> - internal AssociateUnsuccessfulResponse(AssociateRequest originatingRequest) - : base(originatingRequest) { - } - - /// <summary> - /// Gets or sets an association type supported by the OP from Section 8.3 (Association Types). - /// </summary> - [MessagePart("assoc_type", IsRequired = false, AllowEmpty = false)] - internal string AssociationType { get; set; } - - /// <summary> - /// Gets or sets a valid association session type from Section 8.4 (Association Session Types) that the OP supports. - /// </summary> - [MessagePart("session_type", IsRequired = false, AllowEmpty = false)] - internal string SessionType { get; set; } - } -} +//-----------------------------------------------------------------------
+// <copyright file="AssociateUnsuccessfulResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Messages {
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// The Provider's response to a Relying Party that requested an association that the Provider does not support.
+ /// </summary>
+ /// <remarks>
+ /// This message type described in OpenID 2.0 section 8.2.4.
+ /// </remarks>
+ [DebuggerDisplay("OpenID {Version} associate (failed) response")]
+ internal class AssociateUnsuccessfulResponse : DirectErrorResponse {
+ /// <summary>
+ /// A hard-coded string indicating an error occurred.
+ /// </summary>
+ /// <value>"unsupported-type" </value>
+ [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Read by reflection")]
+ [MessagePart("error_code", IsRequired = true, AllowEmpty = false)]
+#pragma warning disable 0414 // read by reflection
+ private readonly string Error = "unsupported-type";
+#pragma warning restore 0414
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AssociateUnsuccessfulResponse"/> class.
+ /// </summary>
+ /// <param name="originatingRequest">The originating request.</param>
+ internal AssociateUnsuccessfulResponse(AssociateRequest originatingRequest)
+ : base(originatingRequest) {
+ }
+
+ /// <summary>
+ /// Gets or sets an association type supported by the OP from Section 8.3 (Association Types).
+ /// </summary>
+ [MessagePart("assoc_type", IsRequired = false, AllowEmpty = false)]
+ internal string AssociationType { get; set; }
+
+ /// <summary>
+ /// Gets or sets a valid association session type from Section 8.4 (Association Session Types) that the OP supports.
+ /// </summary>
+ [MessagePart("session_type", IsRequired = false, AllowEmpty = false)]
+ internal string SessionType { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/CheckIdRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/CheckIdRequest.cs index b52474a..34b7d7c 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/CheckIdRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/CheckIdRequest.cs @@ -1,65 +1,65 @@ -//----------------------------------------------------------------------- -// <copyright file="CheckIdRequest.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Messages { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Text; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// An authentication request from a Relying Party to a Provider. - /// </summary> - /// <remarks> - /// This message type satisfies OpenID 2.0 section 9.1. - /// </remarks> - [DebuggerDisplay("OpenID {ProtocolVersion} {Mode} {ClaimedIdentifier}")] - internal class CheckIdRequest : SignedResponseRequest { - /// <summary> - /// Initializes a new instance of the <see cref="CheckIdRequest"/> class. - /// </summary> - /// <param name="version">The OpenID version to use.</param> - /// <param name="providerEndpoint">The Provider endpoint that receives this message.</param> - /// <param name="immediate"> - /// <c>true</c> for asynchronous javascript clients; - /// <c>false</c> to allow the Provider to interact with the user in order to complete authentication. - /// </param> - internal CheckIdRequest(Version version, Uri providerEndpoint, bool immediate) : - base(version, providerEndpoint, immediate) { - } - - /// <summary> - /// Gets or sets the Claimed Identifier. - /// </summary> - /// <remarks> - /// <para>"openid.claimed_id" and "openid.identity" SHALL be either both present or both absent. - /// If neither value is present, the assertion is not about an identifier, - /// and will contain other information in its payload, using extensions (Extensions). </para> - /// <para>It is RECOMMENDED that OPs accept XRI identifiers with or without the "xri://" prefix, as specified in the Normalization (Normalization) section. </para> - /// </remarks> - [MessagePart("openid.claimed_id", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")] - internal Identifier ClaimedIdentifier { get; set; } - - /// <summary> - /// Gets or sets the OP Local Identifier. - /// </summary> - /// <value>The OP-Local Identifier. </value> - /// <remarks> - /// <para>If a different OP-Local Identifier is not specified, the claimed - /// identifier MUST be used as the value for openid.identity.</para> - /// <para>Note: If this is set to the special value - /// "http://specs.openid.net/auth/2.0/identifier_select" then the OP SHOULD - /// choose an Identifier that belongs to the end user. This parameter MAY - /// be omitted if the request is not about an identifier (for instance if - /// an extension is in use that makes the request meaningful without it; - /// see openid.claimed_id above). </para> - /// </remarks> - [MessagePart("openid.identity", IsRequired = true, AllowEmpty = false)] - internal Identifier LocalIdentifier { get; set; } - } -} +//-----------------------------------------------------------------------
+// <copyright file="CheckIdRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// An authentication request from a Relying Party to a Provider.
+ /// </summary>
+ /// <remarks>
+ /// This message type satisfies OpenID 2.0 section 9.1.
+ /// </remarks>
+ [DebuggerDisplay("OpenID {Version} {Mode} {ClaimedIdentifier}")]
+ internal class CheckIdRequest : SignedResponseRequest {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CheckIdRequest"/> class.
+ /// </summary>
+ /// <param name="version">The OpenID version to use.</param>
+ /// <param name="providerEndpoint">The Provider endpoint that receives this message.</param>
+ /// <param name="immediate">
+ /// <c>true</c> for asynchronous javascript clients;
+ /// <c>false</c> to allow the Provider to interact with the user in order to complete authentication.
+ /// </param>
+ internal CheckIdRequest(Version version, Uri providerEndpoint, bool immediate) :
+ base(version, providerEndpoint, immediate) {
+ }
+
+ /// <summary>
+ /// Gets or sets the Claimed Identifier.
+ /// </summary>
+ /// <remarks>
+ /// <para>"openid.claimed_id" and "openid.identity" SHALL be either both present or both absent.
+ /// If neither value is present, the assertion is not about an identifier,
+ /// and will contain other information in its payload, using extensions (Extensions). </para>
+ /// <para>It is RECOMMENDED that OPs accept XRI identifiers with or without the "xri://" prefix, as specified in the Normalization (Normalization) section. </para>
+ /// </remarks>
+ [MessagePart("openid.claimed_id", IsRequired = true, AllowEmpty = false, MinVersion = "2.0")]
+ internal Identifier ClaimedIdentifier { get; set; }
+
+ /// <summary>
+ /// Gets or sets the OP Local Identifier.
+ /// </summary>
+ /// <value>The OP-Local Identifier. </value>
+ /// <remarks>
+ /// <para>If a different OP-Local Identifier is not specified, the claimed
+ /// identifier MUST be used as the value for openid.identity.</para>
+ /// <para>Note: If this is set to the special value
+ /// "http://specs.openid.net/auth/2.0/identifier_select" then the OP SHOULD
+ /// choose an Identifier that belongs to the end user. This parameter MAY
+ /// be omitted if the request is not about an identifier (for instance if
+ /// an extension is in use that makes the request meaningful without it;
+ /// see openid.claimed_id above). </para>
+ /// </remarks>
+ [MessagePart("openid.identity", IsRequired = true, AllowEmpty = false)]
+ internal Identifier LocalIdentifier { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs b/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs index 1d2f4a1..850212c 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs @@ -14,7 +14,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary>
/// A common base class for OpenID direct message responses.
/// </summary>
- [DebuggerDisplay("OpenID {ProtocolVersion} response")]
+ [DebuggerDisplay("OpenID {Version} response")]
internal class DirectResponseBase : IDirectResponseProtocolMessage {
/// <summary>
/// The openid.ns parameter in the message.
diff --git a/src/DotNetOpenAuth/OpenId/Messages/IOpenIdProtocolMessageExtension.cs b/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs index 5b5d69f..8792e60 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IOpenIdProtocolMessageExtension.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs @@ -1,5 +1,5 @@ //-----------------------------------------------------------------------
-// <copyright file="IOpenIdProtocolMessageExtension.cs" company="Andrew Arnott">
+// <copyright file="IOpenIdMessageExtension.cs" company="Andrew Arnott">
// Copyright (c) Andrew Arnott. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
@@ -14,7 +14,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary>
/// The contract any OpenID extension for DotNetOpenId must implement.
/// </summary>
- internal interface IOpenIdProtocolMessageExtension : IExtensionMessage {
+ internal interface IOpenIdMessageExtension : IExtensionMessage {
/// <summary>
/// Gets the TypeURI the extension uses in the OpenID protocol and in XRDS advertisements.
/// </summary>
diff --git a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs index 2c5c150..072cef5 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs @@ -1,197 +1,218 @@ -//----------------------------------------------------------------------- -// <copyright file="IndirectSignedResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Messages { - using System; - using System.Diagnostics; - using System.Globalization; - using System.Net.Security; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.Messaging.Bindings; - using DotNetOpenAuth.Messaging.Reflection; - using DotNetOpenAuth.OpenId.ChannelElements; - - /// <summary> - /// An indirect message from a Provider to a Relying Party where at least part of the - /// payload is signed so the Relying Party can verify it has not been tampered with. - /// </summary> - [DebuggerDisplay("OpenID {ProtocolVersion} {Mode} (no id assertion)")] - internal class IndirectSignedResponse : IndirectResponseBase, ITamperResistantOpenIdMessage { - /// <summary> - /// The allowed date/time formats for the response_nonce parameter. - /// </summary> - /// <remarks> - /// This array of formats is not yet a complete list. - /// </remarks> - private static readonly string[] PermissibleDateTimeFormats = { "yyyy-MM-ddTHH:mm:ssZ" }; - - /// <summary> - /// Backing field for the <see cref="IExpiringProtocolMessage.UtcCreationDate"/> property. - /// </summary> - private DateTime creationDateUtc = DateTime.UtcNow; - - /// <summary> - /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class. - /// </summary> - /// <param name="request"> - /// The authentication request that caused this assertion to be generated. - /// </param> - internal IndirectSignedResponse(SignedResponseRequest request) - : base(request, Protocol.Lookup(GetVersion(request)).Args.Mode.id_res) { - ErrorUtilities.VerifyArgumentNotNull(request, "request"); - - this.ReturnTo = request.ReturnTo; - this.ProviderEndpoint = request.Recipient; - ((ITamperResistantOpenIdMessage)this).AssociationHandle = request.AssociationHandle; - } - - /// <summary> - /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class - /// in order to perform signature verification at the Provider. - /// </summary> - /// <param name="previouslySignedMessage">The previously signed message.</param> - internal IndirectSignedResponse(CheckAuthenticationRequest previouslySignedMessage) - : base(GetVersion(previouslySignedMessage), previouslySignedMessage.ReturnTo, Protocol.Lookup(GetVersion(previouslySignedMessage)).Args.Mode.id_res) { - // Copy all message parts from the check_authentication message into this one, - // except for the openid.mode parameter. - MessageDictionary checkPayload = new MessageDictionary(previouslySignedMessage); - MessageDictionary thisPayload = new MessageDictionary(this); - foreach (var pair in checkPayload) { - if (!string.Equals(pair.Key, this.Protocol.openid.mode)) { - thisPayload[pair.Key] = pair.Value; - } - } - } - - /// <summary> - /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class - /// for unsolicited assertions. - /// </summary> - /// <param name="version">The OpenID version to use.</param> - /// <param name="relyingPartyReturnTo">The return_to URL of the Relying Party. - /// This value will commonly be from <see cref="SignedResponseRequest.ReturnTo"/>, - /// but for unsolicited assertions may come from the Provider performing RP discovery - /// to find the appropriate return_to URL to use.</param> - internal IndirectSignedResponse(Version version, Uri relyingPartyReturnTo) - : base(version, relyingPartyReturnTo, Protocol.Lookup(version).Args.Mode.id_res) { - } - - /// <summary> - /// Gets the level of protection this message requires. - /// </summary> - /// <value><see cref="MessageProtections.All"/></value> - public override MessageProtections RequiredProtection { - get { return MessageProtections.All; } - } - - /// <summary> - /// Gets or sets the message signature. - /// </summary> - /// <value>Base 64 encoded signature calculated as specified in Section 6 (Generating Signatures).</value> - [MessagePart("openid.sig", IsRequired = true, AllowEmpty = false)] - string ITamperResistantProtocolMessage.Signature { get; set; } - - /// <summary> - /// Gets or sets the signed parameter order. - /// </summary> - /// <value>Comma-separated list of signed fields.</value> - /// <example>"op_endpoint,identity,claimed_id,return_to,assoc_handle,response_nonce"</example> - /// <remarks> - /// This entry consists of the fields without the "openid." prefix that the signature covers. - /// This list MUST contain at least "op_endpoint", "return_to" "response_nonce" and "assoc_handle", - /// and if present in the response, "claimed_id" and "identity". - /// Additional keys MAY be signed as part of the message. See Generating Signatures. - /// </remarks> - [MessagePart("openid.signed", IsRequired = true, AllowEmpty = false)] - string ITamperResistantOpenIdMessage.SignedParameterOrder { get; set; } - - /// <summary> - /// Gets or sets the association handle used to sign the message. - /// </summary> - /// <value>The handle for the association that was used to sign this assertion. </value> - [MessagePart("openid.assoc_handle", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign)] - string ITamperResistantOpenIdMessage.AssociationHandle { get; set; } - - /// <summary> - /// Gets or sets the nonce that will protect the message from replay attacks. - /// </summary> - string IReplayProtectedProtocolMessage.Nonce { get; set; } - - /// <summary> - /// Gets or sets the UTC date/time the message was originally sent onto the network. - /// </summary> - /// <remarks> - /// The property setter should ensure a UTC date/time, - /// and throw an exception if this is not possible. - /// </remarks> - /// <exception cref="ArgumentException"> - /// Thrown when a DateTime that cannot be converted to UTC is set. - /// </exception> - DateTime IExpiringProtocolMessage.UtcCreationDate { - get { return this.creationDateUtc; } - set { this.creationDateUtc = value.ToUniversalTime(); } - } - - /// <summary> - /// Gets or sets the association handle that the Provider wants the Relying Party to not use any more. - /// </summary> - /// <value>If the Relying Party sent an invalid association handle with the request, it SHOULD be included here.</value> - [MessagePart("openid.invalidate_handle", IsRequired = false, AllowEmpty = false)] - string ITamperResistantOpenIdMessage.InvalidateHandle { get; set; } - - /// <summary> - /// Gets or sets the Provider Endpoint URI. - /// </summary> - [MessagePart("openid.op_endpoint", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, MinVersion = "2.0")] - internal Uri ProviderEndpoint { get; set; } - - /// <summary> - /// Gets or sets the return_to parameter as the relying party provided - /// it in <see cref="SignedResponseRequest.ReturnTo"/>. - /// </summary> - /// <value>Verbatim copy of the return_to URL parameter sent in the - /// request, before the Provider modified it. </value> - [MessagePart("openid.return_to", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, Encoder = typeof(OriginalStringUriEncoder))] - internal Uri ReturnTo { get; set; } - - /// <summary> - /// Gets or sets the nonce that will protect the message from replay attacks. - /// </summary> - /// <value> - /// <para>A string 255 characters or less in length, that MUST be unique to - /// this particular successful authentication response. The nonce MUST start - /// with the current time on the server, and MAY contain additional ASCII - /// characters in the range 33-126 inclusive (printable non-whitespace characters), - /// as necessary to make each response unique. The date and time MUST be - /// formatted as specified in section 5.6 of [RFC3339] - /// (Klyne, G. and C. Newman, “Date and Time on the Internet: Timestamps,” .), - /// with the following restrictions:</para> - /// <list type="bullet"> - /// <item>All times must be in the UTC timezone, indicated with a "Z".</item> - /// <item>No fractional seconds are allowed</item> - /// </list> - /// </value> - /// <example>2005-05-15T17:11:51ZUNIQUE</example> - [MessagePart("openid.response_nonce", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, MinVersion = "2.0")] - private string ResponseNonce { - get { - string uniqueFragment = ((IReplayProtectedProtocolMessage)this).Nonce; - return this.creationDateUtc.ToString(PermissibleDateTimeFormats[0], CultureInfo.InvariantCulture) + uniqueFragment; - } - - set { - if (value == null) { - ((IReplayProtectedProtocolMessage)this).Nonce = null; - } else { - int indexOfZ = value.IndexOf("Z", StringComparison.Ordinal); - ErrorUtilities.VerifyProtocol(indexOfZ >= 0, MessagingStrings.UnexpectedMessagePartValue, Protocol.openid.response_nonce, value); - this.creationDateUtc = DateTime.Parse(value.Substring(0, indexOfZ + 1), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal); - ((IReplayProtectedProtocolMessage)this).Nonce = value.Substring(indexOfZ + 1); - } - } - } - } -} +//-----------------------------------------------------------------------
+// <copyright file="IndirectSignedResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Messages {
+ using System;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.Net.Security;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.Messaging.Reflection;
+ using DotNetOpenAuth.OpenId.ChannelElements;
+ using System.Collections.Generic;
+
+ /// <summary>
+ /// An indirect message from a Provider to a Relying Party where at least part of the
+ /// payload is signed so the Relying Party can verify it has not been tampered with.
+ /// </summary>
+ [DebuggerDisplay("OpenID {Version} {Mode} (no id assertion)")]
+ internal class IndirectSignedResponse : IndirectResponseBase, ITamperResistantOpenIdMessage, IProtocolMessageWithExtensions {
+ /// <summary>
+ /// The allowed date/time formats for the response_nonce parameter.
+ /// </summary>
+ /// <remarks>
+ /// This array of formats is not yet a complete list.
+ /// </remarks>
+ private static readonly string[] PermissibleDateTimeFormats = { "yyyy-MM-ddTHH:mm:ssZ" };
+
+ /// <summary>
+ /// Backing store for the <see cref="Extensions"/> property.
+ /// </summary>
+ private IList<IExtensionMessage> extensions = new List<IExtensionMessage>();
+
+ /// <summary>
+ /// Backing field for the <see cref="IExpiringProtocolMessage.UtcCreationDate"/> property.
+ /// </summary>
+ private DateTime creationDateUtc = DateTime.UtcNow;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class.
+ /// </summary>
+ /// <param name="request">
+ /// The authentication request that caused this assertion to be generated.
+ /// </param>
+ internal IndirectSignedResponse(SignedResponseRequest request)
+ : base(request, Protocol.Lookup(GetVersion(request)).Args.Mode.id_res) {
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+
+ this.ReturnTo = request.ReturnTo;
+ this.ProviderEndpoint = request.Recipient;
+ ((ITamperResistantOpenIdMessage)this).AssociationHandle = request.AssociationHandle;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class
+ /// in order to perform signature verification at the Provider.
+ /// </summary>
+ /// <param name="previouslySignedMessage">The previously signed message.</param>
+ internal IndirectSignedResponse(CheckAuthenticationRequest previouslySignedMessage)
+ : base(GetVersion(previouslySignedMessage), previouslySignedMessage.ReturnTo, Protocol.Lookup(GetVersion(previouslySignedMessage)).Args.Mode.id_res) {
+ // Copy all message parts from the check_authentication message into this one,
+ // except for the openid.mode parameter.
+ MessageDictionary checkPayload = new MessageDictionary(previouslySignedMessage);
+ MessageDictionary thisPayload = new MessageDictionary(this);
+ foreach (var pair in checkPayload) {
+ if (!string.Equals(pair.Key, this.Protocol.openid.mode)) {
+ thisPayload[pair.Key] = pair.Value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="IndirectSignedResponse"/> class
+ /// for unsolicited assertions.
+ /// </summary>
+ /// <param name="version">The OpenID version to use.</param>
+ /// <param name="relyingPartyReturnTo">The return_to URL of the Relying Party.
+ /// This value will commonly be from <see cref="SignedResponseRequest.ReturnTo"/>,
+ /// but for unsolicited assertions may come from the Provider performing RP discovery
+ /// to find the appropriate return_to URL to use.</param>
+ internal IndirectSignedResponse(Version version, Uri relyingPartyReturnTo)
+ : base(version, relyingPartyReturnTo, Protocol.Lookup(version).Args.Mode.id_res) {
+ }
+
+ /// <summary>
+ /// Gets the level of protection this message requires.
+ /// </summary>
+ /// <value><see cref="MessageProtections.All"/></value>
+ public override MessageProtections RequiredProtection {
+ get { return MessageProtections.All; }
+ }
+
+ /// <summary>
+ /// Gets or sets the message signature.
+ /// </summary>
+ /// <value>Base 64 encoded signature calculated as specified in Section 6 (Generating Signatures).</value>
+ [MessagePart("openid.sig", IsRequired = true, AllowEmpty = false)]
+ string ITamperResistantProtocolMessage.Signature { get; set; }
+
+ /// <summary>
+ /// Gets or sets the signed parameter order.
+ /// </summary>
+ /// <value>Comma-separated list of signed fields.</value>
+ /// <example>"op_endpoint,identity,claimed_id,return_to,assoc_handle,response_nonce"</example>
+ /// <remarks>
+ /// This entry consists of the fields without the "openid." prefix that the signature covers.
+ /// This list MUST contain at least "op_endpoint", "return_to" "response_nonce" and "assoc_handle",
+ /// and if present in the response, "claimed_id" and "identity".
+ /// Additional keys MAY be signed as part of the message. See Generating Signatures.
+ /// </remarks>
+ [MessagePart("openid.signed", IsRequired = true, AllowEmpty = false)]
+ string ITamperResistantOpenIdMessage.SignedParameterOrder { get; set; }
+
+ /// <summary>
+ /// Gets or sets the association handle used to sign the message.
+ /// </summary>
+ /// <value>The handle for the association that was used to sign this assertion. </value>
+ [MessagePart("openid.assoc_handle", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign)]
+ string ITamperResistantOpenIdMessage.AssociationHandle { get; set; }
+
+ /// <summary>
+ /// Gets or sets the nonce that will protect the message from replay attacks.
+ /// </summary>
+ string IReplayProtectedProtocolMessage.Nonce { get; set; }
+
+ /// <summary>
+ /// Gets or sets the UTC date/time the message was originally sent onto the network.
+ /// </summary>
+ /// <remarks>
+ /// The property setter should ensure a UTC date/time,
+ /// and throw an exception if this is not possible.
+ /// </remarks>
+ /// <exception cref="ArgumentException">
+ /// Thrown when a DateTime that cannot be converted to UTC is set.
+ /// </exception>
+ DateTime IExpiringProtocolMessage.UtcCreationDate {
+ get { return this.creationDateUtc; }
+ set { this.creationDateUtc = value.ToUniversalTime(); }
+ }
+
+ /// <summary>
+ /// Gets or sets the association handle that the Provider wants the Relying Party to not use any more.
+ /// </summary>
+ /// <value>If the Relying Party sent an invalid association handle with the request, it SHOULD be included here.</value>
+ [MessagePart("openid.invalidate_handle", IsRequired = false, AllowEmpty = false)]
+ string ITamperResistantOpenIdMessage.InvalidateHandle { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Provider Endpoint URI.
+ /// </summary>
+ [MessagePart("openid.op_endpoint", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, MinVersion = "2.0")]
+ internal Uri ProviderEndpoint { get; set; }
+
+ /// <summary>
+ /// Gets or sets the return_to parameter as the relying party provided
+ /// it in <see cref="SignedResponseRequest.ReturnTo"/>.
+ /// </summary>
+ /// <value>Verbatim copy of the return_to URL parameter sent in the
+ /// request, before the Provider modified it. </value>
+ [MessagePart("openid.return_to", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, Encoder = typeof(OriginalStringUriEncoder))]
+ internal Uri ReturnTo { get; set; }
+
+ /// <summary>
+ /// Gets or sets the nonce that will protect the message from replay attacks.
+ /// </summary>
+ /// <value>
+ /// <para>A string 255 characters or less in length, that MUST be unique to
+ /// this particular successful authentication response. The nonce MUST start
+ /// with the current time on the server, and MAY contain additional ASCII
+ /// characters in the range 33-126 inclusive (printable non-whitespace characters),
+ /// as necessary to make each response unique. The date and time MUST be
+ /// formatted as specified in section 5.6 of [RFC3339]
+ /// (Klyne, G. and C. Newman, “Date and Time on the Internet: Timestamps,” .),
+ /// with the following restrictions:</para>
+ /// <list type="bullet">
+ /// <item>All times must be in the UTC timezone, indicated with a "Z".</item>
+ /// <item>No fractional seconds are allowed</item>
+ /// </list>
+ /// </value>
+ /// <example>2005-05-15T17:11:51ZUNIQUE</example>
+ [MessagePart("openid.response_nonce", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, MinVersion = "2.0")]
+ private string ResponseNonce {
+ get {
+ string uniqueFragment = ((IReplayProtectedProtocolMessage)this).Nonce;
+ return this.creationDateUtc.ToString(PermissibleDateTimeFormats[0], CultureInfo.InvariantCulture) + uniqueFragment;
+ }
+
+ set {
+ if (value == null) {
+ ((IReplayProtectedProtocolMessage)this).Nonce = null;
+ } else {
+ int indexOfZ = value.IndexOf("Z", StringComparison.Ordinal);
+ ErrorUtilities.VerifyProtocol(indexOfZ >= 0, MessagingStrings.UnexpectedMessagePartValue, Protocol.openid.response_nonce, value);
+ this.creationDateUtc = DateTime.Parse(value.Substring(0, indexOfZ + 1), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
+ ((IReplayProtectedProtocolMessage)this).Nonce = value.Substring(indexOfZ + 1);
+ }
+ }
+ }
+
+ #region IProtocolMessageWithExtensions Members
+
+ /// <summary>
+ /// Gets the list of extensions that are included with this message.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// Implementations of this interface should ensure that this property never returns null.
+ /// </remarks>
+ public IList<IExtensionMessage> Extensions {
+ get { return this.extensions; }
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/PositiveAssertionResponse.cs b/src/DotNetOpenAuth/OpenId/Messages/PositiveAssertionResponse.cs index a2223e3..ee46a18 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/PositiveAssertionResponse.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/PositiveAssertionResponse.cs @@ -1,74 +1,74 @@ -//----------------------------------------------------------------------- -// <copyright file="PositiveAssertionResponse.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Messages { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Globalization; - using System.Linq; - using System.Net.Security; - using System.Text; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.Messaging.Bindings; - using DotNetOpenAuth.OpenId.ChannelElements; - - /// <summary> - /// An identity assertion from a Provider to a Relying Party, stating that the - /// user operating the user agent is in fact some specific user known to the Provider. - /// </summary> - [DebuggerDisplay("OpenID {ProtocolVersion} {Mode} {LocalIdentifier}")] - internal class PositiveAssertionResponse : IndirectSignedResponse { - /// <summary> - /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class. - /// </summary> - /// <param name="request"> - /// The authentication request that caused this assertion to be generated. - /// </param> - internal PositiveAssertionResponse(CheckIdRequest request) - : base(request) { - this.ClaimedIdentifier = request.ClaimedIdentifier; - this.LocalIdentifier = request.LocalIdentifier; - } - - /// <summary> - /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class - /// for unsolicited assertions. - /// </summary> - /// <param name="version">The OpenID version to use.</param> - /// <param name="relyingPartyReturnTo">The return_to URL of the Relying Party. - /// This value will commonly be from <see cref="SignedResponseRequest.ReturnTo"/>, - /// but for unsolicited assertions may come from the Provider performing RP discovery - /// to find the appropriate return_to URL to use.</param> - internal PositiveAssertionResponse(Version version, Uri relyingPartyReturnTo) - : base(version, relyingPartyReturnTo) { - } - - /// <summary> - /// Gets or sets the Claimed Identifier. - /// </summary> - /// <remarks> - /// <para>"openid.claimed_id" and "openid.identity" SHALL be either both present or both absent. - /// If neither value is present, the assertion is not about an identifier, - /// and will contain other information in its payload, using extensions (Extensions). </para> - /// </remarks> - [MessagePart("openid.claimed_id", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, MinVersion = "2.0")] - internal Identifier ClaimedIdentifier { get; set; } - - /// <summary> - /// Gets or sets the OP Local Identifier. - /// </summary> - /// <value>The OP-Local Identifier. </value> - /// <remarks> - /// <para>OpenID Providers MAY assist the end user in selecting the Claimed - /// and OP-Local Identifiers about which the assertion is made. - /// The openid.identity field MAY be omitted if an extension is in use that - /// makes the response meaningful without it (see openid.claimed_id above). </para> - /// </remarks> - [MessagePart("openid.identity", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign)] - internal Identifier LocalIdentifier { get; set; } - } -} +//-----------------------------------------------------------------------
+// <copyright file="PositiveAssertionResponse.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Globalization;
+ using System.Linq;
+ using System.Net.Security;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+ using DotNetOpenAuth.OpenId.ChannelElements;
+
+ /// <summary>
+ /// An identity assertion from a Provider to a Relying Party, stating that the
+ /// user operating the user agent is in fact some specific user known to the Provider.
+ /// </summary>
+ [DebuggerDisplay("OpenID {Version} {Mode} {LocalIdentifier}")]
+ internal class PositiveAssertionResponse : IndirectSignedResponse {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class.
+ /// </summary>
+ /// <param name="request">
+ /// The authentication request that caused this assertion to be generated.
+ /// </param>
+ internal PositiveAssertionResponse(CheckIdRequest request)
+ : base(request) {
+ this.ClaimedIdentifier = request.ClaimedIdentifier;
+ this.LocalIdentifier = request.LocalIdentifier;
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PositiveAssertionResponse"/> class
+ /// for unsolicited assertions.
+ /// </summary>
+ /// <param name="version">The OpenID version to use.</param>
+ /// <param name="relyingPartyReturnTo">The return_to URL of the Relying Party.
+ /// This value will commonly be from <see cref="SignedResponseRequest.ReturnTo"/>,
+ /// but for unsolicited assertions may come from the Provider performing RP discovery
+ /// to find the appropriate return_to URL to use.</param>
+ internal PositiveAssertionResponse(Version version, Uri relyingPartyReturnTo)
+ : base(version, relyingPartyReturnTo) {
+ }
+
+ /// <summary>
+ /// Gets or sets the Claimed Identifier.
+ /// </summary>
+ /// <remarks>
+ /// <para>"openid.claimed_id" and "openid.identity" SHALL be either both present or both absent.
+ /// If neither value is present, the assertion is not about an identifier,
+ /// and will contain other information in its payload, using extensions (Extensions). </para>
+ /// </remarks>
+ [MessagePart("openid.claimed_id", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign, MinVersion = "2.0")]
+ internal Identifier ClaimedIdentifier { get; set; }
+
+ /// <summary>
+ /// Gets or sets the OP Local Identifier.
+ /// </summary>
+ /// <value>The OP-Local Identifier. </value>
+ /// <remarks>
+ /// <para>OpenID Providers MAY assist the end user in selecting the Claimed
+ /// and OP-Local Identifiers about which the assertion is made.
+ /// The openid.identity field MAY be omitted if an extension is in use that
+ /// makes the response meaningful without it (see openid.claimed_id above). </para>
+ /// </remarks>
+ [MessagePart("openid.identity", IsRequired = true, AllowEmpty = false, RequiredProtection = ProtectionLevel.Sign)]
+ internal Identifier LocalIdentifier { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs b/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs index acd8e5f..2003bd9 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs @@ -14,7 +14,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary>
/// A common base class for OpenID request messages and indirect responses (since they are ultimately requests).
/// </summary>
- [DebuggerDisplay("OpenID {ProtocolVersion} {Mode}")]
+ [DebuggerDisplay("OpenID {Version} {Mode}")]
internal class RequestBase : IDirectedProtocolMessage {
/// <summary>
/// The openid.ns parameter in the message.
diff --git a/src/DotNetOpenAuth/OpenId/Messages/SignedResponseRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/SignedResponseRequest.cs index de15fa2..aaf6004 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/SignedResponseRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/SignedResponseRequest.cs @@ -1,127 +1,147 @@ -//----------------------------------------------------------------------- -// <copyright file="SignedResponseRequest.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Messages { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Linq; - using System.Text; - using DotNetOpenAuth.Messaging; - - /// <summary> - /// An indirect request from a Relying Party to a Provider where the response - /// is expected to be signed. - /// </summary> - internal class SignedResponseRequest : RequestBase { - /// <summary> - /// Initializes a new instance of the <see cref="SignedResponseRequest"/> class. - /// </summary> - /// <param name="version">The OpenID version to use.</param> - /// <param name="providerEndpoint">The Provider endpoint that receives this message.</param> - /// <param name="immediate"> - /// <c>true</c> for asynchronous javascript clients; - /// <c>false</c> to allow the Provider to interact with the user in order to complete authentication. - /// </param> - internal SignedResponseRequest(Version version, Uri providerEndpoint, bool immediate) : - base(version, providerEndpoint, GetMode(version, immediate), DotNetOpenAuth.Messaging.MessageTransport.Indirect) { - } - - /// <summary> - /// Gets a value indicating whether the Provider is allowed to interact with the user - /// as part of authentication. - /// </summary> - /// <value><c>true</c> if using OpenID immediate mode; otherwise, <c>false</c>.</value> - internal bool Immediate { - get { return String.Equals(this.Mode, Protocol.Args.Mode.checkid_immediate, StringComparison.Ordinal); } - } - - /// <summary> - /// Gets or sets the handle of the association the RP would like the Provider - /// to use for signing a positive assertion in the response message. - /// </summary> - /// <value>A handle for an association between the Relying Party and the OP - /// that SHOULD be used to sign the response. </value> - /// <remarks> - /// If no association handle is sent, the transaction will take place in Stateless Mode - /// (Verifying Directly with the OpenID Provider). - /// </remarks> - [MessagePart("openid.assoc_handle", IsRequired = false, AllowEmpty = false)] - internal string AssociationHandle { get; set; } - - /// <summary> - /// Gets or sets the URL the Provider should redirect the user agent to following - /// the authentication attempt. - /// </summary> - /// <value>URL to which the OP SHOULD return the User-Agent with the response - /// indicating the status of the request.</value> - /// <remarks> - /// <para>If this value is not sent in the request it signifies that the Relying Party - /// does not wish for the end user to be returned. </para> - /// <para>The return_to URL MAY be used as a mechanism for the Relying Party to attach - /// context about the authentication request to the authentication response. - /// This document does not define a mechanism by which the RP can ensure that query - /// parameters are not modified by outside parties; such a mechanism can be defined - /// by the RP itself. </para> - /// </remarks> - [MessagePart("openid.return_to", IsRequired = true, AllowEmpty = false)] - [MessagePart("openid.return_to", IsRequired = false, AllowEmpty = false, MinVersion = "2.0")] - internal Uri ReturnTo { get; set; } - - /// <summary> - /// Gets or sets the Relying Party discovery URL the Provider may use to verify the - /// source of the authentication request. - /// </summary> - /// <value> - /// URL pattern the OP SHOULD ask the end user to trust. See Section 9.2 (Realms). - /// This value MUST be sent if openid.return_to is omitted. - /// Default: The <see cref="ReturnTo"/> URL. - /// </value> - [MessagePart("openid.trust_root", IsRequired = false, AllowEmpty = false)] - [MessagePart("openid.realm", IsRequired = false, AllowEmpty = false, MinVersion = "2.0")] - internal Realm Realm { get; set; } - - /// <summary> - /// Checks the message state for conformity to the protocol specification - /// and throws an exception if the message is invalid. - /// </summary> - /// <remarks> - /// <para>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.</para> - /// <para>Note that this property should <i>not</i> check signatures or perform any state checks - /// outside this scope of this particular message.</para> - /// </remarks> - /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception> - public override void EnsureValidMessage() { - base.EnsureValidMessage(); - - if (this.Realm == null) { - // Set the default Realm per the spec if it is not explicitly given. - this.Realm = this.ReturnTo; - } else if (this.ReturnTo != null) { - // Verify that the realm and return_to agree. - ErrorUtilities.VerifyProtocol(this.Realm.Contains(this.ReturnTo), OpenIdStrings.ReturnToNotUnderRealm, this.ReturnTo, this.Realm); - } - } - - /// <summary> - /// Gets the value of the openid.mode parameter based on the protocol version and immediate flag. - /// </summary> - /// <param name="version">The OpenID version to use.</param> - /// <param name="immediate"> - /// <c>true</c> for asynchronous javascript clients; - /// <c>false</c> to allow the Provider to interact with the user in order to complete authentication. - /// </param> - /// <returns>checkid_immediate or checkid_setup</returns> - private static string GetMode(Version version, bool immediate) { - ErrorUtilities.VerifyArgumentNotNull(version, "version"); - - Protocol protocol = Protocol.Lookup(version); - return immediate ? protocol.Args.Mode.checkid_immediate : protocol.Args.Mode.checkid_setup; - } - } -} +//-----------------------------------------------------------------------
+// <copyright file="SignedResponseRequest.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Messages {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// An indirect request from a Relying Party to a Provider where the response
+ /// is expected to be signed.
+ /// </summary>
+ internal class SignedResponseRequest : RequestBase, IProtocolMessageWithExtensions {
+ /// <summary>
+ /// Backing store for the <see cref="Extensions"/> property.
+ /// </summary>
+ private IList<IExtensionMessage> extensions = new List<IExtensionMessage>();
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="SignedResponseRequest"/> class.
+ /// </summary>
+ /// <param name="version">The OpenID version to use.</param>
+ /// <param name="providerEndpoint">The Provider endpoint that receives this message.</param>
+ /// <param name="immediate">
+ /// <c>true</c> for asynchronous javascript clients;
+ /// <c>false</c> to allow the Provider to interact with the user in order to complete authentication.
+ /// </param>
+ internal SignedResponseRequest(Version version, Uri providerEndpoint, bool immediate) :
+ base(version, providerEndpoint, GetMode(version, immediate), DotNetOpenAuth.Messaging.MessageTransport.Indirect) {
+ }
+
+ #region IProtocolMessageWithExtensions Members
+
+ /// <summary>
+ /// Gets the list of extensions that are included with this message.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// Implementations of this interface should ensure that this property never returns null.
+ /// </remarks>
+ public IList<IExtensionMessage> Extensions {
+ get { return this.extensions; }
+ }
+
+ #endregion
+
+ /// <summary>
+ /// Gets a value indicating whether the Provider is allowed to interact with the user
+ /// as part of authentication.
+ /// </summary>
+ /// <value><c>true</c> if using OpenID immediate mode; otherwise, <c>false</c>.</value>
+ internal bool Immediate {
+ get { return String.Equals(this.Mode, Protocol.Args.Mode.checkid_immediate, StringComparison.Ordinal); }
+ }
+
+ /// <summary>
+ /// Gets or sets the handle of the association the RP would like the Provider
+ /// to use for signing a positive assertion in the response message.
+ /// </summary>
+ /// <value>A handle for an association between the Relying Party and the OP
+ /// that SHOULD be used to sign the response. </value>
+ /// <remarks>
+ /// If no association handle is sent, the transaction will take place in Stateless Mode
+ /// (Verifying Directly with the OpenID Provider).
+ /// </remarks>
+ [MessagePart("openid.assoc_handle", IsRequired = false, AllowEmpty = false)]
+ internal string AssociationHandle { get; set; }
+
+ /// <summary>
+ /// Gets or sets the URL the Provider should redirect the user agent to following
+ /// the authentication attempt.
+ /// </summary>
+ /// <value>URL to which the OP SHOULD return the User-Agent with the response
+ /// indicating the status of the request.</value>
+ /// <remarks>
+ /// <para>If this value is not sent in the request it signifies that the Relying Party
+ /// does not wish for the end user to be returned. </para>
+ /// <para>The return_to URL MAY be used as a mechanism for the Relying Party to attach
+ /// context about the authentication request to the authentication response.
+ /// This document does not define a mechanism by which the RP can ensure that query
+ /// parameters are not modified by outside parties; such a mechanism can be defined
+ /// by the RP itself. </para>
+ /// </remarks>
+ [MessagePart("openid.return_to", IsRequired = true, AllowEmpty = false)]
+ [MessagePart("openid.return_to", IsRequired = false, AllowEmpty = false, MinVersion = "2.0")]
+ internal Uri ReturnTo { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Relying Party discovery URL the Provider may use to verify the
+ /// source of the authentication request.
+ /// </summary>
+ /// <value>
+ /// URL pattern the OP SHOULD ask the end user to trust. See Section 9.2 (Realms).
+ /// This value MUST be sent if openid.return_to is omitted.
+ /// Default: The <see cref="ReturnTo"/> URL.
+ /// </value>
+ [MessagePart("openid.trust_root", IsRequired = false, AllowEmpty = false)]
+ [MessagePart("openid.realm", IsRequired = false, AllowEmpty = false, MinVersion = "2.0")]
+ internal Realm Realm { get; set; }
+
+ /// <summary>
+ /// Checks the message state for conformity to the protocol specification
+ /// and throws an exception if the message is invalid.
+ /// </summary>
+ /// <remarks>
+ /// <para>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.</para>
+ /// <para>Note that this property should <i>not</i> check signatures or perform any state checks
+ /// outside this scope of this particular message.</para>
+ /// </remarks>
+ /// <exception cref="ProtocolException">Thrown if the message is invalid.</exception>
+ public override void EnsureValidMessage() {
+ base.EnsureValidMessage();
+
+ if (this.Realm == null) {
+ // Set the default Realm per the spec if it is not explicitly given.
+ this.Realm = this.ReturnTo;
+ } else if (this.ReturnTo != null) {
+ // Verify that the realm and return_to agree.
+ ErrorUtilities.VerifyProtocol(this.Realm.Contains(this.ReturnTo), OpenIdStrings.ReturnToNotUnderRealm, this.ReturnTo, this.Realm);
+ }
+ }
+
+ /// <summary>
+ /// Gets the value of the openid.mode parameter based on the protocol version and immediate flag.
+ /// </summary>
+ /// <param name="version">The OpenID version to use.</param>
+ /// <param name="immediate">
+ /// <c>true</c> for asynchronous javascript clients;
+ /// <c>false</c> to allow the Provider to interact with the user in order to complete authentication.
+ /// </param>
+ /// <returns>checkid_immediate or checkid_setup</returns>
+ private static string GetMode(Version version, bool immediate) {
+ ErrorUtilities.VerifyArgumentNotNull(version, "version");
+
+ Protocol protocol = Protocol.Lookup(version);
+ return immediate ? protocol.Args.Mode.checkid_immediate : protocol.Args.Mode.checkid_setup;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs index 4405204..9083d9e 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs @@ -277,6 +277,15 @@ namespace DotNetOpenAuth.OpenId { }
/// <summary>
+ /// Looks up a localized string similar to Invalid birthdate value. Must be in the form yyyy-MM-dd..
+ /// </summary>
+ internal static string SregInvalidBirthdate {
+ get {
+ return ResourceManager.GetString("SregInvalidBirthdate", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The openid.user_setup_url parameter is required when sending negative assertion messages in response to immediate mode requests..
/// </summary>
internal static string UserSetupUrlRequiredInImmediateNegativeResponse {
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx index f7f134d..d1d63bc 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx @@ -189,6 +189,9 @@ <data name="SignatureDoesNotIncludeMandatoryParts" xml:space="preserve">
<value>The following parameter(s) are not included in the signature but must be: {0}</value>
</data>
+ <data name="SregInvalidBirthdate" xml:space="preserve">
+ <value>Invalid birthdate value. Must be in the form yyyy-MM-dd.</value>
+ </data>
<data name="UserSetupUrlRequiredInImmediateNegativeResponse" xml:space="preserve">
<value>The openid.user_setup_url parameter is required when sending negative assertion messages in response to immediate mode requests.</value>
</data>
|