summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj361
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/CollectionAssert.cs45
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ClaimsResponseTests.cs142
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionTestBase.cs67
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/SimpleRegistrationTests.cs83
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj4
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs8
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/ExtensionsBindingElement.cs34
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/IOpenIdExtensionFactory.cs32
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/OpenIdChannel.cs353
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/ExtensionArgumentsManager.cs21
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/ExtensionBase.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/OpenIdExtensionFactory.cs73
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsRequest.cs8
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/SimpleRegistration/ClaimsResponse.cs64
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateSuccessfulResponse.cs240
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/AssociateUnsuccessfulResponse.cs100
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/CheckIdRequest.cs130
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/DirectResponseBase.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/IOpenIdMessageExtension.cs (renamed from src/DotNetOpenAuth/OpenId/Messages/IOpenIdProtocolMessageExtension.cs)4
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/IndirectSignedResponse.cs415
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/PositiveAssertionResponse.cs148
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/RequestBase.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Messages/SignedResponseRequest.cs274
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs9
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.resx3
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>