diff options
155 files changed, 4247 insertions, 1781 deletions
@@ -189,7 +189,7 @@ <TopLevelVSProjectTemplates Include="@(VSProjectTemplates)" Condition="'%(RootDir)%(Directory)' == '$(ProjectTemplatesLayoutPath)'" /> <!-- Include the template icon --> - <ProjectTemplatesSource Include="$(ProjectRoot)doc\logo\dotnetopenid.ico" /> + <ProjectTemplatesSource Include="$(ProjectRoot)doc\logo\favicon.ico" /> <ProjectTemplatesLayout Include="$(ProjectTemplatesLayoutPath)__TemplateIcon.ico" /> <!-- Add external libraries --> diff --git a/doc/logo/DotNetOpenAuth.png b/doc/logo/DotNetOpenAuth.png Binary files differnew file mode 100644 index 0000000..442b986 --- /dev/null +++ b/doc/logo/DotNetOpenAuth.png diff --git a/doc/logo/dnoa-icon-colour.ico b/doc/logo/dnoa-icon-colour.ico Binary files differnew file mode 100644 index 0000000..5789dfa --- /dev/null +++ b/doc/logo/dnoa-icon-colour.ico diff --git a/doc/logo/dnoa-logo.png b/doc/logo/dnoa-logo.png Binary files differnew file mode 100644 index 0000000..442b986 --- /dev/null +++ b/doc/logo/dnoa-logo.png diff --git a/doc/logo/dnoa-logo_32x32.png b/doc/logo/dnoa-logo_32x32.png Binary files differnew file mode 100644 index 0000000..73670db --- /dev/null +++ b/doc/logo/dnoa-logo_32x32.png diff --git a/doc/logo/dnoa-logo_48x48.png b/doc/logo/dnoa-logo_48x48.png Binary files differnew file mode 100644 index 0000000..1cfb438 --- /dev/null +++ b/doc/logo/dnoa-logo_48x48.png diff --git a/doc/logo/dnoa-logo_64x64.png b/doc/logo/dnoa-logo_64x64.png Binary files differnew file mode 100644 index 0000000..f4d361a --- /dev/null +++ b/doc/logo/dnoa-logo_64x64.png diff --git a/doc/logo/dotnetopenid.ico b/doc/logo/dotnetopenid.ico Binary files differdeleted file mode 100644 index 5cd6121..0000000 --- a/doc/logo/dotnetopenid.ico +++ /dev/null diff --git a/doc/logo/dotnetopenid.pdf b/doc/logo/dotnetopenid.pdf Binary files differdeleted file mode 100644 index 62bea0b..0000000 --- a/doc/logo/dotnetopenid.pdf +++ /dev/null diff --git a/doc/logo/dotnetopenid_16x16.gif b/doc/logo/dotnetopenid_16x16.gif Binary files differdeleted file mode 100644 index 52dd653..0000000 --- a/doc/logo/dotnetopenid_16x16.gif +++ /dev/null diff --git a/doc/logo/dotnetopenid_64x64.png b/doc/logo/dotnetopenid_64x64.png Binary files differdeleted file mode 100644 index 7b11cad..0000000 --- a/doc/logo/dotnetopenid_64x64.png +++ /dev/null diff --git a/doc/logo/dotnetopenid_big.png b/doc/logo/dotnetopenid_big.png Binary files differdeleted file mode 100644 index 234b899..0000000 --- a/doc/logo/dotnetopenid_big.png +++ /dev/null diff --git a/doc/logo/dotnetopenid_big_transparent.png b/doc/logo/dotnetopenid_big_transparent.png Binary files differdeleted file mode 100644 index 1d92eb2..0000000 --- a/doc/logo/dotnetopenid_big_transparent.png +++ /dev/null diff --git a/doc/logo/dotnetopenid_black.pdf b/doc/logo/dotnetopenid_black.pdf Binary files differdeleted file mode 100644 index 57a45ab..0000000 --- a/doc/logo/dotnetopenid_black.pdf +++ /dev/null diff --git a/doc/logo/dotnetopenid_black_big_transparent.png b/doc/logo/dotnetopenid_black_big_transparent.png Binary files differdeleted file mode 100644 index 1db8283..0000000 --- a/doc/logo/dotnetopenid_black_big_transparent.png +++ /dev/null diff --git a/doc/logo/dotnetopenid_little.png b/doc/logo/dotnetopenid_little.png Binary files differdeleted file mode 100644 index 6d609f1..0000000 --- a/doc/logo/dotnetopenid_little.png +++ /dev/null diff --git a/doc/logo/dotnetopenid_medium.png b/doc/logo/dotnetopenid_medium.png Binary files differdeleted file mode 100644 index 093ad05..0000000 --- a/doc/logo/dotnetopenid_medium.png +++ /dev/null diff --git a/doc/logo/dotnetopenid_tiny.gif b/doc/logo/dotnetopenid_tiny.gif Binary files differdeleted file mode 100644 index c4ed4f5..0000000 --- a/doc/logo/dotnetopenid_tiny.gif +++ /dev/null diff --git a/doc/logo/dotnetopenid_vertical.gif b/doc/logo/dotnetopenid_vertical.gif Binary files differdeleted file mode 100644 index 39d1691..0000000 --- a/doc/logo/dotnetopenid_vertical.gif +++ /dev/null diff --git a/doc/logo/dotnetopenid_white_big_transparent.png b/doc/logo/dotnetopenid_white_big_transparent.png Binary files differdeleted file mode 100644 index 06a6a33..0000000 --- a/doc/logo/dotnetopenid_white_big_transparent.png +++ /dev/null diff --git a/doc/logo/favicon.ico b/doc/logo/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/doc/logo/favicon.ico diff --git a/doc/logo/making_of.jpg b/doc/logo/making_of.jpg Binary files differdeleted file mode 100644 index 0ee52a0..0000000 --- a/doc/logo/making_of.jpg +++ /dev/null diff --git a/projecttemplates/WebFormsRelyingParty/LoginFrame.aspx.cs b/projecttemplates/WebFormsRelyingParty/LoginFrame.aspx.cs index 07c24ae..152884e 100644 --- a/projecttemplates/WebFormsRelyingParty/LoginFrame.aspx.cs +++ b/projecttemplates/WebFormsRelyingParty/LoginFrame.aspx.cs @@ -13,7 +13,6 @@ using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.RelyingParty; using RelyingPartyLogic; - using WebFormsRelyingParty.Code; public partial class LoginFrame : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { diff --git a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs index c21ae26..16e48f0 100644 --- a/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs +++ b/projecttemplates/WebFormsRelyingParty/Members/OAuthAuthorize.aspx.cs @@ -14,7 +14,6 @@ namespace WebFormsRelyingParty.Members { using DotNetOpenAuth.OAuth; using DotNetOpenAuth.OAuth.Messages; using RelyingPartyLogic; - using WebFormsRelyingParty.Code; public partial class OAuthAuthorize : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { diff --git a/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs b/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs index e7d1619..cb7c819 100644 --- a/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs +++ b/projecttemplates/WebFormsRelyingParty/OAuth.ashx.cs @@ -14,7 +14,6 @@ namespace WebFormsRelyingParty { using DotNetOpenAuth.OAuth; using DotNetOpenAuth.OAuth.Messages; using RelyingPartyLogic; - using WebFormsRelyingParty.Code; /// <summary> /// Responds to incoming OAuth Service Provider messages. diff --git a/samples/InfoCardRelyingParty/Site.Master b/samples/InfoCardRelyingParty/Site.Master index 508f62c..bd3f896 100644 --- a/samples/InfoCardRelyingParty/Site.Master +++ b/samples/InfoCardRelyingParty/Site.Master @@ -20,7 +20,7 @@ </span> <div> <a href="http://dotnetopenauth.net"> - <img runat="server" src="~/images/dotnetopenid_tiny.gif" title="Jump to the project web site." + <img runat="server" src="~/images/DotNetOpenAuth.png" title="Jump to the project web site." alt="DotNetOpenAuth" border='0' /></a> </div> <div> diff --git a/samples/InfoCardRelyingParty/favicon.ico b/samples/InfoCardRelyingParty/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/InfoCardRelyingParty/favicon.ico diff --git a/samples/InfoCardRelyingParty/images/DotNetOpenAuth.png b/samples/InfoCardRelyingParty/images/DotNetOpenAuth.png Binary files differnew file mode 100644 index 0000000..442b986 --- /dev/null +++ b/samples/InfoCardRelyingParty/images/DotNetOpenAuth.png diff --git a/samples/InfoCardRelyingParty/images/dotnetopenid_tiny.gif b/samples/InfoCardRelyingParty/images/dotnetopenid_tiny.gif Binary files differdeleted file mode 100644 index c4ed4f5..0000000 --- a/samples/InfoCardRelyingParty/images/dotnetopenid_tiny.gif +++ /dev/null diff --git a/samples/OAuthConsumer/favicon.ico b/samples/OAuthConsumer/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OAuthConsumer/favicon.ico diff --git a/samples/OAuthConsumerWpf/favicon.ico b/samples/OAuthConsumerWpf/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OAuthConsumerWpf/favicon.ico diff --git a/samples/OAuthServiceProvider/favicon.ico b/samples/OAuthServiceProvider/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OAuthServiceProvider/favicon.ico diff --git a/samples/OpenIdOfflineProvider/openid.ico b/samples/OpenIdOfflineProvider/openid.ico Binary files differindex 651aeba..e227dbe 100644 --- a/samples/OpenIdOfflineProvider/openid.ico +++ b/samples/OpenIdOfflineProvider/openid.ico diff --git a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj index 82bfbbe..9201688 100644 --- a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj +++ b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj @@ -90,6 +90,7 @@ <ItemGroup> <Content Include="App_Data\Users.xml" /> <Content Include="Default.aspx" /> + <Content Include="favicon.ico" /> <Content Include="Global.asax" /> <Content Include="Views\Account\ChangePassword.aspx" /> <Content Include="Views\Account\ChangePasswordSuccess.aspx" /> diff --git a/samples/OpenIdProviderMvc/favicon.ico b/samples/OpenIdProviderMvc/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OpenIdProviderMvc/favicon.ico diff --git a/samples/OpenIdProviderWebForms/OpenIdProviderWebForms.csproj b/samples/OpenIdProviderWebForms/OpenIdProviderWebForms.csproj index 6cfca49..885f6a7 100644 --- a/samples/OpenIdProviderWebForms/OpenIdProviderWebForms.csproj +++ b/samples/OpenIdProviderWebForms/OpenIdProviderWebForms.csproj @@ -159,7 +159,6 @@ </ItemGroup> <ItemGroup> <Content Include="favicon.ico" /> - <Content Include="images\dotnetopenid_tiny.gif" /> <Content Include="Site.Master" /> <Content Include="styles.css" /> <Content Include="TracePage.aspx" /> @@ -177,6 +176,7 @@ <None Include="Code\CustomStoreDataSet.xss"> <DependentUpon>CustomStoreDataSet.xsd</DependentUpon> </None> + <Content Include="images\DotNetOpenAuth.png" /> <Content Include="Provider.ashx" /> </ItemGroup> <ItemGroup> diff --git a/samples/OpenIdProviderWebForms/Site.Master b/samples/OpenIdProviderWebForms/Site.Master index 4df9e0a..bc4f933 100644 --- a/samples/OpenIdProviderWebForms/Site.Master +++ b/samples/OpenIdProviderWebForms/Site.Master @@ -10,7 +10,7 @@ <body> <form id="form1" runat="server"> <div><a href="http://dotnetopenauth.net"> - <img runat="server" src="~/images/dotnetopenid_tiny.gif" title="Jump to the project web site." + <img runat="server" src="~/images/DotNetOpenAuth.png" title="Jump to the project web site." alt="DotNetOpenAuth" border='0' /></a> </div> <div> <asp:ContentPlaceHolder ID="Main" runat="server" /> diff --git a/samples/OpenIdProviderWebForms/Web.config b/samples/OpenIdProviderWebForms/Web.config index 701543c..c568de8 100644 --- a/samples/OpenIdProviderWebForms/Web.config +++ b/samples/OpenIdProviderWebForms/Web.config @@ -64,14 +64,14 @@ </providers> </membership> <authentication mode="Forms"> - <forms name="ProviderSession"/> <!-- named cookie prevents conflicts with other samples --> + <forms name="OpenIdProviderWebForms"/> </authentication> <customErrors mode="RemoteOnly"/> <!-- Trust level discussion: - Full: everything works + Full: everything works (this is required for Google Apps for Domains support) High: TRACE compilation symbol must NOT be defined - Medium: doesn't work unless originUrl=".*" or WebPermission.Connect is extended. + Medium: doesn't work unless originUrl=".*" or WebPermission.Connect is extended, and Google Apps doesn't work. Low: doesn't work because WebPermission.Connect is denied. --> <trust level="Medium" originUrl=".*"/> diff --git a/samples/OpenIdProviderWebForms/favicon.ico b/samples/OpenIdProviderWebForms/favicon.ico Binary files differindex beb3cb5..e227dbe 100644 --- a/samples/OpenIdProviderWebForms/favicon.ico +++ b/samples/OpenIdProviderWebForms/favicon.ico diff --git a/samples/OpenIdProviderWebForms/images/DotNetOpenAuth.png b/samples/OpenIdProviderWebForms/images/DotNetOpenAuth.png Binary files differnew file mode 100644 index 0000000..442b986 --- /dev/null +++ b/samples/OpenIdProviderWebForms/images/DotNetOpenAuth.png diff --git a/samples/OpenIdProviderWebForms/images/dotnetopenid_tiny.gif b/samples/OpenIdProviderWebForms/images/dotnetopenid_tiny.gif Binary files differdeleted file mode 100644 index c4ed4f5..0000000 --- a/samples/OpenIdProviderWebForms/images/dotnetopenid_tiny.gif +++ /dev/null diff --git a/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp b/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp index da6c18b..9f5917e 100644 --- a/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp +++ b/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp @@ -12,7 +12,7 @@ End If <body> <div> <a href="http://dotnetopenauth.net"> - <img runat="server" src="images/DotNetOpenId_tiny.gif" title="Jump to the project web site." + <img runat="server" src="images/DotNetOpenAuth.png" title="Jump to the project web site." alt="DotNetOpenAuth" border='0' /></a> </div> <h2> diff --git a/samples/OpenIdRelyingPartyClassicAsp/default.asp b/samples/OpenIdRelyingPartyClassicAsp/default.asp index f4d1d1d..cc2bd57 100644 --- a/samples/OpenIdRelyingPartyClassicAsp/default.asp +++ b/samples/OpenIdRelyingPartyClassicAsp/default.asp @@ -7,7 +7,7 @@ <body> <div> <a href="http://dotnetopenauth.net"> - <img runat="server" src="images/DotNetOpenId_tiny.gif" title="Jump to the project web site." + <img runat="server" src="images/DotNetOpenAuth.png" title="Jump to the project web site." alt="DotNetOpenAuth" border='0' /></a> </div> <h2>Classic ASP OpenID Relying Party</h2> diff --git a/samples/OpenIdRelyingPartyClassicAsp/favicon.ico b/samples/OpenIdRelyingPartyClassicAsp/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OpenIdRelyingPartyClassicAsp/favicon.ico diff --git a/samples/OpenIdRelyingPartyClassicAsp/images/DotNetOpenAuth.png b/samples/OpenIdRelyingPartyClassicAsp/images/DotNetOpenAuth.png Binary files differnew file mode 100644 index 0000000..442b986 --- /dev/null +++ b/samples/OpenIdRelyingPartyClassicAsp/images/DotNetOpenAuth.png diff --git a/samples/OpenIdRelyingPartyClassicAsp/images/dotnetopenid_tiny.gif b/samples/OpenIdRelyingPartyClassicAsp/images/dotnetopenid_tiny.gif Binary files differdeleted file mode 100644 index c4ed4f5..0000000 --- a/samples/OpenIdRelyingPartyClassicAsp/images/dotnetopenid_tiny.gif +++ /dev/null diff --git a/samples/OpenIdRelyingPartyClassicAsp/login.asp b/samples/OpenIdRelyingPartyClassicAsp/login.asp index 449af3e..18c4d4f 100644 --- a/samples/OpenIdRelyingPartyClassicAsp/login.asp +++ b/samples/OpenIdRelyingPartyClassicAsp/login.asp @@ -7,7 +7,7 @@ <body> <div> <a href="http://dotnetopenauth.net"> - <img runat="server" src="images/DotNetOpenId_tiny.gif" title="Jump to the project web site." + <img runat="server" src="images/DotNetOpenAuth.png" title="Jump to the project web site." alt="DotNetOpenAuth" border='0' /></a> </div> <h2>Login Page</h2> diff --git a/samples/OpenIdRelyingPartyMvc/OpenIdRelyingPartyMvc.csproj b/samples/OpenIdRelyingPartyMvc/OpenIdRelyingPartyMvc.csproj index b38e7dd..5fb83d1 100644 --- a/samples/OpenIdRelyingPartyMvc/OpenIdRelyingPartyMvc.csproj +++ b/samples/OpenIdRelyingPartyMvc/OpenIdRelyingPartyMvc.csproj @@ -117,6 +117,7 @@ <Content Include="Content\theme\ui.tabs.css" /> <Content Include="Content\theme\ui.theme.css" /> <Content Include="Default.aspx" /> + <Content Include="favicon.ico" /> <Content Include="Global.asax" /> <Content Include="Views\User\Index.aspx" /> <Content Include="Views\User\Login.aspx" /> diff --git a/samples/OpenIdRelyingPartyMvc/favicon.ico b/samples/OpenIdRelyingPartyMvc/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OpenIdRelyingPartyMvc/favicon.ico diff --git a/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj b/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj index 62d697c..bd42be1 100644 --- a/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj +++ b/samples/OpenIdRelyingPartyWebForms/OpenIdRelyingPartyWebForms.csproj @@ -110,6 +110,13 @@ <Compile Include="Code\InMemoryTokenManager.cs" /> <Compile Include="Code\State.cs" /> <Compile Include="Code\TracePageAppender.cs" /> + <Compile Include="loginGoogleApps.aspx.cs"> + <DependentUpon>loginGoogleApps.aspx</DependentUpon> + <SubType>ASPXCodeBehind</SubType> + </Compile> + <Compile Include="loginGoogleApps.aspx.designer.cs"> + <DependentUpon>loginGoogleApps.aspx</DependentUpon> + </Compile> <Compile Include="loginPlusOAuthSampleOP.aspx.cs"> <DependentUpon>loginPlusOAuthSampleOP.aspx</DependentUpon> <SubType>ASPXCodeBehind</SubType> @@ -178,9 +185,11 @@ <Content Include="xrds.aspx" /> </ItemGroup> <ItemGroup> + <Content Include="favicon.ico" /> + <Content Include="images\DotNetOpenAuth.png" /> + <Content Include="loginGoogleApps.aspx" /> <Content Include="loginPlusOAuthSampleOP.aspx" /> <Content Include="images\attention.png" /> - <Content Include="images\dotnetopenid_tiny.gif" /> <Content Include="images\openid_login.gif" /> <Content Include="images\yahoo.png" /> <Content Include="loginPlusOAuth.aspx" /> diff --git a/samples/OpenIdRelyingPartyWebForms/Site.Master b/samples/OpenIdRelyingPartyWebForms/Site.Master index cf8c507..c4f3dda 100644 --- a/samples/OpenIdRelyingPartyWebForms/Site.Master +++ b/samples/OpenIdRelyingPartyWebForms/Site.Master @@ -28,7 +28,7 @@ </span> <div> <a href="http://dotnetopenauth.net"> - <img runat="server" src="~/images/dotnetopenid_tiny.gif" title="Jump to the project web site." + <img runat="server" src="~/images/DotNetOpenAuth.png" title="Jump to the project web site." alt="DotNetOpenAuth" border='0' /></a> </div> <div> diff --git a/samples/OpenIdRelyingPartyWebForms/Web.config b/samples/OpenIdRelyingPartyWebForms/Web.config index 7abcfce..f7338f8 100644 --- a/samples/OpenIdRelyingPartyWebForms/Web.config +++ b/samples/OpenIdRelyingPartyWebForms/Web.config @@ -64,9 +64,9 @@ </authentication> <trace enabled="false" writeToDiagnosticsTrace="true"/> <!-- Trust level discussion: - Full: everything works + Full: everything works (this is required for Google Apps for Domains support) High: TRACE compilation symbol must NOT be defined - Medium: doesn't work unless originUrl=".*" or WebPermission.Connect is extended. + Medium: doesn't work unless originUrl=".*" or WebPermission.Connect is extended, and Google Apps doesn't work. Low: doesn't work because WebPermission.Connect is denied. --> <trust level="Medium" originUrl=".*"/> diff --git a/samples/OpenIdRelyingPartyWebForms/favicon.ico b/samples/OpenIdRelyingPartyWebForms/favicon.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/samples/OpenIdRelyingPartyWebForms/favicon.ico diff --git a/samples/OpenIdRelyingPartyWebForms/images/DotNetOpenAuth.png b/samples/OpenIdRelyingPartyWebForms/images/DotNetOpenAuth.png Binary files differnew file mode 100644 index 0000000..442b986 --- /dev/null +++ b/samples/OpenIdRelyingPartyWebForms/images/DotNetOpenAuth.png diff --git a/samples/OpenIdRelyingPartyWebForms/images/dotnetopenid_tiny.gif b/samples/OpenIdRelyingPartyWebForms/images/dotnetopenid_tiny.gif Binary files differdeleted file mode 100644 index c4ed4f5..0000000 --- a/samples/OpenIdRelyingPartyWebForms/images/dotnetopenid_tiny.gif +++ /dev/null diff --git a/samples/OpenIdRelyingPartyWebForms/login.aspx b/samples/OpenIdRelyingPartyWebForms/login.aspx index d0cdb1a..efa2052 100644 --- a/samples/OpenIdRelyingPartyWebForms/login.aspx +++ b/samples/OpenIdRelyingPartyWebForms/login.aspx @@ -21,6 +21,7 @@ </asp:CheckBoxList> <p>Try the PPID identifier functionality against the OpenIDProviderMvc sample.</p> </fieldset> + <p><a href="loginGoogleApps.aspx">Log in using Google Apps for Domains</a>. </p> <p> <rp:OpenIdButton runat="server" ImageUrl="~/images/yahoo.png" Text="Login with Yahoo!" ID="yahooLoginButton" Identifier="https://me.yahoo.com/" OnLoggingIn="OpenIdLogin1_LoggingIn" OnLoggedIn="OpenIdLogin1_LoggedIn" /> diff --git a/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx b/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx new file mode 100644 index 0000000..3f3860e --- /dev/null +++ b/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx @@ -0,0 +1,16 @@ +<%@ Page Language="C#" AutoEventWireup="True" CodeBehind="loginGoogleApps.aspx.cs" + Inherits="OpenIdRelyingPartyWebForms.loginGoogleApps" ValidateRequest="false" + MasterPageFile="~/Site.Master" %> + +<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.RelyingParty" + TagPrefix="rp" %> +<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="Main"> + <rp:OpenIdLogin ID="OpenIdLogin1" runat="server" ExampleUrl="yourname@yourdomain.com" + TabIndex="1" LabelText="Google Apps email address or domain:" + RegisterVisible="False" onloggedin="OpenIdLogin1_LoggedIn" /> + <asp:Panel runat="server" ID="fullTrustRequired" EnableViewState="false"> + <b>STOP:</b> Full trust permissions are required for Google Apps support + due to certificate chain verification requirements. + Modify web.config to allow full trust before trying this sample. + </asp:Panel> +</asp:Content> diff --git a/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx.cs b/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx.cs new file mode 100644 index 0000000..8c84b40 --- /dev/null +++ b/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx.cs @@ -0,0 +1,51 @@ +namespace OpenIdRelyingPartyWebForms { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security; + using System.Security.Permissions; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + + public partial class loginGoogleApps : System.Web.UI.Page { + private static readonly HostMetaDiscoveryService GoogleAppsDiscovery = new HostMetaDiscoveryService { + UseGoogleHostedHostMeta = true, + }; + + private static readonly OpenIdRelyingParty relyingParty; + + static loginGoogleApps() { + relyingParty = new OpenIdRelyingParty(); + + // We don't necessarily HAVE to clear the other discovery services, but + // because host-meta discovery (particularly with Google) can cause ambiguity + // in knowing which discovered endpoints are authoritative. Because of the + // extra security concerns it's a good idea to have a separate box + relyingParty.DiscoveryServices.Clear(); + relyingParty.DiscoveryServices.Insert(0, GoogleAppsDiscovery); // it should be first if we don't clear the other discovery services + } + + protected void Page_Load(object sender, EventArgs e) { + this.OpenIdLogin1.RelyingParty = relyingParty; + this.OpenIdLogin1.Focus(); + + this.fullTrustRequired.Visible = IsPartiallyTrusted(); + } + + protected void OpenIdLogin1_LoggedIn(object sender, OpenIdEventArgs e) { + State.FriendlyLoginName = e.Response.FriendlyIdentifierForDisplay; + } + + private static bool IsPartiallyTrusted() { + try { + new SecurityPermission(PermissionState.Unrestricted).Demand(); + return false; + } catch (SecurityException) { + return true; + } + } + } +} diff --git a/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx.designer.cs b/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx.designer.cs new file mode 100644 index 0000000..e927f65 --- /dev/null +++ b/samples/OpenIdRelyingPartyWebForms/loginGoogleApps.aspx.designer.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdRelyingPartyWebForms { + + + public partial class loginGoogleApps { + + /// <summary> + /// OpenIdLogin1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::DotNetOpenAuth.OpenId.RelyingParty.OpenIdLogin OpenIdLogin1; + + /// <summary> + /// fullTrustRequired control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.Panel fullTrustRequired; + } +} diff --git a/samples/OpenIdRelyingPartyWebForms/xrds.aspx b/samples/OpenIdRelyingPartyWebForms/xrds.aspx index 92983fd..55b5e35 100644 --- a/samples/OpenIdRelyingPartyWebForms/xrds.aspx +++ b/samples/OpenIdRelyingPartyWebForms/xrds.aspx @@ -23,7 +23,7 @@ is default.aspx. </Service> <Service> <Type>http://specs.openid.net/extensions/ui/icon</Type> - <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/images/dotnetopenid_tiny.gif"))%></URI> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/images/DotNetOpenAuth.png"))%></URI> </Service> </XRD> </xrds:XRDS> diff --git a/samples/OpenIdWebRingSsoProvider/Code/Util.cs b/samples/OpenIdWebRingSsoProvider/Code/Util.cs new file mode 100644 index 0000000..07064a2 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Code/Util.cs @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------- +// <copyright file="Util.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace OpenIdWebRingSsoProvider.Code { + using System; + using System.Configuration; + using System.Web; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.AttributeExchange; + using DotNetOpenAuth.OpenId.Provider; + + public class Util { + private const string RolesAttribute = "http://samples.dotnetopenauth.net/sso/roles"; + + public static string ExtractUserName(Uri url) { + return url.Segments[url.Segments.Length - 1]; + } + + public static string ExtractUserName(Identifier identifier) { + return ExtractUserName(new Uri(identifier.ToString())); + } + + public static Identifier BuildIdentityUrl() { + string username = HttpContext.Current.User.Identity.Name; + int slash = username.IndexOf('\\'); + if (slash >= 0) { + username = username.Substring(slash + 1); + } + return BuildIdentityUrl(username); + } + + public static Identifier BuildIdentityUrl(string username) { + // This sample Provider has a custom policy for normalizing URIs, which is that the whole + // path of the URI be lowercase except for the first letter of the username. + username = username.Substring(0, 1).ToUpperInvariant() + username.Substring(1).ToLowerInvariant(); + return new Uri(HttpContext.Current.Request.Url, HttpContext.Current.Response.ApplyAppPathModifier("~/user.aspx/" + username)); + } + + internal static void ProcessAuthenticationChallenge(IAuthenticationRequest idrequest) { + // Verify that RP discovery is successful. + if (idrequest.IsReturnUrlDiscoverable(ProviderEndpoint.Provider) != RelyingPartyDiscoveryResult.Success) { + idrequest.IsAuthenticated = false; + return; + } + + // Verify that the RP is on the whitelist. Realms are case sensitive. + string[] whitelist = ConfigurationManager.AppSettings["whitelistedRealms"].Split(';'); + if (Array.IndexOf(whitelist, idrequest.Realm.ToString()) < 0) { + idrequest.IsAuthenticated = false; + return; + } + + if (idrequest.IsDirectedIdentity) { + if (HttpContext.Current.User.Identity.IsAuthenticated) { + idrequest.LocalIdentifier = Util.BuildIdentityUrl(); + idrequest.IsAuthenticated = true; + } else { + idrequest.IsAuthenticated = false; + } + } else { + string userOwningOpenIdUrl = Util.ExtractUserName(idrequest.LocalIdentifier); + + // NOTE: in a production provider site, you may want to only + // respond affirmatively if the user has already authorized this consumer + // to know the answer. + idrequest.IsAuthenticated = userOwningOpenIdUrl == HttpContext.Current.User.Identity.Name; + } + + if (idrequest.IsAuthenticated.Value) { + // add extension responses here. + var fetchRequest = idrequest.GetExtension<FetchRequest>(); + if (fetchRequest != null) { + var fetchResponse = new FetchResponse(); + if (fetchRequest.Attributes.Contains(RolesAttribute)) { + // Inform the RP what roles this user should fill + // These roles would normally come out of the user database. + fetchResponse.Attributes.Add(RolesAttribute, "Member", "Admin"); + } + idrequest.AddResponseExtension(fetchResponse); + } + } + } + } +}
\ No newline at end of file diff --git a/samples/OpenIdWebRingSsoProvider/Default.aspx b/samples/OpenIdWebRingSsoProvider/Default.aspx new file mode 100644 index 0000000..9bddc98 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Default.aspx @@ -0,0 +1,25 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="OpenIdWebRingSsoProvider._Default" %> + +<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth" TagPrefix="openid" %> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> + <openid:XrdsPublisher ID="XrdsPublisher1" runat="server" XrdsUrl="~/op_xrds.aspx" /> +</head> +<body> + <form id="form1" runat="server"> + <p> + This sample is of an OpenID Provider that acts within a controlled set of web + sites (perhaps all belonging to the same organization). It authenticates + the user in its own way (Windows Auth, username/password, InfoCard, X.509, + anything), and then sends an automatically OpenID assertion to a limited set of + whitelisted RPs without prompting the user. + </p> + <p> + This particular sample uses Windows Authentication so that when the user visits + an RP and the RP sends the user to this OP for authentication, the process is + completely implicit -- the user never sees the OP.</p> + </form> +</body> +</html> diff --git a/samples/OpenIdWebRingSsoProvider/Default.aspx.cs b/samples/OpenIdWebRingSsoProvider/Default.aspx.cs new file mode 100644 index 0000000..1f64fea --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Default.aspx.cs @@ -0,0 +1,13 @@ +namespace OpenIdWebRingSsoProvider { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + + public partial class _Default : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + } + } +} diff --git a/samples/OpenIdWebRingSsoProvider/Default.aspx.designer.cs b/samples/OpenIdWebRingSsoProvider/Default.aspx.designer.cs new file mode 100644 index 0000000..b2f84f7 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Default.aspx.designer.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdWebRingSsoProvider { + + + public partial class _Default { + + /// <summary> + /// XrdsPublisher1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::DotNetOpenAuth.XrdsPublisher XrdsPublisher1; + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/samples/OpenIdWebRingSsoProvider/OpenIdWebRingSsoProvider.csproj b/samples/OpenIdWebRingSsoProvider/OpenIdWebRingSsoProvider.csproj new file mode 100644 index 0000000..29963c4 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/OpenIdWebRingSsoProvider.csproj @@ -0,0 +1,125 @@ +<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>{0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}</ProjectGuid> + <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>OpenIdWebRingSsoProvider</RootNamespace> + <AssemblyName>OpenIdWebRingSsoProvider</AssemblyName> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\</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\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Core"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Data.DataSetExtensions"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Web.Extensions"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Xml.Linq"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Drawing" /> + <Reference Include="System.Web" /> + <Reference Include="System.Xml" /> + <Reference Include="System.Configuration" /> + <Reference Include="System.Web.Services" /> + <Reference Include="System.EnterpriseServices" /> + <Reference Include="System.Web.Mobile" /> + </ItemGroup> + <ItemGroup> + <Content Include="Default.aspx" /> + <Content Include="op_xrds.aspx" /> + <Content Include="Server.aspx" /> + <Content Include="user.aspx" /> + <Content Include="user_xrds.aspx" /> + <Content Include="Web.config" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Code\Util.cs" /> + <Compile Include="Default.aspx.cs"> + <SubType>ASPXCodeBehind</SubType> + <DependentUpon>Default.aspx</DependentUpon> + </Compile> + <Compile Include="Default.aspx.designer.cs"> + <DependentUpon>Default.aspx</DependentUpon> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="Server.aspx.cs"> + <DependentUpon>Server.aspx</DependentUpon> + <SubType>ASPXCodeBehind</SubType> + </Compile> + <Compile Include="Server.aspx.designer.cs"> + <DependentUpon>Server.aspx</DependentUpon> + </Compile> + <Compile Include="user.aspx.cs"> + <DependentUpon>user.aspx</DependentUpon> + <SubType>ASPXCodeBehind</SubType> + </Compile> + <Compile Include="user.aspx.designer.cs"> + <DependentUpon>user.aspx</DependentUpon> + </Compile> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\src\DotNetOpenAuth\DotNetOpenAuth.csproj"> + <Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project> + <Name>DotNetOpenAuth</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Folder Include="App_Data\" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ProjectExtensions> + <VisualStudio> + <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}"> + <WebProjectProperties> + <UseIIS>False</UseIIS> + <AutoAssignPort>False</AutoAssignPort> + <DevelopmentServerPort>39167</DevelopmentServerPort> + <DevelopmentServerVPath>/</DevelopmentServerVPath> + <IISUrl> + </IISUrl> + <NTLMAuthentication>False</NTLMAuthentication> + <UseCustomServer>False</UseCustomServer> + <CustomServerUrl> + </CustomServerUrl> + <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> + </WebProjectProperties> + </FlavorProperties> + </VisualStudio> + </ProjectExtensions> +</Project>
\ No newline at end of file diff --git a/samples/OpenIdWebRingSsoProvider/Properties/AssemblyInfo.cs b/samples/OpenIdWebRingSsoProvider/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..41e7441 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenIdWebRingSsoProvider")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft IT")] +[assembly: AssemblyProduct("OpenIdWebRingSsoProvider")] +[assembly: AssemblyCopyright("Copyright © Microsoft IT 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OpenIdWebRingSsoProvider/Server.aspx b/samples/OpenIdWebRingSsoProvider/Server.aspx new file mode 100644 index 0000000..0665320 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Server.aspx @@ -0,0 +1,17 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Server.aspx.cs" Inherits="OpenIdWebRingSsoProvider.Server" %> + +<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.Provider" + TagPrefix="openid" %> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> + <openid:ProviderEndpoint runat="server" ID="providerEndpoint1" OnAuthenticationChallenge="providerEndpoint1_AuthenticationChallenge" /> +</head> +<body> + <form id="form1" runat="server"> + <div> + </div> + </form> +</body> +</html> diff --git a/samples/OpenIdWebRingSsoProvider/Server.aspx.cs b/samples/OpenIdWebRingSsoProvider/Server.aspx.cs new file mode 100644 index 0000000..101e608 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Server.aspx.cs @@ -0,0 +1,19 @@ +namespace OpenIdWebRingSsoProvider { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + using DotNetOpenAuth.OpenId.Provider; + using OpenIdWebRingSsoProvider.Code; + + public partial class Server : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + } + + protected void providerEndpoint1_AuthenticationChallenge(object sender, AuthenticationChallengeEventArgs e) { + Util.ProcessAuthenticationChallenge(e.Request); + } + } +} diff --git a/samples/OpenIdWebRingSsoProvider/Server.aspx.designer.cs b/samples/OpenIdWebRingSsoProvider/Server.aspx.designer.cs new file mode 100644 index 0000000..0fdea16 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Server.aspx.designer.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdWebRingSsoProvider { + + + public partial class Server { + + /// <summary> + /// providerEndpoint1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::DotNetOpenAuth.OpenId.Provider.ProviderEndpoint providerEndpoint1; + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/samples/OpenIdWebRingSsoProvider/Web.config b/samples/OpenIdWebRingSsoProvider/Web.config new file mode 100644 index 0000000..c32e0e3 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/Web.config @@ -0,0 +1,169 @@ +<?xml version="1.0"?> +<configuration> + <configSections> + <section name="uri" type="System.Configuration.UriSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/> + <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" requirePermission="false"/> + <section name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection" requirePermission="false" allowLocation="true"/> + <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> + <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" /> + <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> + <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> + <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> + </sectionGroup> + </sectionGroup> + </sectionGroup> + </configSections> + + <!-- The uri section is necessary to turn on .NET 3.5 support for IDN (international domain names), + which is necessary for OpenID urls with unicode characters in the domain/host name. + It is also required to put the Uri class into RFC 3986 escaping mode, which OpenID and OAuth require. --> + <uri> + <idn enabled="All"/> + <iriParsing enabled="true"/> + </uri> + + <system.net> + <defaultProxy enabled="true" /> + <settings> + <!-- This setting causes .NET to check certificate revocation lists (CRL) + before trusting HTTPS certificates. But this setting tends to not + be allowed in shared hosting environments. --> + <!--<servicePointManager checkCertificateRevocationList="true"/>--> + </settings> + </system.net> + + <!-- this is an optional configuration section where aspects of DotNetOpenAuth can be customized --> + <dotNetOpenAuth> + <openid> + <provider> + <security requireSsl="false" /> + <behaviors> + <!-- Behaviors activate themselves automatically for individual matching requests. + The first one in this list to match an incoming request "owns" the request. If no + profile matches, the default behavior is assumed. --> + <!--<add type="DotNetOpenAuth.OpenId.Behaviors.PpidGeneration, DotNetOpenAuth" />--> + </behaviors> + </provider> + </openid> + <messaging> + <untrustedWebRequest> + <whitelistHosts> + <!-- since this is a sample, and will often be used with localhost --> + <add name="localhost"/> + </whitelistHosts> + </untrustedWebRequest> + </messaging> + <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. --> + <reporting enabled="true" /> + </dotNetOpenAuth> + + <appSettings> + <add key="whitelistedRealms" value="http://localhost:39165/;http://othertrustedrealm/"/> + </appSettings> + <connectionStrings/> + + <system.web> + <!-- + Set compilation debug="true" to insert debugging + symbols into the compiled page. Because this + affects performance, set this value to true only + during development. + --> + <compilation debug="false"> + + <assemblies> + <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + </assemblies> + + </compilation> + <!-- + The <authentication> section enables configuration + of the security authentication mode used by + ASP.NET to identify an incoming user. + --> + <authentication mode="Windows" /> + <!-- + The <customErrors> section enables configuration + of what to do if/when an unhandled error occurs + during the execution of a request. Specifically, + it enables developers to configure html error pages + to be displayed in place of a error stack trace. + + <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm"> + <error statusCode="403" redirect="NoAccess.htm" /> + <error statusCode="404" redirect="FileNotFound.htm" /> + </customErrors> + --> + + <pages> + <controls> + <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </controls> + </pages> + + <httpHandlers> + <remove verb="*" path="*.asmx"/> + <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/> + </httpHandlers> + <httpModules> + <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </httpModules> + + </system.web> + + <system.codedom> + <compilers> + <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" + type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <providerOption name="CompilerVersion" value="v3.5"/> + <providerOption name="WarnAsError" value="false"/> + </compiler> + </compilers> + </system.codedom> + + <!-- + The system.webServer section is required for running ASP.NET AJAX under Internet + Information Services 7.0. It is not necessary for previous version of IIS. + --> + <system.webServer> + <validation validateIntegratedModeConfiguration="false"/> + <modules> + <remove name="ScriptModule" /> + <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </modules> + <handlers> + <remove name="WebServiceHandlerFactory-Integrated"/> + <remove name="ScriptHandlerFactory" /> + <remove name="ScriptHandlerFactoryAppServices" /> + <remove name="ScriptResource" /> + <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" + type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" + type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> + </handlers> + </system.webServer> + + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/> + <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/> + <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> + </dependentAssembly> + </assemblyBinding> + </runtime> + +</configuration> diff --git a/samples/OpenIdWebRingSsoProvider/op_xrds.aspx b/samples/OpenIdWebRingSsoProvider/op_xrds.aspx new file mode 100644 index 0000000..afcfc75 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/op_xrds.aspx @@ -0,0 +1,19 @@ +<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?> +<%-- +This page is a required as part of the service discovery phase of the openid +protocol (step 1). It simply renders the xml for doing service discovery of +server.aspx using the xrds mechanism. +This XRDS doc is discovered via the user.aspx page. +--%> +<xrds:XRDS + xmlns:xrds="xri://$xrds" + xmlns:openid="http://openid.net/xmlns/1.0" + xmlns="xri://$xrd*($v*2.0)"> + <XRD> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/server</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/server.aspx"))%></URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/samples/OpenIdWebRingSsoProvider/user.aspx b/samples/OpenIdWebRingSsoProvider/user.aspx new file mode 100644 index 0000000..0cef559 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/user.aspx @@ -0,0 +1,22 @@ +<%@ Page Language="C#" AutoEventWireup="true" Inherits="OpenIdWebRingSsoProvider.User" + CodeBehind="user.aspx.cs" %> + +<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.Provider" + TagPrefix="openid" %> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head id="Head1" runat="server"> + <openid:IdentityEndpoint ID="IdentityEndpoint20" runat="server" ProviderEndpointUrl="~/Server.aspx" + XrdsUrl="~/user_xrds.aspx" ProviderVersion="V20" AutoNormalizeRequest="true" + OnNormalizeUri="IdentityEndpoint20_NormalizeUri" /> + <!-- and for backward compatibility with OpenID 1.x RPs... --> + <openid:IdentityEndpoint ID="IdentityEndpoint11" runat="server" ProviderEndpointUrl="~/Server.aspx" + ProviderVersion="V11" /> +</head> +<body> + <p> + OpenID identity page for + <asp:Label runat="server" ID="usernameLabel" EnableViewState="false" /> + </p> +</body> +</html> diff --git a/samples/OpenIdWebRingSsoProvider/user.aspx.cs b/samples/OpenIdWebRingSsoProvider/user.aspx.cs new file mode 100644 index 0000000..8050367 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/user.aspx.cs @@ -0,0 +1,23 @@ +namespace OpenIdWebRingSsoProvider { + using System; + using DotNetOpenAuth.OpenId.Provider; + using OpenIdWebRingSsoProvider.Code; + + /// <summary> + /// This page is a required as part of the service discovery phase of the openid protocol (step 1). + /// </summary> + /// <remarks> + /// <para>The XRDS (or Yadis) content is also rendered to provide the consumer with an alternative discovery mechanism. The Yadis protocol allows the consumer + /// to provide the user with a more flexible range of authentication mechanisms (which ever has been defined in xrds.aspx). See http://en.wikipedia.org/wiki/Yadis.</para> + /// </remarks> + public partial class User : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + this.usernameLabel.Text = Util.ExtractUserName(Page.Request.Url); + } + + protected void IdentityEndpoint20_NormalizeUri(object sender, IdentityEndpointNormalizationEventArgs e) { + string username = Util.ExtractUserName(Page.Request.Url); + e.NormalizedIdentifier = new Uri(Util.BuildIdentityUrl(username)); + } + } +}
\ No newline at end of file diff --git a/samples/OpenIdWebRingSsoProvider/user.aspx.designer.cs b/samples/OpenIdWebRingSsoProvider/user.aspx.designer.cs new file mode 100644 index 0000000..171c898 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/user.aspx.designer.cs @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdWebRingSsoProvider { + + + public partial class User { + + /// <summary> + /// Head1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlHead Head1; + + /// <summary> + /// IdentityEndpoint20 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::DotNetOpenAuth.OpenId.Provider.IdentityEndpoint IdentityEndpoint20; + + /// <summary> + /// IdentityEndpoint11 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::DotNetOpenAuth.OpenId.Provider.IdentityEndpoint IdentityEndpoint11; + + /// <summary> + /// usernameLabel control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.Label usernameLabel; + } +} diff --git a/samples/OpenIdWebRingSsoProvider/user_xrds.aspx b/samples/OpenIdWebRingSsoProvider/user_xrds.aspx new file mode 100644 index 0000000..275e413 --- /dev/null +++ b/samples/OpenIdWebRingSsoProvider/user_xrds.aspx @@ -0,0 +1,24 @@ +<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?> +<%-- +This page is a required as part of the service discovery phase of the openid +protocol (step 1). It simply renders the xml for doing service discovery of +server.aspx using the xrds mechanism. +This XRDS doc is discovered via the user.aspx page. +--%> +<xrds:XRDS + xmlns:xrds="xri://$xrds" + xmlns:openid="http://openid.net/xmlns/1.0" + xmlns="xri://$xrd*($v*2.0)"> + <XRD> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/signon</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/server.aspx"))%></URI> + </Service> + <Service priority="20"> + <Type>http://openid.net/signon/1.0</Type> + <Type>http://openid.net/extensions/sreg/1.1</Type> + <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/server.aspx"))%></URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx b/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx new file mode 100644 index 0000000..d3653e7 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx @@ -0,0 +1,19 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="OpenIdWebRingSsoRelyingParty.Admin.Default" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <div> + You must be an admin! + </div> + <p> + The roles you're assigned come from the trusted Provider's identity assertion. The + sample OP comes hard-wired to assert membership in the Admin and Member roles. + </p> + </form> +</body> +</html> diff --git a/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx.cs b/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx.cs new file mode 100644 index 0000000..94da1f7 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx.cs @@ -0,0 +1,13 @@ +namespace OpenIdWebRingSsoRelyingParty.Admin { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + + public partial class Default : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + } + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx.designer.cs b/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx.designer.cs new file mode 100644 index 0000000..9519fc3 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Admin/Default.aspx.designer.cs @@ -0,0 +1,25 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdWebRingSsoRelyingParty.Admin { + + + public partial class Default { + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/Admin/Web.config b/samples/OpenIdWebRingSsoRelyingParty/Admin/Web.config new file mode 100644 index 0000000..52a5faf --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Admin/Web.config @@ -0,0 +1,9 @@ +<?xml version="1.0"?> +<configuration> + <system.web> + <authorization> + <allow roles="Admin"/> + <deny users="*"/> + </authorization> + </system.web> +</configuration> diff --git a/samples/OpenIdWebRingSsoRelyingParty/AuthTicketRoles.cs b/samples/OpenIdWebRingSsoRelyingParty/AuthTicketRoles.cs new file mode 100644 index 0000000..06783bd --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/AuthTicketRoles.cs @@ -0,0 +1,57 @@ +//----------------------------------------------------------------------- +// <copyright file="AuthTicketRoles.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace OpenIdWebRingSsoRelyingParty { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Principal; + using System.Web; + using System.Web.Security; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OAuth; + using DotNetOpenAuth.OAuth.ChannelElements; + using DotNetOpenAuth.OAuth.Messages; + + /// <summary> + /// An authentication module that utilizes the forms auth ticket cookie + /// as a cache for the users' roles, since those roles are determined by + /// the OpenID Provider and we don't have a local user-roles cache at this + /// RP since those relationships are always managed by the Provider. + /// </summary> + public class AuthTicketRoles : IHttpModule { + #region IHttpModule Members + + /// <summary> + /// Initializes a module and prepares it to handle requests. + /// </summary> + /// <param name="context">An <see cref="T:System.Web.HttpApplication"/> that provides access to the methods, properties, and events common to all application objects within an ASP.NET application</param> + public void Init(HttpApplication context) { + context.AuthenticateRequest += this.application_AuthenticateRequest; + } + + /// <summary> + /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>. + /// </summary> + public void Dispose() { + } + + #endregion + + private void application_AuthenticateRequest(object sender, EventArgs e) { + if (HttpContext.Current.User != null) { + var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName]; + if (cookie != null) { + var ticket = FormsAuthentication.Decrypt(cookie.Value); + if (!string.IsNullOrEmpty(ticket.UserData)) { + string[] roles = ticket.UserData.Split(';'); + HttpContext.Current.User = new GenericPrincipal(HttpContext.Current.User.Identity, roles); + } + } + } + } + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/Default.aspx b/samples/OpenIdWebRingSsoRelyingParty/Default.aspx new file mode 100644 index 0000000..00efb08 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Default.aspx @@ -0,0 +1,29 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="OpenIdWebRingSsoRelyingParty._Default" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title>Sample SSO relying party</title> +</head> +<body> + <form id="form1" runat="server"> + <div> + We've recognized you (via the SSO OP) as: + <asp:LoginName ID="LoginName1" runat="server" /> + <p>Try visiting the <a href="Admin/Default.aspx">Admin area</a></p> + </div> + <p>This sample is of an OpenID Relying Party that acts within a controlled set of + web sites (perhaps all belonging to the same organization). This + particular RP is configured to require authentication for all web pages, and to + always use just one (trusted) OP (the OpenIdWebRingSsoProvider) without ever + prompting the user.</p> + <p>Although the sample OP uses Windows Authentication, and so this RP could easily + do the same, the idea is that the OP and RP may exist on different network + topologies, or the OP may be the only site with access to the user credential + database, or any number of other scenarios where the RP doesn't have the freedom + to authenticate the user the way the OP has, yet this set of web sites want to + have the users only authenticate themselves to one site with one set of + credentials.</p> + </form> +</body> +</html> diff --git a/samples/OpenIdWebRingSsoRelyingParty/Default.aspx.cs b/samples/OpenIdWebRingSsoRelyingParty/Default.aspx.cs new file mode 100644 index 0000000..9e6009e --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Default.aspx.cs @@ -0,0 +1,18 @@ +namespace OpenIdWebRingSsoRelyingParty { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using System.Web.UI; + using System.Web.UI.WebControls; + + public partial class _Default : System.Web.UI.Page { + protected void Page_Load(object sender, EventArgs e) { + if (Array.IndexOf(Request.AcceptTypes, "application/xrds+xml") >= 0) { + Server.Transfer("xrds.aspx"); + } else if (!User.Identity.IsAuthenticated) { + Response.Redirect("Login.aspx"); + } + } + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/Default.aspx.designer.cs b/samples/OpenIdWebRingSsoRelyingParty/Default.aspx.designer.cs new file mode 100644 index 0000000..49d071e --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Default.aspx.designer.cs @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdWebRingSsoRelyingParty { + + + public partial class _Default { + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// <summary> + /// LoginName1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.LoginName LoginName1; + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/Login.aspx b/samples/OpenIdWebRingSsoRelyingParty/Login.aspx new file mode 100644 index 0000000..2e7df2e --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Login.aspx @@ -0,0 +1,26 @@ +<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="OpenIdWebRingSsoRelyingParty.Login" %> + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head runat="server"> + <title></title> +</head> +<body> + <form id="form1" runat="server"> + <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0"> + <asp:View ID="View1" runat="server"> + <div> + Sorry. We couldn't log you in. + </div> + <asp:Label runat="server" ID="errorLabel" /> + <p> + <asp:Button ID="retryButton" runat="server" Text="Try Again" OnClick="retryButton_Click" /> + </p> + </asp:View> + <asp:View ID="View2" runat="server"> + You don't have permission to visit <%=HttpUtility.HtmlEncode(Request.QueryString["ReturnUrl"]) %>. + </asp:View> + </asp:MultiView> + </form> +</body> +</html> diff --git a/samples/OpenIdWebRingSsoRelyingParty/Login.aspx.cs b/samples/OpenIdWebRingSsoRelyingParty/Login.aspx.cs new file mode 100644 index 0000000..ec5af08 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Login.aspx.cs @@ -0,0 +1,96 @@ +namespace OpenIdWebRingSsoRelyingParty { + using System; + using System.Collections.Generic; + using System.Configuration; + using System.Linq; + using System.Web; + using System.Web.Security; + using System.Web.UI; + using System.Web.UI.WebControls; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.AttributeExchange; + using DotNetOpenAuth.OpenId.RelyingParty; + + public partial class Login : System.Web.UI.Page { + private const string RolesAttribute = "http://samples.dotnetopenauth.net/sso/roles"; + + private static OpenIdRelyingParty relyingParty = new OpenIdRelyingParty(); + + static Login() { + // Configure the RP to only allow assertions from our trusted OP endpoint. + relyingParty.EndpointFilter = ep => ep.Uri.AbsoluteUri == ConfigurationManager.AppSettings["SsoProviderOPEndpoint"]; + } + + protected void Page_Load(object sender, EventArgs e) { + UriBuilder returnToBuilder = new UriBuilder(Request.Url); + returnToBuilder.Path = "/login.aspx"; + returnToBuilder.Query = null; + returnToBuilder.Fragment = null; + Uri returnTo = returnToBuilder.Uri; + returnToBuilder.Path = "/"; + Realm realm = returnToBuilder.Uri; + + var response = relyingParty.GetResponse(); + if (response == null) { + if (Request.QueryString["ReturnUrl"] != null && User.Identity.IsAuthenticated) { + // The user must have been directed here because he has insufficient + // permissions to access something. + MultiView1.ActiveViewIndex = 1; + } else { + // Because this is a sample of a controlled SSO environment, + // we don't ask the user which Provider to use... we just send + // them straight off to the one Provider we trust. + var request = relyingParty.CreateRequest( + ConfigurationManager.AppSettings["SsoProviderOPIdentifier"], + realm, + returnTo); + var fetchRequest = new FetchRequest(); + fetchRequest.Attributes.AddOptional(RolesAttribute); + request.AddExtension(fetchRequest); + request.RedirectToProvider(); + } + } else { + switch (response.Status) { + case AuthenticationStatus.Canceled: + this.errorLabel.Text = "Login canceled."; + break; + case AuthenticationStatus.Failed: + this.errorLabel.Text = HttpUtility.HtmlEncode(response.Exception.Message); + break; + case AuthenticationStatus.Authenticated: + IList<string> roles = null; + var fetchResponse = response.GetExtension<FetchResponse>(); + if (fetchResponse != null) { + if (fetchResponse.Attributes.Contains(RolesAttribute)) { + roles = fetchResponse.Attributes[RolesAttribute].Values; + } + } + if (roles == null) { + roles = new List<string>(0); + } + + // Apply the roles to this auth ticket + const int TimeoutInMinutes = 100; // TODO: look up the right value from the web.config file + var ticket = new FormsAuthenticationTicket( + 2, + response.ClaimedIdentifier, + DateTime.Now, + DateTime.Now.AddMinutes(TimeoutInMinutes), + false, // non-persistent, since login is automatic and we wanted updated roles + string.Join(";", roles.ToArray())); + + HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket)); + Response.SetCookie(cookie); + Response.Redirect(Request.QueryString["ReturnUrl"] ?? FormsAuthentication.DefaultUrl); + break; + default: + break; + } + } + } + + protected void retryButton_Click(object sender, EventArgs e) { + Response.Redirect("/login.aspx"); + } + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/Login.aspx.designer.cs b/samples/OpenIdWebRingSsoRelyingParty/Login.aspx.designer.cs new file mode 100644 index 0000000..7ed2669 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Login.aspx.designer.cs @@ -0,0 +1,70 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace OpenIdWebRingSsoRelyingParty { + + + public partial class Login { + + /// <summary> + /// form1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.HtmlControls.HtmlForm form1; + + /// <summary> + /// MultiView1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.MultiView MultiView1; + + /// <summary> + /// View1 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.View View1; + + /// <summary> + /// errorLabel control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.Label errorLabel; + + /// <summary> + /// retryButton control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.Button retryButton; + + /// <summary> + /// View2 control. + /// </summary> + /// <remarks> + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// </remarks> + protected global::System.Web.UI.WebControls.View View2; + } +} diff --git a/samples/OpenIdWebRingSsoRelyingParty/OpenIdWebRingSsoRelyingParty.csproj b/samples/OpenIdWebRingSsoRelyingParty/OpenIdWebRingSsoRelyingParty.csproj new file mode 100644 index 0000000..978a1a57 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/OpenIdWebRingSsoRelyingParty.csproj @@ -0,0 +1,127 @@ +<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>{B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}</ProjectGuid> + <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>OpenIdWebRingSsoRelyingParty</RootNamespace> + <AssemblyName>OpenIdWebRingSsoRelyingParty</AssemblyName> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\</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\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Core"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Data.DataSetExtensions"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Web.Extensions"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Xml.Linq"> + <RequiredTargetFramework>3.5</RequiredTargetFramework> + </Reference> + <Reference Include="System.Drawing" /> + <Reference Include="System.Web" /> + <Reference Include="System.Xml" /> + <Reference Include="System.Configuration" /> + <Reference Include="System.Web.Services" /> + <Reference Include="System.EnterpriseServices" /> + <Reference Include="System.Web.Mobile" /> + </ItemGroup> + <ItemGroup> + <Content Include="Default.aspx" /> + <Content Include="Login.aspx" /> + <Content Include="Web.config" /> + <Content Include="xrds.aspx" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Admin\Default.aspx.cs"> + <DependentUpon>Default.aspx</DependentUpon> + <SubType>ASPXCodeBehind</SubType> + </Compile> + <Compile Include="Admin\Default.aspx.designer.cs"> + <DependentUpon>Default.aspx</DependentUpon> + </Compile> + <Compile Include="Default.aspx.cs"> + <SubType>ASPXCodeBehind</SubType> + <DependentUpon>Default.aspx</DependentUpon> + </Compile> + <Compile Include="Default.aspx.designer.cs"> + <DependentUpon>Default.aspx</DependentUpon> + </Compile> + <Compile Include="Login.aspx.cs"> + <DependentUpon>Login.aspx</DependentUpon> + <SubType>ASPXCodeBehind</SubType> + </Compile> + <Compile Include="Login.aspx.designer.cs"> + <DependentUpon>Login.aspx</DependentUpon> + </Compile> + <Compile Include="AuthTicketRoles.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\..\src\DotNetOpenAuth\DotNetOpenAuth.csproj"> + <Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project> + <Name>DotNetOpenAuth</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Content Include="Admin\Default.aspx" /> + <Content Include="Admin\Web.config" /> + </ItemGroup> + <ItemGroup> + <Folder Include="App_Data\" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> + <ProjectExtensions> + <VisualStudio> + <FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}"> + <WebProjectProperties> + <UseIIS>False</UseIIS> + <AutoAssignPort>False</AutoAssignPort> + <DevelopmentServerPort>39165</DevelopmentServerPort> + <DevelopmentServerVPath>/</DevelopmentServerVPath> + <IISUrl> + </IISUrl> + <NTLMAuthentication>False</NTLMAuthentication> + <UseCustomServer>False</UseCustomServer> + <CustomServerUrl> + </CustomServerUrl> + <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> + </WebProjectProperties> + </FlavorProperties> + </VisualStudio> + </ProjectExtensions> +</Project>
\ No newline at end of file diff --git a/samples/OpenIdWebRingSsoRelyingParty/Properties/AssemblyInfo.cs b/samples/OpenIdWebRingSsoRelyingParty/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..eaf99ae --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("OpenIdWebRingSsoRelyingParty")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft IT")] +[assembly: AssemblyProduct("OpenIdWebRingSsoRelyingParty")] +[assembly: AssemblyCopyright("Copyright © Microsoft IT 2009")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("3d5900ae-111a-45be-96b3-d9e4606ca793")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Revision and Build Numbers +// by using the '*' as shown below: +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/samples/OpenIdWebRingSsoRelyingParty/Web.config b/samples/OpenIdWebRingSsoRelyingParty/Web.config new file mode 100644 index 0000000..94ef60c --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/Web.config @@ -0,0 +1,194 @@ +<?xml version="1.0"?> + +<configuration> + <configSections> + <section name="uri" type="System.Configuration.UriSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> + <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler" requirePermission="false" /> + <section name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection" requirePermission="false" allowLocation="true"/> + <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/> + <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"> + <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" /> + <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> + <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> + <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" /> + </sectionGroup> + </sectionGroup> + </sectionGroup> + </configSections> + + <!-- The uri section is necessary to turn on .NET 3.5 support for IDN (international domain names), + which is necessary for OpenID urls with unicode characters in the domain/host name. + It is also required to put the Uri class into RFC 3986 escaping mode, which OpenID and OAuth require. --> + <uri> + <idn enabled="All"/> + <iriParsing enabled="true"/> + </uri> + + <system.net> + <defaultProxy enabled="true" /> + <settings> + <!-- This setting causes .NET to check certificate revocation lists (CRL) + before trusting HTTPS certificates. But this setting tends to not + be allowed in shared hosting environments. --> + <!--<servicePointManager checkCertificateRevocationList="true"/>--> + </settings> + </system.net> + + <!-- this is an optional configuration section where aspects of dotnetopenauth can be customized --> + <dotNetOpenAuth> + <openid> + <relyingParty> + <security requireSsl="false" /> + <behaviors> + <!-- The following OPTIONAL behavior allows RPs to use SREG only, but be compatible + with OPs that use Attribute Exchange (in various formats). --> + <add type="DotNetOpenAuth.OpenId.Behaviors.AXFetchAsSregTransform, DotNetOpenAuth" /> + <!--<add type="DotNetOpenAuth.OpenId.Behaviors.GsaIcamProfile, DotNetOpenAuth" />--> + </behaviors> + <!-- Uncomment the following to activate the sample custom store. --> + <!--<store type="OpenIdRelyingPartyWebForms.CustomStore, OpenIdRelyingPartyWebForms" />--> + </relyingParty> + </openid> + <messaging> + <untrustedWebRequest> + <whitelistHosts> + <!-- since this is a sample, and will often be used with localhost --> + <add name="localhost" /> + </whitelistHosts> + </untrustedWebRequest> + </messaging> + <!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. --> + <reporting enabled="true" /> + </dotNetOpenAuth> + + <appSettings> + <add key="SsoProviderOPIdentifier" value="http://localhost:39167/" /> + <add key="SsoProviderOPEndpoint" value="http://localhost:39167/server.aspx" /> + </appSettings> + <connectionStrings/> + + <system.web> + <!-- + Set compilation debug="true" to insert debugging + symbols into the compiled page. Because this + affects performance, set this value to true only + during development. + --> + <compilation debug="false"> + + <assemblies> + <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> + </assemblies> + + </compilation> + <!-- + The <authentication> section enables configuration + of the security authentication mode used by + ASP.NET to identify an incoming user. + --> + <authentication mode="Forms"> + <forms name="OpenIdWebRingSsoRelyingParty" /> + </authentication> + <authorization> + <deny users="?"/> + </authorization> + <!-- + The <customErrors> section enables configuration + of what to do if/when an unhandled error occurs + during the execution of a request. Specifically, + it enables developers to configure html error pages + to be displayed in place of a error stack trace. + + <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm"> + <error statusCode="403" redirect="NoAccess.htm" /> + <error statusCode="404" redirect="FileNotFound.htm" /> + </customErrors> + --> + + <pages> + <controls> + <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </controls> + </pages> + + <httpHandlers> + <remove verb="*" path="*.asmx"/> + <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/> + </httpHandlers> + <httpModules> + <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="AuthTicketRoles" type="OpenIdWebRingSsoRelyingParty.AuthTicketRoles, OpenIdWebRingSsoRelyingParty"/> + </httpModules> + + </system.web> + + <system.codedom> + <compilers> + <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" + type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> + <providerOption name="CompilerVersion" value="v3.5"/> + <providerOption name="WarnAsError" value="false"/> + </compiler> + </compilers> + </system.codedom> + + <!-- + The system.webServer section is required for running ASP.NET AJAX under Internet + Information Services 7.0. It is not necessary for previous version of IIS. + --> + <system.webServer> + <validation validateIntegratedModeConfiguration="false"/> + <modules> + <remove name="ScriptModule" /> + <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + </modules> + <handlers> + <remove name="WebServiceHandlerFactory-Integrated"/> + <remove name="ScriptHandlerFactory" /> + <remove name="ScriptHandlerFactoryAppServices" /> + <remove name="ScriptResource" /> + <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" + type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" + type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> + <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> + </handlers> + </system.webServer> + + <runtime> + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> + <dependentAssembly> + <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/> + <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> + </dependentAssembly> + <dependentAssembly> + <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/> + <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/> + </dependentAssembly> + </assemblyBinding> + </runtime> + + <location path="xrds.aspx"> + <system.web> + <authorization> + <allow users="*"/> + </authorization> + </system.web> + </location> + + <location path="default.aspx"> + <system.web> + <authorization> + <allow users="*"/> + </authorization> + </system.web> + </location> +</configuration> diff --git a/samples/OpenIdWebRingSsoRelyingParty/xrds.aspx b/samples/OpenIdWebRingSsoRelyingParty/xrds.aspx new file mode 100644 index 0000000..b45d063 --- /dev/null +++ b/samples/OpenIdWebRingSsoRelyingParty/xrds.aspx @@ -0,0 +1,20 @@ +<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?> +<%-- +This page is a required for relying party discovery per OpenID 2.0. +It allows Providers to call back to the relying party site to confirm the +identity that it is claiming in the realm and return_to URLs. +This page should be pointed to by the 'realm' home page, which in this sample +is default.aspx. +--%> +<xrds:XRDS + xmlns:xrds="xri://$xrds" + xmlns:openid="http://openid.net/xmlns/1.0" + xmlns="xri://$xrd*($v*2.0)"> + <XRD> + <Service priority="1"> + <Type>http://specs.openid.net/auth/2.0/return_to</Type> + <%-- Every page with an OpenID login should be listed here. --%> + <URI priority="1"><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/login.aspx"))%></URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj index 5e92e57..1a05349 100644 --- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj +++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj @@ -204,6 +204,7 @@ <Compile Include="Mocks\InMemoryTokenManager.cs" /> <Compile Include="Mocks\MockHttpRequest.cs" /> <Compile Include="Mocks\MockIdentifier.cs" /> + <Compile Include="Mocks\MockIdentifierDiscoveryService.cs" /> <Compile Include="Mocks\MockOpenIdExtension.cs" /> <Compile Include="Mocks\MockRealm.cs" /> <Compile Include="Mocks\MockTransformationBindingElement.cs" /> @@ -238,6 +239,8 @@ <Compile Include="Messaging\Bindings\StandardReplayProtectionBindingElementTests.cs" /> <Compile Include="OpenId\ChannelElements\SigningBindingElementTests.cs" /> <Compile Include="OpenId\DiffieHellmanTests.cs" /> + <Compile Include="OpenId\DiscoveryServices\UriDiscoveryServiceTests.cs" /> + <Compile Include="OpenId\DiscoveryServices\XriDiscoveryProxyServiceTests.cs" /> <Compile Include="OpenId\Extensions\AttributeExchange\FetchRequestTests.cs" /> <Compile Include="OpenId\Extensions\AttributeExchange\FetchResponseTests.cs" /> <Compile Include="OpenId\Extensions\AttributeExchange\AttributeExchangeRoundtripTests.cs" /> @@ -274,6 +277,7 @@ <Compile Include="OpenId\OpenIdCoordinator.cs" /> <Compile Include="OpenId\AssociationHandshakeTests.cs" /> <Compile Include="OpenId\OpenIdTestBase.cs" /> + <Compile Include="OpenId\OpenIdUtilitiesTests.cs" /> <Compile Include="OpenId\Provider\PerformanceTests.cs" /> <Compile Include="OpenId\ProviderEndpointDescriptionTests.cs" /> <Compile Include="OpenId\Provider\AnonymousRequestTests.cs" /> @@ -289,7 +293,7 @@ <Compile Include="OpenId\RelyingParty\PositiveAuthenticationResponseTests.cs" /> <Compile Include="OpenId\RelyingParty\OpenIdRelyingPartyTests.cs" /> <Compile Include="OpenId\RelyingParty\RelyingPartySecuritySettingsTests.cs" /> - <Compile Include="OpenId\RelyingParty\ServiceEndpointTests.cs" /> + <Compile Include="OpenId\RelyingParty\IdentifierDiscoveryResultTests.cs" /> <Compile Include="OpenId\UriIdentifierTests.cs" /> <Compile Include="OpenId\XriIdentifierTests.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> @@ -344,6 +348,9 @@ <None Include="App.config" /> </ItemGroup> <ItemGroup> + <EmbeddedResource Include="OpenId\Discovery\xrdsdiscovery\xrds20dual.xml" /> + </ItemGroup> + <ItemGroup> <Folder Include="OpenId\UI\" /> </ItemGroup> <ItemGroup> diff --git a/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs b/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs index 0213a33..c18ea33 100644 --- a/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs +++ b/src/DotNetOpenAuth.Test/Mocks/MockHttpRequest.cs @@ -83,7 +83,7 @@ namespace DotNetOpenAuth.Test.Mocks { } } - internal void RegisterMockXrdsResponse(ServiceEndpoint endpoint) { + internal void RegisterMockXrdsResponse(IdentifierDiscoveryResult endpoint) { Contract.Requires<ArgumentNullException>(endpoint != null); string identityUri; @@ -92,10 +92,10 @@ namespace DotNetOpenAuth.Test.Mocks { } else { identityUri = endpoint.UserSuppliedIdentifier ?? endpoint.ClaimedIdentifier; } - this.RegisterMockXrdsResponse(new Uri(identityUri), new ServiceEndpoint[] { endpoint }); + this.RegisterMockXrdsResponse(new Uri(identityUri), new IdentifierDiscoveryResult[] { endpoint }); } - internal void RegisterMockXrdsResponse(Uri respondingUri, IEnumerable<ServiceEndpoint> endpoints) { + internal void RegisterMockXrdsResponse(Uri respondingUri, IEnumerable<IdentifierDiscoveryResult> endpoints) { Contract.Requires<ArgumentNullException>(endpoints != null); StringBuilder xrds = new StringBuilder(); @@ -130,12 +130,12 @@ namespace DotNetOpenAuth.Test.Mocks { this.RegisterMockResponse(respondingUri, ContentTypes.Xrds, xrds.ToString()); } - internal void RegisterMockXrdsResponse(UriIdentifier directedIdentityAssignedIdentifier, ServiceEndpoint providerEndpoint) { - ServiceEndpoint identityEndpoint = ServiceEndpoint.CreateForClaimedIdentifier( + internal void RegisterMockXrdsResponse(UriIdentifier directedIdentityAssignedIdentifier, IdentifierDiscoveryResult providerEndpoint) { + IdentifierDiscoveryResult identityEndpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier( directedIdentityAssignedIdentifier, directedIdentityAssignedIdentifier, - providerEndpoint.ProviderEndpoint, - providerEndpoint.ProviderDescription, + providerEndpoint.ProviderLocalIdentifier, + new ProviderEndpointDescription(providerEndpoint.ProviderEndpoint, providerEndpoint.Capabilities), 10, 10); this.RegisterMockXrdsResponse(identityEndpoint); diff --git a/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs b/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs index 346dde9..9f032b8 100644 --- a/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs +++ b/src/DotNetOpenAuth.Test/Mocks/MockIdentifier.cs @@ -18,13 +18,13 @@ namespace DotNetOpenAuth.Test.Mocks { /// having a dependency on a hosted web site to actually perform discovery on. /// </summary> internal class MockIdentifier : Identifier { - private IEnumerable<ServiceEndpoint> endpoints; + private IEnumerable<IdentifierDiscoveryResult> endpoints; private MockHttpRequest mockHttpRequest; private Identifier wrappedIdentifier; - public MockIdentifier(Identifier wrappedIdentifier, MockHttpRequest mockHttpRequest, IEnumerable<ServiceEndpoint> endpoints) + public MockIdentifier(Identifier wrappedIdentifier, MockHttpRequest mockHttpRequest, IEnumerable<IdentifierDiscoveryResult> endpoints) : base(wrappedIdentifier.OriginalString, false) { Contract.Requires<ArgumentNullException>(wrappedIdentifier != null); Contract.Requires<ArgumentNullException>(mockHttpRequest != null); @@ -39,6 +39,10 @@ namespace DotNetOpenAuth.Test.Mocks { mockHttpRequest.RegisterMockXrdsResponse(new Uri(wrappedIdentifier.ToString()), endpoints); } + internal IEnumerable<IdentifierDiscoveryResult> DiscoveryEndpoints { + get { return this.endpoints; } + } + public override string ToString() { return this.wrappedIdentifier.ToString(); } @@ -51,10 +55,6 @@ namespace DotNetOpenAuth.Test.Mocks { return this.wrappedIdentifier.GetHashCode(); } - internal override IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { - return this.endpoints; - } - internal override Identifier TrimFragment() { return this; } diff --git a/src/DotNetOpenAuth.Test/Mocks/MockIdentifierDiscoveryService.cs b/src/DotNetOpenAuth.Test/Mocks/MockIdentifierDiscoveryService.cs new file mode 100644 index 0000000..d74258d --- /dev/null +++ b/src/DotNetOpenAuth.Test/Mocks/MockIdentifierDiscoveryService.cs @@ -0,0 +1,47 @@ +//----------------------------------------------------------------------- +// <copyright file="MockIdentifierDiscoveryService.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.Mocks { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + + internal class MockIdentifierDiscoveryService : IIdentifierDiscoveryService { + /// <summary> + /// Initializes a new instance of the <see cref="MockIdentifierDiscoveryService"/> class. + /// </summary> + public MockIdentifierDiscoveryService() { + } + + #region IIdentifierDiscoveryService Members + + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + public IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { + var mockIdentifier = identifier as MockIdentifier; + if (mockIdentifier == null) { + abortDiscoveryChain = false; + return Enumerable.Empty<IdentifierDiscoveryResult>(); + } + + abortDiscoveryChain = true; + return mockIdentifier.DiscoveryEndpoints; + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs index af3b1b1..a9d2f56 100644 --- a/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/AssociationHandshakeTests.cs @@ -318,9 +318,9 @@ namespace DotNetOpenAuth.Test.OpenId { private void ParameterizedAssociationTest( ProviderEndpointDescription opDescription, string expectedAssociationType) { - Protocol protocol = Protocol.Lookup(opDescription.ProtocolVersion); + Protocol protocol = Protocol.Lookup(Protocol.Lookup(opDescription.Version).ProtocolVersion); bool expectSuccess = expectedAssociationType != null; - bool expectDiffieHellman = !opDescription.Endpoint.IsTransportSecure(); + bool expectDiffieHellman = !opDescription.Uri.IsTransportSecure(); Association rpAssociation = null, opAssociation; AssociateSuccessfulResponse associateSuccessfulResponse = null; AssociateUnsuccessfulResponse associateUnsuccessfulResponse = null; @@ -337,7 +337,7 @@ namespace DotNetOpenAuth.Test.OpenId { op.SendResponse(req); }); coordinator.IncomingMessageFilter = message => { - Assert.AreSame(opDescription.ProtocolVersion, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, opDescription.ProtocolVersion); + Assert.AreSame(opDescription.Version, message.Version, "The message was recognized as version {0} but was expected to be {1}.", message.Version, Protocol.Lookup(opDescription.Version).ProtocolVersion); var associateSuccess = message as AssociateSuccessfulResponse; var associateFailed = message as AssociateUnsuccessfulResponse; if (associateSuccess != null) { @@ -348,7 +348,7 @@ namespace DotNetOpenAuth.Test.OpenId { } }; coordinator.OutgoingMessageFilter = message => { - Assert.AreSame(opDescription.ProtocolVersion, message.Version, "The message was for version {0} but was expected to be for {1}.", message.Version, opDescription.ProtocolVersion); + Assert.AreEqual(opDescription.Version, message.Version, "The message was for version {0} but was expected to be for {1}.", message.Version, opDescription.Version); }; coordinator.Run(); @@ -356,7 +356,7 @@ namespace DotNetOpenAuth.Test.OpenId { if (expectSuccess) { Assert.IsNotNull(rpAssociation); - Assert.AreSame(rpAssociation, associationManagerAccessor.associationStore.GetAssociation(opDescription.Endpoint, rpAssociation.Handle)); + Assert.AreSame(rpAssociation, associationManagerAccessor.associationStore.GetAssociation(opDescription.Uri, rpAssociation.Handle)); opAssociation = coordinator.Provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, rpAssociation.Handle); Assert.IsNotNull(opAssociation, "The Provider should have stored the association."); @@ -375,7 +375,7 @@ namespace DotNetOpenAuth.Test.OpenId { var unencryptedResponse = (AssociateUnencryptedResponse)associateSuccessfulResponse; } } else { - Assert.IsNull(associationManagerAccessor.associationStore.GetAssociation(opDescription.Endpoint, new RelyingPartySecuritySettings())); + Assert.IsNull(associationManagerAccessor.associationStore.GetAssociation(opDescription.Uri, new RelyingPartySecuritySettings())); Assert.IsNull(coordinator.Provider.AssociationStore.GetAssociation(AssociationRelyingPartyType.Smart, new ProviderSecuritySettings())); } } diff --git a/src/DotNetOpenAuth.Test/OpenId/Discovery/xrdsdiscovery/xrds20dual.xml b/src/DotNetOpenAuth.Test/OpenId/Discovery/xrdsdiscovery/xrds20dual.xml new file mode 100644 index 0000000..9e6a66b --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/Discovery/xrdsdiscovery/xrds20dual.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xrds:XRDS + xmlns:xrds="xri://$xrds" + xmlns:openid="http://openid.net/xmlns/1.0" + xmlns="xri://$xrd*($v*2.0)"> + <XRD> + <Service priority="10"> + <Type>http://specs.openid.net/auth/2.0/signon</Type> + <Type>http://specs.openid.net/auth/2.0/server</Type> + <URI>http://a/b</URI> + </Service> + </XRD> +</xrds:XRDS> diff --git a/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/UriDiscoveryServiceTests.cs b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/UriDiscoveryServiceTests.cs new file mode 100644 index 0000000..f71d82f --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/UriDiscoveryServiceTests.cs @@ -0,0 +1,286 @@ +//----------------------------------------------------------------------- +// <copyright file="UriDiscoveryServiceTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId.DiscoveryServices { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using System.Web; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + using DotNetOpenAuth.OpenId.RelyingParty; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class UriDiscoveryServiceTests : OpenIdTestBase { + [TestMethod] + public void DiscoveryWithRedirects() { + Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, false); + + // Add a couple of chained redirect pages that lead to the claimedId. + Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); + Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); + this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); + this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); + + // don't require secure SSL discovery for this test. + Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, false); + Assert.AreEqual(1, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod] + public void DiscoverRequireSslWithSecureRedirects() { + Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); + + // Add a couple of chained redirect pages that lead to the claimedId. + // All redirects should be secure. + Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); + Uri secureMidpointUri = new Uri("https://localhost/secureStop"); + this.MockResponder.RegisterMockRedirect(userSuppliedUri, secureMidpointUri); + this.MockResponder.RegisterMockRedirect(secureMidpointUri, new Uri(claimedId.ToString())); + + Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); + Assert.AreEqual(1, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod, ExpectedException(typeof(ProtocolException))] + public void DiscoverRequireSslWithInsecureRedirect() { + Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); + + // Add a couple of chained redirect pages that lead to the claimedId. + // Include an insecure HTTP jump in those redirects to verify that + // the ultimate endpoint is never found as a result of high security profile. + Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); + Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); + this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); + this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); + + Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); + this.Discover(userSuppliedIdentifier); + } + + [TestMethod] + public void DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead() { + var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); + Uri secureClaimedUri = new Uri("https://localhost/secureId"); + + string html = string.Format("<html><head><meta http-equiv='X-XRDS-Location' content='{0}'/></head><body></body></html>", insecureXrdsSource); + this.MockResponder.RegisterMockResponse(secureClaimedUri, "text/html", html); + + Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true); + Assert.AreEqual(0, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod] + public void DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader() { + var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); + + string html = "<html><head></head><body></body></html>"; + WebHeaderCollection headers = new WebHeaderCollection { + { "X-XRDS-Location", insecureXrdsSource } + }; + this.MockResponder.RegisterMockResponse(VanityUriSsl, VanityUriSsl, "text/html", headers, html); + + Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); + Assert.AreEqual(0, this.Discover(userSuppliedIdentifier).Count()); + } + + [TestMethod] + public void DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags() { + var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); + string html = string.Format( + @" + <html><head> + <meta http-equiv='X-XRDS-Location' content='{0}'/> <!-- this one will be insecure and ignored --> + <link rel='openid2.provider' href='{1}' /> + <link rel='openid2.local_id' href='{2}' /> + </head><body></body></html>", + HttpUtility.HtmlEncode(insecureXrdsSource), + HttpUtility.HtmlEncode(OPUriSsl.AbsoluteUri), + HttpUtility.HtmlEncode(OPLocalIdentifiersSsl[1].AbsoluteUri)); + this.MockResponder.RegisterMockResponse(VanityUriSsl, "text/html", html); + + Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); + + // We verify that the XRDS was ignored and the LINK tags were used + // because the XRDS OP-LocalIdentifier uses different local identifiers. + Assert.AreEqual(OPLocalIdentifiersSsl[1], this.Discover(userSuppliedIdentifier).Single().ProviderLocalIdentifier); + } + + [TestMethod] + public void DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds() { + var insecureEndpoint = GetServiceEndpoint(0, ProtocolVersion.V20, 10, false); + var secureEndpoint = GetServiceEndpoint(1, ProtocolVersion.V20, 20, true); + UriIdentifier secureClaimedId = new UriIdentifier(VanityUriSsl, true); + this.MockResponder.RegisterMockXrdsResponse(secureClaimedId, new IdentifierDiscoveryResult[] { insecureEndpoint, secureEndpoint }); + Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, this.Discover(secureClaimedId).Single().ProviderLocalIdentifier); + } + + [TestMethod] + public void XrdsDirectDiscovery_10() { + this.FailDiscoverXrds("xrds-irrelevant"); + this.DiscoverXrds("xrds10", ProtocolVersion.V10, null, "http://a/b"); + this.DiscoverXrds("xrds11", ProtocolVersion.V11, null, "http://a/b"); + this.DiscoverXrds("xrds1020", ProtocolVersion.V10, null, "http://a/b"); + } + + [TestMethod] + public void XrdsDirectDiscovery_20() { + this.DiscoverXrds("xrds20", ProtocolVersion.V20, null, "http://a/b"); + this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b"); + this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b"); + } + + [TestMethod] + public void HtmlDiscover_11() { + this.DiscoverHtml("html10prov", ProtocolVersion.V11, null, "http://a/b"); + this.DiscoverHtml("html10both", ProtocolVersion.V11, "http://c/d", "http://a/b"); + this.FailDiscoverHtml("html10del"); + + // Verify that HTML discovery generates the 1.x endpoints when appropriate + this.DiscoverHtml("html2010", ProtocolVersion.V11, "http://g/h", "http://e/f"); + this.DiscoverHtml("html1020", ProtocolVersion.V11, "http://g/h", "http://e/f"); + this.DiscoverHtml("html2010combinedA", ProtocolVersion.V11, "http://c/d", "http://a/b"); + this.DiscoverHtml("html2010combinedB", ProtocolVersion.V11, "http://c/d", "http://a/b"); + this.DiscoverHtml("html2010combinedC", ProtocolVersion.V11, "http://c/d", "http://a/b"); + } + + [TestMethod] + public void HtmlDiscover_20() { + this.DiscoverHtml("html20prov", ProtocolVersion.V20, null, "http://a/b"); + this.DiscoverHtml("html20both", ProtocolVersion.V20, "http://c/d", "http://a/b"); + this.FailDiscoverHtml("html20del"); + this.DiscoverHtml("html2010", ProtocolVersion.V20, "http://c/d", "http://a/b"); + this.DiscoverHtml("html1020", ProtocolVersion.V20, "http://c/d", "http://a/b"); + this.DiscoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d", "http://a/b"); + this.DiscoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d", "http://a/b"); + this.DiscoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d", "http://a/b"); + this.FailDiscoverHtml("html20relative"); + } + + [TestMethod] + public void XrdsDiscoveryFromHead() { + this.MockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml")); + this.DiscoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null, "http://a/b"); + } + + [TestMethod] + public void XrdsDiscoveryFromHttpHeader() { + WebHeaderCollection headers = new WebHeaderCollection(); + headers.Add("X-XRDS-Location", new Uri("http://localhost/xrds1020.xml").AbsoluteUri); + this.MockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml")); + this.DiscoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, "http://a/b", headers); + } + + /// <summary> + /// Verifies that a dual identifier yields only one service endpoint by default. + /// </summary> + [TestMethod] + public void DualIdentifierOffByDefault() { + this.MockResponder.RegisterMockResponse(VanityUri, "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds20dual.xml")); + var results = this.Discover(VanityUri).ToList(); + Assert.AreEqual(1, results.Count(r => r.ClaimedIdentifier == r.Protocol.ClaimedIdentifierForOPIdentifier), "OP Identifier missing from discovery results."); + Assert.AreEqual(1, results.Count, "Unexpected additional services discovered."); + } + + /// <summary> + /// Verifies that a dual identifier yields two service endpoints when that feature is turned on. + /// </summary> + [TestMethod] + public void DualIdentifier() { + this.MockResponder.RegisterMockResponse(VanityUri, "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds20dual.xml")); + var rp = this.CreateRelyingParty(true); + rp.Channel.WebRequestHandler = this.RequestHandler; + rp.SecuritySettings.AllowDualPurposeIdentifiers = true; + var results = rp.Discover(VanityUri).ToList(); + Assert.AreEqual(1, results.Count(r => r.ClaimedIdentifier == r.Protocol.ClaimedIdentifierForOPIdentifier), "OP Identifier missing from discovery results."); + Assert.AreEqual(1, results.Count(r => r.ClaimedIdentifier == VanityUri), "Claimed identifier missing from discovery results."); + Assert.AreEqual(2, results.Count, "Unexpected additional services discovered."); + } + + private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool expectSreg, bool useRedirect) { + this.Discover(url, version, expectedLocalId, providerEndpoint, expectSreg, useRedirect, null); + } + + private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool expectSreg, bool useRedirect, WebHeaderCollection headers) { + Protocol protocol = Protocol.Lookup(version); + Uri baseUrl = new Uri("http://localhost/"); + UriIdentifier claimedId = new Uri(baseUrl, url); + UriIdentifier userSuppliedIdentifier = new Uri(baseUrl, "Discovery/htmldiscovery/redirect.aspx?target=" + url); + if (expectedLocalId == null) { + expectedLocalId = claimedId; + } + Identifier idToDiscover = useRedirect ? userSuppliedIdentifier : claimedId; + + string contentType; + if (url.EndsWith("html")) { + contentType = "text/html"; + } else if (url.EndsWith("xml")) { + contentType = "application/xrds+xml"; + } else { + throw new InvalidOperationException(); + } + this.MockResponder.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType, headers ?? new WebHeaderCollection(), LoadEmbeddedFile(url)); + + IdentifierDiscoveryResult expected = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + claimedId, + expectedLocalId, + new ProviderEndpointDescription(new Uri(providerEndpoint), new string[] { protocol.ClaimedIdentifierServiceTypeURI }), // services aren't checked by Equals + null, + null); + + IdentifierDiscoveryResult se = this.Discover(idToDiscover).FirstOrDefault(ep => ep.Equals(expected)); + Assert.IsNotNull(se, url + " failed to be discovered."); + + // Do extra checking of service type URIs, which aren't included in + // the ServiceEndpoint.Equals method. + Assert.AreEqual(expectSreg ? 2 : 1, se.Capabilities.Count); + Assert.IsTrue(se.Capabilities.Contains(protocol.ClaimedIdentifierServiceTypeURI)); + Assert.AreEqual(expectSreg, se.IsExtensionSupported<ClaimsRequest>()); + } + + private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) { + this.DiscoverXrds(page, version, expectedLocalId, providerEndpoint, null); + } + + private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, WebHeaderCollection headers) { + if (!page.Contains(".")) { + page += ".xml"; + } + this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, providerEndpoint, true, false, headers); + this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, providerEndpoint, true, true, headers); + } + + private void DiscoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool useRedirect) { + this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, providerEndpoint, false, useRedirect); + } + + private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) { + string page = scenario + ".html"; + this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, false); + this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, true); + } + + private void FailDiscover(string url) { + UriIdentifier userSuppliedId = new Uri(new Uri("http://localhost"), url); + + this.MockResponder.RegisterMockResponse(new Uri(userSuppliedId), userSuppliedId, "text/html", LoadEmbeddedFile(url)); + + Assert.AreEqual(0, this.Discover(userSuppliedId).Count()); // ... but that no endpoint info is discoverable + } + + private void FailDiscoverHtml(string scenario) { + this.FailDiscover("/Discovery/htmldiscovery/" + scenario + ".html"); + } + + private void FailDiscoverXrds(string scenario) { + this.FailDiscover("/Discovery/xrdsdiscovery/" + scenario + ".xml"); + } + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/XriDiscoveryProxyServiceTests.cs b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/XriDiscoveryProxyServiceTests.cs new file mode 100644 index 0000000..9247bb6 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/DiscoveryServices/XriDiscoveryProxyServiceTests.cs @@ -0,0 +1,394 @@ +//----------------------------------------------------------------------- +// <copyright file="XriDiscoveryProxyServiceTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId.DiscoveryServices { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.RelyingParty; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class XriDiscoveryProxyServiceTests : OpenIdTestBase { + [TestMethod] + public void Discover() { + string xrds = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> + <Query>*Arnott</Query> + <Status ceid='off' cid='verified' code='100'/> + <Expires>2008-07-14T02:03:24.000Z</Expires> + <ProviderID>xri://=</ProviderID> + <LocalID>!9b72.7dd1.50a9.5ccd</LocalID> + <CanonicalID>=!9B72.7DD1.50A9.5CCD</CanonicalID> + + <Service priority='10'> + <ProviderID>xri://!!1008</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='default' select='false'/> + <Path select='true'>(+contact)</Path> + <Path match='null' select='false'/> + <URI append='qxri' priority='1'>http://1id.com/contact/</URI> + + </Service> + <Service priority='10'> + <ProviderID>xri://!!1008</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <URI append='qxri' priority='1'>http://1id.com/</URI> + </Service> + + <Service priority='10'> + <ProviderID>xri://!!1008</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='10'>http://1id.com/sso</URI> + </Service> +</XRD>"; + Dictionary<string, string> mocks = new Dictionary<string, string> { + { "https://xri.net/=Arnott?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, + { "https://xri.net/=!9B72.7DD1.50A9.5CCD?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, + }; + this.MockResponder.RegisterMockXrdsResponses(mocks); + + string expectedCanonicalId = "=!9B72.7DD1.50A9.5CCD"; + IdentifierDiscoveryResult se = this.VerifyCanonicalId("=Arnott", expectedCanonicalId); + Assert.AreEqual(Protocol.V10, Protocol.Lookup(se.Version)); + Assert.AreEqual("http://1id.com/sso", se.ProviderEndpoint.ToString()); + Assert.AreEqual(se.ClaimedIdentifier, se.ProviderLocalIdentifier); + Assert.AreEqual("=Arnott", se.FriendlyIdentifierForDisplay); + } + + [TestMethod] + public void DiscoverCommunityInameCanonicalIDs() { + string llliResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> + <Query>*llli</Query> + <Status ceid='off' cid='verified' code='100'/> + <Expires>2008-07-14T02:21:06.000Z</Expires> + <ProviderID>xri://@</ProviderID> + <LocalID>!72cd.a072.157e.a9c6</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6</CanonicalID> + <Service priority='10'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type match='null' select='false'/> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Path match='default'/> + <Path>(+index)</Path> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> + <Service priority='10'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType>application/xrds+xml;trust=none</MediaType> + <URI priority='10'>http://resolve.ezibroker.net/resolve/@llli/</URI> + </Service> + <Service priority='10'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> +</XRD> +"; + string llliAreaResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*area</Query> + <Status cid='verified' code='100'>SUCCESS</Status> + <ServerStatus code='100'>SUCCESS</ServerStatus> + <Expires>2008-07-15T01:21:07.000Z</Expires> + <ProviderID>xri://!!1003</ProviderID> + <LocalID>0000.0000.3B9A.CA0C</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C</CanonicalID> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path>(+index)</Path> + <Path match='default'/> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType>application/xrds+xml;trust=none</MediaType> + <URI>http://resolve.ezibroker.net/resolve/@llli*area/</URI> + </Service> +</XRD>"; + string llliAreaCanadaUnattachedResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*canada.unattached</Query> + <Status cid='verified' code='100'>SUCCESS</Status> + <ServerStatus code='100'>SUCCESS</ServerStatus> + <Expires>2008-07-15T01:21:08.000Z</Expires> + <ProviderID>xri://!!1003</ProviderID> + <LocalID>0000.0000.3B9A.CA41</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41</CanonicalID> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path>(+index)</Path> + <Path match='default'/> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType>application/xrds+xml;trust=none</MediaType> + <URI>http://resolve.ezibroker.net/resolve/@llli*area*canada.unattached/</URI> + </Service> +</XRD>"; + string llliAreaCanadaUnattachedAdaResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*ada</Query> + <Status cid='verified' code='100'>SUCCESS</Status> + <ServerStatus code='100'>SUCCESS</ServerStatus> + <Expires>2008-07-15T01:21:10.000Z</Expires> + <ProviderID>xri://!!1003</ProviderID> + <LocalID>0000.0000.3B9A.CA01</LocalID> + <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01</CanonicalID> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <URI append='none' priority='1'>https://login.llli.org/server/</URI> + </Service> + <Service> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> + </Service> + <Service priority='1'> + <ProviderID>xri://!!1003!103</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path>(+index)</Path> + <Path match='default'/> + <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> + </Service> +</XRD>"; + string webResponse = @"<?xml version='1.0' encoding='UTF-8'?> +<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> + <Query>*Web</Query> + <Status ceid='off' cid='verified' code='100'/> + <Expires>2008-07-14T02:21:12.000Z</Expires> + <ProviderID>xri://=</ProviderID> + <LocalID>!91f2.8153.f600.ae24</LocalID> + <CanonicalID>=!91F2.8153.F600.AE24</CanonicalID> + <Service priority='10'> + <Type select='true'>xri://+i-service*(+locator)*($v*1.0)</Type> + <Path select='true'>(+locator)</Path> + <MediaType match='default' select='false'/> + <URI append='qxri'>http://locator.fullxri.com/locator/</URI> + </Service> + <Service priority='10'> + <ProviderID>xri://=web</ProviderID> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <Type select='true'>xri://$res*auth*($v*2.0)</Type> + <MediaType select='true'>application/xrds+xml</MediaType> + <URI append='qxri' priority='1'>https://resolve.freexri.com/ns/=web/</URI> + <URI append='qxri' priority='2'>http://resolve.freexri.com/ns/=web/</URI> + </Service> + <Service priority='10'> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Type select='true'>http://specs.openid.net/auth/2.0/signon</Type> + <Path select='true'>(+login)</Path> + <Path match='default' select='false'/> + <MediaType match='default' select='false'/> + <URI append='none' priority='2'>http://authn.fullxri.com/authentication/</URI> + <URI append='none' priority='1'>https://authn.fullxri.com/authentication/</URI> + </Service> + <Service priority='10'> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null' select='false'/> + <Path select='true'>(+contact)</Path> + <Path match='null' select='false'/> + <MediaType match='default' select='false'/> + <URI append='qxri'>http://contact.fullxri.com/contact/</URI> + </Service> + <KeyInfo xmlns='http://www.w3.org/2000/09/xmldsig#'> + <X509Data> + <X509Certificate> +MIIExzCCA6+gAwIBAgIJAM+MlFr0Sth6MA0GCSqGSIb3DQEBBQUAMIGdMR8wHQYD +VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE +CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs +YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs +YWluLmVkdTAeFw0wNjA4MTcxOTU5NTNaFw0xMTA4MTYxOTU5NTNaMIGdMR8wHQYD +VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE +CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs +YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs +YWluLmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6uFqas4dK6 +A2wTZL0viRQNJrPyFnFBDSZGib/2ijhgzed/vvmZIBM9sFpwahcuR5hvyKUe37/c +/RSZXoNDi/eiNOx4qb0l9UB6bd8qvc4V1PnLE7L+ZYcmwrvTKm4x8qXMgEv1wca2 +FPsreHNPdLiTUZ8v0tDTWi3Mgi7y47VTzJaTkcfmO1nL6xAtln5sLdH0PbMM3LAp +T1d3nwI3VdbhqqZ+6+OKEuC8gk5iH4lfrbr6C9bYS6vzIKrotHpZ3N2aIC3NMjJD +PMw/mfCuADfRNlHXgZW+0zyUkwGTMDea8qgsoAMWJGdeTIw8I1I3RhnbgLzdsNQl +b/1ZXx1uJRUCAwEAAaOCAQYwggECMB0GA1UdDgQWBBQe+xSjYTrlfraJARjMxscb +j36jvDCB0gYDVR0jBIHKMIHHgBQe+xSjYTrlfraJARjMxscbj36jvKGBo6SBoDCB +nTEfMB0GA1UEAxMWU3VwZXJ2aWxsYWluOiBUaGUgUm9vdDELMAkGA1UEBhMCVVMx +ETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZHb3RoYW0xIDAeBgNVBAoTF1N1 +cGVydmlsbGFpbiBVbml2ZXJzaXR5MScwJQYJKoZIhvcNAQkBFhhwZW5ndWluQHN1 +cGVydmlsbGFpbi5lZHWCCQDPjJRa9ErYejAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBQUAA4IBAQC4SPBDGYAxfbXd8N5OvG0drM7a5hjXfcCZpiILlPSRpxp79yh7 +I5vVWxBxUfolwbei7PTBVy7CE27SUbSICeqWjcDCfjNjiZk6mLS80rm/TdLrHSyM ++Ujlw9MGcBGaLI+sdziDUMtTQDpeAyQTaGVbh1mx5874Hlo1VXqGYNo0RwR+iLfs +x48VuO6GbWVyxtktkE2ypz1KLWiyI056YynydRvuBCBHeRqGUixPlH9CrmeSCP2S +sfbiKnMOGXjIYbvbsTAMdW2iqg6IWa/fgxhvZoAXChM9bkhisJQc0qD0J5TJQwgr +uEyb50RJ7DWmXctSC0b3eymZ2lSXxAWNOsNy + </X509Certificate> + </X509Data> + </KeyInfo> +</XRD>"; + this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { + { "https://xri.net/@llli?_xrd_r=application/xrd%2Bxml;sep=false", llliResponse }, + { "https://xri.net/@llli*area?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaResponse }, + { "https://xri.net/@llli*area*canada.unattached?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedResponse }, + { "https://xri.net/@llli*area*canada.unattached*ada?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedAdaResponse }, + { "https://xri.net/=Web?_xrd_r=application/xrd%2Bxml;sep=false", webResponse }, + }); + this.VerifyCanonicalId("@llli", "@!72CD.A072.157E.A9C6"); + this.VerifyCanonicalId("@llli*area", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C"); + this.VerifyCanonicalId("@llli*area*canada.unattached", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41"); + this.VerifyCanonicalId("@llli*area*canada.unattached*ada", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01"); + this.VerifyCanonicalId("=Web", "=!91F2.8153.F600.AE24"); + } + + [TestMethod] + public void DiscoveryCommunityInameDelegateWithoutCanonicalID() { + this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { + { "https://xri.net/=Web*andrew.arnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*andrew.arnott</Query> + <Status cid='absent' code='100'>Success</Status> + <ServerStatus code='100'>Success</ServerStatus> + <Expires>2008-07-14T03:30:59.722Z</Expires> + <ProviderID>=!91F2.8153.F600.AE24</ProviderID> + <Service> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Path select='true'>(+login)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='none' priority='2'>http://www.myopenid.com/server</URI> + <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <MediaType match='default'/> + <URI append='qxri'>http://contact.freexri.com/contact/</URI> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Path select='true'>(+index)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Path select='true'>(+login)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='none' priority='2'>http://authn.freexri.com/authentication/</URI> + <URI append='none' priority='1'>https://authn.freexri.com/authentication/</URI> + </Service> + <ServedBy>OpenXRI</ServedBy> +</XRD>" }, + { "https://xri.net/@id*andrewarnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> +<XRD xmlns='xri://$xrd*($v*2.0)'> + <Query>*andrewarnott</Query> + <Status cid='absent' code='100'>Success</Status> + <ServerStatus code='100'>Success</ServerStatus> + <Expires>2008-07-14T03:31:00.466Z</Expires> + <ProviderID>@!B1E8.C27B.E41C.25C3</ProviderID> + <Service> + <Type select='true'>http://openid.net/signon/1.0</Type> + <Path select='true'>(+login)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='none' priority='2'>http://www.myopenid.com/server</URI> + <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> + <Type match='null'/> + <Path select='true'>(+contact)</Path> + <Path match='null'/> + <MediaType match='default'/> + <URI append='qxri'>http://contact.freexri.com/contact/</URI> + </Service> + <Service> + <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> + <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> + <Path select='true'>(+index)</Path> + <Path match='default'/> + <MediaType match='default'/> + <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> + </Service> + <ServedBy>OpenXRI</ServedBy> +</XRD>" }, + }); + // Consistent with spec section 7.3.2.3, we do not permit + // delegation on XRI discovery when there is no CanonicalID present. + this.VerifyCanonicalId("=Web*andrew.arnott", null); + this.VerifyCanonicalId("@id*andrewarnott", null); + } + + private IdentifierDiscoveryResult VerifyCanonicalId(Identifier iname, string expectedClaimedIdentifier) { + var se = this.Discover(iname).FirstOrDefault(); + if (expectedClaimedIdentifier != null) { + Assert.IsNotNull(se); + Assert.AreEqual(expectedClaimedIdentifier, se.ClaimedIdentifier.ToString(), "i-name {0} discovery resulted in unexpected CanonicalId", iname); + Assert.IsTrue(se.Capabilities.Count > 0); + } else { + Assert.IsNull(se); + } + return se; + } + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs index ba5e335..b913f96 100644 --- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs @@ -5,6 +5,7 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.Test.OpenId { + using System.Collections.ObjectModel; using System.Linq; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.Extensions; @@ -118,11 +119,9 @@ namespace DotNetOpenAuth.Test.OpenId { /// </summary> /// <param name="typeUri">The type URI.</param> private void InjectAdvertisedTypeUri(string typeUri) { - var serviceEndpoint = ServiceEndpoint_Accessor.AttachShadow(((ServiceEndpoint)this.authReq.Provider)); - serviceEndpoint.ProviderDescription = ProviderEndpointDescription_Accessor.AttachShadow( - new ProviderEndpointDescription( - serviceEndpoint.ProviderDescription.Endpoint, - serviceEndpoint.ProviderDescription.Capabilities.Concat(new[] { typeUri }))); + var serviceEndpoint = (IdentifierDiscoveryResult)this.authReq.Provider; + serviceEndpoint.SetCapabilitiesForTestHook( + new ReadOnlyCollection<string>(serviceEndpoint.Capabilities.Concat(new[] { typeUri }).ToList())); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs index 0f9d472..d4884e8 100644 --- a/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs +++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdCoordinator.cs @@ -57,10 +57,12 @@ namespace DotNetOpenAuth.Test.OpenId { private void EnsurePartiesAreInitialized() { if (this.RelyingParty == null) { this.RelyingParty = new OpenIdRelyingParty(new StandardRelyingPartyApplicationStore()); + this.RelyingParty.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); } if (this.Provider == null) { this.Provider = new OpenIdProvider(new StandardProviderApplicationStore()); + this.Provider.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs index 5034b7e..d8f5674 100644 --- a/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs +++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdTestBase.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.Test.OpenId { using System; + using System.Collections.Generic; using System.IO; using System.Reflection; using DotNetOpenAuth.Configuration; @@ -116,17 +117,17 @@ namespace DotNetOpenAuth.Test.OpenId { } } - internal static ServiceEndpoint GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl) { + internal static IdentifierDiscoveryResult GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl) { return GetServiceEndpoint(user, providerVersion, servicePriority, useSsl, false); } - internal static ServiceEndpoint GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl, bool delegating) { + internal static IdentifierDiscoveryResult GetServiceEndpoint(int user, ProtocolVersion providerVersion, int servicePriority, bool useSsl, bool delegating) { var providerEndpoint = new ProviderEndpointDescription( useSsl ? OpenIdTestBase.OPUriSsl : OpenIdTestBase.OPUri, new string[] { Protocol.Lookup(providerVersion).ClaimedIdentifierServiceTypeURI }); var local_id = useSsl ? OPLocalIdentifiersSsl[user] : OPLocalIdentifiers[user]; var claimed_id = delegating ? (useSsl ? VanityUriSsl : VanityUri) : local_id; - return ServiceEndpoint.CreateForClaimedIdentifier( + return IdentifierDiscoveryResult.CreateForClaimedIdentifier( claimed_id, claimed_id, local_id, @@ -176,6 +177,12 @@ namespace DotNetOpenAuth.Test.OpenId { } } + internal IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier) { + var rp = this.CreateRelyingParty(true); + rp.Channel.WebRequestHandler = this.RequestHandler; + return rp.Discover(identifier); + } + protected Realm GetMockRealm(bool useSsl) { var rpDescription = new RelyingPartyEndpointDescription(useSsl ? RPUriSsl : RPUri, new string[] { Protocol.V20.RPReturnToTypeURI }); return new MockRealm(useSsl ? RPRealmUriSsl : RPRealmUri, rpDescription); @@ -190,9 +197,21 @@ namespace DotNetOpenAuth.Test.OpenId { } protected Identifier GetMockIdentifier(ProtocolVersion providerVersion, bool useSsl, bool delegating) { - ServiceEndpoint se = GetServiceEndpoint(0, providerVersion, 10, useSsl, delegating); + var se = GetServiceEndpoint(0, providerVersion, 10, useSsl, delegating); UriIdentifier identityUri = (UriIdentifier)se.ClaimedIdentifier; - return new MockIdentifier(identityUri, this.MockResponder, new ServiceEndpoint[] { se }); + return new MockIdentifier(identityUri, this.MockResponder, new IdentifierDiscoveryResult[] { se }); + } + + protected Identifier GetMockDualIdentifier() { + Protocol protocol = Protocol.Default; + var opDesc = new ProviderEndpointDescription(OPUri, protocol.Version); + var dualResults = new IdentifierDiscoveryResult[] { + IdentifierDiscoveryResult.CreateForClaimedIdentifier(VanityUri.AbsoluteUri, OPLocalIdentifiers[0], opDesc, 10, 10), + IdentifierDiscoveryResult.CreateForProviderIdentifier(protocol.ClaimedIdentifierForOPIdentifier, opDesc, 20, 20), + }; + + Identifier dualId = new MockIdentifier(VanityUri, this.MockResponder, dualResults); + return dualId; } /// <summary> @@ -211,6 +230,7 @@ namespace DotNetOpenAuth.Test.OpenId { protected OpenIdRelyingParty CreateRelyingParty(bool stateless) { var rp = new OpenIdRelyingParty(stateless ? null : new StandardRelyingPartyApplicationStore()); rp.Channel.WebRequestHandler = this.MockResponder.MockWebRequestHandler; + rp.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); return rp; } @@ -221,6 +241,7 @@ namespace DotNetOpenAuth.Test.OpenId { protected OpenIdProvider CreateProvider() { var op = new OpenIdProvider(new StandardProviderApplicationStore()); op.Channel.WebRequestHandler = this.MockResponder.MockWebRequestHandler; + op.DiscoveryServices.Add(new MockIdentifierDiscoveryService()); return op; } } diff --git a/src/DotNetOpenAuth.Test/OpenId/OpenIdUtilitiesTests.cs b/src/DotNetOpenAuth.Test/OpenId/OpenIdUtilitiesTests.cs new file mode 100644 index 0000000..389ef81 --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/OpenIdUtilitiesTests.cs @@ -0,0 +1,20 @@ +//----------------------------------------------------------------------- +// <copyright file="OpenIdUtilitiesTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + using DotNetOpenAuth.OpenId.Messages; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class OpenIdUtilitiesTests : OpenIdTestBase { + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs b/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs index 089265f..60cd25f 100644 --- a/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/ProviderEndpointDescriptionTests.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.Test.OpenId { using System; + using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.Messages; @@ -13,50 +14,15 @@ namespace DotNetOpenAuth.Test.OpenId { [TestClass] public class ProviderEndpointDescriptionTests : OpenIdTestBase { - private ProviderEndpointDescription se; - - private string[] v20TypeUris = { Protocol.V20.ClaimedIdentifierServiceTypeURI }; - - [TestInitialize] - public override void SetUp() { - base.SetUp(); - - this.se = new ProviderEndpointDescription(OPUri, Protocol.V20.Version); - } - - [TestMethod, ExpectedException(typeof(ArgumentNullException))] - public void IsExtensionSupportedNullType() { - this.se.IsExtensionSupported((Type)null); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsExtensionSupportedNullString() { - this.se.IsExtensionSupported((string)null); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsExtensionSupportedEmptyString() { - this.se.IsExtensionSupported(string.Empty); - } - - [TestMethod, ExpectedException(typeof(ArgumentNullException))] - public void IsExtensionSupportedNullExtension() { - this.se.IsExtensionSupported((IOpenIdMessageExtension)null); - } - [TestMethod] - public void IsExtensionSupported() { - this.se = new ProviderEndpointDescription(OPUri, this.v20TypeUris); - Assert.IsFalse(this.se.IsExtensionSupported<ClaimsRequest>()); - Assert.IsFalse(this.se.IsExtensionSupported(new ClaimsRequest())); - Assert.IsFalse(this.se.IsExtensionSupported("http://someextension/typeuri")); + public void NonNullCapabilities() { + var epd = new ProviderEndpointDescription(OPUri, Protocol.Default.Version); + Assert.IsNotNull(epd.Capabilities); + } - this.se = new ProviderEndpointDescription( - OPUri, - new[] { Protocol.V20.ClaimedIdentifierServiceTypeURI, "http://someextension", Constants.sreg_ns }); - Assert.IsTrue(this.se.IsExtensionSupported<ClaimsRequest>()); - Assert.IsTrue(this.se.IsExtensionSupported(new ClaimsRequest())); - Assert.IsTrue(this.se.IsExtensionSupported("http://someextension")); + [TestMethod, ExpectedException(typeof(ProtocolException))] + public void ProtocolDetectionWithoutClues() { + new ProviderEndpointDescription(OPUri, new[] { Protocol.V20.HtmlDiscoveryLocalIdKey }); // random type URI irrelevant to detection } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs index 10497b2..8f53cdd 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs @@ -16,6 +16,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; using DotNetOpenAuth.OpenId.Messages; using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Test.Mocks; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -37,7 +38,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void IsDirectedIdentity() { - IAuthenticationRequest_Accessor iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); Assert.IsFalse(iauthRequest.IsDirectedIdentity); iauthRequest = this.CreateAuthenticationRequest(IdentifierSelect, IdentifierSelect); @@ -49,7 +50,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void ClaimedIdentifier() { - IAuthenticationRequest_Accessor iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.delegatedLocalId); + var iauthRequest = this.CreateAuthenticationRequest(this.claimedId, this.delegatedLocalId); Assert.AreEqual(this.claimedId, iauthRequest.ClaimedIdentifier); iauthRequest = this.CreateAuthenticationRequest(IdentifierSelect, IdentifierSelect); @@ -62,7 +63,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { [TestMethod] public void ProviderVersion() { var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); - Assert.AreEqual(this.protocol.Version, authRequest.endpoint.Protocol.Version); + Assert.AreEqual(this.protocol.Version, authRequest.DiscoveryResult.Version); } /// <summary> @@ -124,7 +125,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void Provider() { - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); Assert.IsNotNull(authRequest.Provider); Assert.AreEqual(OPUri, authRequest.Provider.Uri); Assert.AreEqual(this.protocol.Version, authRequest.Provider.Version); @@ -135,7 +136,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void AddCallbackArgument() { - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); Assert.AreEqual(this.returnTo, authRequest.ReturnToUrl); authRequest.AddCallbackArguments("p1", "v1"); var req = (SignedResponseRequest)authRequest.RedirectingResponse.OriginalMessage; @@ -152,7 +153,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { UriBuilder returnToWithArgs = new UriBuilder(this.returnTo); returnToWithArgs.AppendQueryArgs(new Dictionary<string, string> { { "p1", "v1" } }); this.returnTo = returnToWithArgs.Uri; - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); authRequest.AddCallbackArguments("p1", "v2"); var req = (SignedResponseRequest)authRequest.RedirectingResponse.OriginalMessage; NameValueCollection query = HttpUtility.ParseQueryString(req.ReturnTo.Query); @@ -164,7 +165,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { /// </summary> [TestMethod] public void NonIdentityRequest() { - IAuthenticationRequest_Accessor authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); + var authRequest = this.CreateAuthenticationRequest(this.claimedId, this.claimedId); authRequest.IsExtensionOnly = true; Assert.IsTrue(authRequest.IsExtensionOnly); var req = (SignedResponseRequest)authRequest.RedirectingResponse.OriginalMessage; @@ -172,6 +173,24 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { } /// <summary> + /// Verifies that discovery on identifiers that serve as OP identifiers and claimed identifiers + /// only generate OP Identifier auth requests. + /// </summary> + [TestMethod] + public void DualIdentifierUsedOnlyAsOPIdentifierForAuthRequest() { + var rp = this.CreateRelyingParty(true); + var results = AuthenticationRequest.Create(GetMockDualIdentifier(), rp, this.realm, this.returnTo, false).ToList(); + Assert.AreEqual(1, results.Count); + Assert.IsTrue(results[0].IsDirectedIdentity); + + // Also test when dual identiifer support is turned on. + rp.SecuritySettings.AllowDualPurposeIdentifiers = true; + results = AuthenticationRequest.Create(GetMockDualIdentifier(), rp, this.realm, this.returnTo, false).ToList(); + Assert.AreEqual(1, results.Count); + Assert.IsTrue(results[0].IsDirectedIdentity); + } + + /// <summary> /// Verifies that authentication requests are generated first for OPs that respond /// to authentication requests. /// </summary> @@ -181,13 +200,11 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { Assert.Inconclusive("Not yet implemented."); } - private AuthenticationRequest_Accessor CreateAuthenticationRequest(Identifier claimedIdentifier, Identifier providerLocalIdentifier) { + private AuthenticationRequest CreateAuthenticationRequest(Identifier claimedIdentifier, Identifier providerLocalIdentifier) { ProviderEndpointDescription providerEndpoint = new ProviderEndpointDescription(OPUri, this.protocol.Version); - ServiceEndpoint endpoint = ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier, providerEndpoint, 10, 5); - ServiceEndpoint_Accessor endpointAccessor = ServiceEndpoint_Accessor.AttachShadow(endpoint); + IdentifierDiscoveryResult endpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, providerLocalIdentifier, providerEndpoint, 10, 5); OpenIdRelyingParty rp = this.CreateRelyingParty(); - AuthenticationRequest_Accessor authRequest = new AuthenticationRequest_Accessor(endpointAccessor, this.realm, this.returnTo, rp); - return authRequest; + return AuthenticationRequest.CreateForTest(endpoint, this.realm, this.returnTo, rp); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/IdentifierDiscoveryResultTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/IdentifierDiscoveryResultTests.cs new file mode 100644 index 0000000..1ed281c --- /dev/null +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/IdentifierDiscoveryResultTests.cs @@ -0,0 +1,199 @@ +//----------------------------------------------------------------------- +// <copyright file="IdentifierDiscoveryResultTests.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.Test.OpenId.RelyingParty { + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; + using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; + using DotNetOpenAuth.OpenId.Messages; + using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Test.Messaging; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + [TestClass] + public class IdentifierDiscoveryResultTests : OpenIdTestBase { + private UriIdentifier claimedId = new UriIdentifier("http://claimedid.justatest.com"); + private XriIdentifier claimedXri = new XriIdentifier("=!9B72.7DD1.50A9.5CCD"); + private XriIdentifier userSuppliedXri = new XriIdentifier("=Arnot"); + private Uri providerEndpoint = new Uri("http://someprovider.com"); + private Identifier localId = "http://localid.someprovider.com"; + private string[] v20TypeUris = { Protocol.V20.ClaimedIdentifierServiceTypeURI }; + private string[] v11TypeUris = { Protocol.V11.ClaimedIdentifierServiceTypeURI }; + private int servicePriority = 10; + private int uriPriority = 10; + + [TestInitialize] + public override void SetUp() { + base.SetUp(); + } + + [TestMethod] + public void Ctor() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); + Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); + Assert.AreSame(this.localId, se.ProviderLocalIdentifier); + CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.Capabilities); + Assert.AreEqual(this.servicePriority, se.ServicePriority); + } + + [TestMethod] + public void CtorImpliedLocalIdentifier() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, null, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); + Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); + Assert.AreSame(this.claimedId, se.ProviderLocalIdentifier); + CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.Capabilities); + } + + [TestMethod] + public void ProtocolDetection() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreSame(Protocol.V20, se.Protocol); + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + this.claimedId, + this.localId, + new ProviderEndpointDescription(this.providerEndpoint, new[] { Protocol.V20.OPIdentifierServiceTypeURI }), + this.servicePriority, + this.uriPriority); + Assert.AreSame(Protocol.V20, se.Protocol); + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); + Assert.AreSame(Protocol.V11, se.Protocol); + } + + [TestMethod] + public void EqualsTests() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + IdentifierDiscoveryResult se2 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), (int?)null, (int?)null); + Assert.AreEqual(se2, se); + Assert.AreNotEqual(se, null); + Assert.AreNotEqual(null, se); + + IdentifierDiscoveryResult se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(new UriIdentifier(this.claimedId + "a"), this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(new Uri(this.providerEndpoint.AbsoluteUri + "a"), this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId + "a", new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + se3 = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); + Assert.AreNotEqual(se, se3); + + // make sure that Collection<T>.Contains works as desired. + var list = new List<IdentifierDiscoveryResult>(); + list.Add(se); + Assert.IsTrue(list.Contains(se2)); + } + + [TestMethod] + public void GetFriendlyIdentifierForDisplay() { + Uri providerEndpoint = new Uri("http://someprovider"); + Identifier localId = "someuser"; + string[] serviceTypeUris = new string[] { + Protocol.V20.ClaimedIdentifierServiceTypeURI, + }; + IdentifierDiscoveryResult se; + + // strip of protocol, port, query and fragment + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + "http://someprovider.somedomain.com:79/someuser?query#frag", + localId, + new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), + null, + null); + Assert.AreEqual("someprovider.somedomain.com/someuser", se.FriendlyIdentifierForDisplay); + + // unescape characters + Uri foreignUri = new Uri("http://server崎/村"); + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(foreignUri, localId, new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), null, null); + Assert.AreEqual("server崎/村", se.FriendlyIdentifierForDisplay); + + // restore user supplied identifier to XRIs + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), + new XriIdentifier("=Arnott崎村"), + localId, + new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), + null, + null); + Assert.AreEqual("=Arnott崎村", se.FriendlyIdentifierForDisplay); + + // If UserSuppliedIdentifier is the same as the ClaimedIdentifier, don't display it twice... + se = IdentifierDiscoveryResult.CreateForClaimedIdentifier( + new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), + new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), + localId, + new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), + null, + null); + Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.FriendlyIdentifierForDisplay); + } + + [TestMethod] + public void IsTypeUriPresent() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + Assert.IsTrue(se.IsTypeUriPresent(Protocol.Default.ClaimedIdentifierServiceTypeURI)); + Assert.IsFalse(se.IsTypeUriPresent("http://someother")); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentNull() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + se.IsTypeUriPresent(null); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentEmpty() { + IdentifierDiscoveryResult se = IdentifierDiscoveryResult.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); + se.IsTypeUriPresent(string.Empty); + } + + [TestMethod, ExpectedException(typeof(ArgumentNullException))] + public void IsExtensionSupportedNullType() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsExtensionSupported((Type)null); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentNullString() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsTypeUriPresent((string)null); + } + + [TestMethod, ExpectedException(typeof(ArgumentException))] + public void IsTypeUriPresentEmptyString() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsTypeUriPresent(string.Empty); + } + + [TestMethod, ExpectedException(typeof(ArgumentNullException))] + public void IsExtensionSupportedNullExtension() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + se.IsExtensionSupported((IOpenIdMessageExtension)null); + } + + [TestMethod] + public void IsExtensionSupported() { + var se = IdentifierDiscoveryResult.CreateForProviderIdentifier(OPUri, new ProviderEndpointDescription(OPUri, this.v20TypeUris), null, null); + Assert.IsFalse(se.IsExtensionSupported<ClaimsRequest>()); + Assert.IsFalse(se.IsExtensionSupported(new ClaimsRequest())); + Assert.IsFalse(se.IsTypeUriPresent("http://someextension/typeuri")); + + se = IdentifierDiscoveryResult.CreateForProviderIdentifier( + OPUri, + new ProviderEndpointDescription(OPUri, new[] { Protocol.V20.ClaimedIdentifierServiceTypeURI, "http://someextension", Constants.sreg_ns }), + null, + null); + Assert.IsTrue(se.IsExtensionSupported<ClaimsRequest>()); + Assert.IsTrue(se.IsExtensionSupported(new ClaimsRequest())); + Assert.IsTrue(se.IsTypeUriPresent("http://someextension")); + } + } +} diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs index f6a57e7..7f0eb81 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/OpenIdRelyingPartyTests.cs @@ -23,7 +23,7 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { [TestMethod] public void CreateRequestDumbMode() { - var rp = new OpenIdRelyingParty(null); + var rp = this.CreateRelyingParty(true); Identifier id = this.GetMockIdentifier(ProtocolVersion.V20); var authReq = rp.CreateRequest(id, RPRealmUri, RPUri); CheckIdRequest requestMessage = (CheckIdRequest)authReq.RedirectingResponse.OriginalMessage; diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs index 701bcae..38dd0e6 100644 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/PositiveAuthenticationResponseTests.cs @@ -46,6 +46,32 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { } /// <summary> + /// Verifies that discovery verification of a positive assertion can match a dual identifier. + /// </summary> + [TestMethod] + public void DualIdentifierMatchesInAssertionVerification() { + PositiveAssertionResponse assertion = this.GetPositiveAssertion(true); + ClaimsResponse extension = new ClaimsResponse(); + assertion.Extensions.Add(extension); + var rp = CreateRelyingParty(); + rp.SecuritySettings.AllowDualPurposeIdentifiers = true; + new PositiveAuthenticationResponse(assertion, rp); // this will throw if it fails to find a match + } + + /// <summary> + /// Verifies that discovery verification of a positive assertion cannot match a dual identifier + /// if the default settings are in place. + /// </summary> + [TestMethod, ExpectedException(typeof(ProtocolException))] + public void DualIdentifierNoMatchInAssertionVerificationByDefault() { + PositiveAssertionResponse assertion = this.GetPositiveAssertion(true); + ClaimsResponse extension = new ClaimsResponse(); + assertion.Extensions.Add(extension); + var rp = CreateRelyingParty(); + new PositiveAuthenticationResponse(assertion, rp); // this will throw if it fails to find a match + } + + /// <summary> /// Verifies that the RP rejects signed solicited assertions by an OP that /// makes up a claimed Id that was not part of the original request, and /// that the OP has no authority to assert positively regarding. @@ -95,9 +121,13 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty { } private PositiveAssertionResponse GetPositiveAssertion() { + return this.GetPositiveAssertion(false); + } + + private PositiveAssertionResponse GetPositiveAssertion(bool dualIdentifier) { Protocol protocol = Protocol.Default; PositiveAssertionResponse assertion = new PositiveAssertionResponse(protocol.Version, this.returnTo); - assertion.ClaimedIdentifier = this.GetMockIdentifier(protocol.ProtocolVersion, false); + assertion.ClaimedIdentifier = dualIdentifier ? this.GetMockDualIdentifier() : this.GetMockIdentifier(protocol.ProtocolVersion, false); assertion.LocalIdentifier = OPLocalIdentifiers[0]; assertion.ReturnTo = this.returnTo; assertion.ProviderEndpoint = OPUri; diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/ServiceEndpointTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/ServiceEndpointTests.cs deleted file mode 100644 index ff15aa3..0000000 --- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/ServiceEndpointTests.cs +++ /dev/null @@ -1,195 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="ServiceEndpointTests.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.Test.OpenId.RelyingParty { - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.IO; - using System.Text; - using DotNetOpenAuth.Messaging; - using DotNetOpenAuth.OpenId; - using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration; - using DotNetOpenAuth.OpenId.Messages; - using DotNetOpenAuth.OpenId.RelyingParty; - using DotNetOpenAuth.Test.Messaging; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - [TestClass] - public class ServiceEndpointTests : OpenIdTestBase { - private UriIdentifier claimedId = new UriIdentifier("http://claimedid.justatest.com"); - private XriIdentifier claimedXri = new XriIdentifier("=!9B72.7DD1.50A9.5CCD"); - private XriIdentifier userSuppliedXri = new XriIdentifier("=Arnot"); - private Uri providerEndpoint = new Uri("http://someprovider.com"); - private Identifier localId = "http://localid.someprovider.com"; - private string[] v20TypeUris = { Protocol.V20.ClaimedIdentifierServiceTypeURI }; - private string[] v11TypeUris = { Protocol.V11.ClaimedIdentifierServiceTypeURI }; - private int servicePriority = 10; - private int uriPriority = 10; - - [TestMethod] - public void Ctor() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); - Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); - Assert.AreSame(this.localId, se.ProviderLocalIdentifier); - CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.ProviderSupportedServiceTypeUris); - Assert.AreEqual(this.servicePriority, ((IXrdsProviderEndpoint)se).ServicePriority); - } - - [TestMethod] - public void CtorImpliedLocalIdentifier() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, null, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreEqual(this.claimedId, se.ClaimedIdentifier); - Assert.AreSame(this.providerEndpoint, se.ProviderEndpoint); - Assert.AreSame(this.claimedId, se.ProviderLocalIdentifier); - CollectionAssert<string>.AreEquivalent(this.v20TypeUris, se.ProviderSupportedServiceTypeUris); - } - - [TestMethod] - public void ProtocolDetection() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreSame(Protocol.V20, se.Protocol); - se = ServiceEndpoint.CreateForClaimedIdentifier( - this.claimedId, - this.localId, - new ProviderEndpointDescription(this.providerEndpoint, new[] { Protocol.V20.OPIdentifierServiceTypeURI }), - this.servicePriority, - this.uriPriority); - Assert.AreSame(Protocol.V20, se.Protocol); - se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); - Assert.AreSame(Protocol.V11, se.Protocol); - } - - [TestMethod, ExpectedException(typeof(ProtocolException))] - public void ProtocolDetectionWithoutClues() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier( - this.claimedId, - this.localId, - new ProviderEndpointDescription(this.providerEndpoint, new[] { Protocol.V20.HtmlDiscoveryLocalIdKey }), // random type URI irrelevant to detection - this.servicePriority, - this.uriPriority); - } - - [TestMethod] - public void SerializationWithUri() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - StringBuilder sb = new StringBuilder(); - using (StringWriter sw = new StringWriter(sb)) { - se.Serialize(sw); - } - using (StringReader sr = new StringReader(sb.ToString())) { - ServiceEndpoint se2 = ServiceEndpoint.Deserialize(sr); - Assert.AreEqual(se, se2); - Assert.AreEqual(se.Protocol.Version, se2.Protocol.Version, "Particularly interested in this, since type URIs are not serialized but version info is."); - Assert.AreEqual(se.UserSuppliedIdentifier, se2.UserSuppliedIdentifier); - Assert.AreEqual(se.FriendlyIdentifierForDisplay, se2.FriendlyIdentifierForDisplay); - } - } - - [TestMethod] - public void SerializationWithXri() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - StringBuilder sb = new StringBuilder(); - using (StringWriter sw = new StringWriter(sb)) { - se.Serialize(sw); - } - using (StringReader sr = new StringReader(sb.ToString())) { - ServiceEndpoint se2 = ServiceEndpoint.Deserialize(sr); - Assert.AreEqual(se, se2); - Assert.AreEqual(se.Protocol.Version, se2.Protocol.Version, "Particularly interested in this, since type URIs are not serialized but version info is."); - Assert.AreEqual(se.UserSuppliedIdentifier, se2.UserSuppliedIdentifier); - Assert.AreEqual(se.FriendlyIdentifierForDisplay, se2.FriendlyIdentifierForDisplay); - } - } - - [TestMethod] - public void EqualsTests() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - ServiceEndpoint se2 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), (int?)null, (int?)null); - Assert.AreEqual(se2, se); - Assert.AreNotEqual(se, null); - Assert.AreNotEqual(null, se); - - ServiceEndpoint se3 = ServiceEndpoint.CreateForClaimedIdentifier(new UriIdentifier(this.claimedId + "a"), this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - se3 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(new Uri(this.providerEndpoint.AbsoluteUri + "a"), this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - se3 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId + "a", new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - se3 = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedId, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v11TypeUris), this.servicePriority, this.uriPriority); - Assert.AreNotEqual(se, se3); - - // make sure that Collection<T>.Contains works as desired. - List<ServiceEndpoint> list = new List<ServiceEndpoint>(); - list.Add(se); - Assert.IsTrue(list.Contains(se2)); - } - - [TestMethod] - public void FriendlyIdentifierForDisplay() { - Uri providerEndpoint = new Uri("http://someprovider"); - Identifier localId = "someuser"; - string[] serviceTypeUris = new string[] { - Protocol.V20.ClaimedIdentifierServiceTypeURI, - }; - ServiceEndpoint se; - - // strip of protocol, port, query and fragment - se = ServiceEndpoint.CreateForClaimedIdentifier( - "http://someprovider.somedomain.com:79/someuser?query#frag", - localId, - new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), - null, - null); - Assert.AreEqual("someprovider.somedomain.com/someuser", se.FriendlyIdentifierForDisplay); - - // unescape characters - Uri foreignUri = new Uri("http://server崎/村"); - se = ServiceEndpoint.CreateForClaimedIdentifier(foreignUri, localId, new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), null, null); - Assert.AreEqual("server崎/村", se.FriendlyIdentifierForDisplay); - - // restore user supplied identifier to XRIs - se = ServiceEndpoint.CreateForClaimedIdentifier( - new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), - new XriIdentifier("=Arnott崎村"), - localId, - new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), - null, - null); - Assert.AreEqual("=Arnott崎村", se.FriendlyIdentifierForDisplay); - - // If UserSuppliedIdentifier is the same as the ClaimedIdentifier, don't display it twice... - se = ServiceEndpoint.CreateForClaimedIdentifier( - new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), - new XriIdentifier("=!9B72.7DD1.50A9.5CCD"), - localId, - new ProviderEndpointDescription(providerEndpoint, serviceTypeUris), - null, - null); - Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", se.FriendlyIdentifierForDisplay); - } - - [TestMethod] - public void IsTypeUriPresent() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - Assert.IsTrue(se.IsTypeUriPresent(Protocol.Default.ClaimedIdentifierServiceTypeURI)); - Assert.IsFalse(se.IsTypeUriPresent("http://someother")); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsTypeUriPresentNull() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - se.IsTypeUriPresent(null); - } - - [TestMethod, ExpectedException(typeof(ArgumentException))] - public void IsTypeUriPresentEmpty() { - ServiceEndpoint se = ServiceEndpoint.CreateForClaimedIdentifier(this.claimedXri, this.userSuppliedXri, this.localId, new ProviderEndpointDescription(this.providerEndpoint, this.v20TypeUris), this.servicePriority, this.uriPriority); - se.IsTypeUriPresent(string.Empty); - } - } -} diff --git a/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs b/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs index 5a5182f..d504cdf 100644 --- a/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/UriIdentifierTests.cs @@ -141,62 +141,6 @@ namespace DotNetOpenAuth.Test.OpenId { } [TestMethod] - public void HtmlDiscover_11() { - this.DiscoverHtml("html10prov", ProtocolVersion.V11, null, "http://a/b"); - this.DiscoverHtml("html10both", ProtocolVersion.V11, "http://c/d", "http://a/b"); - this.FailDiscoverHtml("html10del"); - - // Verify that HTML discovery generates the 1.x endpoints when appropriate - this.DiscoverHtml("html2010", ProtocolVersion.V11, "http://g/h", "http://e/f"); - this.DiscoverHtml("html1020", ProtocolVersion.V11, "http://g/h", "http://e/f"); - this.DiscoverHtml("html2010combinedA", ProtocolVersion.V11, "http://c/d", "http://a/b"); - this.DiscoverHtml("html2010combinedB", ProtocolVersion.V11, "http://c/d", "http://a/b"); - this.DiscoverHtml("html2010combinedC", ProtocolVersion.V11, "http://c/d", "http://a/b"); - } - - [TestMethod] - public void HtmlDiscover_20() { - this.DiscoverHtml("html20prov", ProtocolVersion.V20, null, "http://a/b"); - this.DiscoverHtml("html20both", ProtocolVersion.V20, "http://c/d", "http://a/b"); - this.FailDiscoverHtml("html20del"); - this.DiscoverHtml("html2010", ProtocolVersion.V20, "http://c/d", "http://a/b"); - this.DiscoverHtml("html1020", ProtocolVersion.V20, "http://c/d", "http://a/b"); - this.DiscoverHtml("html2010combinedA", ProtocolVersion.V20, "http://c/d", "http://a/b"); - this.DiscoverHtml("html2010combinedB", ProtocolVersion.V20, "http://c/d", "http://a/b"); - this.DiscoverHtml("html2010combinedC", ProtocolVersion.V20, "http://c/d", "http://a/b"); - this.FailDiscoverHtml("html20relative"); - } - - [TestMethod] - public void XrdsDiscoveryFromHead() { - this.MockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml")); - this.DiscoverXrds("XrdsReferencedInHead.html", ProtocolVersion.V10, null, "http://a/b"); - } - - [TestMethod] - public void XrdsDiscoveryFromHttpHeader() { - WebHeaderCollection headers = new WebHeaderCollection(); - headers.Add("X-XRDS-Location", new Uri("http://localhost/xrds1020.xml").AbsoluteUri); - this.MockResponder.RegisterMockResponse(new Uri("http://localhost/xrds1020.xml"), "application/xrds+xml", LoadEmbeddedFile("/Discovery/xrdsdiscovery/xrds1020.xml")); - this.DiscoverXrds("XrdsReferencedInHttpHeader.html", ProtocolVersion.V10, null, "http://a/b", headers); - } - - [TestMethod] - public void XrdsDirectDiscovery_10() { - this.FailDiscoverXrds("xrds-irrelevant"); - this.DiscoverXrds("xrds10", ProtocolVersion.V10, null, "http://a/b"); - this.DiscoverXrds("xrds11", ProtocolVersion.V11, null, "http://a/b"); - this.DiscoverXrds("xrds1020", ProtocolVersion.V10, null, "http://a/b"); - } - - [TestMethod] - public void XrdsDirectDiscovery_20() { - this.DiscoverXrds("xrds20", ProtocolVersion.V20, null, "http://a/b"); - this.DiscoverXrds("xrds2010a", ProtocolVersion.V20, null, "http://a/b"); - this.DiscoverXrds("xrds2010b", ProtocolVersion.V20, null, "http://a/b"); - } - - [TestMethod] public void NormalizeCase() { // only the host name can be normalized in casing safely. Identifier id = "http://HOST:80/PaTH?KeY=VaLUE#fRag"; @@ -221,21 +165,6 @@ namespace DotNetOpenAuth.Test.OpenId { } [TestMethod] - public void DiscoveryWithRedirects() { - Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, false); - - // Add a couple of chained redirect pages that lead to the claimedId. - Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); - Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); - this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); - this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); - - // don't require secure SSL discovery for this test. - Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, false); - Assert.AreEqual(1, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod] public void TryRequireSslAdjustsIdentifier() { Identifier secureId; // Try Parse and ctor without explicit scheme @@ -256,180 +185,13 @@ namespace DotNetOpenAuth.Test.OpenId { Assert.IsFalse(id.TryRequireSsl(out secureId)); Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd, "Although the TryRequireSsl failed, the created identifier should retain the Ssl status."); Assert.AreEqual("http://www.yahoo.com/", secureId.ToString()); - Assert.AreEqual(0, secureId.Discover(this.RequestHandler).Count(), "Since TryRequireSsl failed, the created Identifier should never discover anything."); + Assert.AreEqual(0, Discover(secureId).Count(), "Since TryRequireSsl failed, the created Identifier should never discover anything."); id = new UriIdentifier("http://www.yahoo.com"); Assert.IsFalse(id.TryRequireSsl(out secureId)); Assert.IsTrue(secureId.IsDiscoverySecureEndToEnd); Assert.AreEqual("http://www.yahoo.com/", secureId.ToString()); - Assert.AreEqual(0, secureId.Discover(this.RequestHandler).Count()); - } - - [TestMethod] - public void DiscoverRequireSslWithSecureRedirects() { - Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); - - // Add a couple of chained redirect pages that lead to the claimedId. - // All redirects should be secure. - Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); - Uri secureMidpointUri = new Uri("https://localhost/secureStop"); - this.MockResponder.RegisterMockRedirect(userSuppliedUri, secureMidpointUri); - this.MockResponder.RegisterMockRedirect(secureMidpointUri, new Uri(claimedId.ToString())); - - Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); - Assert.AreEqual(1, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod, ExpectedException(typeof(ProtocolException))] - public void DiscoverRequireSslWithInsecureRedirect() { - Identifier claimedId = this.GetMockIdentifier(ProtocolVersion.V20, true); - - // Add a couple of chained redirect pages that lead to the claimedId. - // Include an insecure HTTP jump in those redirects to verify that - // the ultimate endpoint is never found as a result of high security profile. - Uri userSuppliedUri = new Uri("https://localhost/someSecurePage"); - Uri insecureMidpointUri = new Uri("http://localhost/insecureStop"); - this.MockResponder.RegisterMockRedirect(userSuppliedUri, insecureMidpointUri); - this.MockResponder.RegisterMockRedirect(insecureMidpointUri, new Uri(claimedId.ToString())); - - Identifier userSuppliedIdentifier = new UriIdentifier(userSuppliedUri, true); - userSuppliedIdentifier.Discover(this.RequestHandler); - } - - [TestMethod] - public void DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead() { - var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); - Uri secureClaimedUri = new Uri("https://localhost/secureId"); - - string html = string.Format("<html><head><meta http-equiv='X-XRDS-Location' content='{0}'/></head><body></body></html>", insecureXrdsSource); - this.MockResponder.RegisterMockResponse(secureClaimedUri, "text/html", html); - - Identifier userSuppliedIdentifier = new UriIdentifier(secureClaimedUri, true); - Assert.AreEqual(0, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod] - public void DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader() { - var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); - - string html = "<html><head></head><body></body></html>"; - WebHeaderCollection headers = new WebHeaderCollection { - { "X-XRDS-Location", insecureXrdsSource } - }; - this.MockResponder.RegisterMockResponse(VanityUriSsl, VanityUriSsl, "text/html", headers, html); - - Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); - Assert.AreEqual(0, userSuppliedIdentifier.Discover(this.RequestHandler).Count()); - } - - [TestMethod] - public void DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags() { - var insecureXrdsSource = this.GetMockIdentifier(ProtocolVersion.V20, false); - string html = string.Format( - @" - <html><head> - <meta http-equiv='X-XRDS-Location' content='{0}'/> <!-- this one will be insecure and ignored --> - <link rel='openid2.provider' href='{1}' /> - <link rel='openid2.local_id' href='{2}' /> - </head><body></body></html>", - HttpUtility.HtmlEncode(insecureXrdsSource), - HttpUtility.HtmlEncode(OPUriSsl.AbsoluteUri), - HttpUtility.HtmlEncode(OPLocalIdentifiersSsl[1].AbsoluteUri)); - this.MockResponder.RegisterMockResponse(VanityUriSsl, "text/html", html); - - Identifier userSuppliedIdentifier = new UriIdentifier(VanityUriSsl, true); - - // We verify that the XRDS was ignored and the LINK tags were used - // because the XRDS OP-LocalIdentifier uses different local identifiers. - Assert.AreEqual(OPLocalIdentifiersSsl[1], userSuppliedIdentifier.Discover(this.RequestHandler).Single().ProviderLocalIdentifier); - } - - [TestMethod] - public void DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds() { - var insecureEndpoint = GetServiceEndpoint(0, ProtocolVersion.V20, 10, false); - var secureEndpoint = GetServiceEndpoint(1, ProtocolVersion.V20, 20, true); - UriIdentifier secureClaimedId = new UriIdentifier(VanityUriSsl, true); - this.MockResponder.RegisterMockXrdsResponse(secureClaimedId, new ServiceEndpoint[] { insecureEndpoint, secureEndpoint }); - Assert.AreEqual(secureEndpoint.ProviderLocalIdentifier, secureClaimedId.Discover(this.RequestHandler).Single().ProviderLocalIdentifier); - } - - private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool expectSreg, bool useRedirect) { - this.Discover(url, version, expectedLocalId, providerEndpoint, expectSreg, useRedirect, null); - } - - private void Discover(string url, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool expectSreg, bool useRedirect, WebHeaderCollection headers) { - Protocol protocol = Protocol.Lookup(version); - Uri baseUrl = new Uri("http://localhost/"); - UriIdentifier claimedId = new Uri(baseUrl, url); - UriIdentifier userSuppliedIdentifier = new Uri(baseUrl, "Discovery/htmldiscovery/redirect.aspx?target=" + url); - if (expectedLocalId == null) { - expectedLocalId = claimedId; - } - Identifier idToDiscover = useRedirect ? userSuppliedIdentifier : claimedId; - - string contentType; - if (url.EndsWith("html")) { - contentType = "text/html"; - } else if (url.EndsWith("xml")) { - contentType = "application/xrds+xml"; - } else { - throw new InvalidOperationException(); - } - this.MockResponder.RegisterMockResponse(new Uri(idToDiscover), claimedId, contentType, headers ?? new WebHeaderCollection(), LoadEmbeddedFile(url)); - - ServiceEndpoint expected = ServiceEndpoint.CreateForClaimedIdentifier( - claimedId, - expectedLocalId, - new ProviderEndpointDescription(new Uri(providerEndpoint), new string[] { protocol.ClaimedIdentifierServiceTypeURI }), // services aren't checked by Equals - null, - null); - - ServiceEndpoint se = idToDiscover.Discover(this.RequestHandler).FirstOrDefault(ep => ep.Equals(expected)); - Assert.IsNotNull(se, url + " failed to be discovered."); - - // Do extra checking of service type URIs, which aren't included in - // the ServiceEndpoint.Equals method. - Assert.AreEqual(expectSreg ? 2 : 1, se.ProviderSupportedServiceTypeUris.Count); - Assert.IsTrue(se.ProviderSupportedServiceTypeUris.Contains(protocol.ClaimedIdentifierServiceTypeURI)); - Assert.AreEqual(expectSreg, se.IsExtensionSupported<ClaimsRequest>()); - } - - private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) { - this.DiscoverXrds(page, version, expectedLocalId, providerEndpoint, null); - } - - private void DiscoverXrds(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, WebHeaderCollection headers) { - if (!page.Contains(".")) { - page += ".xml"; - } - this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, providerEndpoint, true, false, headers); - this.Discover("/Discovery/xrdsdiscovery/" + page, version, expectedLocalId, providerEndpoint, true, true, headers); - } - - private void DiscoverHtml(string page, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint, bool useRedirect) { - this.Discover("/Discovery/htmldiscovery/" + page, version, expectedLocalId, providerEndpoint, false, useRedirect); - } - - private void DiscoverHtml(string scenario, ProtocolVersion version, Identifier expectedLocalId, string providerEndpoint) { - string page = scenario + ".html"; - this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, false); - this.DiscoverHtml(page, version, expectedLocalId, providerEndpoint, true); - } - - private void FailDiscover(string url) { - UriIdentifier userSuppliedId = new Uri(new Uri("http://localhost"), url); - - this.MockResponder.RegisterMockResponse(new Uri(userSuppliedId), userSuppliedId, "text/html", LoadEmbeddedFile(url)); - - Assert.AreEqual(0, userSuppliedId.Discover(this.RequestHandler).Count()); // ... but that no endpoint info is discoverable - } - - private void FailDiscoverHtml(string scenario) { - this.FailDiscover("/Discovery/htmldiscovery/" + scenario + ".html"); - } - - private void FailDiscoverXrds(string scenario) { - this.FailDiscover("/Discovery/xrdsdiscovery/" + scenario + ".xml"); + Assert.AreEqual(0, Discover(secureId).Count()); } } } diff --git a/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs b/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs index 46427bb..d5a51cf 100644 --- a/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs +++ b/src/DotNetOpenAuth.Test/OpenId/XriIdentifierTests.cs @@ -88,386 +88,10 @@ namespace DotNetOpenAuth.Test.OpenId { Assert.AreEqual(this.goodXri, new XriIdentifier(this.goodXri)); } - [TestMethod] - public void Discover() { - string xrds = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> - <Query>*Arnott</Query> - <Status ceid='off' cid='verified' code='100'/> - <Expires>2008-07-14T02:03:24.000Z</Expires> - <ProviderID>xri://=</ProviderID> - <LocalID>!9b72.7dd1.50a9.5ccd</LocalID> - <CanonicalID>=!9B72.7DD1.50A9.5CCD</CanonicalID> - - <Service priority='10'> - <ProviderID>xri://!!1008</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='default' select='false'/> - <Path select='true'>(+contact)</Path> - <Path match='null' select='false'/> - <URI append='qxri' priority='1'>http://1id.com/contact/</URI> - - </Service> - <Service priority='10'> - <ProviderID>xri://!!1008</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <URI append='qxri' priority='1'>http://1id.com/</URI> - </Service> - - <Service priority='10'> - <ProviderID>xri://!!1008</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='10'>http://1id.com/sso</URI> - </Service> -</XRD>"; - Dictionary<string, string> mocks = new Dictionary<string, string> { - { "https://xri.net/=Arnott?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, - { "https://xri.net/=!9B72.7DD1.50A9.5CCD?_xrd_r=application/xrd%2Bxml;sep=false", xrds }, - }; - this.MockResponder.RegisterMockXrdsResponses(mocks); - - string expectedCanonicalId = "=!9B72.7DD1.50A9.5CCD"; - ServiceEndpoint se = this.VerifyCanonicalId("=Arnott", expectedCanonicalId); - Assert.AreEqual(Protocol.V10, se.Protocol); - Assert.AreEqual("http://1id.com/sso", se.ProviderEndpoint.ToString()); - Assert.AreEqual(se.ClaimedIdentifier, se.ProviderLocalIdentifier); - Assert.AreEqual("=Arnott", se.FriendlyIdentifierForDisplay); - } - - [TestMethod] - public void DiscoverCommunityInameCanonicalIDs() { - string llliResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> - <Query>*llli</Query> - <Status ceid='off' cid='verified' code='100'/> - <Expires>2008-07-14T02:21:06.000Z</Expires> - <ProviderID>xri://@</ProviderID> - <LocalID>!72cd.a072.157e.a9c6</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6</CanonicalID> - <Service priority='10'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type match='null' select='false'/> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Path match='default'/> - <Path>(+index)</Path> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> - <Service priority='10'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType>application/xrds+xml;trust=none</MediaType> - <URI priority='10'>http://resolve.ezibroker.net/resolve/@llli/</URI> - </Service> - <Service priority='10'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> -</XRD> -"; - string llliAreaResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*area</Query> - <Status cid='verified' code='100'>SUCCESS</Status> - <ServerStatus code='100'>SUCCESS</ServerStatus> - <Expires>2008-07-15T01:21:07.000Z</Expires> - <ProviderID>xri://!!1003</ProviderID> - <LocalID>0000.0000.3B9A.CA0C</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C</CanonicalID> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path>(+index)</Path> - <Path match='default'/> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType>application/xrds+xml;trust=none</MediaType> - <URI>http://resolve.ezibroker.net/resolve/@llli*area/</URI> - </Service> -</XRD>"; - string llliAreaCanadaUnattachedResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*canada.unattached</Query> - <Status cid='verified' code='100'>SUCCESS</Status> - <ServerStatus code='100'>SUCCESS</ServerStatus> - <Expires>2008-07-15T01:21:08.000Z</Expires> - <ProviderID>xri://!!1003</ProviderID> - <LocalID>0000.0000.3B9A.CA41</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41</CanonicalID> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path>(+index)</Path> - <Path match='default'/> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType>application/xrds+xml;trust=none</MediaType> - <URI>http://resolve.ezibroker.net/resolve/@llli*area*canada.unattached/</URI> - </Service> -</XRD>"; - string llliAreaCanadaUnattachedAdaResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*ada</Query> - <Status cid='verified' code='100'>SUCCESS</Status> - <ServerStatus code='100'>SUCCESS</ServerStatus> - <Expires>2008-07-15T01:21:10.000Z</Expires> - <ProviderID>xri://!!1003</ProviderID> - <LocalID>0000.0000.3B9A.CA01</LocalID> - <CanonicalID>@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01</CanonicalID> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <URI append='none' priority='1'>https://login.llli.org/server/</URI> - </Service> - <Service> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <URI append='authority' priority='1'>http://linksafe-contact.ezibroker.net/contact/</URI> - </Service> - <Service priority='1'> - <ProviderID>xri://!!1003!103</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path>(+index)</Path> - <Path match='default'/> - <URI append='qxri' priority='1'>http://linksafe-forward.ezibroker.net/forwarding/</URI> - </Service> -</XRD>"; - string webResponse = @"<?xml version='1.0' encoding='UTF-8'?> -<XRD version='2.0' xmlns='xri://$xrd*($v*2.0)'> - <Query>*Web</Query> - <Status ceid='off' cid='verified' code='100'/> - <Expires>2008-07-14T02:21:12.000Z</Expires> - <ProviderID>xri://=</ProviderID> - <LocalID>!91f2.8153.f600.ae24</LocalID> - <CanonicalID>=!91F2.8153.F600.AE24</CanonicalID> - <Service priority='10'> - <Type select='true'>xri://+i-service*(+locator)*($v*1.0)</Type> - <Path select='true'>(+locator)</Path> - <MediaType match='default' select='false'/> - <URI append='qxri'>http://locator.fullxri.com/locator/</URI> - </Service> - <Service priority='10'> - <ProviderID>xri://=web</ProviderID> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <Type select='true'>xri://$res*auth*($v*2.0)</Type> - <MediaType select='true'>application/xrds+xml</MediaType> - <URI append='qxri' priority='1'>https://resolve.freexri.com/ns/=web/</URI> - <URI append='qxri' priority='2'>http://resolve.freexri.com/ns/=web/</URI> - </Service> - <Service priority='10'> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Type select='true'>http://specs.openid.net/auth/2.0/signon</Type> - <Path select='true'>(+login)</Path> - <Path match='default' select='false'/> - <MediaType match='default' select='false'/> - <URI append='none' priority='2'>http://authn.fullxri.com/authentication/</URI> - <URI append='none' priority='1'>https://authn.fullxri.com/authentication/</URI> - </Service> - <Service priority='10'> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null' select='false'/> - <Path select='true'>(+contact)</Path> - <Path match='null' select='false'/> - <MediaType match='default' select='false'/> - <URI append='qxri'>http://contact.fullxri.com/contact/</URI> - </Service> - <KeyInfo xmlns='http://www.w3.org/2000/09/xmldsig#'> - <X509Data> - <X509Certificate> -MIIExzCCA6+gAwIBAgIJAM+MlFr0Sth6MA0GCSqGSIb3DQEBBQUAMIGdMR8wHQYD -VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE -CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs -YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs -YWluLmVkdTAeFw0wNjA4MTcxOTU5NTNaFw0xMTA4MTYxOTU5NTNaMIGdMR8wHQYD -VQQDExZTdXBlcnZpbGxhaW46IFRoZSBSb290MQswCQYDVQQGEwJVUzERMA8GA1UE -CBMITmV3IFlvcmsxDzANBgNVBAcTBkdvdGhhbTEgMB4GA1UEChMXU3VwZXJ2aWxs -YWluIFVuaXZlcnNpdHkxJzAlBgkqhkiG9w0BCQEWGHBlbmd1aW5Ac3VwZXJ2aWxs -YWluLmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL6uFqas4dK6 -A2wTZL0viRQNJrPyFnFBDSZGib/2ijhgzed/vvmZIBM9sFpwahcuR5hvyKUe37/c -/RSZXoNDi/eiNOx4qb0l9UB6bd8qvc4V1PnLE7L+ZYcmwrvTKm4x8qXMgEv1wca2 -FPsreHNPdLiTUZ8v0tDTWi3Mgi7y47VTzJaTkcfmO1nL6xAtln5sLdH0PbMM3LAp -T1d3nwI3VdbhqqZ+6+OKEuC8gk5iH4lfrbr6C9bYS6vzIKrotHpZ3N2aIC3NMjJD -PMw/mfCuADfRNlHXgZW+0zyUkwGTMDea8qgsoAMWJGdeTIw8I1I3RhnbgLzdsNQl -b/1ZXx1uJRUCAwEAAaOCAQYwggECMB0GA1UdDgQWBBQe+xSjYTrlfraJARjMxscb -j36jvDCB0gYDVR0jBIHKMIHHgBQe+xSjYTrlfraJARjMxscbj36jvKGBo6SBoDCB -nTEfMB0GA1UEAxMWU3VwZXJ2aWxsYWluOiBUaGUgUm9vdDELMAkGA1UEBhMCVVMx -ETAPBgNVBAgTCE5ldyBZb3JrMQ8wDQYDVQQHEwZHb3RoYW0xIDAeBgNVBAoTF1N1 -cGVydmlsbGFpbiBVbml2ZXJzaXR5MScwJQYJKoZIhvcNAQkBFhhwZW5ndWluQHN1 -cGVydmlsbGFpbi5lZHWCCQDPjJRa9ErYejAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 -DQEBBQUAA4IBAQC4SPBDGYAxfbXd8N5OvG0drM7a5hjXfcCZpiILlPSRpxp79yh7 -I5vVWxBxUfolwbei7PTBVy7CE27SUbSICeqWjcDCfjNjiZk6mLS80rm/TdLrHSyM -+Ujlw9MGcBGaLI+sdziDUMtTQDpeAyQTaGVbh1mx5874Hlo1VXqGYNo0RwR+iLfs -x48VuO6GbWVyxtktkE2ypz1KLWiyI056YynydRvuBCBHeRqGUixPlH9CrmeSCP2S -sfbiKnMOGXjIYbvbsTAMdW2iqg6IWa/fgxhvZoAXChM9bkhisJQc0qD0J5TJQwgr -uEyb50RJ7DWmXctSC0b3eymZ2lSXxAWNOsNy - </X509Certificate> - </X509Data> - </KeyInfo> -</XRD>"; - this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { - { "https://xri.net/@llli?_xrd_r=application/xrd%2Bxml;sep=false", llliResponse }, - { "https://xri.net/@llli*area?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaResponse }, - { "https://xri.net/@llli*area*canada.unattached?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedResponse }, - { "https://xri.net/@llli*area*canada.unattached*ada?_xrd_r=application/xrd%2Bxml;sep=false", llliAreaCanadaUnattachedAdaResponse }, - { "https://xri.net/=Web?_xrd_r=application/xrd%2Bxml;sep=false", webResponse }, - }); - this.VerifyCanonicalId("@llli", "@!72CD.A072.157E.A9C6"); - this.VerifyCanonicalId("@llli*area", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C"); - this.VerifyCanonicalId("@llli*area*canada.unattached", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41"); - this.VerifyCanonicalId("@llli*area*canada.unattached*ada", "@!72CD.A072.157E.A9C6!0000.0000.3B9A.CA0C!0000.0000.3B9A.CA41!0000.0000.3B9A.CA01"); - this.VerifyCanonicalId("=Web", "=!91F2.8153.F600.AE24"); - } - - [TestMethod] - public void DiscoveryCommunityInameDelegateWithoutCanonicalID() { - this.MockResponder.RegisterMockXrdsResponses(new Dictionary<string, string> { - { "https://xri.net/=Web*andrew.arnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*andrew.arnott</Query> - <Status cid='absent' code='100'>Success</Status> - <ServerStatus code='100'>Success</ServerStatus> - <Expires>2008-07-14T03:30:59.722Z</Expires> - <ProviderID>=!91F2.8153.F600.AE24</ProviderID> - <Service> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Path select='true'>(+login)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='none' priority='2'>http://www.myopenid.com/server</URI> - <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <MediaType match='default'/> - <URI append='qxri'>http://contact.freexri.com/contact/</URI> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Path select='true'>(+index)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Path select='true'>(+login)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='none' priority='2'>http://authn.freexri.com/authentication/</URI> - <URI append='none' priority='1'>https://authn.freexri.com/authentication/</URI> - </Service> - <ServedBy>OpenXRI</ServedBy> -</XRD>" }, - { "https://xri.net/@id*andrewarnott?_xrd_r=application/xrd%2Bxml;sep=false", @"<?xml version='1.0' encoding='UTF-8'?> -<XRD xmlns='xri://$xrd*($v*2.0)'> - <Query>*andrewarnott</Query> - <Status cid='absent' code='100'>Success</Status> - <ServerStatus code='100'>Success</ServerStatus> - <Expires>2008-07-14T03:31:00.466Z</Expires> - <ProviderID>@!B1E8.C27B.E41C.25C3</ProviderID> - <Service> - <Type select='true'>http://openid.net/signon/1.0</Type> - <Path select='true'>(+login)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='none' priority='2'>http://www.myopenid.com/server</URI> - <openid:Delegate xmlns:openid='http://openid.net/xmlns/1.0'>http://blog.nerdbank.net</openid:Delegate> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+contact)*($v*1.0)</Type> - <Type match='null'/> - <Path select='true'>(+contact)</Path> - <Path match='null'/> - <MediaType match='default'/> - <URI append='qxri'>http://contact.freexri.com/contact/</URI> - </Service> - <Service> - <ProviderID>@!7F6F.F50.A4E4.1133</ProviderID> - <Type select='true'>xri://+i-service*(+forwarding)*($v*1.0)</Type> - <Path select='true'>(+index)</Path> - <Path match='default'/> - <MediaType match='default'/> - <URI append='qxri'>http://forwarding.freexri.com/forwarding/</URI> - </Service> - <ServedBy>OpenXRI</ServedBy> -</XRD>" }, - }); - // Consistent with spec section 7.3.2.3, we do not permit - // delegation on XRI discovery when there is no CanonicalID present. - this.VerifyCanonicalId("=Web*andrew.arnott", null); - this.VerifyCanonicalId("@id*andrewarnott", null); - } - [TestMethod, Ignore] // XRI parsing and normalization is not implemented (yet). public void NormalizeCase() { Identifier id = "=!9B72.7dd1.50a9.5ccd"; Assert.AreEqual("=!9B72.7DD1.50A9.5CCD", id.ToString()); } - - private ServiceEndpoint VerifyCanonicalId(Identifier iname, string expectedClaimedIdentifier) { - ServiceEndpoint se = iname.Discover(this.RequestHandler).FirstOrDefault(); - if (expectedClaimedIdentifier != null) { - Assert.IsNotNull(se); - Assert.AreEqual(expectedClaimedIdentifier, se.ClaimedIdentifier.ToString(), "i-name {0} discovery resulted in unexpected CanonicalId", iname); - Assert.IsTrue(se.ProviderSupportedServiceTypeUris.Count > 0); - } else { - Assert.IsNull(se); - } - return se; - } } } diff --git a/src/DotNetOpenAuth.sln b/src/DotNetOpenAuth.sln index 4dbb521..34269f2 100644 --- a/src/DotNetOpenAuth.sln +++ b/src/DotNetOpenAuth.sln @@ -176,6 +176,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelyingPartyLogic", "..\pro EndProject Project("{C8D11400-126E-41CD-887F-60BD40844F9E}") = "RelyingPartyDatabase", "..\projecttemplates\RelyingPartyDatabase\RelyingPartyDatabase.dbproj", "{2B4261AC-25AC-4B8D-B459-1C42B6B1401D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIdWebRingSsoRelyingParty", "..\samples\OpenIdWebRingSsoRelyingParty\OpenIdWebRingSsoRelyingParty.csproj", "{B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenIdWebRingSsoProvider", "..\samples\OpenIdWebRingSsoProvider\OpenIdWebRingSsoProvider.csproj", "{0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}" +EndProject Global GlobalSection(TestCaseManagementSettings) = postSolution CategoryFile = DotNetOpenAuth.vsmdi @@ -291,6 +295,18 @@ Global {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Release|Any CPU.Build.0 = Release|Any CPU {2B4261AC-25AC-4B8D-B459-1C42B6B1401D}.Release|Any CPU.Deploy.0 = Release|Any CPU + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}.CodeAnalysis|Any CPU.ActiveCfg = Release|Any CPU + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}.CodeAnalysis|Any CPU.Build.0 = Release|Any CPU + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942}.Release|Any CPU.Build.0 = Release|Any CPU + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}.CodeAnalysis|Any CPU.ActiveCfg = Release|Any CPU + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}.CodeAnalysis|Any CPU.Build.0 = Release|Any CPU + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -306,6 +322,10 @@ Global {07B193F1-68AD-4E9C-98AF-BEFB5E9403CB} = {034D5B5B-7D00-4A9D-8AFE-4A476E0575B1} {1E8AEA89-BF69-47A1-B290-E8B0FE588700} = {034D5B5B-7D00-4A9D-8AFE-4A476E0575B1} {BBACD972-014D-478F-9B07-56B9E1D4CC73} = {034D5B5B-7D00-4A9D-8AFE-4A476E0575B1} + {2A59DE0A-B76A-4B42-9A33-04D34548353D} = {034D5B5B-7D00-4A9D-8AFE-4A476E0575B1} + {B64A1E7E-6A15-4B91-AF13-7D48F7DA5942} = {034D5B5B-7D00-4A9D-8AFE-4A476E0575B1} + {0B4EB2A8-283D-48FB-BCD0-85B8DFFE05E4} = {034D5B5B-7D00-4A9D-8AFE-4A476E0575B1} + {6EB90284-BD15-461C-BBF2-131CF55F7C8B} = {8A5CEDB9-7F8A-4BE2-A1B9-97130F453277} {6EC36418-DBC5-4AD1-A402-413604AA7A08} = {1E2CBAA5-60A3-4AED-912E-541F5753CDC6} {9ADBE36D-9960-48F6-82E9-B4AC559E9AC3} = {1E2CBAA5-60A3-4AED-912E-541F5753CDC6} {7ADCCD5C-AC2B-4340-9410-FE3A31A48191} = {1E2CBAA5-60A3-4AED-912E-541F5753CDC6} diff --git a/src/DotNetOpenAuth.vsmdi b/src/DotNetOpenAuth.vsmdi index d5c4279..ea99f15 100644 --- a/src/DotNetOpenAuth.vsmdi +++ b/src/DotNetOpenAuth.vsmdi @@ -10,16 +10,17 @@ <TestList name="Fast" id="7e880f0f-2224-4f4c-a555-910a3bc2c0e5" parentListId="f0eeb325-0558-48a3-9a99-952133d8148e"> <Description>Fast running unit tests</Description> <TestLinks> + <TestLink id="3027bfe5-3612-7089-16cc-d6a2a556a41f" name="Transport" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="89de77d8-729a-7efe-9667-71b1f5d78859" name="CtorBadXri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="4ba7ca33-72f1-3fc6-d37c-65134eda904d" name="AddDeclaredValueThatAlreadyExists" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="06b350b0-79d1-9393-7620-cd919061898c" name="ParseEndUserSuppliedUriIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="300ae1f7-fc61-1d41-b262-f8c830b6e115" name="RemoveTest1" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="12304550-5647-5e61-64b4-a5e051f20a03" name="IsExtensionSupported" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="734dd45c-6320-26a9-e412-62ecacfd285a" name="CtorNullAttribute" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="70c08ce3-cbd0-d553-61c0-a6d2ca203dc4" name="IsExtensionSupportedNullExtension" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1d5fb5a9-e15c-d99c-7a7e-95a4c4d123c2" name="DirectRequestsUsePost" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="6b218bf7-a4e9-8dac-d2c2-9bc3ee3ffc3e" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1c531011-403a-0821-d630-d5433d968f31" name="CtorFromRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="73c6c979-205d-2216-d98d-2dd136b352c6" name="UtcCreationDateConvertsToUniversal" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="e7aacb49-62ef-637d-ada2-0a12d836414d" name="ExtensionFactory" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="d39dbdbd-7daf-9d4c-9ef1-8bbdeda2ffb0" name="DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="49a266cf-4ab6-3fdc-f4fd-21533f42c7cb" name="CtorWithProtocolMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d12e8df0-1195-ab75-2275-7c8f854ddf98" name="UserSetupUrl" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="21cf1f9a-063f-395a-f8aa-92c190c69146" name="SignaturesMatchKnownGood" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -27,7 +28,6 @@ <TestLink id="a9f7897c-b299-807b-0612-384732cd10c9" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f4bec8d2-0531-34ab-8d50-bca260b58c61" name="ReadFromRequestWithContext" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a314e3b9-36a5-bfbb-3e15-e5003f22cf87" name="Serialize" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="0f80456a-5465-dd68-bfb0-ba27b676187c" name="EqualsTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1bfbe1e1-3827-824f-27ad-4c990b0e22ab" name="Defaults" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ca9f3da7-e19f-b58b-54fe-54fa56ab9556" name="AddByKeyAndValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d766edce-59de-a03d-830a-0f0477521cff" name="ApplyHeadersToResponseNullAspNetResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -36,18 +36,17 @@ <TestLink id="889ba616-43dc-8a7f-ee13-46288969d617" name="ParameterNames" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fdf5b3df-239b-26fd-c1a2-152057195b7e" name="ReadFromRequestForm" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="555edc3b-5abf-7e46-b4f6-ddf44800b5df" name="SpreadSregToAXBasic" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="f8e523fa-a36b-5b4b-5f9d-b4f257f14ac5" name="XrdsDiscoveryFromHttpHeader" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="149a95cf-a538-f853-e11b-3133c15579c5" name="RequestTokenUriTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f3cbbcda-49ff-fc43-140b-f362081654c3" name="CtorNullTypeUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="352d9fd6-cf38-4b72-478f-e3e17ace55f5" name="NoValueLoose" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fa52f2db-fc1e-ba31-cc5e-0bcc05998187" name="NoValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="65752c29-fa1f-7b88-bbec-5329af8db4d8" name="IsValid" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="cd1142a5-f77a-5626-a739-65eb0228bf7d" name="ProtocolDetection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="68532d6d-a0cf-5883-17e2-6060707ba9ae" name="DecodeOobToNullUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="188ce83b-3117-adb5-4b89-12f2b09be1de" name="CtorSimpleConsumer" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="93c157e8-1293-3aff-f616-66502872b37d" name="DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="782d64c8-46af-a624-b3f6-a65aeaa57bfe" name="LastLineNotTerminatedLoose" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f6ecb459-cc64-36ee-438c-4514e9413586" name="AddAttributeByPrimitives" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="03e293d0-dbe8-ad09-1ddd-de7be2cf9276" name="CopyTo" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="c87bee54-0edd-1051-b5f8-2233692249ba" name="DiscoverCommunityInameCanonicalIDs" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5fa10f12-3de5-1783-0a97-9802d5469dfa" name="AddAttributeNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5ab06bb5-d047-8c3a-6b91-5951e0a55cc5" name="ToStringTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="454165a2-c26e-5740-09a9-d234db052ba3" name="InvalidRealmNullUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -60,25 +59,26 @@ <TestLink id="83aba528-c8ea-f464-177e-2ea8ae2cfd0b" name="Birthdates" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3c4e0438-94f5-a132-3949-8d94718e4839" name="PassThruCollection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b63c4b89-3889-6dcf-8890-c92fc44c0b10" name="VerifyBadTimestampIsRejected" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="9126d9e0-14dc-490b-3cd3-d3e424d38f9e" name="BinarySerialization" storage="..\bin\debug\dotnetopenauth.test.dll" enabled="false" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="9126d9e0-14dc-490b-3cd3-d3e424d38f9e" name="BinarySerialization" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="4c399759-263f-5eba-8855-de14f197e647" name="QueryStringContainPrefixedParametersNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1757957f-17bb-ef9f-39f8-c008863ec033" name="AssuranceLevels" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c11e5541-0a92-85ab-4f90-0db7766ebdcb" name="CtorUnsolicited" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8aecb3a5-2cb5-143d-aa99-9514fa8dfacb" name="AddAttributeByValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="ef6cebca-f8da-edf6-0217-8bb854710090" name="DiscoveryCommunityInameDelegateWithoutCanonicalID" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b09311d4-4dea-6786-3e59-9c62fe16e301" name="ParameterNames" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="ad56539c-6156-5f62-a98a-b24ae0159cc6" name="XmlSerialization" storage="..\bin\debug\dotnetopenauth.test.dll" enabled="false" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="ad56539c-6156-5f62-a98a-b24ae0159cc6" name="XmlSerialization" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="54eae9ed-bed1-eeda-b6ea-045c8f7e2ba5" name="SendIndirectMessage301GetNullFields" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2d0ee03a-f082-768c-a0db-574ac8efeffb" name="Valid" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="6c20a52a-bab7-e84e-faca-fd79ec5303d9" name="CtorCountZero" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7fb8d29c-c8ea-7f88-ed42-ae7368d6a429" name="CtorNullStore" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="50986611-9de6-a112-2fe8-691210989f45" name="IsTypeUriPresent" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="c63c9935-54a0-398a-f44b-214e17faf1f1" name="SendDirectMessageResponseHonorsHttpStatusCodes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="264cd371-e830-c09b-5511-18f54d4c69d5" name="RespondSimpleValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="77cb0e92-f1d8-44ba-eb16-83fdce2fb762" name="ProtocolDetectionWithoutClues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="163c8ba8-f829-c21e-a5a1-3c4565ec4425" name="UnifyExtensionsAsSregNoExtensions" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="054484ce-12c5-83ad-49a4-b241cd81557d" name="ClaimedIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e8337858-a320-8aad-51aa-402e65a90b75" name="ReplayDetectionTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="507cd1b6-1010-0bca-cf7f-f96e3f4f6c6c" name="QueryBeforeSettingUrl" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1dcbaac6-0b11-8d8f-50d7-237574abbab1" name="ToDictionaryWithSkippedNullKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="5c66a1b8-5b20-2e3b-8427-d6ff4640ac53" name="BadRequestsGenerateValidErrorResponses" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="8c3f05ce-10de-f3f0-fac6-1471d1f146ed" name="IsTypeUriPresentEmptyString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="715dcbdd-28f5-3c33-7d88-e0a1b648d89a" name="CreateRequestDumbMode" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a1ff4ada-fe5d-d2f3-b7fb-8e72db02b3c3" name="Full" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="85a71d28-5f2f-75ce-9008-94982438bb5f" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -86,44 +86,43 @@ <TestLink id="fa05cc5f-2aaf-da22-ff52-caf1c3c6bb08" name="InsecureIdentifiersRejectedWithRequireSsl" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7debb527-142a-6ca6-3b9b-1e131c18e801" name="AccessTokenUriTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="98e7a0f9-ab6c-7ff1-3a2c-00d8244e1bec" name="CommonMethods" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="f583b298-139a-e733-dde6-f9dc4b73d4bf" name="SendDirectMessageResponseHonorsHttpStatusCodes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="44afc59c-60fc-3179-b5a6-1e58e7752d54" name="ApplyHeadersToResponseNullHeaders" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="af7cb01c-950e-23d7-0f32-082b7af8b382" name="CtorNullToObject" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="a260d196-066f-b0ae-a40e-fb9d962b28a4" name="XrdsDirectDiscovery_20" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="13acd546-c82e-324c-220d-34f42a6d705e" name="DeserializeSimple" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b56cdf04-0d29-8b13-468c-fb4b4258c619" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d474830d-3636-522c-1564-1b83e7a844d3" name="EmptyLine" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="f44fb549-fc8a-7469-6eed-09d9f86cebff" name="SendDirectMessageResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="63e5025b-5ccf-5f13-6e05-d1e44502a6e9" name="RequestBadPreferredScheme" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="8fc08a6d-6dcf-6256-42ff-073d4e4b6859" name="RequireDirectedIdentity" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d80bf2a0-bcd5-f1c1-4835-8e5ceb523387" name="GetPublicFacingUrlSSLForwarder3" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f20bd439-e277-dc27-4ec4-5d5949d1c6bf" name="RequestUsingAuthorizationHeaderScattered" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3fc3ac8d-7772-b620-0927-f4bd3a24ce2f" name="SendNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5f3758b3-1410-c742-e623-b964c01b0633" name="AuthenticationTimeUtcConvertsToUtc" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9d4a230d-9e74-dc1b-ecdc-bf875b56e1b3" name="CtorNullVersion" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="f8d8d555-7a04-ab6e-918a-3dae32f4b52b" name="IsExtensionSupportedNullString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7b1fb2c4-39c0-0d39-700c-96d992f5a01f" name="AuthenticationTimeUtcSetUnspecified" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="00089858-d849-1e5f-4fb5-31d8d0590233" name="VerifyArgumentNotNullThrows" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="54a65e0b-1857-72b9-797b-fe3d9a082131" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f17424d2-ed4b-1ea0-a339-733f5092d9d0" name="MaximumAuthenticationAgeTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d067c55c-3715-ed87-14a2-c07349813c94" name="IsDirectedIdentity" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="8fc08a6d-6dcf-6256-42ff-073d4e4b6859" name="RequireDirectedIdentity" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3aa4e498-fd14-8274-22da-895436c1659e" name="AssociateUnencrypted" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="1f46ce86-bc66-3f5c-4061-3f851cf6dd7f" name="HtmlDiscover_20" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="a66588b5-989d-8f8e-4994-4a066220516b" name="FileSerializeMatchesLength" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2f9d176e-4137-63bd-ee2a-6b79fde70d0d" name="Clear" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="fc7af2d7-6262-d761-335b-ef3ec029484d" name="DeserializeVerifyElementOrdering" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="5c6d64b8-6368-5609-aa2c-ca32e273cdfd" name="IsTypeUriPresentNullString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="df159af7-abf5-089c-b592-e6f535dab1c1" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="577b8522-8516-4f62-22db-76227bf82f4c" name="UserSetupUrlNotRequiredInV1SetupOrV2" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e137b84a-d2a7-9af6-d15d-a92417668ccf" name="Transport" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ac4ff1af-8333-e54e-0322-27d8824d7573" name="RequestUsingAuthorizationHeader" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e78ab82c-3b49-468a-b2ad-ca038e98ff07" name="GetEnumerator" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8e86c2fd-24b9-44c5-7cda-d66aa7cd4418" name="Serializable" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="62096188-a8d2-d540-0157-57974e058035" name="HtmlDiscover_20" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="2e473003-940f-259e-ea10-3ddd8360e74d" name="IsTypeUriPresentEmpty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e344ba35-96b7-d441-c174-8c8b295fd157" name="AddCallbackArgument" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="06ec5bce-5a78-89c3-0cda-fa8bddfea27d" name="SetCountZero" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="5435ab79-de25-e2fc-0b2d-b05d5686d27d" name="IsUrlWithinRealmTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e2287de6-cbd2-4298-3fb8-297013749e70" name="SendIndirectMessageFormPostNullFields" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="db8d66cc-8206-57cc-0ce5-c8117813d77c" name="UnifyExtensionsasSregFromSchemaOpenIdNet" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ef8a2274-4e58-0dde-4c5c-7f286865fc3a" name="SendReplayProtectedMessageSetsNonce" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="63e5025b-5ccf-5f13-6e05-d1e44502a6e9" name="RequestBadPreferredScheme" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e2ab77b2-a6dc-f165-1485-140b9b3d916f" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2eb7c3dd-08aa-bfc0-edc8-e14bd82f7507" name="IdentifierTextInteraction" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="0d99e0a9-295e-08a6-bc31-2abb79c00ff8" name="IsReturnUrlDiscoverableRequireSsl" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="a098eccc-1909-2f95-6fdf-848b7b7fd7d6" name="DiscoverRequireSslWithInsecureRedirect" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f41ce7ab-5500-7eea-ab4d-8c646bffff23" name="HttpSchemePrepended" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="55b078e4-3933-d4e0-1151-a0a61321638e" name="ReadFromRequestAuthorization" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="38239ff0-1dfd-1116-55df-2790243dc768" name="IsValid" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="04be6602-31a2-f4ae-8fdb-b9ad2ac370be" name="PrepareMessageForReceiving" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2c2b48d0-8009-e7e0-9ff4-34f9973f59da" name="EqualsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -149,15 +148,14 @@ <TestLink id="f4537b23-bb5e-5c6f-da53-64b34472f0dc" name="ChannelGetter" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="75fa4664-bb0e-3a54-de29-c18ac712b231" name="Mode" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="94ba9fd3-851d-13b2-e273-6294b167c13e" name="HttpsSignatureVerification" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="cbfeb75b-d031-7df3-c281-3c9e1c450042" name="CtorFromRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5460f9c6-ec9d-969d-5aff-b946d6776e25" name="CtorWithNullProtocolMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="d5f4e610-eabe-1dc0-ab3f-7c9dcb17fcc3" name="CtorImpliedLocalIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="069995aa-4136-610b-3f41-df80a138c244" name="AppendQueryArgsNullUriBuilder" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="64d8c630-76c6-e420-937b-19c889dd7f59" name="CtorNonMessageType" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="fba4d9a6-d8c7-a063-7c07-4a27c38c94a9" name="InvalidRealmBadWildcard3" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="7c2d7790-f8fa-9af7-cd23-cfb360ae2c7b" name="IsExtensionSupported" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="be41e9c1-ecde-cc80-37d0-4126225e4cda" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="48115dc0-1323-bab0-c540-695a2160e0a3" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a79e43c9-ad5a-5543-51ff-22271ec87ab0" name="PrepareMessageForSendingNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="7ca16e07-126d-58ac-2ac5-a09a8bf77592" name="InvalidRealmBadWildcard1" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="eb932fc7-76c7-b63f-e1e6-a59dea8e4da1" name="AddAttribute" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="832dbf28-5bf2-bd95-9029-bf798349d917" name="GetCallbackArguments" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="11108b79-f360-9f7c-aebc-2d11bebff96a" name="ReadFromRequestForm" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="735b7a56-0f6f-77d8-8968-6708792a7ce8" name="UnifyExtensionsAsSregWithAXSchemaOpenIdNet" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -166,61 +164,61 @@ <TestLink id="c2c78c43-7f50-ffc3-affb-e60de2b76c94" name="CreateQueryStringNullDictionary" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="dc6af36d-0efc-9291-a603-2af7bac2a269" name="ErrorMessagesAsHttp400" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cc584a29-684c-75e8-3d77-96201d9ba537" name="ProviderTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="ef20222d-b2e2-d593-17fa-512041020643" name="InvalidRealmNullString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="9684f7bf-cdda-a2c5-0822-29cb0add3835" name="ResponseNonceGetter" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b2e1bba0-ab24-cdd5-906c-a3655814ab2d" name="SendSetsTimestamp" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2f1a3fc4-77ec-2ae3-668c-9e18f9ab0ebe" name="SendIndirectMessage301Get" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e4403d9e-73c1-967d-345c-4a2c83880d4e" name="EqualsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="6ce37652-2f47-6952-fb6d-568c2ca85224" name="TransformAXFormatTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a145f430-8062-5ad7-0cf5-b51eba0f8de7" name="HttpsSignatureGeneration" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="a6ea74e5-8681-4eb4-a51b-5051e5f7603c" name="NonFieldOrPropertyMember" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="066ce22f-103c-56ee-0250-d9e28d43ffcd" name="Values" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="bb542259-4c10-4b88-1b3c-f842b0bb49a9" name="ImmediateVsSetupModes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="71564ca7-7845-92b3-7433-2f2beeb6b9f7" name="VerifyNonZeroLengthOnNonEmpty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7ea157db-cf32-529f-f1d3-b3351f17725a" name="CtorSimpleServiceProvider" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c905ca57-e427-3833-c2dd-17ca9f6962cd" name="SendIndirectMessageFormPost" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="50594141-1a00-b4ab-d794-5b06e67327e5" name="IsTypeUriPresentNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="44ced969-83dd-201d-a660-e3744ee81cf8" name="ConstructorTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="4a5b601d-475d-e6cc-1fec-19a2850681ad" name="Serializable" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="ca6a3643-2978-a695-2c7e-819c8dfebfc9" name="IsTypeUriPresentNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c7f6459d-9e6e-b4bc-cae8-65f5a3785403" name="SendIndirectMessageNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="aa79cdf5-e0bc-194e-fdbb-78369c19c30f" name="ConstantFieldMemberInvalidValues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="dd9e3279-2d7e-e88e-ccfa-ef213055fc3d" name="SendDirectedNoRecipientMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b384002f-26a9-7dde-c3f6-9ceff34dd8e2" name="GetRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="5a77a48f-00d6-da6f-5ef7-c897ebf8fe6b" name="EscapeUriDataStringRfc3986Tests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="81f670d0-d314-c53c-9d91-c0765dfc30c1" name="MessagePartsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="efd570c9-5e74-17e4-f332-ac257c8e8aff" name="RealmReturnToMismatchV1" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="fda58c48-e03a-73a3-4294-9a49e776ffb6" name="CtorWithTextMessageAndInnerException" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="60cf73e0-c801-a9e1-43c7-83998350953b" name="IsExtensionSupportedNullExtension" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="660ad25a-b02b-1b17-7d6e-3af3303fa7bc" name="ModeEncoding" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ae384709-e9a4-0142-20ba-6adb6b40b3e2" name="CtorStringHttpsSchemeSecure" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3b70dd09-384d-5b99-222b-dc8ce8e791f2" name="SecuritySettingsSetNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f787ae5d-b8fc-0862-a527-9157d11bbed7" name="UntrustedWebRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8df5d75f-bd4d-ce4e-2faf-6106b623de42" name="AddAttributeRequestStrangeUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="51a08d94-c327-4d28-1f0c-f7920ea54870" name="ValidMessageTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="bc3e979b-09ea-c45d-5714-2d1fb00244cf" name="IncomingMessageMissingRequiredParameters" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="051a85ed-eef9-9437-507d-d6208b6a8f74" name="DiscoveryWithRedirects" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="be6a14aa-c0d9-cf61-286a-236b92239597" name="EnumerableCache" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="dc821571-7c36-7ac2-1a8f-ae946b8352da" name="DiscoveryCommunityInameDelegateWithoutCanonicalID" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e0606da1-e4fd-45ee-114c-a2878b89b615" name="XrdsDiscoveryFromHead" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="3f4f8ac9-84c4-3933-71b0-fa3367e34ce1" name="DiscoverCommunityInameCanonicalIDs" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="f7733adb-f021-669a-a89e-95cd56666648" name="DualIdentifierOffByDefault" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5a4df395-962e-0b7c-de71-abcb7e8930db" name="CreateFiltersDelegatingIdentifiers" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="bf73c7f2-33b1-8e18-c4f6-cb8609388754" name="DiscoveryRequireSslWithInsecureXrdsInSecureHttpHeader" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="feb0a53e-1592-b878-b70c-1a272d9c6908" name="SpreadSregToAxTargetedAtOPFormat" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e071a119-c7e9-1a55-b132-72e161fea598" name="CtorAndProperties" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e9cdffd6-e5f9-2d24-b1c6-8195de7f3c40" name="DiscoverRequireSslWithSecureRedirects" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a6e464af-42df-1ba4-17e5-b955352664b5" name="RPOnlyRenegotiatesOnce" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="0290975f-02ce-d8a7-d723-5dae623cab46" name="CtorNullTokenManager" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="45003a0c-fdb3-863c-3331-d5c5af704c66" name="DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="79c0d33a-f7f2-fd69-1b4d-57ee3ece2cca" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3b535521-90c8-7f49-545f-bcfc4ad16d40" name="UnresponsiveProvidersComeLast" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="77934ac4-bd65-7ad8-9c53-9c9447f9e175" name="GetReturnToArgumentAndNames" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="4bd86299-18d7-abbe-e5d2-1afad17279e9" name="Parse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="0443f5f8-aa08-80d5-dcc6-261802debe5a" name="XrdsDirectDiscovery_10" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="03b47440-3d09-ab28-97f1-39809f5703b6" name="NormalizeCase" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="6c95f443-463e-2856-f500-b9029645e44c" name="RequestNullRecipient" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="3744e1f1-6be1-f27f-78e9-5410d356ccf4" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="afafb5ef-662e-2da3-35b8-1d67bb0d79ce" name="AddPolicies" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="d0a92f93-9bb4-1821-81cf-e9b50e3e7d62" name="SendDirectMessageResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="a66588b5-989d-8f8e-4994-4a066220516b" name="FileSerializeMatchesLength" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="be6a14aa-c0d9-cf61-286a-236b92239597" name="EnumerableCache" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="17267cde-a296-8293-5bd1-9ca629817e4b" name="OpenIdRelyingParty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cab73921-470b-331f-e601-b44805b67c81" name="GetAttributeValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="14ce54ee-5507-ac70-5514-99b7b83ba3d6" name="ExtensionFactories" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ebd84587-bbc2-9889-c500-b6fbdf2bf209" name="GetRequestNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="565140c9-c9fe-9466-1e39-740d7e368cb5" name="TryParse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="782d64c8-46af-a624-b3f6-a65aeaa57bfe" name="LastLineNotTerminatedLoose" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="30a8eab6-6423-26af-da1a-ec304935fe43" name="RemoveNonexistentHandle" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e9bc3f63-aeb1-d84d-8abc-fc6ed77955e6" name="SignedResponsesIncludeExtraDataInSignature" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9e209599-5924-f624-48de-ed31588cb425" name="EncodeDecode" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="3027bfe5-3612-7089-16cc-d6a2a556a41f" name="Transport" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="51a08d94-c327-4d28-1f0c-f7920ea54870" name="ValidMessageTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="152e7a3a-21f9-eabf-0065-08597a0cc9a6" name="AuthorizationHeaderScheme" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="25e2c593-2e69-6215-90c0-67f269939865" name="CtorEmptyTypeUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="95e1fc36-2500-2721-1919-35e9e8349a1c" name="AddPolicyMultipleTimes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9af943f7-b289-1a24-8e3e-bfbd7a55b4c7" name="CtorGoodUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ae1ef27c-fbfe-c57e-a1e0-c1ef9de4ea23" name="CommonProperties" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -229,7 +227,6 @@ <TestLink id="88aaa032-b18a-b334-937b-66837c5f987c" name="AssociateRenegotiateBitLength" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="dd5be0e2-a1fc-3369-0b11-78b728eeaba5" name="CtorNullUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="0362a92c-a21c-f718-6b1e-3d154c14acd0" name="RequestUsingPost" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="264cd371-e830-c09b-5511-18f54d4c69d5" name="RespondSimpleValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="4a009f39-66b1-9cc5-ea8b-13b75ab22a5b" name="ContainsKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9bdc56c0-33ce-b46c-4031-bd3252b499a6" name="PrivateAssociationPositive" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="32604ca2-2577-9c33-f778-ff7e4c985ce5" name="RequestTokenUriWithOAuthParametersTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -238,7 +235,8 @@ <TestLink id="3df1f62b-4fb4-d399-cf7f-40b72001d9d6" name="CtorUnsolicited" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7c688207-e58a-86ed-90d0-687e28ee7e38" name="MultiPartPostAscii" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8b11aa63-4c0f-41ff-f70c-882aacf939fe" name="CtorCountNegative" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="83271647-7da8-70b1-48a3-f1253a636088" name="IsExtensionSupportedEmptyString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="fba4d9a6-d8c7-a063-7c07-4a27c38c94a9" name="InvalidRealmBadWildcard3" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="f583b298-139a-e733-dde6-f9dc4b73d4bf" name="SendDirectMessageResponseHonorsHttpStatusCodes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b671ea40-3b8c-58d5-7788-f776810c49be" name="UnicodeTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="501fa941-c1ac-d4ef-56e7-46827788b571" name="GetRequestNoContext" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="01e33554-07cc-ff90-46f8-7d0ca036c9f6" name="ToDictionaryNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -247,97 +245,98 @@ <TestLink id="7c048c58-c456-3406-995f-adb742cc2501" name="DeserializeInvalidMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="704a32d0-3f50-d462-f767-fd9cf1981b7f" name="ProviderVersion" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f362baf3-da5b-1b8c-39ae-7c9b2051270a" name="AuthenticationTimeUtcSetUtc" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="decb3fef-ef61-6794-5bc6-f7ff722a146e" name="EqualsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3bb818b4-5423-ad91-8cd9-8606ec85d2cb" name="ReadFromRequestAuthorizationScattered" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="30f3c12b-e510-de63-5acd-ae8e32866592" name="CreateQueryString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="cbfeb75b-d031-7df3-c281-3c9e1c450042" name="CtorFromRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9302541c-9c30-9ce7-66db-348ee4e9f6ee" name="UnifyExtensionsAsSregWithSreg" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="997253fb-7591-c151-1705-02976b400f27" name="AddAttributeTwice" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9bf0528f-c3ab-9a38-fd8a-fd14bade0d0b" name="EnumerableCacheCurrentThrowsAfter" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="8346368c-9c8a-de76-18dd-5faeeac3917d" name="OPRejectsMismatchingAssociationAndSessionTypes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="3d0effa3-894a-630c-02b0-ada4b5cef795" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="7ca16e07-126d-58ac-2ac5-a09a8bf77592" name="InvalidRealmBadWildcard1" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="2fb2563b-b908-2fad-5efc-522a68c76780" name="ValidMessageNoNonceReceivedTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3c438474-63f3-b56c-dcba-1ed923fcdbdd" name="CreateResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="47706bc6-7bee-0385-62b4-4f9cec6cc702" name="CtorWithTextMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2495fc9b-d766-5ae7-7324-f044c4ce1242" name="AddNullValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fb6c270f-ff72-73f4-b8b3-82851537427c" name="MultiVersionedMessageTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="10245b55-8130-e0aa-e211-4a16fa14d0b1" name="ClearValues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="c2119f75-468b-8440-5ba1-2bcf6f62d91a" name="DualIdentifierNoMatchInAssertionVerificationByDefault" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c9d67d40-1903-8319-0f7c-d70db4846380" name="SendWithoutAspNetContext" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a2b3835e-8edb-89aa-ba6c-f10b28a3af81" name="ReadFromRequestQueryString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e97cee09-4163-d83f-f65f-14e424294172" name="ExtensionsAreIdentifiedAsSignedOrUnsigned" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f4fd129a-a7c3-dc1e-2b4a-5059a4207a8a" name="Send" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cc0031b8-1fdb-cd87-97c1-c6f893c296e0" name="TooManyBindingElementsProvidingSameProtection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="152e7a3a-21f9-eabf-0065-08597a0cc9a6" name="AuthorizationHeaderScheme" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e7aacb49-62ef-637d-ada2-0a12d836414d" name="ExtensionFactory" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="8346368c-9c8a-de76-18dd-5faeeac3917d" name="OPRejectsMismatchingAssociationAndSessionTypes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="93041654-1050-3878-6b90-656a7e2e3cfd" name="CtorDefault" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="e2ab77b2-a6dc-f165-1485-140b9b3d916f" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="035cd43a-23d5-af91-12ee-0a0ce78b3548" name="XrdsDiscoveryFromHttpHeader" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="f70b368e-da33-bc64-6096-1b467d49a9d4" name="NonIdentityRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="c7bdb960-68ca-50dd-8020-609224f93213" name="DualIdentifierMatchesInAssertionVerification" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="dbf7855c-0cc6-309f-b5f5-022e0b95fe3b" name="QueryStringLookupWithoutQuery" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="abb0610a-c06f-0767-ac99-f37a2b573d1b" name="ParameterPrefix" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="32532d1f-d817-258d-ca72-021772bfc185" name="UriEncodeDecode" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f3345901-2e76-34dd-32f1-0b312d6e1c1e" name="IsReturnUrlDiscoverableNotSsl" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1deb0ca9-923a-8ef7-7a24-d5d5af04acdf" name="SpecAppendixAExample" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="b32b6295-d4a9-3369-f072-28a71e84d4e8" name="SerializationWithUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="2fb2563b-b908-2fad-5efc-522a68c76780" name="ValidMessageNoNonceReceivedTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="ee052b02-681f-2303-3cc6-37f7b2319579" name="RequireAssociation" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="81442cf1-8c5f-7937-dc78-79474e3d3e80" name="DualIdentifierUsedOnlyAsOPIdentifierForAuthRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="c63c9935-54a0-398a-f44b-214e17faf1f1" name="SendDirectMessageResponseHonorsHttpStatusCodes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="ff47215f-1c38-8c55-e411-bf5608dd98f5" name="XrdsDirectDiscovery_20" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fb0e478e-0f55-b257-75fe-2ab60b57292e" name="SendInvalidMessageTransport" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a4aa113a-57b5-a52c-c4e3-f70d6702badb" name="Default" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ee7a04ba-0419-e08f-b838-01ec0f2a838e" name="UnsolicitedAssertion" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="547cfee6-bbb4-6138-a114-fc0eb6cc94f6" name="PrivateAssociationTampered" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5803e93d-e256-86ba-e10e-499d2f813c6d" name="Trivial" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="beb086e9-5eb7-fb8f-480a-70ede9efd70d" name="CreateRequests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="78f622a3-750c-12c5-afc6-470c1bf71d85" name="ProtocolDetectionWithoutClues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="88ae5661-da27-91c5-4d78-1f43cd716127" name="EqualsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="0c1a0323-092a-34b3-1601-1f941569efab" name="CtorGoodXri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8538caf8-48bd-7cf8-6ad8-15e1c3766f92" name="CtorNullType" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e1958fc5-a979-88b2-b593-3bc89ad6ad4e" name="GetEnumeratorUntyped" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="f4893153-bb84-bf45-7889-8350a7e1db66" name="DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="536ecd26-4bda-a35e-5af8-666eb9b44940" name="NullValueEncoding" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5218fba2-d1af-e1f4-7641-9ae1d4975430" name="DirectResponsesSentUsingKeyValueForm" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="a1a0178c-cd4a-1651-8535-3c9ee3d40821" name="ToDictionaryWithNullKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="1c2226d3-5cf9-dba6-80b9-ff2710808567" name="IsExtensionSupportedNullType" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="0f36556d-ece7-eb70-8597-a9d085165c2c" name="Sign" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="19d2219e-c04d-fa3a-5e26-92448f35f21d" name="RespondNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="eb932fc7-76c7-b63f-e1e6-a59dea8e4da1" name="AddAttribute" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="a59c5dc0-de4d-8136-8545-2e2e9616de46" name="SerializationWithXri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="0aa1bc22-0b26-3977-5983-5dc4a454cea5" name="OptionalNullableStruct" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="1d7932c1-22de-b750-4602-7ed419f9d7f8" name="DiscoveryRequiresSslIgnoresInsecureEndpointsInXrds" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="0d99e0a9-295e-08a6-bc31-2abb79c00ff8" name="IsReturnUrlDiscoverableRequireSsl" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c205832e-711c-62d0-5f5e-78f1250ea7cc" name="AuthenticationTimeUtcSetNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3536ba12-fdb0-2ac9-3fef-00a2dd8e9a65" name="SharedAssociationTampered" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e7b8770d-b26c-e7b3-e80e-fac46285f59d" name="PassThruList" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="14acb719-f090-018f-b870-9a5acb1d7179" name="AddAuthLevelTypes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="aef95d4e-ad69-0eca-6528-7fce78512336" name="EqualityTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1b66e135-bdab-c2ed-18d8-aa89b46a57fc" name="RPRejectsUnrecognizedAssociationType" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="2f5cfa57-bcb4-39af-e769-2d7c34e2598e" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1ea8bd07-75a5-bfc0-5f8c-1a78d04240c2" name="TryGetValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7b89844d-f60a-fb66-c48d-e483864c66b5" name="RespondTooManyValues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b9cda1a0-83cd-cf4b-b61f-4faa75fa37ba" name="ReceivedReplayProtectedMessageTwice" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7f9c4a9e-de7a-555c-543d-db89b757588e" name="AppendQueryArgs" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="cf58b7b9-9718-f6cd-1839-fc53174598f2" name="IsExtensionSupportedNullType" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e6b412e5-3a53-e717-6393-254e1c93e239" name="PassThruDoubleCache" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9aa6a81e-c198-c0fd-0252-003b856b7674" name="ConstantFieldMemberValidValues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d6b120b7-fc16-6815-927e-af382cd44bbd" name="ReceivedInvalidSignature" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b71d12f6-58a1-cf82-d06e-e57c0a3ea55c" name="RPRejectsUnencryptedSuggestion" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="77e5af06-b02d-692e-b32f-40ea39e77fbd" name="FriendlyIdentifierForDisplay" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="2f6a81c5-cd04-0ca0-22ee-d4213f9cf147" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3c67903e-15ce-9ed4-34c8-f77059af79ca" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="87593646-8db5-fb47-3a5b-bf84d7d828c2" name="InvalidMessageTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="65f16786-7296-ee46-8a8f-82f18b211234" name="AddByKeyValuePair" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c891c6bc-da47-d4ab-b450-f3e3a0d6cba8" name="NoAssociationNegative" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="47e8fae9-542d-1ebb-e17c-568cf9594539" name="RelativeUriDecodeFails" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="bd130894-b7ba-9d89-5170-a67e8a2add7c" name="NonNullCapabilities" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f3af5fd8-f661-dc4f-4539-947b081a8b54" name="ReceivedReplayProtectedMessageJustOnce" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a14ddf08-796b-6cf1-a9bf-856dd50520fa" name="RequiredProtection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="7203b777-33d6-a659-564a-8c7294f4c28b" name="Discover" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5b4fee50-7c15-8c6b-3398-c82279646e5f" name="RequiredOptionalLists" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="59295023-d248-e9c4-68b9-65f6ea38490c" name="VerifyArgumentNotNullDoesNotThrow" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="e137b84a-d2a7-9af6-d15d-a92417668ccf" name="Transport" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a94ee2ec-02df-b535-1d2e-0c5db9c76b49" name="ReceiveUnrecognizedMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="88ae5661-da27-91c5-4d78-1f43cd716127" name="EqualsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cea48223-04e2-d336-0ac4-255c514bd188" name="RoundTripFullStackTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ba35acc7-78d2-6710-57ac-6843210d4202" name="UserSetupUrlRequiredInV1Immediate" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f18b514c-4f78-5421-8bdf-8b0f1fdf2282" name="HandleLifecycle" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1e2ae78c-d2f3-a808-2b82-eca9f9f2e458" name="Keys" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9173c754-a358-91cc-a8f0-2c2703a55da8" name="AssertionWithEndpointFilter" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="6badbaa8-33d1-13c4-c1f9-aef73a9ac5bf" name="InvalidRawBirthdate" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="d3c4624f-f78a-2ff3-199a-77c922059718" name="Best" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="0435e38a-71f2-d58d-9c07-d97d830a1578" name="ExtensionResponsesAreSigned" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2f2ea001-a4f8-ff0d-5d12-74180e0bf610" name="HttpsSignatureVerificationNotApplicable" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fe55cc74-98eb-c6c7-622f-77ad3e304c10" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ca5360e1-ca08-d00f-6ade-7c9441db4294" name="CreateQueryStringEmptyCollection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="4735a071-3c06-509b-05f5-912ab0e39f13" name="InvalidRealmBadProtocol" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="6fbd433d-cd54-b206-6df3-fbd591690a4d" name="HtmlDiscover_11" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="577b8522-8516-4f62-22db-76227bf82f4c" name="UserSetupUrlNotRequiredInV1SetupOrV2" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="175b6eb8-a448-4e07-7fed-001355edc128" name="PassThruArray" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="777af676-ee70-0e16-799b-85b9ec33cd63" name="IsValid" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d083396b-db68-1318-e62b-6dc9f89e26bd" name="CtorDefault" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="2f6a81c5-cd04-0ca0-22ee-d4213f9cf147" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="72d3f240-67f2-0b04-bd31-a99c3f7a8e12" name="SharedAssociationPositive" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3cd9447e-9ffd-f706-37bb-e7eb5828e430" name="InvalidRealmEmpty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="28fe030c-d36e-13cf-475c-7813210bf886" name="AddAttributeRequestAgain" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -346,22 +345,23 @@ <TestLink id="8d0df47c-c381-0487-6c19-77548ad7fc13" name="UnifyExtensionsAsSregWithBothSregAndAX" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2237b8ce-94ce-28c1-7eb2-14e59f47e926" name="UnifyExtensionsAsSregFromAXSchemaOrg" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a2f79410-e593-9155-e03d-8168cbb9f091" name="GetPublicFacingUrlSSLForwarder1" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="069995aa-4136-610b-3f41-df80a138c244" name="AppendQueryArgsNullUriBuilder" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="7cdabb8a-aefa-e90e-c32e-047404b64c2d" name="SerializeTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="457d6b32-d224-8a06-5e34-dbef3e935655" name="HttpSignatureVerification" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2e1b27e8-2e3e-0290-2bee-d88e2914efd9" name="SpreadSregToAXNoExtensions" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c15c3ab5-e969-efc9-366d-78ebc43ce08f" name="Fetch" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7bf8e806-68a1-86bc-8d91-9a99d237d35c" name="CreateRequestMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a883dc73-d6be-e59a-6da2-0db1d4452679" name="BindingElementsOrdering" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="056e3331-9ffb-bd58-a668-68c3dd8091d1" name="XrdsDirectDiscovery_10" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5dcd69c3-e979-7316-4551-a73fe4645dcd" name="SecuritySettings" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f533bf9e-daa1-b26a-4789-372f3a9291d6" name="TryRequireSslAdjustsIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="6ef9df5a-d069-0103-5260-593808f232da" name="XrdsDiscoveryFromHead" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="f44fb549-fc8a-7469-6eed-09d9f86cebff" name="SendDirectMessageResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="313faac6-6357-5468-2d4d-4c9fba001678" name="TryParseNoThrow" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7cbe4350-38d0-db7e-335c-93d9398fc95b" name="ExtensionOnlyFacadeLevel" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="2f5cfa57-bcb4-39af-e769-2d7c34e2598e" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="ff78d828-b437-aaeb-e48a-85a5ad1fe396" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="29e45877-ca7a-85de-5c39-6d43befe1a1e" name="DiscoveryRequireSslWithInsecureXrdsButSecureLinkTags" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="5f02e24c-2972-c598-ca71-ea362b2fe7d8" name="SecuritySettingsSetNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="ef20222d-b2e2-d593-17fa-512041020643" name="InvalidRealmNullString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c351c660-d583-d869-0129-2e312665d815" name="CtorBlank" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f063a3c6-5a36-2801-53d7-5142416199a9" name="ImplicitConversionFromStringTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="8ae44d86-85d0-8eef-7aff-c1a3b517df79" name="EqualsTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="02333934-cfea-2fb6-5e08-7a24be050f44" name="CreateRequestsOnNonOpenID" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5298ecb0-bcad-9022-8b93-87793eb2c669" name="UnsolicitedDelegatingIdentifierRejection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b97c4a66-a832-401c-a98b-6342ad7bcdcf" name="LanguagePreferenceEncodingDecoding" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -369,21 +369,23 @@ <TestLink id="315b5857-7697-8222-f94c-f6f10d539491" name="BaseSignatureStringTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cd219db4-4f6e-8ff4-f957-c8428d38c118" name="HttpSignatureGeneration" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="864578a5-61a2-bc5d-1d19-17093885bea3" name="InvalidRealmTwoWildcards1" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="8a5c9404-1e77-68cf-229a-ef7ed413e6e7" name="OptionalNonNullableStruct" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ab653060-5bec-3dc6-78ee-a5ef7d393b1d" name="AddPolicyMultipleTimes" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2599d559-d036-5dd2-0b5b-fb229c3bf486" name="InvalidRealmBadWildcard2" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="9684f7bf-cdda-a2c5-0822-29cb0add3835" name="ResponseNonceGetter" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="4b55986d-de09-7176-4565-af763f30861d" name="DiscoveryRequireSslWithInsecureXrdsInSecureHtmlHead" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="3744e1f1-6be1-f27f-78e9-5410d356ccf4" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f341c47f-ac23-2fc0-fcf5-c999fe8d2611" name="SetBodyToByteStream" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="79c0d33a-f7f2-fd69-1b4d-57ee3ece2cca" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="937b85f4-1ef3-84d1-a567-8bba079a33a9" name="Properties" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="80719076-10fd-20a7-7ff3-a0aa2bc661cb" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="8a5c9404-1e77-68cf-229a-ef7ed413e6e7" name="OptionalNonNullableStruct" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="ce1b9b53-2cb8-f764-bf2f-1458cb576773" name="ProtocolDetection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="53bc1962-e7c2-04b6-cafa-0f6fde7592a9" name="ReadFromRequestNoContext" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c057a3e5-b527-62a9-c19b-abb82e6be621" name="SendIndirectMessage301GetEmptyRecipient" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="0dc9284e-cba4-9d87-8955-19639578c70d" name="Serializable" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="384fecbf-f18e-edcb-a2eb-fb0322f031aa" name="ApplyHeadersToResponseNullListenerResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e3a3b3b6-e05f-0a99-e20c-af91a9065819" name="AssociateRequestDeterminedBySecuritySettings" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="d3c4624f-f78a-2ff3-199a-77c922059718" name="Best" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="30f3c12b-e510-de63-5acd-ae8e32866592" name="CreateQueryString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7f3144c7-95a1-affa-1a37-9e6169c19be6" name="SharedAssociationNegative" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="aedfde98-4357-5b63-7dca-cced838ee416" name="Provider" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="9e59b8d8-2fc4-b425-b5c4-c0a9fde3bf4d" name="SetValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b71e8878-b20e-5d96-bce4-7f10831ceaf8" name="AddPolicies" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ddf4f3ec-07bb-09e8-b5e8-0837cb8cb684" name="IsReturnUrlDiscoverableNoResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a18ae750-318b-bb1f-c2b3-c31da845c085" name="Count" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -395,32 +397,33 @@ <TestLink id="bdba0004-be80-f5c1-1aae-487db09bdf04" name="GetReturnToArgumentDoesNotReturnExtraArgs" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ccfda025-cb1a-a2ff-78bd-5e9af885ae0b" name="ToDictionary" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="64142858-d52e-be06-d11f-6be326c6176b" name="RespondTwoValues" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="03b47440-3d09-ab28-97f1-39809f5703b6" name="NormalizeCase" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e7e85e0f-5dfb-ae98-f796-ea23c27195ea" name="HtmlDiscover_11" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="34357633-4745-6fba-9316-493d3c6c5b90" name="ParseEmpty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="85a0dec0-983c-8f21-b093-a2179624cc88" name="UnifyExtensionsAsSregWithSreg" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="5c66a1b8-5b20-2e3b-8427-d6ff4640ac53" name="BadRequestsGenerateValidErrorResponses" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="4ba7ca33-72f1-3fc6-d37c-65134eda904d" name="AddDeclaredValueThatAlreadyExists" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="06b350b0-79d1-9393-7620-cd919061898c" name="ParseEndUserSuppliedUriIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="fc7af2d7-6262-d761-335b-ef3ec029484d" name="DeserializeVerifyElementOrdering" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="06ec5bce-5a78-89c3-0cda-fa8bddfea27d" name="SetCountZero" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="a6ea74e5-8681-4eb4-a51b-5051e5f7603c" name="NonFieldOrPropertyMember" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="46ec24da-deb7-27c7-6dc6-52090e4fd1fb" name="Serialize" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e9a5efc6-fde8-8fa4-0bda-2675a4a7e06b" name="DefaultReferenceTypeDeclaredPropertyHasNoKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b70b4bd5-6dae-b4ad-349c-c3ad70603773" name="ReadFromRequestQueryString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="5f02e24c-2972-c598-ca71-ea362b2fe7d8" name="SecuritySettingsSetNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="809afd59-8f10-ce37-6630-06b59351a05a" name="CommonProperties" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="98a2ece8-c9e6-e6f3-c65e-f915b22077fa" name="RequestUsingGet" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2cfefc4a-918a-3e16-0670-53eb33634525" name="GeneratesOnlyRequiredElements" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="da8fcfa9-bd2c-eca0-ecbf-90364f84e8e5" name="AddExtraFieldThatAlreadyExists" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fb91e9dd-fc3b-d8a7-a5d7-d215d5ba880f" name="CtorStringHttpSchemeSecure" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5211652f-1c25-fd4b-890d-05d2178a60e2" name="ExtensionFactories" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="b7441cac-9ee6-b2f4-d096-0f52c6eea5f6" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="7650ec62-b144-f36f-8b56-31ad20521d0e" name="DoesNotStripFragment" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e2b1ae2a-8f30-b6b3-bca6-ef28fc5a0175" name="ClaimedIdAndLocalIdSpecifiedIsValid" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="58d69d1e-3bd2-3379-0af1-188f9cff2dd0" name="IsTypeUriPresentEmpty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="495dd486-08dd-d365-7a84-67d96fef8460" name="SendIndirectedUndirectedMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="10a8b8e5-e147-838c-0708-be98d5e4490e" name="CtorFull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="24fb403f-be35-278e-9beb-e11177f2cd1e" name="FormDataSerializeMatchesLength" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="7cdabb8a-aefa-e90e-c32e-047404b64c2d" name="SerializeTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f6979feb-7016-4e2b-14e2-e6c2c392419f" name="RemoveByKeyValuePair" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="58df167c-cf19-351c-cb09-5c52ae9f97be" name="DeserializeNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="e8094568-0c57-b752-2bc5-a630ebf075b8" name="DiscoveryWithRedirects" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a778f331-f14e-9d6e-f942-a023423540f6" name="Ctor" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="90f06a50-7b81-05ec-3dc0-7b3e8ade8cfa" name="NormalizeCase" storage="..\bin\debug\dotnetopenauth.test.dll" enabled="false" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="be00d3ef-f24d-eb8a-d251-4d691736ee6f" name="AddAttributeRequestNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="90f06a50-7b81-05ec-3dc0-7b3e8ade8cfa" name="NormalizeCase" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="ee052b02-681f-2303-3cc6-37f7b2319579" name="RequireAssociation" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="593e1d86-a6c2-c937-a1b4-6d25a595a1f1" name="EnumerableCacheCurrentThrowsBefore" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="030ac3cf-cfb6-ca47-f822-ec1d2979f0b3" name="Defaults" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3fe0b432-dbb4-b334-e504-a83fe5ffdbaf" name="EqualityTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -434,30 +437,31 @@ <TestLink id="4b44b825-36cc-77f8-3a4a-5892c540f577" name="GetValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f17128c1-5953-5391-ed75-c33774eacbfc" name="LastLineNotTerminated" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="671ddaf5-238d-a517-b0f3-d79bd591a396" name="EmptyMailAddress" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="98f169da-4e46-340a-cd72-ec0b1e504472" name="GetFriendlyIdentifierForDisplay" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d8118997-ecf7-7130-f068-5e2bc867786d" name="SerializeNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="e9c2087b-1c52-5bb9-bf4e-9046cf281e36" name="DiscoverRequireSslWithInsecureRedirect" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="f69f1c0c-e258-95fb-4fcb-ad14bfc40e3c" name="Discover" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="25e2c593-2e69-6215-90c0-67f269939865" name="CtorEmptyTypeUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="6fc900ea-f861-a6ec-47ec-709d0b91e003" name="IsTypeUriPresent" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e1e9dde8-30e6-6ce0-d5a6-4e22e0347ac4" name="UnifyExtensionsAsSregWithAX" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f50a0bdb-380e-30f6-492a-a6dd9664d0f0" name="ExtensionOnlyChannelLevel" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="64b41c6c-2b67-af35-0c93-df41bd6f2dbb" name="Store" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="44afc59c-60fc-3179-b5a6-1e58e7752d54" name="ApplyHeadersToResponseNullHeaders" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="55b078e4-3933-d4e0-1151-a0a61321638e" name="ReadFromRequestAuthorization" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2d82ac4b-99b4-a132-eb62-d943e02d1498" name="ApplyHeadersToResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="599add9e-e9eb-5e8a-ce6b-6dc73c2bb408" name="DataContractNamespace" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="643c9887-3f12-300e-fdac-17ae59652712" name="Mode" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="ed7efca3-c3c1-bc4a-cef7-eaf984749355" name="ValidMessageReceivedTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="5435ab79-de25-e2fc-0b2d-b05d5686d27d" name="IsUrlWithinRealmTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="44ced969-83dd-201d-a660-e3744ee81cf8" name="ConstructorTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="1c5d54e2-d96a-d3a6-aeac-95f137b96421" name="CommonMethods" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cfc4032d-936a-6532-09d5-4a1267e57d63" name="GetPublicFacingUrlSSLForwarder2" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="e9cceef5-383d-92f0-a8bb-f3e207582836" name="RealmReturnToMismatchV2" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="e6b412e5-3a53-e717-6393-254e1c93e239" name="PassThruDoubleCache" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="f3b7d131-2c26-86e0-6654-ad6b2e4b706d" name="DualIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="bc3e979b-09ea-c45d-5714-2d1fb00244cf" name="IncomingMessageMissingRequiredParameters" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5aa4dfa9-9691-bfe0-7d81-587cfa519a55" name="DirectResponsesReceivedAsKeyValueForm" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="924b5295-0d39-5c89-8794-22518091e05a" name="CtorNullToString" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="a63c169c-4e9a-bcba-b7cd-c4c5280cd652" name="PrepareMessageForSendingNonExtendableMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="937b85f4-1ef3-84d1-a567-8bba079a33a9" name="Properties" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="63944cb8-4c61-c42c-906f-986fa793370b" name="SignatureTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="77934ac4-bd65-7ad8-9c53-9c9447f9e175" name="GetReturnToArgumentAndNames" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="5a77a48f-00d6-da6f-5ef7-c897ebf8fe6b" name="EscapeUriDataStringRfc3986Tests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="309fdc0f-150c-5992-9a79-63be5f479d89" name="RequiredProtection" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="4a5b601d-475d-e6cc-1fec-19a2850681ad" name="Serializable" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="3d0effa3-894a-630c-02b0-ada4b5cef795" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9bcc2d64-870f-7675-a314-fbb975446817" name="IsApprovedDeterminesReturnedMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3e676e31-3b6d-9d12-febd-d632ece804ec" name="RPRejectsMismatchingAssociationAndSessionBitLengths" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9026e58c-8582-0852-3c3c-9eadfd544cbc" name="VerifyNonZeroLengthOnEmpty" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -468,7 +472,7 @@ <TestLink id="62c6ee5b-ac29-461c-2373-bf620e948825" name="InvalidRealmNoScheme" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="115283b9-d95c-9a92-2197-96685ee8e96a" name="TwoExtensionsSameTypeUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d24a246f-5017-49f0-8030-e44a68ba534d" name="GetPublicFacingUrlSSLForwarder4" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="80719076-10fd-20a7-7ff3-a0aa2bc661cb" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="96382f34-8075-73d1-e8cd-21dcb9235c84" name="CtorImpliedLocalIdentifier" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b2b54c72-1d26-8c28-ebf5-7a5a4beeec43" name="VerifyNonZeroLengthOnNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c4001e1c-75ad-236b-284f-318905d2bc3a" name="CreateRequestOnNonOpenID" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b58e4791-68c0-1bc0-2e48-e1351459ee46" name="UserSetupUrlSetForV1Immediate" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -476,7 +480,6 @@ <TestLink id="32e95494-d0bb-cfc7-a8d6-652f8816c6b4" name="ReadFromResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f967c0af-c04c-d156-4faf-8978bfcab5d7" name="RequiredNullableStruct" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="248f0afc-979f-a86f-e7de-fdeb4f9dd3ea" name="CtorBadUri" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="536ecd26-4bda-a35e-5af8-666eb9b44940" name="NullValueEncoding" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="fa2e5bbd-4c41-f2b1-e875-38c6ef011fa1" name="RandomCharactersTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3e2f1dad-3684-587c-9039-8d116582be10" name="GetReturnToArgumentEmptyKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="00ed61cd-46cd-9c0e-f044-38d784c8bcfb" name="DecodeEmptyStringFails" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> @@ -488,31 +491,32 @@ <TestLink id="b4b00582-dcc9-7672-0c02-52432b074a92" name="GetNullType" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="f1e1aa37-c712-6096-22fa-394008f0820a" name="CtorNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cb48421f-f4ff-3994-3abc-4be35f8bfd99" name="AssociateQuietlyFailsAfterHttpError" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="decb3fef-ef61-6794-5bc6-f7ff722a146e" name="EqualsTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="0aa1bc22-0b26-3977-5983-5dc4a454cea5" name="OptionalNullableStruct" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="736a09b4-f56e-0176-6c1c-81db0fbe3412" name="CtorUriHttpsSchemeSecure" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9f880280-aa8f-91bb-4a5f-3fe044b6815a" name="CreateVerificationCode" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="10a8b8e5-e147-838c-0708-be98d5e4490e" name="CtorFull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="be00d3ef-f24d-eb8a-d251-4d691736ee6f" name="AddAttributeRequestNull" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="6daa360b-71e4-a972-143f-01b801fada84" name="DeserializeWithExtraFields" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="8bbc6a02-b5a4-ea8e-2a77-8d1b6671ceb5" name="ImplicitConverstionFromUriTests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="d6088ffe-ccf5-9738-131b-0fc1bc7e3707" name="TrimFragment" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="90d3c411-8895-a07f-7a21-258b9d43c5b2" name="InvalidMessageNoNonceReceivedTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="121983e3-1336-70cb-8d2a-498629e92bec" name="GetReturnToArgumentNullKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="d0a92f93-9bb4-1821-81cf-e9b50e3e7d62" name="SendDirectMessageResponse" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="5e0c892d-7ad8-6d56-1f1d-2fb6236670d6" name="CtorDefault" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="643d722c-2c2b-fbd8-a499-5a852ef14dc7" name="PrepareMessageForSending" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="c23e762d-4162-cb9e-47b3-455a568b5072" name="SendIndirectMessageFormPostEmptyRecipient" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="809afd59-8f10-ce37-6630-06b59351a05a" name="CommonProperties" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="f70b368e-da33-bc64-6096-1b467d49a9d4" name="NonIdentityRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="46877579-ba4c-c30c-38c4-9c6ad3922390" name="InsufficientlyProtectedMessageReceived" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="b191e585-49d9-df8e-c156-307f798db169" name="AddAttributeRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="3772f97f-3fe6-3fc0-350d-4085e7c4329e" name="Test" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="44091d36-98db-2115-8647-7bd7cd308796" name="ToStringTest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="9e59b8d8-2fc4-b425-b5c4-c0a9fde3bf4d" name="SetValue" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="a1a0178c-cd4a-1651-8535-3c9ee3d40821" name="ToDictionaryWithNullKey" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="90557d85-db17-e9ab-e17b-32d6cc9fd437" name="TrimFragment" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="534bee09-36e1-c3e0-f6af-bc191b10aa48" name="CtorNullSigner" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="9986fea9-8d64-9ada-60cb-ab95adb50fb7" name="ToStringDeferredEmptyMultiLine" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="de1cdd00-a226-0d43-62b6-0c1ad325be8c" name="RequiredMinAndMaxVersions" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cbdfd707-7ba8-4b8f-9d58-17b125aa4cd4" name="SendIndirectMessage301GetNullMessage" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="2a7b77c3-27d5-7788-e664-5d20118d223b" name="OPRejectsHttpNoEncryptionAssociateRequests" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> - <TestLink id="8fd673c8-977a-7b66-72cb-38c7054796c7" name="DiscoverRequireSslWithSecureRedirects" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> + <TestLink id="fda58c48-e03a-73a3-4294-9a49e776ffb6" name="CtorWithTextMessageAndInnerException" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> <TestLink id="cc9200bf-1399-d40a-9754-6415f0b7bcf8" name="CreateRequest" storage="..\bin\debug\dotnetopenauth.test.dll" type="Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestElement, Microsoft.VisualStudio.QualityTools.Tips.UnitTest.ObjectModel, PublicKeyToken=b03f5f7f11d50a3a" /> </TestLinks> </TestList> diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd index a462f83..18e1c5c 100644 --- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd +++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd @@ -319,6 +319,7 @@ </xs:documentation> </xs:annotation> </xs:attribute> + <xs:attribute name="allowDualPurposeIdentifiers" type="xs:boolean" /> </xs:complexType> </xs:element> <xs:element name="behaviors"> @@ -361,6 +362,27 @@ </xs:choice> </xs:complexType> </xs:element> + <xs:element name="discoveryServices"> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="add"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="remove"> + <xs:complexType> + <xs:attribute name="name" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element name="clear"> + <xs:complexType> + <!--tag is empty--> + </xs:complexType> + </xs:element> + </xs:choice> + </xs:complexType> + </xs:element> <xs:element name="store"> <xs:annotation> <xs:documentation> diff --git a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs index cdf4fd3..2ee2e91 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartyElement.cs @@ -5,8 +5,10 @@ //----------------------------------------------------------------------- namespace DotNetOpenAuth.Configuration { + using System; using System.Configuration; using System.Diagnostics.Contracts; + using DotNetOpenAuth.OpenId; using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> @@ -25,11 +27,21 @@ namespace DotNetOpenAuth.Configuration { private const string SecuritySettingsConfigName = "security"; /// <summary> - /// Gets the name of the <behaviors> sub-element. + /// The name of the <behaviors> sub-element. /// </summary> private const string BehaviorsElementName = "behaviors"; /// <summary> + /// The name of the <discoveryServices> sub-element. + /// </summary> + private const string DiscoveryServicesElementName = "discoveryServices"; + + /// <summary> + /// The built-in set of identifier discovery services. + /// </summary> + private static readonly TypeConfigurationCollection<IIdentifierDiscoveryService> defaultDiscoveryServices = new TypeConfigurationCollection<IIdentifierDiscoveryService>(new Type[] { typeof(UriDiscoveryService), typeof(XriDiscoveryProxyService) }); + + /// <summary> /// Initializes a new instance of the <see cref="OpenIdRelyingPartyElement"/> class. /// </summary> public OpenIdRelyingPartyElement() { @@ -62,5 +74,25 @@ namespace DotNetOpenAuth.Configuration { get { return (TypeConfigurationElement<IRelyingPartyApplicationStore>)this[StoreConfigName] ?? new TypeConfigurationElement<IRelyingPartyApplicationStore>(); } set { this[StoreConfigName] = value; } } + + /// <summary> + /// Gets or sets the services to use for discovering service endpoints for identifiers. + /// </summary> + /// <remarks> + /// If no discovery services are defined in the (web) application's .config file, + /// the default set of discovery services built into the library are used. + /// </remarks> + [ConfigurationProperty(DiscoveryServicesElementName, IsDefaultCollection = false)] + [ConfigurationCollection(typeof(TypeConfigurationCollection<IIdentifierDiscoveryService>))] + internal TypeConfigurationCollection<IIdentifierDiscoveryService> DiscoveryServices { + get { + var configResult = (TypeConfigurationCollection<IIdentifierDiscoveryService>)this[DiscoveryServicesElementName]; + return configResult != null && configResult.Count > 0 ? configResult : defaultDiscoveryServices; + } + + set { + this[DiscoveryServicesElementName] = value; + } + } } } diff --git a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs index d10d9bd..0d8b768 100644 --- a/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs +++ b/src/DotNetOpenAuth/Configuration/OpenIdRelyingPartySecuritySettingsElement.cs @@ -66,6 +66,11 @@ namespace DotNetOpenAuth.Configuration { private const string PrivateSecretMaximumAgeConfigName = "privateSecretMaximumAge"; /// <summary> + /// Gets the name of the @allowDualPurposeIdentifiers attribute. + /// </summary> + private const string AllowDualPurposeIdentifiersConfigName = "allowDualPurposeIdentifiers"; + + /// <summary> /// Initializes a new instance of the <see cref="OpenIdRelyingPartySecuritySettingsElement"/> class. /// </summary> public OpenIdRelyingPartySecuritySettingsElement() { @@ -183,6 +188,19 @@ namespace DotNetOpenAuth.Configuration { } /// <summary> + /// Gets or sets a value indicating whether identifiers that are both OP Identifiers and Claimed Identifiers + /// should ever be recognized as claimed identifiers. + /// </summary> + /// <value> + /// The default value is <c>false</c>, per the OpenID 2.0 spec. + /// </value> + [ConfigurationProperty(AllowDualPurposeIdentifiersConfigName, DefaultValue = false)] + public bool AllowDualPurposeIdentifiers { + get { return (bool)this[AllowDualPurposeIdentifiersConfigName]; } + set { this[AllowDualPurposeIdentifiersConfigName] = value; } + } + + /// <summary> /// Initializes a programmatically manipulatable bag of these security settings with the settings from the config file. /// </summary> /// <returns>The newly created security settings object.</returns> @@ -200,6 +218,7 @@ namespace DotNetOpenAuth.Configuration { settings.RejectUnsolicitedAssertions = this.RejectUnsolicitedAssertions; settings.RejectDelegatingIdentifiers = this.RejectDelegatingIdentifiers; settings.IgnoreUnsignedExtensions = this.IgnoreUnsignedExtensions; + settings.AllowDualPurposeIdentifiers = this.AllowDualPurposeIdentifiers; return settings; } diff --git a/src/DotNetOpenAuth/Configuration/ReportingElement.cs b/src/DotNetOpenAuth/Configuration/ReportingElement.cs index ab1437f..2374448 100644 --- a/src/DotNetOpenAuth/Configuration/ReportingElement.cs +++ b/src/DotNetOpenAuth/Configuration/ReportingElement.cs @@ -69,7 +69,7 @@ namespace DotNetOpenAuth.Configuration { /// Gets or sets a value indicating whether this reporting is enabled. /// </summary> /// <value><c>true</c> if enabled; otherwise, <c>false</c>.</value> - [ConfigurationProperty(EnabledAttributeName, DefaultValue = false)] + [ConfigurationProperty(EnabledAttributeName, DefaultValue = true)] internal bool Enabled { get { return (bool)this[EnabledAttributeName]; } set { this[EnabledAttributeName] = value; } diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index 5bda05d..9e22d4b 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -37,6 +37,7 @@ http://opensource.org/licenses/ms-pl.html <ApplicationVersion>1.0.0.%2a</ApplicationVersion> <UseApplicationTrust>false</UseApplicationTrust> <BootstrapperEnabled>true</BootstrapperEnabled> + <ApplicationIcon>DotNetOpenAuth.ico</ApplicationIcon> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> @@ -454,12 +455,14 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\Extensions\UI\UIUtilities.cs" /> <Compile Include="OpenId\Extensions\UI\UIModes.cs" /> <Compile Include="OpenId\Extensions\UI\UIRequest.cs" /> + <Compile Include="OpenId\HostMetaDiscoveryService.cs" /> <Compile Include="OpenId\Identifier.cs" /> <Compile Include="OpenId\IdentifierContract.cs" /> <Compile Include="OpenId\Extensions\ExtensionsInteropHelper.cs" /> <Compile Include="OpenId\Interop\AuthenticationResponseShim.cs" /> <Compile Include="OpenId\Interop\ClaimsResponseShim.cs" /> <Compile Include="OpenId\Interop\OpenIdRelyingPartyShim.cs" /> + <Compile Include="OpenId\IIdentifierDiscoveryService.cs" /> <Compile Include="OpenId\Messages\CheckAuthenticationRequest.cs" /> <Compile Include="OpenId\Messages\CheckAuthenticationResponse.cs" /> <Compile Include="OpenId\Messages\CheckIdRequest.cs" /> @@ -526,6 +529,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\RelyingParty\AssociationPreference.cs" /> <Compile Include="OpenId\RelyingParty\AuthenticationRequest.cs" /> <Compile Include="OpenId\RelyingParty\AuthenticationRequestMode.cs" /> + <Compile Include="OpenId\RelyingParty\IProviderEndpoint.cs" /> <Compile Include="OpenId\RelyingParty\SelectorButtonContract.cs" /> <Compile Include="OpenId\RelyingParty\SelectorProviderButton.cs" /> <Compile Include="OpenId\RelyingParty\SelectorOpenIdButton.cs" /> @@ -533,7 +537,6 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\RelyingParty\IRelyingPartyBehavior.cs" /> <Compile Include="OpenId\RelyingParty\OpenIdSelector.cs" /> <Compile Include="OpenId\RelyingParty\OpenIdRelyingPartyAjaxControlBase.cs" /> - <Compile Include="OpenId\RelyingParty\IXrdsProviderEndpointContract.cs" /> <Compile Include="OpenId\RelyingParty\IAuthenticationRequestContract.cs" /> <Compile Include="OpenId\RelyingParty\NegativeAuthenticationResponse.cs" /> <Compile Include="OpenId\RelyingParty\OpenIdAjaxTextBox.cs" /> @@ -550,9 +553,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\RelyingParty\FailedAuthenticationResponse.cs" /> <Compile Include="OpenId\RelyingParty\IAuthenticationRequest.cs" /> <Compile Include="OpenId\RelyingParty\IAuthenticationResponse.cs" /> - <Compile Include="OpenId\RelyingParty\IProviderEndpoint.cs" /> <Compile Include="OpenId\RelyingParty\ISetupRequiredAuthenticationResponse.cs" /> - <Compile Include="OpenId\RelyingParty\IXrdsProviderEndpoint.cs" /> <Compile Include="OpenId\RelyingParty\OpenIdRelyingParty.cs" /> <Compile Include="OpenId\OpenIdStrings.Designer.cs"> <DependentUpon>OpenIdStrings.resx</DependentUpon> @@ -567,7 +568,7 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\RelyingParty\PrivateSecretManager.cs" /> <Compile Include="OpenId\RelyingParty\RelyingPartySecuritySettings.cs" /> <Compile Include="OpenId\RelyingParty\SelectorButton.cs" /> - <Compile Include="OpenId\RelyingParty\ServiceEndpoint.cs" /> + <Compile Include="OpenId\IdentifierDiscoveryResult.cs" /> <Compile Include="OpenId\OpenIdXrdsHelper.cs" /> <Compile Include="OpenId\RelyingParty\SimpleXrdsProviderEndpoint.cs" /> <Compile Include="OpenId\RelyingParty\StandardRelyingPartyApplicationStore.cs" /> @@ -575,7 +576,9 @@ http://opensource.org/licenses/ms-pl.html <Compile Include="OpenId\RelyingParty\WellKnownProviders.cs" /> <Compile Include="OpenId\SecuritySettings.cs" /> <Compile Include="Messaging\UntrustedWebRequestHandler.cs" /> + <Compile Include="OpenId\UriDiscoveryService.cs" /> <Compile Include="OpenId\UriIdentifier.cs" /> + <Compile Include="OpenId\XriDiscoveryProxyService.cs" /> <Compile Include="OpenId\XriIdentifier.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="OAuth\Messages\UnauthorizedTokenRequest.cs" /> @@ -723,8 +726,9 @@ http://opensource.org/licenses/ms-pl.html <ProductName>Windows Installer 3.1</ProductName> <Install>true</Install> </BootstrapperPackage> + <Content Include="DotNetOpenAuth.ico" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" /> <Import Project="..\..\tools\JavascriptPacker.targets" /> -</Project>
\ No newline at end of file +</Project> diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.ico b/src/DotNetOpenAuth/DotNetOpenAuth.ico Binary files differnew file mode 100644 index 0000000..e227dbe --- /dev/null +++ b/src/DotNetOpenAuth/DotNetOpenAuth.ico diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs index c55e3bd..9e7ccd2 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs @@ -51,7 +51,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { return; } - if (req.Provider.IsExtensionSupported<ClaimsRequest>()) { + if (req.DiscoveryResult.IsExtensionSupported<ClaimsRequest>()) { Logger.OpenId.Debug("Skipping generation of AX request because the Identifier advertises the Provider supports the Sreg extension."); return; } @@ -276,8 +276,7 @@ namespace DotNetOpenAuth.OpenId.Extensions { /// <returns>The AX format(s) to use based on the Provider's advertised AX support.</returns> private static bool TryDetectOPAttributeFormat(RelyingParty.IAuthenticationRequest request, out AXAttributeFormats attributeFormat) { Contract.Requires<ArgumentNullException>(request != null); - var provider = (RelyingParty.ServiceEndpoint)request.Provider; - attributeFormat = DetectAXFormat(provider.ProviderDescription.Capabilities); + attributeFormat = DetectAXFormat(request.DiscoveryResult.Capabilities); return attributeFormat != AXAttributeFormats.None; } diff --git a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs index 61e6f85..67efe8e 100644 --- a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs @@ -28,8 +28,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI { /// <see cref="UIModes.Popup"/>. </para> /// <para>An RP may determine whether an arbitrary OP supports this extension (and thereby determine /// whether to use a standard full window redirect or a popup) via the - /// <see cref="IProviderEndpoint.IsExtensionSupported"/> method on the <see cref="DotNetOpenAuth.OpenId.RelyingParty.IAuthenticationRequest.Provider"/> - /// object.</para> + /// <see cref="IdentifierDiscoveryResult.IsExtensionSupported<T>()"/> method.</para> /// </remarks> public sealed class UIRequest : IOpenIdMessageExtension, IMessageWithEvents { /// <summary> diff --git a/src/DotNetOpenAuth/OpenId/HostMetaDiscoveryService.cs b/src/DotNetOpenAuth/OpenId/HostMetaDiscoveryService.cs new file mode 100644 index 0000000..b6ed2f7 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/HostMetaDiscoveryService.cs @@ -0,0 +1,501 @@ +//----------------------------------------------------------------------- +// <copyright file="HostMetaDiscoveryService.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Net; + using System.Security; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + using System.Security.Permissions; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml; + using System.Xml.XPath; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Xrds; + using DotNetOpenAuth.Yadis; + + /// <summary> + /// The discovery service to support host-meta based discovery, such as Google Apps for Domains. + /// </summary> + /// <remarks> + /// The spec for this discovery mechanism can be found at: + /// http://groups.google.com/group/google-federated-login-api/web/openid-discovery-for-hosted-domains + /// and the XMLDSig spec referenced in that spec can be found at: + /// http://wiki.oasis-open.org/xri/XrdOne/XmlDsigProfile + /// </remarks> + public class HostMetaDiscoveryService : IIdentifierDiscoveryService { + /// <summary> + /// The URI template for discovery host-meta on domains hosted by + /// Google Apps for Domains. + /// </summary> + private static readonly HostMetaProxy GoogleHostedHostMeta = new HostMetaProxy("https://www.google.com/accounts/o8/.well-known/host-meta?hd={0}", "hosted-id.google.com"); + + /// <summary> + /// Path to the well-known location of the host-meta document at a domain. + /// </summary> + private const string LocalHostMetaPath = "/.well-known/host-meta"; + + /// <summary> + /// The pattern within a host-meta file to look for to obtain the URI to the XRDS document. + /// </summary> + private static readonly Regex HostMetaLink = new Regex(@"^Link: <(?<location>.+?)>; rel=""describedby http://reltype.google.com/openid/xrd-op""; type=""application/xrds\+xml""$"); + + /// <summary> + /// Initializes a new instance of the <see cref="HostMetaDiscoveryService"/> class. + /// </summary> + public HostMetaDiscoveryService() { + this.TrustedHostMetaProxies = new List<HostMetaProxy>(); + } + + /// <summary> + /// Gets the set of URI templates to use to contact host-meta hosting proxies + /// for domain discovery. + /// </summary> + public IList<HostMetaProxy> TrustedHostMetaProxies { get; private set; } + + /// <summary> + /// Gets or sets a value indicating whether to trust Google to host domains' host-meta documents. + /// </summary> + /// <remarks> + /// This property is just a convenient mechanism for checking or changing the set of + /// trusted host-meta proxies in the <see cref="TrustedHostMetaProxies"/> property. + /// </remarks> + public bool UseGoogleHostedHostMeta { + get { + return this.TrustedHostMetaProxies.Contains(GoogleHostedHostMeta); + } + + set { + if (value != this.UseGoogleHostedHostMeta) { + if (value) { + this.TrustedHostMetaProxies.Add(GoogleHostedHostMeta); + } else { + this.TrustedHostMetaProxies.Remove(GoogleHostedHostMeta); + } + } + } + } + + #region IIdentifierDiscoveryService Members + + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + public IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { + abortDiscoveryChain = false; + + // Google Apps are always URIs -- not XRIs. + var uriIdentifier = identifier as UriIdentifier; + if (uriIdentifier == null) { + return Enumerable.Empty<IdentifierDiscoveryResult>(); + } + + var results = new List<IdentifierDiscoveryResult>(); + string signingHost; + var response = GetXrdsResponse(uriIdentifier, requestHandler, out signingHost); + + if (response != null) { + try { + var document = new XrdsDocument(XmlReader.Create(response.ResponseStream)); + ValidateXmlDSig(document, uriIdentifier, response, signingHost); + var xrds = GetXrdElements(document, uriIdentifier.Uri.Host); + + // Look for claimed identifier template URIs for an additional XRDS document. + results.AddRange(GetExternalServices(xrds, uriIdentifier, requestHandler)); + + // If we couldn't find any claimed identifiers, look for OP identifiers. + // Normally this would be the opposite (OP Identifiers take precedence over + // claimed identifiers, but for Google Apps, XRDS' always have OP Identifiers + // mixed in, which the OpenID spec mandate should eclipse Claimed Identifiers, + // which would break positive assertion checks). + if (results.Count == 0) { + results.AddRange(xrds.CreateServiceEndpoints(uriIdentifier, uriIdentifier)); + } + + abortDiscoveryChain = true; + } catch (XmlException ex) { + Logger.Yadis.ErrorFormat("Error while parsing XRDS document at {0} pointed to by host-meta: {1}", response.FinalUri, ex); + } + } + + return results; + } + + #endregion + + /// <summary> + /// Gets the XRD elements that have a given CanonicalID. + /// </summary> + /// <param name="document">The XRDS document.</param> + /// <param name="canonicalId">The CanonicalID to match on.</param> + /// <returns>A sequence of XRD elements.</returns> + private static IEnumerable<XrdElement> GetXrdElements(XrdsDocument document, string canonicalId) { + // filter to include only those XRD elements describing the host whose host-meta pointed us to this document. + return document.XrdElements.Where(xrd => string.Equals(xrd.CanonicalID, canonicalId, StringComparison.Ordinal)); + } + + /// <summary> + /// Gets the described-by services in XRD elements. + /// </summary> + /// <param name="xrds">The XRDs to search.</param> + /// <returns>A sequence of services.</returns> + private static IEnumerable<ServiceElement> GetDescribedByServices(IEnumerable<XrdElement> xrds) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Ensures(Contract.Result<IEnumerable<ServiceElement>>() != null); + + var describedBy = from xrd in xrds + from service in xrd.SearchForServiceTypeUris(p => "http://www.iana.org/assignments/relation/describedby") + select service; + return describedBy; + } + + /// <summary> + /// Gets the services for an identifier that are described by an external XRDS document. + /// </summary> + /// <param name="xrds">The XRD elements to search for described-by services.</param> + /// <param name="identifier">The identifier under discovery.</param> + /// <param name="requestHandler">The request handler.</param> + /// <returns>The discovered services.</returns> + private static IEnumerable<IdentifierDiscoveryResult> GetExternalServices(IEnumerable<XrdElement> xrds, UriIdentifier identifier, IDirectWebRequestHandler requestHandler) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); + + var results = new List<IdentifierDiscoveryResult>(); + foreach (var serviceElement in GetDescribedByServices(xrds)) { + var templateNode = serviceElement.Node.SelectSingleNode("google:URITemplate", serviceElement.XmlNamespaceResolver); + var nextAuthorityNode = serviceElement.Node.SelectSingleNode("google:NextAuthority", serviceElement.XmlNamespaceResolver); + if (templateNode != null) { + Uri externalLocation = new Uri(templateNode.Value.Trim().Replace("{%uri}", Uri.EscapeDataString(identifier.Uri.AbsoluteUri))); + string nextAuthority = nextAuthorityNode != null ? nextAuthorityNode.Value.Trim() : identifier.Uri.Host; + try { + var externalXrdsResponse = GetXrdsResponse(identifier, requestHandler, externalLocation); + XrdsDocument externalXrds = new XrdsDocument(XmlReader.Create(externalXrdsResponse.ResponseStream)); + ValidateXmlDSig(externalXrds, identifier, externalXrdsResponse, nextAuthority); + results.AddRange(GetXrdElements(externalXrds, identifier).CreateServiceEndpoints(identifier, identifier)); + } catch (ProtocolException ex) { + Logger.Yadis.WarnFormat("HTTP GET error while retrieving described-by XRDS document {0}: {1}", externalLocation.AbsoluteUri, ex); + } catch (XmlException ex) { + Logger.Yadis.ErrorFormat("Error while parsing described-by XRDS document {0}: {1}", externalLocation.AbsoluteUri, ex); + } + } + } + + return results; + } + + /// <summary> + /// Validates the XML digital signature on an XRDS document. + /// </summary> + /// <param name="document">The XRDS document whose signature should be validated.</param> + /// <param name="identifier">The identifier under discovery.</param> + /// <param name="response">The response.</param> + /// <param name="signingHost">The host name on the certificate that should be used to verify the signature in the XRDS.</param> + /// <exception cref="ProtocolException">Thrown if the XRDS document has an invalid or a missing signature.</exception> + private static void ValidateXmlDSig(XrdsDocument document, UriIdentifier identifier, IncomingWebResponse response, string signingHost) { + Contract.Requires<ArgumentNullException>(document != null); + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(response != null); + + var signatureNode = document.Node.SelectSingleNode("/xrds:XRDS/ds:Signature", document.XmlNamespaceResolver); + ErrorUtilities.VerifyProtocol(signatureNode != null, "Missing Signature element."); + var signedInfoNode = signatureNode.SelectSingleNode("ds:SignedInfo", document.XmlNamespaceResolver); + ErrorUtilities.VerifyProtocol(signedInfoNode != null, "Missing SignedInfo element."); + ErrorUtilities.VerifyProtocol( + signedInfoNode.SelectSingleNode("ds:CanonicalizationMethod[@Algorithm='http://docs.oasis-open.org/xri/xrd/2009/01#canonicalize-raw-octets']", document.XmlNamespaceResolver) != null, + "Unrecognized or missing canonicalization method."); + ErrorUtilities.VerifyProtocol( + signedInfoNode.SelectSingleNode("ds:SignatureMethod[@Algorithm='http://www.w3.org/2000/09/xmldsig#rsa-sha1']", document.XmlNamespaceResolver) != null, + "Unrecognized or missing signature method."); + var certNodes = signatureNode.Select("ds:KeyInfo/ds:X509Data/ds:X509Certificate", document.XmlNamespaceResolver); + ErrorUtilities.VerifyProtocol(certNodes.Count > 0, "Missing X509Certificate element."); + var certs = certNodes.Cast<XPathNavigator>().Select(n => new X509Certificate2(Convert.FromBase64String(n.Value.Trim()))).ToList(); + + // Verify that we trust the signer of the certificates. + // Start by trying to validate just the certificate used to sign the XRDS document, + // since we can do that with partial trust. + if (!certs[0].Verify()) { + // We couldn't verify just the signing certificate, so try to verify the whole certificate chain. + try { + VerifyCertChain(certs); + } catch (SecurityException) { + Logger.Yadis.Warn("Signing certificate verification failed and we have insufficient code access security permissions to perform certificate chain validation."); + ErrorUtilities.ThrowProtocol(OpenIdStrings.X509CertificateNotTrusted); + } + } + + // Verify that the certificate is issued to the host on whom we are performing discovery. + string hostName = certs[0].GetNameInfo(X509NameType.DnsName, false); + ErrorUtilities.VerifyProtocol(string.Equals(hostName, signingHost, StringComparison.OrdinalIgnoreCase), "X.509 signing certificate issued to {0}, but a certificate for {1} was expected.", hostName, signingHost); + + // Verify the signature itself + byte[] signature = Convert.FromBase64String(response.Headers["Signature"]); + var provider = (RSACryptoServiceProvider)certs.First().PublicKey.Key; + byte[] data = new byte[response.ResponseStream.Length]; + response.ResponseStream.Seek(0, SeekOrigin.Begin); + response.ResponseStream.Read(data, 0, data.Length); + ErrorUtilities.VerifyProtocol(provider.VerifyData(data, "SHA1", signature), "Invalid XmlDSig signature on XRDS document."); + } + + /// <summary> + /// Verifies the cert chain. + /// </summary> + /// <param name="certs">The certs.</param> + /// <remarks> + /// This must be in a method of its own because there is a LinkDemand on the <see cref="X509Chain.Build"/> + /// method. By being in a method of its own, the caller of this method may catch a + /// <see cref="SecurityException"/> that is thrown if we're not running with full trust and execute + /// an alternative plan. + /// </remarks> + /// <exception cref="ProtocolException">Thrown if the certificate chain is invalid or unverifiable.</exception> + private static void VerifyCertChain(List<X509Certificate2> certs) { + var chain = new X509Chain(); + foreach (var cert in certs) { + chain.Build(cert); + } + + if (chain.ChainStatus.Length > 0) { + ErrorUtilities.ThrowProtocol( + string.Format( + CultureInfo.CurrentCulture, + OpenIdStrings.X509CertificateNotTrusted + " {0}", + string.Join(", ", chain.ChainStatus.Select(status => status.StatusInformation).ToArray()))); + } + } + + /// <summary> + /// Gets the XRDS HTTP response for a given identifier. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <param name="requestHandler">The request handler.</param> + /// <param name="xrdsLocation">The location of the XRDS document to retrieve.</param> + /// <returns> + /// A HTTP response carrying an XRDS document. + /// </returns> + /// <exception cref="ProtocolException">Thrown if the XRDS document could not be obtained.</exception> + private static IncomingWebResponse GetXrdsResponse(UriIdentifier identifier, IDirectWebRequestHandler requestHandler, Uri xrdsLocation) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + Contract.Requires<ArgumentNullException>(xrdsLocation != null); + Contract.Ensures(Contract.Result<IncomingWebResponse>() != null); + + var request = (HttpWebRequest)WebRequest.Create(xrdsLocation); + request.CachePolicy = Yadis.IdentifierDiscoveryCachePolicy; + request.Accept = ContentTypes.Xrds; + var options = identifier.IsDiscoverySecureEndToEnd ? DirectWebRequestOptions.RequireSsl : DirectWebRequestOptions.None; + var response = requestHandler.GetResponse(request, options); + if (!string.Equals(response.ContentType.MediaType, ContentTypes.Xrds, StringComparison.Ordinal)) { + Logger.Yadis.WarnFormat("Host-meta pointed to XRDS at {0}, but Content-Type at that URL was unexpected value '{1}'.", xrdsLocation, response.ContentType); + } + + return response; + } + + /// <summary> + /// Gets the XRDS HTTP response for a given identifier. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <param name="requestHandler">The request handler.</param> + /// <param name="signingHost">The host name on the certificate that should be used to verify the signature in the XRDS.</param> + /// <returns>A HTTP response carrying an XRDS document, or <c>null</c> if one could not be obtained.</returns> + /// <exception cref="ProtocolException">Thrown if the XRDS document could not be obtained.</exception> + private IncomingWebResponse GetXrdsResponse(UriIdentifier identifier, IDirectWebRequestHandler requestHandler, out string signingHost) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + Uri xrdsLocation = this.GetXrdsLocation(identifier, requestHandler, out signingHost); + if (xrdsLocation == null) { + return null; + } + + var response = GetXrdsResponse(identifier, requestHandler, xrdsLocation); + + return response; + } + + /// <summary> + /// Gets the location of the XRDS document that describes a given identifier. + /// </summary> + /// <param name="identifier">The identifier under discovery.</param> + /// <param name="requestHandler">The request handler.</param> + /// <param name="signingHost">The host name on the certificate that should be used to verify the signature in the XRDS.</param> + /// <returns>An absolute URI, or <c>null</c> if one could not be determined.</returns> + private Uri GetXrdsLocation(UriIdentifier identifier, IDirectWebRequestHandler requestHandler, out string signingHost) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + var hostMetaResponse = this.GetHostMeta(identifier, requestHandler, out signingHost); + if (hostMetaResponse == null) { + return null; + } + + using (var sr = hostMetaResponse.GetResponseReader()) { + string line = sr.ReadLine(); + Match m = HostMetaLink.Match(line); + if (m.Success) { + Uri location = new Uri(m.Groups["location"].Value); + Logger.Yadis.InfoFormat("Found link to XRDS at {0} in host-meta document {1}.", location, hostMetaResponse.FinalUri); + return location; + } + } + + Logger.Yadis.WarnFormat("Could not find link to XRDS in host-meta document: {0}", hostMetaResponse.FinalUri); + return null; + } + + /// <summary> + /// Gets the host-meta for a given identifier. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <param name="requestHandler">The request handler.</param> + /// <param name="signingHost">The host name on the certificate that should be used to verify the signature in the XRDS.</param> + /// <returns> + /// The host-meta response, or <c>null</c> if no host-meta document could be obtained. + /// </returns> + private IncomingWebResponse GetHostMeta(UriIdentifier identifier, IDirectWebRequestHandler requestHandler, out string signingHost) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + foreach (var hostMetaProxy in this.GetHostMetaLocations(identifier)) { + var hostMetaLocation = hostMetaProxy.GetProxy(identifier); + var request = (HttpWebRequest)WebRequest.Create(hostMetaLocation); + request.CachePolicy = Yadis.IdentifierDiscoveryCachePolicy; + var options = DirectWebRequestOptions.AcceptAllHttpResponses; + if (identifier.IsDiscoverySecureEndToEnd) { + options |= DirectWebRequestOptions.RequireSsl; + } + var response = requestHandler.GetResponse(request, options); + if (response.Status == HttpStatusCode.OK) { + Logger.Yadis.InfoFormat("Found host-meta for {0} at: {1}", identifier.Uri.Host, hostMetaLocation); + signingHost = hostMetaProxy.GetSigningHost(identifier); + return response; + } else { + Logger.Yadis.InfoFormat("Could not obtain host-meta for {0} from {1}", identifier.Uri.Host, hostMetaLocation); + } + } + + signingHost = null; + return null; + } + + /// <summary> + /// Gets the URIs authorized to host host-meta documents on behalf of a given domain. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <returns>A sequence of URIs that MAY provide the host-meta for a given identifier.</returns> + private IEnumerable<HostMetaProxy> GetHostMetaLocations(UriIdentifier identifier) { + Contract.Requires<ArgumentNullException>(identifier != null); + + // First try the proxies, as they are considered more "secure" than the local + // host-meta for a domain since the domain may be defaced. + IEnumerable<HostMetaProxy> result = this.TrustedHostMetaProxies; + + // Finally, look for the local host-meta. + UriBuilder localHostMetaBuilder = new UriBuilder(); + localHostMetaBuilder.Scheme = identifier.IsDiscoverySecureEndToEnd || identifier.Uri.IsTransportSecure() ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; + localHostMetaBuilder.Host = identifier.Uri.Host; + localHostMetaBuilder.Path = LocalHostMetaPath; + result = result.Concat(new[] { new HostMetaProxy(localHostMetaBuilder.Uri.AbsoluteUri, identifier.Uri.Host) }); + + return result; + } + + /// <summary> + /// A description of a web server that hosts host-meta documents. + /// </summary> + public class HostMetaProxy { + /// <summary> + /// Initializes a new instance of the <see cref="HostMetaProxy"/> class. + /// </summary> + /// <param name="proxyFormat">The proxy formatting string.</param> + /// <param name="signingHostFormat">The signing host formatting string.</param> + public HostMetaProxy(string proxyFormat, string signingHostFormat) { + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(proxyFormat)); + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(signingHostFormat)); + this.ProxyFormat = proxyFormat; + this.SigningHostFormat = signingHostFormat; + } + + /// <summary> + /// Gets the URL of the host-meta proxy. + /// </summary> + /// <value>The absolute proxy URL, which may include {0} to be replaced with the host of the identifier to be discovered.</value> + public string ProxyFormat { get; private set; } + + /// <summary> + /// Gets the formatting string to determine the expected host name on the certificate + /// that is expected to be used to sign the XRDS document. + /// </summary> + /// <value> + /// Either a string literal, or a formatting string where these placeholders may exist: + /// {0} the host on the identifier discovery was originally performed on; + /// {1} the host on this proxy. + /// </value> + public string SigningHostFormat { get; private set; } + + /// <summary> + /// Gets the absolute proxy URI. + /// </summary> + /// <param name="identifier">The identifier being discovered.</param> + /// <returns>The an absolute URI.</returns> + public virtual Uri GetProxy(UriIdentifier identifier) { + Contract.Requires<ArgumentNullException>(identifier != null); + return new Uri(string.Format(CultureInfo.InvariantCulture, this.ProxyFormat, Uri.EscapeDataString(identifier.Uri.Host))); + } + + /// <summary> + /// Gets the signing host URI. + /// </summary> + /// <param name="identifier">The identifier being discovered.</param> + /// <returns>A host name.</returns> + public virtual string GetSigningHost(UriIdentifier identifier) { + Contract.Requires<ArgumentNullException>(identifier != null); + return string.Format(CultureInfo.InvariantCulture, this.SigningHostFormat, identifier.Uri.Host, this.GetProxy(identifier).Host); + } + + /// <summary> + /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>. + /// </summary> + /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param> + /// <returns> + /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false. + /// </returns> + /// <exception cref="T:System.NullReferenceException"> + /// The <paramref name="obj"/> parameter is null. + /// </exception> + public override bool Equals(object obj) { + var other = obj as HostMetaProxy; + if (other == null) { + return false; + } + + return this.ProxyFormat == other.ProxyFormat && this.SigningHostFormat == other.SigningHostFormat; + } + + /// <summary> + /// Serves as a hash function for a particular type. + /// </summary> + /// <returns> + /// A hash code for the current <see cref="T:System.Object"/>. + /// </returns> + public override int GetHashCode() { + return this.ProxyFormat.GetHashCode(); + } + } + } +} diff --git a/src/DotNetOpenAuth/OpenId/IIdentifierDiscoveryService.cs b/src/DotNetOpenAuth/OpenId/IIdentifierDiscoveryService.cs new file mode 100644 index 0000000..f637b37 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/IIdentifierDiscoveryService.cs @@ -0,0 +1,59 @@ +//----------------------------------------------------------------------- +// <copyright file="IIdentifierDiscoveryService.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.RelyingParty; + + /// <summary> + /// A module that provides discovery services for OpenID identifiers. + /// </summary> + [ContractClass(typeof(IIdentifierDiscoveryServiceContract))] + public interface IIdentifierDiscoveryService { + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + [Pure] + IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain); + } + + /// <summary> + /// Code contract for the <see cref="IIdentifierDiscoveryService"/> interface. + /// </summary> + [ContractClassFor(typeof(IIdentifierDiscoveryService))] + internal class IIdentifierDiscoveryServiceContract : IIdentifierDiscoveryService { + #region IDiscoveryService Members + + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + IEnumerable<IdentifierDiscoveryResult> IIdentifierDiscoveryService.Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); + throw new NotImplementedException(); + } + + #endregion + } +} diff --git a/src/DotNetOpenAuth/OpenId/Identifier.cs b/src/DotNetOpenAuth/OpenId/Identifier.cs index e32251b..548a673 100644 --- a/src/DotNetOpenAuth/OpenId/Identifier.cs +++ b/src/DotNetOpenAuth/OpenId/Identifier.cs @@ -207,16 +207,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Performs discovery on the Identifier. - /// </summary> - /// <param name="requestHandler">The web request handler to use for discovery.</param> - /// <returns> - /// An initialized structure containing the discovered provider endpoint information. - /// </returns> - [Pure] - internal abstract IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler); - - /// <summary> /// Returns an <see cref="Identifier"/> that has no URI fragment. /// Quietly returns the original <see cref="Identifier"/> if it is not /// a <see cref="UriIdentifier"/> or no fragment exists. diff --git a/src/DotNetOpenAuth/OpenId/IdentifierContract.cs b/src/DotNetOpenAuth/OpenId/IdentifierContract.cs index 498ae45..4af18e1 100644 --- a/src/DotNetOpenAuth/OpenId/IdentifierContract.cs +++ b/src/DotNetOpenAuth/OpenId/IdentifierContract.cs @@ -24,19 +24,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Performs discovery on the Identifier. - /// </summary> - /// <param name="requestHandler">The web request handler to use for discovery.</param> - /// <returns> - /// An initialized structure containing the discovered provider endpoint information. - /// </returns> - internal override IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { - Contract.Requires<ArgumentNullException>(requestHandler != null); - Contract.Ensures(Contract.Result<IEnumerable<ServiceEndpoint>>() != null); - throw new NotImplementedException(); - } - - /// <summary> /// Returns an <see cref="Identifier"/> that has no URI fragment. /// Quietly returns the original <see cref="Identifier"/> if it is not /// a <see cref="UriIdentifier"/> or no fragment exists. diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/ServiceEndpoint.cs b/src/DotNetOpenAuth/OpenId/IdentifierDiscoveryResult.cs index f8744d0..3190920 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/ServiceEndpoint.cs +++ b/src/DotNetOpenAuth/OpenId/IdentifierDiscoveryResult.cs @@ -1,13 +1,15 @@ //----------------------------------------------------------------------- -// <copyright file="ServiceEndpoint.cs" company="Andrew Arnott"> +// <copyright file="IdentifierDiscoveryResult.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- -namespace DotNetOpenAuth.OpenId.RelyingParty { +namespace DotNetOpenAuth.OpenId { using System; + using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; using System.IO; @@ -15,17 +17,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System.Text; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; + using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// Represents a single OP endpoint from discovery on some OpenID Identifier. /// </summary> [DebuggerDisplay("ClaimedIdentifier: {ClaimedIdentifier}, ProviderEndpoint: {ProviderEndpoint}, OpenId: {Protocol.Version}")] - internal class ServiceEndpoint : IXrdsProviderEndpoint { + public sealed class IdentifierDiscoveryResult : IProviderEndpoint { /// <summary> - /// The i-name identifier the user actually typed in - /// or the url identifier with the scheme stripped off. + /// Backing field for the <see cref="Protocol"/> property. /// </summary> - private string friendlyIdentifierForDisplay; + private Protocol protocol; /// <summary> /// Backing field for the <see cref="ClaimedIdentifier"/> property. @@ -33,23 +35,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private Identifier claimedIdentifier; /// <summary> - /// The OpenID protocol version used at the identity Provider. - /// </summary> - private Protocol protocol; - - /// <summary> - /// The @priority given in the XRDS document for this specific OP endpoint. - /// </summary> - private int? uriPriority; - - /// <summary> - /// The @priority given in the XRDS document for this service - /// (which may consist of several endpoints). + /// Backing field for the <see cref="FriendlyIdentifierForDisplay"/> property. /// </summary> - private int? servicePriority; + private string friendlyIdentifierForDisplay; /// <summary> - /// Initializes a new instance of the <see cref="ServiceEndpoint"/> class. + /// Initializes a new instance of the <see cref="IdentifierDiscoveryResult"/> class. /// </summary> /// <param name="providerEndpoint">The provider endpoint.</param> /// <param name="claimedIdentifier">The Claimed Identifier.</param> @@ -57,47 +48,23 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="providerLocalIdentifier">The Provider Local Identifier.</param> /// <param name="servicePriority">The service priority.</param> /// <param name="uriPriority">The URI priority.</param> - private ServiceEndpoint(ProviderEndpointDescription providerEndpoint, Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, int? servicePriority, int? uriPriority) { - Contract.Requires<ArgumentNullException>(claimedIdentifier != null); - Contract.Requires<ArgumentNullException>(providerEndpoint != null); - this.ProviderDescription = providerEndpoint; - this.ClaimedIdentifier = claimedIdentifier; - this.UserSuppliedIdentifier = userSuppliedIdentifier; - this.ProviderLocalIdentifier = providerLocalIdentifier ?? claimedIdentifier; - this.servicePriority = servicePriority; - this.uriPriority = uriPriority; - } - - /// <summary> - /// Initializes a new instance of the <see cref="ServiceEndpoint"/> class. - /// </summary> - /// <param name="providerEndpoint">The provider endpoint.</param> - /// <param name="claimedIdentifier">The Claimed Identifier.</param> - /// <param name="userSuppliedIdentifier">The User-supplied Identifier.</param> - /// <param name="providerLocalIdentifier">The Provider Local Identifier.</param> - /// <param name="protocol">The protocol.</param> - /// <remarks> - /// Used for deserializing <see cref="ServiceEndpoint"/> from authentication responses. - /// </remarks> - private ServiceEndpoint(Uri providerEndpoint, Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, Protocol protocol) { + private IdentifierDiscoveryResult(ProviderEndpointDescription providerEndpoint, Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, int? servicePriority, int? uriPriority) { Contract.Requires<ArgumentNullException>(providerEndpoint != null); Contract.Requires<ArgumentNullException>(claimedIdentifier != null); - Contract.Requires<ArgumentNullException>(providerLocalIdentifier != null); - Contract.Requires<ArgumentNullException>(protocol != null); - + this.ProviderEndpoint = providerEndpoint.Uri; + this.Capabilities = new ReadOnlyCollection<string>(providerEndpoint.Capabilities); + this.Version = providerEndpoint.Version; this.ClaimedIdentifier = claimedIdentifier; - this.UserSuppliedIdentifier = userSuppliedIdentifier; - this.ProviderDescription = new ProviderEndpointDescription(providerEndpoint, protocol.Version); this.ProviderLocalIdentifier = providerLocalIdentifier ?? claimedIdentifier; - this.protocol = protocol; + this.UserSuppliedIdentifier = userSuppliedIdentifier; + this.ServicePriority = servicePriority; + this.ProviderEndpointPriority = uriPriority; } /// <summary> - /// Gets the URL that the OpenID Provider receives authentication requests at. + /// Gets the detected version of OpenID implemented by the Provider. /// </summary> - Uri IProviderEndpoint.Uri { - get { return this.ProviderDescription.Endpoint; } - } + public Version Version { get; private set; } /// <summary> /// Gets the Identifier that was presented by the end user to the Relying Party, @@ -110,14 +77,14 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public Identifier UserSuppliedIdentifier { get; private set; } /// <summary> - /// Gets or sets the Identifier that the end user claims to own. + /// Gets the Identifier that the end user claims to control. /// </summary> public Identifier ClaimedIdentifier { get { return this.claimedIdentifier; } - set { + internal set { // Take care to reparse the incoming identifier to make sure it's // not a derived type that will override expected behavior. // Elsewhere in this class, we count on the fact that this property @@ -134,8 +101,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public Identifier ProviderLocalIdentifier { get; private set; } /// <summary> - /// Gets the value for the <see cref="IAuthenticationResponse.FriendlyIdentifierForDisplay"/> property. + /// Gets a more user-friendly (but NON-secure!) string to display to the user as his identifier. /// </summary> + /// <returns>A human-readable, abbreviated (but not secure) identifier the user MAY recognize as his own.</returns> public string FriendlyIdentifierForDisplay { get { if (this.friendlyIdentifierForDisplay == null) { @@ -149,8 +117,15 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } } else if (uri != null) { if (uri != this.Protocol.ClaimedIdentifierForOPIdentifier) { - string displayUri = uri.Uri.Host + uri.Uri.AbsolutePath; - displayUri = displayUri.TrimEnd('/'); + string displayUri = uri.Uri.Host; + + // We typically want to display the path, because that will often have the username in it. + // As Google Apps for Domains and the like become more popular, a standard /openid path + // will often appear, which is not helpful to identifying the user so we'll avoid including + // that path if it's present. + if (!string.Equals(uri.Uri.AbsolutePath, "/openid", StringComparison.OrdinalIgnoreCase)) { + displayUri += uri.Uri.AbsolutePath.TrimEnd('/'); + } // Multi-byte unicode characters get encoded by the Uri class for transit. // Since this is for display purposes, we want to reverse this and display a readable @@ -162,57 +137,45 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.friendlyIdentifierForDisplay = this.ClaimedIdentifier; } } + return this.friendlyIdentifierForDisplay; } } /// <summary> - /// Gets the list of services available at this OP Endpoint for the - /// claimed Identifier. May be null. + /// Gets the provider endpoint. /// </summary> - public ReadOnlyCollection<string> ProviderSupportedServiceTypeUris { - get { return this.ProviderDescription.Capabilities; } - } + public Uri ProviderEndpoint { get; private set; } /// <summary> - /// Gets the OpenID protocol used by the Provider. + /// Gets the @priority given in the XRDS document for this specific OP endpoint. /// </summary> - public Protocol Protocol { - get { - if (this.protocol == null) { - this.protocol = Protocol.Lookup(this.ProviderDescription.ProtocolVersion); - } - - return this.protocol; - } - } - - #region IXrdsProviderEndpoint Members + public int? ProviderEndpointPriority { get; private set; } /// <summary> - /// Gets the priority associated with this service that may have been given - /// in the XRDS document. + /// Gets the @priority given in the XRDS document for this service + /// (which may consist of several endpoints). /// </summary> - int? IXrdsProviderEndpoint.ServicePriority { - get { return this.servicePriority; } - } + public int? ServicePriority { get; private set; } /// <summary> - /// Gets the priority associated with the service endpoint URL. + /// Gets the collection of service type URIs found in the XRDS document describing this Provider. /// </summary> - int? IXrdsProviderEndpoint.UriPriority { - get { return this.uriPriority; } - } + /// <value>Should never be null, but may be empty.</value> + public ReadOnlyCollection<string> Capabilities { get; private set; } - #endregion + #region IProviderEndpoint Members /// <summary> - /// Gets the detected version of OpenID implemented by the Provider. + /// Gets the URL that the OpenID Provider receives authentication requests at. /// </summary> - Version IProviderEndpoint.Version { - get { return this.ProviderDescription.ProtocolVersion; } + /// <value>This value MUST be an absolute HTTP or HTTPS URL.</value> + Uri IProviderEndpoint.Uri { + get { return this.ProviderEndpoint; } } + #endregion + /// <summary> /// Gets an XRDS sorting routine that uses the XRDS Service/@Priority /// attribute to determine order. @@ -220,7 +183,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <remarks> /// Endpoints lacking any priority value are sorted to the end of the list. /// </remarks> - internal static Comparison<IXrdsProviderEndpoint> EndpointOrder { + internal static Comparison<IdentifierDiscoveryResult> EndpointOrder { get { // Sort first by service type (OpenID 2.0, 1.1, 1.0), // then by Service/@priority, then by Service/Uri/@priority @@ -234,11 +197,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { if (result != 0) { return result; } - if (se1.UriPriority.HasValue && se2.UriPriority.HasValue) { - return se1.UriPriority.Value.CompareTo(se2.UriPriority.Value); - } else if (se1.UriPriority.HasValue) { + if (se1.ProviderEndpointPriority.HasValue && se2.ProviderEndpointPriority.HasValue) { + return se1.ProviderEndpointPriority.Value.CompareTo(se2.ProviderEndpointPriority.Value); + } else if (se1.ProviderEndpointPriority.HasValue) { return -1; - } else if (se2.UriPriority.HasValue) { + } else if (se2.ProviderEndpointPriority.HasValue) { return 1; } else { return 0; @@ -250,11 +213,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { return 1; } else { // neither service defines a priority, so base ordering by uri priority. - if (se1.UriPriority.HasValue && se2.UriPriority.HasValue) { - return se1.UriPriority.Value.CompareTo(se2.UriPriority.Value); - } else if (se1.UriPriority.HasValue) { + if (se1.ProviderEndpointPriority.HasValue && se2.ProviderEndpointPriority.HasValue) { + return se1.ProviderEndpointPriority.Value.CompareTo(se2.ProviderEndpointPriority.Value); + } else if (se1.ProviderEndpointPriority.HasValue) { return -1; - } else if (se2.UriPriority.HasValue) { + } else if (se2.ProviderEndpointPriority.HasValue) { return 1; } else { return 0; @@ -266,35 +229,25 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> - /// Gets the URL which accepts OpenID Authentication protocol messages. + /// Gets the protocol used by the OpenID Provider. /// </summary> - /// <remarks> - /// Obtained by performing discovery on the User-Supplied Identifier. - /// This value MUST be an absolute HTTP or HTTPS URL. - /// </remarks> - internal Uri ProviderEndpoint { - get { return this.ProviderDescription.Endpoint; } - } + internal Protocol Protocol { + get { + if (this.protocol == null) { + this.protocol = Protocol.Lookup(this.Version); + } - /// <summary> - /// Gets a value indicating whether the <see cref="ProviderEndpoint"/> is using an encrypted channel. - /// </summary> - internal bool IsSecure { - get { return string.Equals(this.ProviderEndpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase); } + return this.protocol; + } } /// <summary> - /// Gets the provider description. - /// </summary> - internal ProviderEndpointDescription ProviderDescription { get; private set; } - - /// <summary> /// Implements the operator ==. /// </summary> /// <param name="se1">The first service endpoint.</param> /// <param name="se2">The second service endpoint.</param> /// <returns>The result of the operator.</returns> - public static bool operator ==(ServiceEndpoint se1, ServiceEndpoint se2) { + public static bool operator ==(IdentifierDiscoveryResult se1, IdentifierDiscoveryResult se2) { return se1.EqualsNullSafe(se2); } @@ -304,44 +257,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="se1">The first service endpoint.</param> /// <param name="se2">The second service endpoint.</param> /// <returns>The result of the operator.</returns> - public static bool operator !=(ServiceEndpoint se1, ServiceEndpoint se2) { + public static bool operator !=(IdentifierDiscoveryResult se1, IdentifierDiscoveryResult se2) { return !(se1 == se2); } /// <summary> - /// Checks for the presence of a given Type URI in an XRDS service. - /// </summary> - /// <param name="typeUri">The type URI to check for.</param> - /// <returns> - /// <c>true</c> if the service type uri is present; <c>false</c> otherwise. - /// </returns> - public bool IsTypeUriPresent(string typeUri) { - return this.ProviderDescription.IsExtensionSupported(typeUri); - } - - /// <summary> - /// Determines whether a given extension is supported by this endpoint. - /// </summary> - /// <typeparam name="T">The type of extension to check support for on this endpoint.</typeparam> - /// <returns> - /// <c>true</c> if the extension is supported by this endpoint; otherwise, <c>false</c>. - /// </returns> - public bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new() { - return this.ProviderDescription.IsExtensionSupported<T>(); - } - - /// <summary> - /// Determines whether a given extension is supported by this endpoint. - /// </summary> - /// <param name="extensionType">The type of extension to check support for on this endpoint.</param> - /// <returns> - /// <c>true</c> if the extension is supported by this endpoint; otherwise, <c>false</c>. - /// </returns> - public bool IsExtensionSupported(Type extensionType) { - return this.ProviderDescription.IsExtensionSupported(extensionType); - } - - /// <summary> /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>. /// </summary> /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param> @@ -352,7 +272,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The <paramref name="obj"/> parameter is null. /// </exception> public override bool Equals(object obj) { - ServiceEndpoint other = obj as ServiceEndpoint; + var other = obj as IdentifierDiscoveryResult; if (other == null) { return false; } @@ -388,57 +308,95 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { StringBuilder builder = new StringBuilder(); builder.AppendLine("ClaimedIdentifier: " + this.ClaimedIdentifier); builder.AppendLine("ProviderLocalIdentifier: " + this.ProviderLocalIdentifier); - builder.AppendLine("ProviderEndpoint: " + this.ProviderEndpoint.AbsoluteUri); - builder.AppendLine("OpenID version: " + this.Protocol.Version); + builder.AppendLine("ProviderEndpoint: " + this.ProviderEndpoint); + builder.AppendLine("OpenID version: " + this.Version); builder.AppendLine("Service Type URIs:"); - if (this.ProviderSupportedServiceTypeUris != null) { - foreach (string serviceTypeUri in this.ProviderSupportedServiceTypeUris) { - builder.Append("\t"); - builder.AppendLine(serviceTypeUri); - } - } else { - builder.AppendLine("\t(unavailable)"); + foreach (string serviceTypeUri in this.Capabilities) { + builder.Append("\t"); + builder.AppendLine(serviceTypeUri); } builder.Length -= Environment.NewLine.Length; // trim last newline return builder.ToString(); } /// <summary> - /// Reads previously discovered information about an endpoint - /// from a solicited authentication assertion for validation. + /// Checks whether the OpenId Identifier claims support for a given extension. /// </summary> - /// <param name="reader">The reader from which to deserialize the <see cref="ServiceEndpoint"/>.</param> + /// <typeparam name="T">The extension whose support is being queried.</typeparam> /// <returns> - /// A <see cref="ServiceEndpoint"/> object that has everything - /// except the <see cref="ProviderSupportedServiceTypeUris"/> - /// deserialized. + /// True if support for the extension is advertised. False otherwise. /// </returns> - internal static ServiceEndpoint Deserialize(TextReader reader) { - var claimedIdentifier = Identifier.Parse(reader.ReadLine()); - var providerLocalIdentifier = Identifier.Parse(reader.ReadLine()); - string userSuppliedIdentifier = reader.ReadLine(); - if (userSuppliedIdentifier.Length == 0) { - userSuppliedIdentifier = null; + /// <remarks> + /// Note that a true or false return value is no guarantee of a Provider's + /// support for or lack of support for an extension. The return value is + /// determined by how the authenticating user filled out his/her XRDS document only. + /// The only way to be sure of support for a given extension is to include + /// the extension in the request and see if a response comes back for that extension. + /// </remarks> + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "No parameter at all.")] + public bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new() { + T extension = new T(); + return this.IsExtensionSupported(extension); + } + + /// <summary> + /// Checks whether the OpenId Identifier claims support for a given extension. + /// </summary> + /// <param name="extensionType">The extension whose support is being queried.</param> + /// <returns> + /// True if support for the extension is advertised. False otherwise. + /// </returns> + /// <remarks> + /// Note that a true or false return value is no guarantee of a Provider's + /// support for or lack of support for an extension. The return value is + /// determined by how the authenticating user filled out his/her XRDS document only. + /// The only way to be sure of support for a given extension is to include + /// the extension in the request and see if a response comes back for that extension. + /// </remarks> + public bool IsExtensionSupported(Type extensionType) { + var extension = (IOpenIdMessageExtension)Activator.CreateInstance(extensionType); + return this.IsExtensionSupported(extension); + } + + /// <summary> + /// Determines whether a given extension is supported by this endpoint. + /// </summary> + /// <param name="extension">An instance of the extension to check support for.</param> + /// <returns> + /// <c>true</c> if the extension is supported by this endpoint; otherwise, <c>false</c>. + /// </returns> + public bool IsExtensionSupported(IOpenIdMessageExtension extension) { + Contract.Requires<ArgumentNullException>(extension != null); + + // Consider the primary case. + if (this.IsTypeUriPresent(extension.TypeUri)) { + return true; + } + + // Consider the secondary cases. + if (extension.AdditionalSupportedTypeUris != null) { + if (extension.AdditionalSupportedTypeUris.Any(typeUri => this.IsTypeUriPresent(typeUri))) { + return true; + } } - var providerEndpoint = new Uri(reader.ReadLine()); - var protocol = Protocol.FindBestVersion(p => p.Version, new[] { new Version(reader.ReadLine()) }); - return new ServiceEndpoint(providerEndpoint, claimedIdentifier, userSuppliedIdentifier, providerLocalIdentifier, protocol); + + return false; } /// <summary> - /// Creates a <see cref="ServiceEndpoint"/> instance to represent some OP Identifier. + /// Creates a <see cref="IdentifierDiscoveryResult"/> instance to represent some OP Identifier. /// </summary> /// <param name="providerIdentifier">The provider identifier (actually the user-supplied identifier).</param> /// <param name="providerEndpoint">The provider endpoint.</param> /// <param name="servicePriority">The service priority.</param> /// <param name="uriPriority">The URI priority.</param> - /// <returns>The created <see cref="ServiceEndpoint"/> instance</returns> - internal static ServiceEndpoint CreateForProviderIdentifier(Identifier providerIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) { + /// <returns>The created <see cref="IdentifierDiscoveryResult"/> instance</returns> + internal static IdentifierDiscoveryResult CreateForProviderIdentifier(Identifier providerIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) { Contract.Requires<ArgumentNullException>(providerEndpoint != null); - Protocol protocol = Protocol.Detect(providerEndpoint.Capabilities); + Protocol protocol = Protocol.Lookup(providerEndpoint.Version); - return new ServiceEndpoint( + return new IdentifierDiscoveryResult( providerEndpoint, protocol.ClaimedIdentifierForOPIdentifier, providerIdentifier, @@ -448,20 +406,20 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> - /// Creates a <see cref="ServiceEndpoint"/> instance to represent some Claimed Identifier. + /// Creates a <see cref="IdentifierDiscoveryResult"/> instance to represent some Claimed Identifier. /// </summary> /// <param name="claimedIdentifier">The claimed identifier.</param> /// <param name="providerLocalIdentifier">The provider local identifier.</param> /// <param name="providerEndpoint">The provider endpoint.</param> /// <param name="servicePriority">The service priority.</param> /// <param name="uriPriority">The URI priority.</param> - /// <returns>The created <see cref="ServiceEndpoint"/> instance</returns> - internal static ServiceEndpoint CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier providerLocalIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) { + /// <returns>The created <see cref="IdentifierDiscoveryResult"/> instance</returns> + internal static IdentifierDiscoveryResult CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier providerLocalIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) { return CreateForClaimedIdentifier(claimedIdentifier, null, providerLocalIdentifier, providerEndpoint, servicePriority, uriPriority); } /// <summary> - /// Creates a <see cref="ServiceEndpoint"/> instance to represent some Claimed Identifier. + /// Creates a <see cref="IdentifierDiscoveryResult"/> instance to represent some Claimed Identifier. /// </summary> /// <param name="claimedIdentifier">The claimed identifier.</param> /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> @@ -469,24 +427,30 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="providerEndpoint">The provider endpoint.</param> /// <param name="servicePriority">The service priority.</param> /// <param name="uriPriority">The URI priority.</param> - /// <returns>The created <see cref="ServiceEndpoint"/> instance</returns> - internal static ServiceEndpoint CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) { - return new ServiceEndpoint(providerEndpoint, claimedIdentifier, userSuppliedIdentifier, providerLocalIdentifier, servicePriority, uriPriority); + /// <returns>The created <see cref="IdentifierDiscoveryResult"/> instance</returns> + internal static IdentifierDiscoveryResult CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, ProviderEndpointDescription providerEndpoint, int? servicePriority, int? uriPriority) { + return new IdentifierDiscoveryResult(providerEndpoint, claimedIdentifier, userSuppliedIdentifier, providerLocalIdentifier, servicePriority, uriPriority); } /// <summary> - /// Saves the discovered information about this endpoint - /// for later comparison to validate assertions. + /// Determines whether a given type URI is present on the specified provider endpoint. /// </summary> - /// <param name="writer">The writer to use for serializing out the fields.</param> - internal void Serialize(TextWriter writer) { - writer.WriteLine(this.ClaimedIdentifier); - writer.WriteLine(this.ProviderLocalIdentifier); - writer.WriteLine(this.UserSuppliedIdentifier); - writer.WriteLine(this.ProviderEndpoint); - writer.WriteLine(this.Protocol.Version); - - // No reason to serialize priority. We only needed priority to decide whether to use this endpoint. + /// <param name="typeUri">The type URI.</param> + /// <returns> + /// <c>true</c> if the type URI is present on the specified provider endpoint; otherwise, <c>false</c>. + /// </returns> + internal bool IsTypeUriPresent(string typeUri) { + Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(typeUri)); + return this.Capabilities.Contains(typeUri); + } + + /// <summary> + /// Sets the Capabilities property (this method is a test hook.) + /// </summary> + /// <param name="value">The value.</param> + /// <remarks>The publicize.exe tool should work for the unit tests, but for some reason it fails on the build server.</remarks> + internal void SetCapabilitiesForTestHook(ReadOnlyCollection<string> value) { + this.Capabilities = value; } /// <summary> @@ -495,22 +459,39 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="endpoint">The endpoint to prioritize.</param> /// <returns>An arbitary integer, which may be used for sorting against other returned values from this method.</returns> - private static double GetEndpointPrecedenceOrderByServiceType(IXrdsProviderEndpoint endpoint) { + private static double GetEndpointPrecedenceOrderByServiceType(IdentifierDiscoveryResult endpoint) { // The numbers returned from this method only need to compare against other numbers // from this method, which makes them arbitrary but relational to only others here. - if (endpoint.IsTypeUriPresent(Protocol.V20.OPIdentifierServiceTypeURI)) { + if (endpoint.Capabilities.Contains(Protocol.V20.OPIdentifierServiceTypeURI)) { return 0; } - if (endpoint.IsTypeUriPresent(Protocol.V20.ClaimedIdentifierServiceTypeURI)) { + if (endpoint.Capabilities.Contains(Protocol.V20.ClaimedIdentifierServiceTypeURI)) { return 1; } - if (endpoint.IsTypeUriPresent(Protocol.V11.ClaimedIdentifierServiceTypeURI)) { + if (endpoint.Capabilities.Contains(Protocol.V11.ClaimedIdentifierServiceTypeURI)) { return 2; } - if (endpoint.IsTypeUriPresent(Protocol.V10.ClaimedIdentifierServiceTypeURI)) { + if (endpoint.Capabilities.Contains(Protocol.V10.ClaimedIdentifierServiceTypeURI)) { return 3; } return 10; } + +#if CONTRACTS_FULL + /// <summary> + /// Verifies conditions that should be true for any valid state of this object. + /// </summary> + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Called by code contracts.")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")] + [ContractInvariantMethod] + private void ObjectInvariant() { + Contract.Invariant(this.ProviderEndpoint != null); + Contract.Invariant(this.ClaimedIdentifier != null); + Contract.Invariant(this.ProviderLocalIdentifier != null); + Contract.Invariant(this.Capabilities != null); + Contract.Invariant(this.Version != null); + Contract.Invariant(this.Protocol != null); + } +#endif } } diff --git a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs index 5215022..3fd9424 100644 --- a/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Messages/AssociateRequest.cs @@ -76,16 +76,16 @@ namespace DotNetOpenAuth.OpenId.Messages { /// Null if no association could be created that meet the security requirements /// and the provider OpenID version. /// </returns> - internal static AssociateRequest Create(SecuritySettings securityRequirements, ProviderEndpointDescription provider) { + internal static AssociateRequest Create(SecuritySettings securityRequirements, IProviderEndpoint provider) { Contract.Requires<ArgumentNullException>(securityRequirements != null); Contract.Requires<ArgumentNullException>(provider != null); // Apply our knowledge of the endpoint's transport, OpenID version, and // security requirements to decide the best association. - bool unencryptedAllowed = provider.Endpoint.IsTransportSecure(); + bool unencryptedAllowed = provider.Uri.IsTransportSecure(); bool useDiffieHellman = !unencryptedAllowed; string associationType, sessionType; - if (!HmacShaAssociation.TryFindBestAssociation(Protocol.Lookup(provider.ProtocolVersion), true, securityRequirements, useDiffieHellman, out associationType, out sessionType)) { + if (!HmacShaAssociation.TryFindBestAssociation(Protocol.Lookup(provider.Version), true, securityRequirements, useDiffieHellman, out associationType, out sessionType)) { // There are no associations that meet all requirements. Logger.OpenId.Warn("Security requirements and protocol combination knock out all possible association types. Dumb mode forced."); return null; @@ -106,19 +106,19 @@ namespace DotNetOpenAuth.OpenId.Messages { /// Null if no association could be created that meet the security requirements /// and the provider OpenID version. /// </returns> - internal static AssociateRequest Create(SecuritySettings securityRequirements, ProviderEndpointDescription provider, string associationType, string sessionType) { + internal static AssociateRequest Create(SecuritySettings securityRequirements, IProviderEndpoint provider, string associationType, string sessionType) { Contract.Requires<ArgumentNullException>(securityRequirements != null); Contract.Requires<ArgumentNullException>(provider != null); Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(associationType)); Contract.Requires<ArgumentNullException>(sessionType != null); - bool unencryptedAllowed = provider.Endpoint.IsTransportSecure(); + bool unencryptedAllowed = provider.Uri.IsTransportSecure(); if (unencryptedAllowed) { - var associateRequest = new AssociateUnencryptedRequest(provider.ProtocolVersion, provider.Endpoint); + var associateRequest = new AssociateUnencryptedRequest(provider.Version, provider.Uri); associateRequest.AssociationType = associationType; return associateRequest; } else { - var associateRequest = new AssociateDiffieHellmanRequest(provider.ProtocolVersion, provider.Endpoint); + var associateRequest = new AssociateDiffieHellmanRequest(provider.Version, provider.Uri); associateRequest.AssociationType = associationType; associateRequest.SessionType = sessionType; associateRequest.InitializeRequest(); diff --git a/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs b/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs index 636df67..1a6e7e9 100644 --- a/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs +++ b/src/DotNetOpenAuth/OpenId/NoDiscoveryIdentifier.cs @@ -70,17 +70,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Performs discovery on the Identifier. - /// </summary> - /// <param name="requestHandler">The web request handler to use for discovery.</param> - /// <returns> - /// An initialized structure containing the discovered provider endpoint information. - /// </returns> - internal override IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { - return Enumerable.Empty<ServiceEndpoint>(); - } - - /// <summary> /// Returns an <see cref="Identifier"/> that has no URI fragment. /// Quietly returns the original <see cref="Identifier"/> if it is not /// a <see cref="UriIdentifier"/> or no fragment exists. diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs index fda81cc..29315bb 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs @@ -722,6 +722,15 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> + /// Looks up a localized string similar to The X.509 certificate used to sign this document is not trusted.. + /// </summary> + internal static string X509CertificateNotTrusted { + get { + return ResourceManager.GetString("X509CertificateNotTrusted", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to XRI support has been disabled at this site.. /// </summary> internal static string XriResolutionDisabled { diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx index c5f506d..ae68fe6 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx +++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx @@ -346,4 +346,7 @@ Discovered endpoint info: <data name="PropertyNotSet" xml:space="preserve"> <value>The {0} property must be set first.</value> </data> + <data name="X509CertificateNotTrusted" xml:space="preserve"> + <value>The X.509 certificate used to sign this document is not trusted.</value> + </data> </root>
\ No newline at end of file diff --git a/src/DotNetOpenAuth/OpenId/OpenIdUtilities.cs b/src/DotNetOpenAuth/OpenId/OpenIdUtilities.cs index 3e75e61..04eb23c 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdUtilities.cs +++ b/src/DotNetOpenAuth/OpenId/OpenIdUtilities.cs @@ -16,13 +16,14 @@ namespace DotNetOpenAuth.OpenId { using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.ChannelElements; using DotNetOpenAuth.OpenId.Extensions; + using DotNetOpenAuth.OpenId.Messages; using DotNetOpenAuth.OpenId.Provider; using DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// A set of utilities especially useful to OpenID. /// </summary> - internal static class OpenIdUtilities { + public static class OpenIdUtilities { /// <summary> /// The prefix to designate this library's proprietary parameters added to the protocol. /// </summary> diff --git a/src/DotNetOpenAuth/OpenId/OpenIdXrdsHelper.cs b/src/DotNetOpenAuth/OpenId/OpenIdXrdsHelper.cs index 664a127..00468ed 100644 --- a/src/DotNetOpenAuth/OpenId/OpenIdXrdsHelper.cs +++ b/src/DotNetOpenAuth/OpenId/OpenIdXrdsHelper.cs @@ -27,6 +27,9 @@ namespace DotNetOpenAuth.OpenId { /// or for Provider's to perform RP discovery/verification as part of authentication. /// </remarks> internal static IEnumerable<RelyingPartyEndpointDescription> FindRelyingPartyReceivingEndpoints(this XrdsDocument xrds) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Ensures(Contract.Result<IEnumerable<RelyingPartyEndpointDescription>>() != null); + return from service in xrds.FindReturnToServices() from uri in service.UriElements select new RelyingPartyEndpointDescription(uri.Uri, service.TypeElementUris); @@ -39,6 +42,9 @@ namespace DotNetOpenAuth.OpenId { /// <param name="xrds">The XrdsDocument to search.</param> /// <returns>A sequence of the icon URLs in preferred order.</returns> internal static IEnumerable<Uri> FindRelyingPartyIcons(this XrdsDocument xrds) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Ensures(Contract.Result<IEnumerable<Uri>>() != null); + return from xrd in xrds.XrdElements from service in xrd.OpenIdRelyingPartyIcons from uri in service.UriElements @@ -55,15 +61,16 @@ namespace DotNetOpenAuth.OpenId { /// <returns> /// A sequence of OpenID Providers that can assert ownership of the <paramref name="claimedIdentifier"/>. /// </returns> - internal static IEnumerable<ServiceEndpoint> CreateServiceEndpoints(this XrdsDocument xrds, UriIdentifier claimedIdentifier, UriIdentifier userSuppliedIdentifier) { - var endpoints = new List<ServiceEndpoint>(); + internal static IEnumerable<IdentifierDiscoveryResult> CreateServiceEndpoints(this IEnumerable<XrdElement> xrds, UriIdentifier claimedIdentifier, UriIdentifier userSuppliedIdentifier) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Requires<ArgumentNullException>(claimedIdentifier != null); + Contract.Requires<ArgumentNullException>(userSuppliedIdentifier != null); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); + + var endpoints = new List<IdentifierDiscoveryResult>(); endpoints.AddRange(xrds.GenerateOPIdentifierServiceEndpoints(userSuppliedIdentifier)); + endpoints.AddRange(xrds.GenerateClaimedIdentifierServiceEndpoints(claimedIdentifier, userSuppliedIdentifier)); - // If any OP Identifier service elements were found, we must not proceed - // to return any Claimed Identifier services. - if (endpoints.Count == 0) { - endpoints.AddRange(xrds.GenerateClaimedIdentifierServiceEndpoints(claimedIdentifier, userSuppliedIdentifier)); - } Logger.Yadis.DebugFormat("Total services discovered in XRDS: {0}", endpoints.Count); Logger.Yadis.Debug(endpoints.ToStringDeferred(true)); return endpoints; @@ -76,18 +83,14 @@ namespace DotNetOpenAuth.OpenId { /// <param name="xrds">The XrdsDocument instance to use in this process.</param> /// <param name="userSuppliedIdentifier">The user-supplied i-name that was used to discover this XRDS document.</param> /// <returns>A sequence of OpenID Providers that can assert ownership of the canonical ID given in this document.</returns> - internal static IEnumerable<ServiceEndpoint> CreateServiceEndpoints(this XrdsDocument xrds, XriIdentifier userSuppliedIdentifier) { + internal static IEnumerable<IdentifierDiscoveryResult> CreateServiceEndpoints(this IEnumerable<XrdElement> xrds, XriIdentifier userSuppliedIdentifier) { Contract.Requires<ArgumentNullException>(xrds != null); Contract.Requires<ArgumentNullException>(userSuppliedIdentifier != null); - Contract.Ensures(Contract.Result<IEnumerable<ServiceEndpoint>>() != null); - var endpoints = new List<ServiceEndpoint>(); - endpoints.AddRange(xrds.GenerateOPIdentifierServiceEndpoints(userSuppliedIdentifier)); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); - // If any OP Identifier service elements were found, we must not proceed - // to return any Claimed Identifier services. - if (endpoints.Count == 0) { - endpoints.AddRange(xrds.GenerateClaimedIdentifierServiceEndpoints(userSuppliedIdentifier)); - } + var endpoints = new List<IdentifierDiscoveryResult>(); + endpoints.AddRange(xrds.GenerateOPIdentifierServiceEndpoints(userSuppliedIdentifier)); + endpoints.AddRange(xrds.GenerateClaimedIdentifierServiceEndpoints(userSuppliedIdentifier)); Logger.Yadis.DebugFormat("Total services discovered in XRDS: {0}", endpoints.Count); Logger.Yadis.Debug(endpoints.ToStringDeferred(true)); return endpoints; @@ -99,15 +102,15 @@ namespace DotNetOpenAuth.OpenId { /// <param name="xrds">The XrdsDocument instance to use in this process.</param> /// <param name="opIdentifier">The OP Identifier entered (and resolved) by the user. Essentially the user-supplied identifier.</param> /// <returns>A sequence of the providers that can offer directed identity services.</returns> - private static IEnumerable<ServiceEndpoint> GenerateOPIdentifierServiceEndpoints(this XrdsDocument xrds, Identifier opIdentifier) { + private static IEnumerable<IdentifierDiscoveryResult> GenerateOPIdentifierServiceEndpoints(this IEnumerable<XrdElement> xrds, Identifier opIdentifier) { Contract.Requires<ArgumentNullException>(xrds != null); Contract.Requires<ArgumentNullException>(opIdentifier != null); - Contract.Ensures(Contract.Result<IEnumerable<ServiceEndpoint>>() != null); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); return from service in xrds.FindOPIdentifierServices() from uri in service.UriElements let protocol = Protocol.FindBestVersion(p => p.OPIdentifierServiceTypeURI, service.TypeElementUris) let providerDescription = new ProviderEndpointDescription(uri.Uri, service.TypeElementUris) - select ServiceEndpoint.CreateForProviderIdentifier(opIdentifier, providerDescription, service.Priority, uri.Priority); + select IdentifierDiscoveryResult.CreateForProviderIdentifier(opIdentifier, providerDescription, service.Priority, uri.Priority); } /// <summary> @@ -120,12 +123,16 @@ namespace DotNetOpenAuth.OpenId { /// <returns> /// A sequence of the providers that can assert ownership of the given identifier. /// </returns> - private static IEnumerable<ServiceEndpoint> GenerateClaimedIdentifierServiceEndpoints(this XrdsDocument xrds, UriIdentifier claimedIdentifier, UriIdentifier userSuppliedIdentifier) { + private static IEnumerable<IdentifierDiscoveryResult> GenerateClaimedIdentifierServiceEndpoints(this IEnumerable<XrdElement> xrds, UriIdentifier claimedIdentifier, UriIdentifier userSuppliedIdentifier) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Requires<ArgumentNullException>(claimedIdentifier != null); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); + return from service in xrds.FindClaimedIdentifierServices() from uri in service.UriElements where uri.Uri != null let providerEndpoint = new ProviderEndpointDescription(uri.Uri, service.TypeElementUris) - select ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, userSuppliedIdentifier, service.ProviderLocalIdentifier, providerEndpoint, service.Priority, uri.Priority); + select IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, userSuppliedIdentifier, service.ProviderLocalIdentifier, providerEndpoint, service.Priority, uri.Priority); } /// <summary> @@ -135,7 +142,12 @@ namespace DotNetOpenAuth.OpenId { /// <param name="xrds">The XrdsDocument instance to use in this process.</param> /// <param name="userSuppliedIdentifier">The i-name supplied by the user.</param> /// <returns>A sequence of the providers that can assert ownership of the given identifier.</returns> - private static IEnumerable<ServiceEndpoint> GenerateClaimedIdentifierServiceEndpoints(this XrdsDocument xrds, XriIdentifier userSuppliedIdentifier) { + private static IEnumerable<IdentifierDiscoveryResult> GenerateClaimedIdentifierServiceEndpoints(this IEnumerable<XrdElement> xrds, XriIdentifier userSuppliedIdentifier) { + // Cannot use code contracts because this method uses yield return. + ////Contract.Requires<ArgumentNullException>(xrds != null); + ////Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); + ErrorUtilities.VerifyArgumentNotNull(xrds, "xrds"); + foreach (var service in xrds.FindClaimedIdentifierServices()) { foreach (var uri in service.UriElements) { // spec section 7.3.2.3 on Claimed Id -> CanonicalID substitution @@ -148,7 +160,7 @@ namespace DotNetOpenAuth.OpenId { // In the case of XRI names, the ClaimedId is actually the CanonicalID. var claimedIdentifier = new XriIdentifier(service.Xrd.CanonicalID); var providerEndpoint = new ProviderEndpointDescription(uri.Uri, service.TypeElementUris); - yield return ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, userSuppliedIdentifier, service.ProviderLocalIdentifier, providerEndpoint, service.Priority, uri.Priority); + yield return IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, userSuppliedIdentifier, service.ProviderLocalIdentifier, providerEndpoint, service.Priority, uri.Priority); } } } @@ -158,8 +170,11 @@ namespace DotNetOpenAuth.OpenId { /// </summary> /// <param name="xrds">The XrdsDocument instance to use in this process.</param> /// <returns>A sequence of service elements.</returns> - private static IEnumerable<ServiceElement> FindOPIdentifierServices(this XrdsDocument xrds) { - return from xrd in xrds.XrdElements + private static IEnumerable<ServiceElement> FindOPIdentifierServices(this IEnumerable<XrdElement> xrds) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Ensures(Contract.Result<IEnumerable<ServiceElement>>() != null); + + return from xrd in xrds from service in xrd.OpenIdProviderIdentifierServices select service; } @@ -170,8 +185,11 @@ namespace DotNetOpenAuth.OpenId { /// </summary> /// <param name="xrds">The XrdsDocument instance to use in this process.</param> /// <returns>A sequence of the services offered.</returns> - private static IEnumerable<ServiceElement> FindClaimedIdentifierServices(this XrdsDocument xrds) { - return from xrd in xrds.XrdElements + private static IEnumerable<ServiceElement> FindClaimedIdentifierServices(this IEnumerable<XrdElement> xrds) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Ensures(Contract.Result<IEnumerable<ServiceElement>>() != null); + + return from xrd in xrds from service in xrd.OpenIdClaimedIdentifierServices select service; } @@ -183,6 +201,9 @@ namespace DotNetOpenAuth.OpenId { /// <param name="xrds">The XrdsDocument instance to use in this process.</param> /// <returns>A sequence of service elements.</returns> private static IEnumerable<ServiceElement> FindReturnToServices(this XrdsDocument xrds) { + Contract.Requires<ArgumentNullException>(xrds != null); + Contract.Ensures(Contract.Result<IEnumerable<ServiceElement>>() != null); + return from xrd in xrds.XrdElements from service in xrd.OpenIdRelyingPartyReturnToServices select service; diff --git a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs index 827ca6c..611101d 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/OpenIdProvider.cs @@ -20,6 +20,7 @@ namespace DotNetOpenAuth.OpenId.Provider { using DotNetOpenAuth.Messaging.Bindings; using DotNetOpenAuth.OpenId.ChannelElements; using DotNetOpenAuth.OpenId.Messages; + using RP = DotNetOpenAuth.OpenId.RelyingParty; /// <summary> /// Offers services for a web page that is acting as an OpenID identity server. @@ -43,6 +44,12 @@ namespace DotNetOpenAuth.OpenId.Provider { private ProviderSecuritySettings securitySettings; /// <summary> + /// The relying party used to perform discovery on identifiers being sent in + /// unsolicited positive assertions. + /// </summary> + private RP.OpenIdRelyingParty relyingParty; + + /// <summary> /// Initializes a new instance of the <see cref="OpenIdProvider"/> class. /// </summary> public OpenIdProvider() @@ -160,6 +167,13 @@ namespace DotNetOpenAuth.OpenId.Provider { } /// <summary> + /// Gets the list of services that can perform discovery on identifiers given to this relying party. + /// </summary> + internal IList<IIdentifierDiscoveryService> DiscoveryServices { + get { return this.RelyingParty.DiscoveryServices; } + } + + /// <summary> /// Gets the association store. /// </summary> internal IAssociationStore<AssociationRelyingPartyType> AssociationStore { get; private set; } @@ -173,6 +187,25 @@ namespace DotNetOpenAuth.OpenId.Provider { } /// <summary> + /// Gets the relying party used for discovery of identifiers sent in unsolicited assertions. + /// </summary> + private RP.OpenIdRelyingParty RelyingParty { + get { + if (this.relyingParty == null) { + lock (this) { + if (this.relyingParty == null) { + // we just need an RP that's capable of discovery, so stateless mode is fine. + this.relyingParty = new RP.OpenIdRelyingParty(null); + } + } + } + + this.relyingParty.Channel.WebRequestHandler = this.WebRequestHandler; + return this.relyingParty; + } + } + + /// <summary> /// Gets the incoming OpenID request if there is one, or null if none was detected. /// </summary> /// <returns>The request that the hosting Provider should possibly process and then transmit the response for.</returns> @@ -314,7 +347,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// web site and log him/her in immediately in one uninterrupted step. /// </summary> /// <param name="providerEndpoint">The absolute URL on the Provider site that receives OpenID messages.</param> - /// <param name="relyingParty">The URL of the Relying Party web site. + /// <param name="relyingPartyRealm">The URL of the Relying Party web site. /// This will typically be the home page, but may be a longer URL if /// that Relying Party considers the scope of its realm to be more specific. /// The URL provided here must allow discovery of the Relying Party's @@ -323,15 +356,15 @@ namespace DotNetOpenAuth.OpenId.Provider { /// <param name="localIdentifier">The Identifier you know your user by internally. This will typically /// be the same as <paramref name="claimedIdentifier"/>.</param> /// <param name="extensions">The extensions.</param> - public void SendUnsolicitedAssertion(Uri providerEndpoint, Realm relyingParty, Identifier claimedIdentifier, Identifier localIdentifier, params IExtensionMessage[] extensions) { + public void SendUnsolicitedAssertion(Uri providerEndpoint, Realm relyingPartyRealm, Identifier claimedIdentifier, Identifier localIdentifier, params IExtensionMessage[] extensions) { Contract.Requires<InvalidOperationException>(HttpContext.Current != null, MessagingStrings.HttpContextRequired); Contract.Requires<ArgumentNullException>(providerEndpoint != null); Contract.Requires<ArgumentException>(providerEndpoint.IsAbsoluteUri); - Contract.Requires<ArgumentNullException>(relyingParty != null); + Contract.Requires<ArgumentNullException>(relyingPartyRealm != null); Contract.Requires<ArgumentNullException>(claimedIdentifier != null); Contract.Requires<ArgumentNullException>(localIdentifier != null); - this.PrepareUnsolicitedAssertion(providerEndpoint, relyingParty, claimedIdentifier, localIdentifier, extensions).Send(); + this.PrepareUnsolicitedAssertion(providerEndpoint, relyingPartyRealm, claimedIdentifier, localIdentifier, extensions).Send(); } /// <summary> @@ -340,7 +373,7 @@ namespace DotNetOpenAuth.OpenId.Provider { /// web site and log him/her in immediately in one uninterrupted step. /// </summary> /// <param name="providerEndpoint">The absolute URL on the Provider site that receives OpenID messages.</param> - /// <param name="relyingParty">The URL of the Relying Party web site. + /// <param name="relyingPartyRealm">The URL of the Relying Party web site. /// This will typically be the home page, but may be a longer URL if /// that Relying Party considers the scope of its realm to be more specific. /// The URL provided here must allow discovery of the Relying Party's @@ -353,10 +386,10 @@ namespace DotNetOpenAuth.OpenId.Provider { /// A <see cref="OutgoingWebResponse"/> object describing the HTTP response to send /// the user agent to allow the redirect with assertion to happen. /// </returns> - public OutgoingWebResponse PrepareUnsolicitedAssertion(Uri providerEndpoint, Realm relyingParty, Identifier claimedIdentifier, Identifier localIdentifier, params IExtensionMessage[] extensions) { + public OutgoingWebResponse PrepareUnsolicitedAssertion(Uri providerEndpoint, Realm relyingPartyRealm, Identifier claimedIdentifier, Identifier localIdentifier, params IExtensionMessage[] extensions) { Contract.Requires<ArgumentNullException>(providerEndpoint != null); Contract.Requires<ArgumentException>(providerEndpoint.IsAbsoluteUri); - Contract.Requires<ArgumentNullException>(relyingParty != null); + Contract.Requires<ArgumentNullException>(relyingPartyRealm != null); Contract.Requires<ArgumentNullException>(claimedIdentifier != null); Contract.Requires<ArgumentNullException>(localIdentifier != null); Contract.Requires<InvalidOperationException>(this.Channel.WebRequestHandler != null); @@ -366,8 +399,8 @@ namespace DotNetOpenAuth.OpenId.Provider { // do due diligence by performing our own discovery on the claimed identifier // and make sure that it is tied to this OP and OP local identifier. if (this.SecuritySettings.UnsolicitedAssertionVerification != ProviderSecuritySettings.UnsolicitedAssertionVerificationLevel.NeverVerify) { - var serviceEndpoint = DotNetOpenAuth.OpenId.RelyingParty.ServiceEndpoint.CreateForClaimedIdentifier(claimedIdentifier, localIdentifier, new ProviderEndpointDescription(providerEndpoint, Protocol.Default.Version), null, null); - var discoveredEndpoints = claimedIdentifier.Discover(this.WebRequestHandler); + var serviceEndpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier(claimedIdentifier, localIdentifier, new ProviderEndpointDescription(providerEndpoint, Protocol.Default.Version), null, null); + var discoveredEndpoints = this.RelyingParty.Discover(claimedIdentifier); if (!discoveredEndpoints.Contains(serviceEndpoint)) { Logger.OpenId.WarnFormat( "Failed to send unsolicited assertion for {0} because its discovered services did not include this endpoint: {1}{2}{1}Discovered endpoints: {1}{3}", @@ -385,11 +418,11 @@ namespace DotNetOpenAuth.OpenId.Provider { Logger.OpenId.InfoFormat("Preparing unsolicited assertion for {0}", claimedIdentifier); RelyingPartyEndpointDescription returnToEndpoint = null; - var returnToEndpoints = relyingParty.DiscoverReturnToEndpoints(this.WebRequestHandler, true); + var returnToEndpoints = relyingPartyRealm.DiscoverReturnToEndpoints(this.WebRequestHandler, true); if (returnToEndpoints != null) { returnToEndpoint = returnToEndpoints.FirstOrDefault(); } - ErrorUtilities.VerifyProtocol(returnToEndpoint != null, OpenIdStrings.NoRelyingPartyEndpointDiscovered, relyingParty); + ErrorUtilities.VerifyProtocol(returnToEndpoint != null, OpenIdStrings.NoRelyingPartyEndpointDiscovered, relyingPartyRealm); var positiveAssertion = new PositiveAssertionResponse(returnToEndpoint) { ProviderEndpoint = providerEndpoint, @@ -428,6 +461,10 @@ namespace DotNetOpenAuth.OpenId.Provider { if (channel != null) { channel.Dispose(); } + + if (this.relyingParty != null) { + this.relyingParty.Dispose(); + } } } diff --git a/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs b/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs index 4cfbac5..bb4a9ba 100644 --- a/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs +++ b/src/DotNetOpenAuth/OpenId/ProviderEndpointDescription.cs @@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OpenId { using System; using System.Collections.Generic; using System.Collections.ObjectModel; + using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Linq; using DotNetOpenAuth.Messaging; @@ -20,8 +21,7 @@ namespace DotNetOpenAuth.OpenId { /// <remarks> /// This is an immutable type. /// </remarks> - [Serializable] - internal class ProviderEndpointDescription : IProviderEndpoint { + internal sealed class ProviderEndpointDescription : IProviderEndpoint { /// <summary> /// Initializes a new instance of the <see cref="ProviderEndpointDescription"/> class. /// </summary> @@ -31,8 +31,9 @@ namespace DotNetOpenAuth.OpenId { Contract.Requires<ArgumentNullException>(providerEndpoint != null); Contract.Requires<ArgumentNullException>(openIdVersion != null); - this.Endpoint = providerEndpoint; - this.ProtocolVersion = openIdVersion; + this.Uri = providerEndpoint; + this.Version = openIdVersion; + this.Capabilities = new ReadOnlyCollection<string>(EmptyList<string>.Instance); } /// <summary> @@ -44,42 +45,24 @@ namespace DotNetOpenAuth.OpenId { Contract.Requires<ArgumentNullException>(providerEndpoint != null); Contract.Requires<ArgumentNullException>(serviceTypeURIs != null); - this.Endpoint = providerEndpoint; + this.Uri = providerEndpoint; this.Capabilities = new ReadOnlyCollection<string>(serviceTypeURIs.ToList()); Protocol opIdentifierProtocol = Protocol.FindBestVersion(p => p.OPIdentifierServiceTypeURI, serviceTypeURIs); Protocol claimedIdentifierProviderVersion = Protocol.FindBestVersion(p => p.ClaimedIdentifierServiceTypeURI, serviceTypeURIs); if (opIdentifierProtocol != null) { - this.ProtocolVersion = opIdentifierProtocol.Version; + this.Version = opIdentifierProtocol.Version; } else if (claimedIdentifierProviderVersion != null) { - this.ProtocolVersion = claimedIdentifierProviderVersion.Version; + this.Version = claimedIdentifierProviderVersion.Version; + } else { + ErrorUtilities.ThrowProtocol(OpenIdStrings.ProviderVersionUnrecognized, this.Uri); } - - ErrorUtilities.VerifyProtocol(this.ProtocolVersion != null, OpenIdStrings.ProviderVersionUnrecognized, this.Endpoint); } - #region IProviderEndpoint Properties - - /// <summary> - /// Gets the detected version of OpenID implemented by the Provider. - /// </summary> - Version IProviderEndpoint.Version { - get { return this.ProtocolVersion; } - } - - /// <summary> - /// Gets the URL that the OpenID Provider receives authentication requests at. - /// </summary> - Uri IProviderEndpoint.Uri { - get { return this.Endpoint; } - } - - #endregion - /// <summary> /// Gets the URL that the OpenID Provider listens for incoming OpenID messages on. /// </summary> - internal Uri Endpoint { get; private set; } + public Uri Uri { get; private set; } /// <summary> /// Gets the OpenID protocol version this endpoint supports. @@ -88,14 +71,14 @@ namespace DotNetOpenAuth.OpenId { /// If an endpoint supports multiple versions, each version must be represented /// by its own <see cref="ProviderEndpointDescription"/> object. /// </remarks> - internal Version ProtocolVersion { get; private set; } + public Version Version { get; private set; } /// <summary> /// Gets the collection of service type URIs found in the XRDS document describing this Provider. /// </summary> internal ReadOnlyCollection<string> Capabilities { get; private set; } - #region IProviderEndpoint Methods + #region IProviderEndpoint Members /// <summary> /// Checks whether the OpenId Identifier claims support for a given extension. @@ -111,10 +94,8 @@ namespace DotNetOpenAuth.OpenId { /// The only way to be sure of support for a given extension is to include /// the extension in the request and see if a response comes back for that extension. /// </remarks> - public bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new() { - ErrorUtilities.VerifyOperation(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); - T extension = new T(); - return this.IsExtensionSupported(extension); + bool IProviderEndpoint.IsExtensionSupported<T>() { + throw new NotImplementedException(); } /// <summary> @@ -131,52 +112,22 @@ namespace DotNetOpenAuth.OpenId { /// The only way to be sure of support for a given extension is to include /// the extension in the request and see if a response comes back for that extension. /// </remarks> - public bool IsExtensionSupported(Type extensionType) { - ErrorUtilities.VerifyOperation(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); - var extension = (IOpenIdMessageExtension)Activator.CreateInstance(extensionType); - return this.IsExtensionSupported(extension); + bool IProviderEndpoint.IsExtensionSupported(Type extensionType) { + throw new NotImplementedException(); } #endregion +#if CONTRACTS_FULL /// <summary> - /// Determines whether some extension is supported by the Provider. + /// Verifies conditions that should be true for any valid state of this object. /// </summary> - /// <param name="extensionUri">The extension URI.</param> - /// <returns> - /// <c>true</c> if the extension is supported; otherwise, <c>false</c>. - /// </returns> - protected internal bool IsExtensionSupported(string extensionUri) { - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(extensionUri)); - Contract.Requires<InvalidOperationException>(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); - return this.Capabilities.Contains(extensionUri); - } - - /// <summary> - /// Determines whether a given extension is supported by this endpoint. - /// </summary> - /// <param name="extension">An instance of the extension to check support for.</param> - /// <returns> - /// <c>true</c> if the extension is supported by this endpoint; otherwise, <c>false</c>. - /// </returns> - protected internal bool IsExtensionSupported(IOpenIdMessageExtension extension) { - Contract.Requires<ArgumentNullException>(extension != null); - Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(extension.TypeUri)); - Contract.Requires<InvalidOperationException>(this.Capabilities != null, OpenIdStrings.ExtensionLookupSupportUnavailable); - - // Consider the primary case. - if (this.IsExtensionSupported(extension.TypeUri)) { - return true; - } - - // Consider the secondary cases. - if (extension.AdditionalSupportedTypeUris != null) { - if (extension.AdditionalSupportedTypeUris.Any(typeUri => this.IsExtensionSupported(typeUri))) { - return true; - } - } - - return false; + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Called by code contracts.")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")] + [ContractInvariantMethod] + private void ObjectInvariant() { + Contract.Invariant(this.Capabilities != null); } +#endif } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs index d3e0686..7d30a3f 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs @@ -95,7 +95,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="provider">The provider to create an association with.</param> /// <returns>The association if one exists and has useful life remaining. Otherwise <c>null</c>.</returns> - internal Association GetExistingAssociation(ProviderEndpointDescription provider) { + internal Association GetExistingAssociation(IProviderEndpoint provider) { Contract.Requires<ArgumentNullException>(provider != null); // If the RP has no application store for associations, there's no point in creating one. @@ -103,7 +103,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { return null; } - Association association = this.associationStore.GetAssociation(provider.Endpoint, this.SecuritySettings); + Association association = this.associationStore.GetAssociation(provider.Uri, this.SecuritySettings); // If the returned association does not fulfill security requirements, ignore it. if (association != null && !this.SecuritySettings.IsAssociationInPermittedRange(association)) { @@ -123,7 +123,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> /// <param name="provider">The provider to get an association for.</param> /// <returns>The existing or new association; <c>null</c> if none existed and one could not be created.</returns> - internal Association GetOrCreateAssociation(ProviderEndpointDescription provider) { + internal Association GetOrCreateAssociation(IProviderEndpoint provider) { return this.GetExistingAssociation(provider) ?? this.CreateNewAssociation(provider); } @@ -140,7 +140,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// association store. /// Any new association is automatically added to the <see cref="associationStore"/>. /// </remarks> - private Association CreateNewAssociation(ProviderEndpointDescription provider) { + private Association CreateNewAssociation(IProviderEndpoint provider) { Contract.Requires<ArgumentNullException>(provider != null); // If there is no association store, there is no point in creating an association. @@ -164,7 +164,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The newly created association, or null if no association can be created with /// the given Provider given the current security settings. /// </returns> - private Association CreateNewAssociation(ProviderEndpointDescription provider, AssociateRequest associateRequest, int retriesRemaining) { + private Association CreateNewAssociation(IProviderEndpoint provider, AssociateRequest associateRequest, int retriesRemaining) { Contract.Requires<ArgumentNullException>(provider != null); if (associateRequest == null || retriesRemaining < 0) { @@ -179,7 +179,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse; if (associateSuccessfulResponse != null) { Association association = associateSuccessfulResponse.CreateAssociation(associateRequest, null); - this.associationStore.StoreAssociation(provider.Endpoint, association); + this.associationStore.StoreAssociation(provider.Uri, association); return association; } else if (associateUnsuccessfulResponse != null) { if (string.IsNullOrEmpty(associateUnsuccessfulResponse.AssociationType)) { @@ -187,7 +187,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { return null; } - if (!this.securitySettings.IsAssociationInPermittedRange(Protocol.Lookup(provider.ProtocolVersion), associateUnsuccessfulResponse.AssociationType)) { + if (!this.securitySettings.IsAssociationInPermittedRange(Protocol.Lookup(provider.Version), associateUnsuccessfulResponse.AssociationType)) { Logger.OpenId.DebugFormat("Provider rejected an association request and suggested '{0}' as an association to try, which this Relying Party does not support. Giving up.", associateUnsuccessfulResponse.AssociationType); return null; } @@ -198,7 +198,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } // Make sure the Provider isn't suggesting an incompatible pair of association/session types. - Protocol protocol = Protocol.Lookup(provider.ProtocolVersion); + Protocol protocol = Protocol.Lookup(provider.Version); ErrorUtilities.VerifyProtocol( HmacShaAssociation.IsDHSessionCompatible(protocol, associateUnsuccessfulResponse.AssociationType, associateUnsuccessfulResponse.SessionType), OpenIdStrings.IncompatibleAssociationAndSessionTypes, @@ -220,7 +220,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // Since having associations with OPs is not totally critical, we'll log and eat // the exception so that auth may continue in dumb mode. - Logger.OpenId.ErrorFormat("An error occurred while trying to create an association with {0}. {1}", provider.Endpoint, ex); + Logger.OpenId.ErrorFormat("An error occurred while trying to create an association with {0}. {1}", provider.Uri, ex); return null; } } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs index a317b95..e90c1d3 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs @@ -32,12 +32,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private readonly OpenIdRelyingParty RelyingParty; /// <summary> - /// The endpoint that describes the particular OpenID Identifier and Provider that - /// will be used to create the authentication request. - /// </summary> - private readonly ServiceEndpoint endpoint; - - /// <summary> /// How an association may or should be created or used in the formulation of the /// authentication request. /// </summary> @@ -67,17 +61,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Initializes a new instance of the <see cref="AuthenticationRequest"/> class. /// </summary> - /// <param name="endpoint">The endpoint that describes the OpenID Identifier and Provider that will complete the authentication.</param> + /// <param name="discoveryResult">The endpoint that describes the OpenID Identifier and Provider that will complete the authentication.</param> /// <param name="realm">The realm, or root URL, of the host web site.</param> /// <param name="returnToUrl">The base return_to URL that the Provider should return the user to to complete authentication. This should not include callback parameters as these should be added using the <see cref="AddCallbackArguments(string, string)"/> method.</param> /// <param name="relyingParty">The relying party that created this instance.</param> - private AuthenticationRequest(ServiceEndpoint endpoint, Realm realm, Uri returnToUrl, OpenIdRelyingParty relyingParty) { - Contract.Requires<ArgumentNullException>(endpoint != null); + private AuthenticationRequest(IdentifierDiscoveryResult discoveryResult, Realm realm, Uri returnToUrl, OpenIdRelyingParty relyingParty) { + Contract.Requires<ArgumentNullException>(discoveryResult != null); Contract.Requires<ArgumentNullException>(realm != null); Contract.Requires<ArgumentNullException>(returnToUrl != null); Contract.Requires<ArgumentNullException>(relyingParty != null); - this.endpoint = endpoint; + this.DiscoveryResult = discoveryResult; this.RelyingParty = relyingParty; this.Realm = realm; this.ReturnToUrl = returnToUrl; @@ -137,7 +131,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// property for a null value. /// </remarks> public Identifier ClaimedIdentifier { - get { return this.IsDirectedIdentity ? null : this.endpoint.ClaimedIdentifier; } + get { return this.IsDirectedIdentity ? null : this.DiscoveryResult.ClaimedIdentifier; } } /// <summary> @@ -145,7 +139,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// determine and send the ClaimedIdentifier after authentication. /// </summary> public bool IsDirectedIdentity { - get { return this.endpoint.ClaimedIdentifier == this.endpoint.Protocol.ClaimedIdentifierForOPIdentifier; } + get { return this.DiscoveryResult.ClaimedIdentifier == this.DiscoveryResult.Protocol.ClaimedIdentifierForOPIdentifier; } } /// <summary> @@ -164,9 +158,15 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// location. /// </summary> public IProviderEndpoint Provider { - get { return this.endpoint; } + get { return this.DiscoveryResult; } } + /// <summary> + /// Gets the discovery result leading to the formulation of this request. + /// </summary> + /// <value>The discovery result.</value> + public IdentifierDiscoveryResult DiscoveryResult { get; private set; } + #endregion /// <summary> @@ -192,13 +192,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { get { return this.extensions; } } - /// <summary> - /// Gets the service endpoint. - /// </summary> - internal ServiceEndpoint Endpoint { - get { return this.endpoint; } - } - #region IAuthenticationRequest methods /// <summary> @@ -364,12 +357,23 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { ErrorUtilities.VerifyProtocol(realm.Contains(returnToUrl), OpenIdStrings.ReturnToNotUnderRealm, returnToUrl, realm); // Perform discovery right now (not deferred). - IEnumerable<ServiceEndpoint> serviceEndpoints; + IEnumerable<IdentifierDiscoveryResult> serviceEndpoints; try { - serviceEndpoints = userSuppliedIdentifier.Discover(relyingParty.WebRequestHandler); + var results = relyingParty.Discover(userSuppliedIdentifier).CacheGeneratedResults(); + + // If any OP Identifier service elements were found, we must not proceed + // to use any Claimed Identifier services, per OpenID 2.0 sections 7.3.2.2 and 11.2. + // For a discussion on this topic, see + // http://groups.google.com/group/dotnetopenid/browse_thread/thread/4b5a8c6b2210f387/5e25910e4d2252c8 + // Usually the Discover method we called will automatically filter this for us, but + // just to be sure, we'll do it here as well since the RP may be configured to allow + // these dual identifiers for assertion verification purposes. + var opIdentifiers = results.Where(result => result.ClaimedIdentifier == result.Protocol.ClaimedIdentifierForOPIdentifier).CacheGeneratedResults(); + var claimedIdentifiers = results.Where(result => result.ClaimedIdentifier != result.Protocol.ClaimedIdentifierForOPIdentifier); + serviceEndpoints = opIdentifiers.Any() ? opIdentifiers : claimedIdentifiers; } catch (ProtocolException ex) { Logger.Yadis.ErrorFormat("Error while performing discovery on: \"{0}\": {1}", userSuppliedIdentifier, ex); - serviceEndpoints = EmptyList<ServiceEndpoint>.Instance; + serviceEndpoints = Enumerable.Empty<IdentifierDiscoveryResult>(); } // Filter disallowed endpoints. @@ -380,6 +384,18 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> + /// Creates an instance of <see cref="AuthenticationRequest"/> FOR TESTING PURPOSES ONLY. + /// </summary> + /// <param name="discoveryResult">The discovery result.</param> + /// <param name="realm">The realm.</param> + /// <param name="returnTo">The return to.</param> + /// <param name="rp">The relying party.</param> + /// <returns>The instantiated <see cref="AuthenticationRequest"/>.</returns> + internal static AuthenticationRequest CreateForTest(IdentifierDiscoveryResult discoveryResult, Realm realm, Uri returnTo, OpenIdRelyingParty rp) { + return new AuthenticationRequest(discoveryResult, realm, returnTo, rp); + } + + /// <summary> /// Performs deferred request generation for the <see cref="Create"/> method. /// </summary> /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> @@ -396,7 +412,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// All data validation and cleansing steps must have ALREADY taken place /// before calling this method. /// </remarks> - private static IEnumerable<AuthenticationRequest> CreateInternal(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, IEnumerable<ServiceEndpoint> serviceEndpoints, bool createNewAssociationsAsNeeded) { + private static IEnumerable<AuthenticationRequest> CreateInternal(Identifier userSuppliedIdentifier, OpenIdRelyingParty relyingParty, Realm realm, Uri returnToUrl, IEnumerable<IdentifierDiscoveryResult> serviceEndpoints, bool createNewAssociationsAsNeeded) { // DO NOT USE CODE CONTRACTS IN THIS METHOD, since it uses yield return ErrorUtilities.VerifyArgumentNotNull(userSuppliedIdentifier, "userSuppliedIdentifier"); ErrorUtilities.VerifyArgumentNotNull(relyingParty, "relyingParty"); @@ -408,12 +424,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { ErrorUtilities.VerifyOperation(!relyingParty.SecuritySettings.RequireAssociation || relyingParty.AssociationManager.HasAssociationStore, OpenIdStrings.AssociationStoreRequired); Logger.Yadis.InfoFormat("Performing discovery on user-supplied identifier: {0}", userSuppliedIdentifier); - IEnumerable<ServiceEndpoint> endpoints = FilterAndSortEndpoints(serviceEndpoints, relyingParty); + IEnumerable<IdentifierDiscoveryResult> endpoints = FilterAndSortEndpoints(serviceEndpoints, relyingParty); // Maintain a list of endpoints that we could not form an association with. // We'll fallback to generating requests to these if the ones we CAN create // an association with run out. - var failedAssociationEndpoints = new List<ServiceEndpoint>(0); + var failedAssociationEndpoints = new List<IdentifierDiscoveryResult>(0); foreach (var endpoint in endpoints) { Logger.OpenId.DebugFormat("Creating authentication request for user supplied Identifier: {0}", userSuppliedIdentifier); @@ -424,7 +440,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // In some scenarios (like the AJAX control wanting ALL auth requests possible), // we don't want to create associations with every Provider. But we'll use // associations where they are already formed from previous authentications. - association = createNewAssociationsAsNeeded ? relyingParty.AssociationManager.GetOrCreateAssociation(endpoint.ProviderDescription) : relyingParty.AssociationManager.GetExistingAssociation(endpoint.ProviderDescription); + association = createNewAssociationsAsNeeded ? relyingParty.AssociationManager.GetOrCreateAssociation(endpoint) : relyingParty.AssociationManager.GetExistingAssociation(endpoint); if (association == null && createNewAssociationsAsNeeded) { Logger.OpenId.WarnFormat("Failed to create association with {0}. Skipping to next endpoint.", endpoint.ProviderEndpoint); @@ -467,17 +483,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <param name="endpoints">The endpoints.</param> /// <param name="relyingParty">The relying party.</param> /// <returns>A filtered and sorted list of endpoints; may be empty if the input was empty or the filter removed all endpoints.</returns> - private static List<ServiceEndpoint> FilterAndSortEndpoints(IEnumerable<ServiceEndpoint> endpoints, OpenIdRelyingParty relyingParty) { + private static List<IdentifierDiscoveryResult> FilterAndSortEndpoints(IEnumerable<IdentifierDiscoveryResult> endpoints, OpenIdRelyingParty relyingParty) { Contract.Requires<ArgumentNullException>(endpoints != null); Contract.Requires<ArgumentNullException>(relyingParty != null); // Construct the endpoints filters based on criteria given by the host web site. - EndpointSelector versionFilter = ep => ((ServiceEndpoint)ep).Protocol.Version >= Protocol.Lookup(relyingParty.SecuritySettings.MinimumRequiredOpenIdVersion).Version; + EndpointSelector versionFilter = ep => ep.Version >= Protocol.Lookup(relyingParty.SecuritySettings.MinimumRequiredOpenIdVersion).Version; EndpointSelector hostingSiteFilter = relyingParty.EndpointFilter ?? (ep => true); bool anyFilteredOut = false; - var filteredEndpoints = new List<IXrdsProviderEndpoint>(); - foreach (ServiceEndpoint endpoint in endpoints) { + var filteredEndpoints = new List<IdentifierDiscoveryResult>(); + foreach (var endpoint in endpoints) { if (versionFilter(endpoint) && hostingSiteFilter(endpoint)) { filteredEndpoints.Add(endpoint); } else { @@ -486,10 +502,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } // Sort endpoints so that the first one in the list is the most preferred one. - filteredEndpoints.Sort(relyingParty.EndpointOrder); + filteredEndpoints.OrderBy(ep => ep, relyingParty.EndpointOrder); - List<ServiceEndpoint> endpointList = new List<ServiceEndpoint>(filteredEndpoints.Count); - foreach (ServiceEndpoint endpoint in filteredEndpoints) { + var endpointList = new List<IdentifierDiscoveryResult>(filteredEndpoints.Count); + foreach (var endpoint in filteredEndpoints) { endpointList.Add(endpoint); } @@ -518,20 +534,20 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { SignedResponseRequest request; if (!this.IsExtensionOnly) { - CheckIdRequest authRequest = new CheckIdRequest(this.endpoint.Protocol.Version, this.endpoint.ProviderEndpoint, this.Mode); - authRequest.ClaimedIdentifier = this.endpoint.ClaimedIdentifier; - authRequest.LocalIdentifier = this.endpoint.ProviderLocalIdentifier; + CheckIdRequest authRequest = new CheckIdRequest(this.DiscoveryResult.Version, this.DiscoveryResult.ProviderEndpoint, this.Mode); + authRequest.ClaimedIdentifier = this.DiscoveryResult.ClaimedIdentifier; + authRequest.LocalIdentifier = this.DiscoveryResult.ProviderLocalIdentifier; request = authRequest; } else { - request = new SignedResponseRequest(this.endpoint.Protocol.Version, this.endpoint.ProviderEndpoint, this.Mode); + request = new SignedResponseRequest(this.DiscoveryResult.Version, this.DiscoveryResult.ProviderEndpoint, this.Mode); } request.Realm = this.Realm; request.ReturnTo = this.ReturnToUrl; request.AssociationHandle = association != null ? association.Handle : null; request.SignReturnTo = this.returnToArgsMustBeSigned; request.AddReturnToArguments(this.returnToArgs); - if (this.endpoint.UserSuppliedIdentifier != null) { - request.AddReturnToArguments(UserSuppliedIdentifierParameterName, this.endpoint.UserSuppliedIdentifier.OriginalString); + if (this.DiscoveryResult.UserSuppliedIdentifier != null) { + request.AddReturnToArguments(UserSuppliedIdentifierParameterName, this.DiscoveryResult.UserSuppliedIdentifier.OriginalString); } foreach (IOpenIdMessageExtension extension in this.extensions) { request.Extensions.Add(extension); @@ -548,7 +564,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Association association = null; switch (this.associationPreference) { case AssociationPreference.IfPossible: - association = this.RelyingParty.AssociationManager.GetOrCreateAssociation(this.endpoint.ProviderDescription); + association = this.RelyingParty.AssociationManager.GetOrCreateAssociation(this.DiscoveryResult); if (association == null) { // Avoid trying to create the association again if the redirecting response // is generated again. @@ -556,7 +572,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } break; case AssociationPreference.IfAlreadyEstablished: - association = this.RelyingParty.AssociationManager.GetExistingAssociation(this.endpoint.ProviderDescription); + association = this.RelyingParty.AssociationManager.GetExistingAssociation(this.DiscoveryResult); break; case AssociationPreference.Never: break; diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs index 3808c85..65db0bd 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequest.cs @@ -97,6 +97,12 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { IProviderEndpoint Provider { get; } /// <summary> + /// Gets the discovery result leading to the formulation of this request. + /// </summary> + /// <value>The discovery result.</value> + IdentifierDiscoveryResult DiscoveryResult { get; } + + /// <summary> /// Makes a dictionary of key/value pairs available when the authentication is completed. /// </summary> /// <param name="arguments">The arguments to add to the request's return_to URI. Values must not be null.</param> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequestContract.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequestContract.cs index 41cc4e9..cd36cc7 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequestContract.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IAuthenticationRequestContract.cs @@ -32,11 +32,16 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } Realm IAuthenticationRequest.Realm { - get { throw new NotImplementedException(); } + get { + Contract.Ensures(Contract.Result<Realm>() != null); + throw new NotImplementedException(); + } } Identifier IAuthenticationRequest.ClaimedIdentifier { - get { throw new NotImplementedException(); } + get { + throw new NotImplementedException(); + } } bool IAuthenticationRequest.IsDirectedIdentity { @@ -54,7 +59,17 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } IProviderEndpoint IAuthenticationRequest.Provider { - get { throw new NotImplementedException(); } + get { + Contract.Ensures(Contract.Result<IProviderEndpoint>() != null); + throw new NotImplementedException(); + } + } + + IdentifierDiscoveryResult IAuthenticationRequest.DiscoveryResult { + get { + Contract.Ensures(Contract.Result<IdentifierDiscoveryResult>() != null); + throw new NotImplementedException(); + } } void IAuthenticationRequest.AddCallbackArguments(IDictionary<string, string> arguments) { diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs index a90ddd4..5d8918d 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/IProviderEndpoint.cs @@ -6,6 +6,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System; + using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Globalization; @@ -30,6 +31,9 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Gets the URL that the OpenID Provider receives authentication requests at. /// </summary> + /// <value> + /// This value MUST be an absolute HTTP or HTTPS URL. + /// </value> Uri Uri { get; } /// <summary> @@ -45,6 +49,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// the extension in the request and see if a response comes back for that extension. /// </remarks> [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter", Justification = "No parameter at all.")] + [Obsolete("Use IAuthenticationRequest.DiscoveryResult.IsExtensionSupported instead.")] bool IsExtensionSupported<T>() where T : IOpenIdMessageExtension, new(); /// <summary> @@ -59,6 +64,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The only way to be sure of support for a given extension is to include /// the extension in the request and see if a response comes back for that extension. /// </remarks> + [Obsolete("Use IAuthenticationRequest.DiscoveryResult.IsExtensionSupported instead.")] bool IsExtensionSupported(Type extensionType); } @@ -67,20 +73,32 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// </summary> [ContractClassFor(typeof(IProviderEndpoint))] internal abstract class IProviderEndpointContract : IProviderEndpoint { + /// <summary> + /// Prevents a default instance of the <see cref="IProviderEndpointContract"/> class from being created. + /// </summary> + private IProviderEndpointContract() { + } + #region IProviderEndpoint Members /// <summary> /// Gets the detected version of OpenID implemented by the Provider. /// </summary> Version IProviderEndpoint.Version { - get { throw new NotImplementedException(); } + get { + Contract.Ensures(Contract.Result<Version>() != null); + throw new System.NotImplementedException(); + } } /// <summary> /// Gets the URL that the OpenID Provider receives authentication requests at. /// </summary> Uri IProviderEndpoint.Uri { - get { throw new NotImplementedException(); } + get { + Contract.Ensures(Contract.Result<Uri>() != null); + throw new System.NotImplementedException(); + } } /// <summary> @@ -118,7 +136,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { bool IProviderEndpoint.IsExtensionSupported(Type extensionType) { Contract.Requires<ArgumentNullException>(extensionType != null); Contract.Requires<ArgumentException>(typeof(IOpenIdMessageExtension).IsAssignableFrom(extensionType)); - ////ErrorUtilities.VerifyArgument(typeof(IOpenIdMessageExtension).IsAssignableFrom(extensionType), string.Format(CultureInfo.CurrentCulture, OpenIdStrings.TypeMustImplementX, typeof(IOpenIdMessageExtension).FullName)); throw new NotImplementedException(); } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IXrdsProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IXrdsProviderEndpoint.cs deleted file mode 100644 index 89b4ef0..0000000 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IXrdsProviderEndpoint.cs +++ /dev/null @@ -1,41 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="IXrdsProviderEndpoint.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.RelyingParty { - using System; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; - - /// <summary> - /// An <see cref="IProviderEndpoint"/> interface with additional members for use - /// in sorting for most preferred endpoint. - /// </summary> - [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Xrds", Justification = "Xrds is an acronym.")] - [ContractClass(typeof(IXrdsProviderEndpointContract))] - public interface IXrdsProviderEndpoint : IProviderEndpoint { - /// <summary> - /// Gets the priority associated with this service that may have been given - /// in the XRDS document. - /// </summary> - int? ServicePriority { get; } - - /// <summary> - /// Gets the priority associated with the service endpoint URL. - /// </summary> - /// <remarks> - /// When sorting by priority, this property should be considered second after - /// <see cref="ServicePriority"/>. - /// </remarks> - int? UriPriority { get; } - - /// <summary> - /// Checks for the presence of a given Type URI in an XRDS service. - /// </summary> - /// <param name="typeUri">The type URI to check for.</param> - /// <returns><c>true</c> if the service type uri is present; <c>false</c> otherwise.</returns> - bool IsTypeUriPresent(string typeUri); - } -} diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/IXrdsProviderEndpointContract.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/IXrdsProviderEndpointContract.cs deleted file mode 100644 index e0e2b0b..0000000 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/IXrdsProviderEndpointContract.cs +++ /dev/null @@ -1,59 +0,0 @@ -// <auto-generated /> - -namespace DotNetOpenAuth.OpenId.RelyingParty { - using System; - using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; - using System.Globalization; - using DotNetOpenAuth.OpenId.Messages; - - [ContractClassFor(typeof(IXrdsProviderEndpoint))] - internal abstract class IXrdsProviderEndpointContract : IXrdsProviderEndpoint { - #region IXrdsProviderEndpoint Properties - - int? IXrdsProviderEndpoint.ServicePriority { - get { throw new System.NotImplementedException(); } - } - - int? IXrdsProviderEndpoint.UriPriority { - get { throw new System.NotImplementedException(); } - } - - #endregion - - #region IProviderEndpoint Properties - - Version IProviderEndpoint.Version { - get { throw new System.NotImplementedException(); } - } - - Uri IProviderEndpoint.Uri { - get { throw new System.NotImplementedException(); } - } - - #endregion - - #region IXrdsProviderEndpoint Methods - - bool IXrdsProviderEndpoint.IsTypeUriPresent(string typeUri) { - throw new System.NotImplementedException(); - } - - #endregion - - #region IProviderEndpoint Methods - - bool IProviderEndpoint.IsExtensionSupported<T>() { - throw new System.NotImplementedException(); - } - - bool IProviderEndpoint.IsExtensionSupported(System.Type extensionType) { - Contract.Requires<ArgumentNullException>(extensionType != null); - Contract.Requires<ArgumentException>(typeof(IOpenIdMessageExtension).IsAssignableFrom(extensionType)); - ////ErrorUtilities.VerifyArgument(typeof(IOpenIdMessageExtension).IsAssignableFrom(extensionType), string.Format(CultureInfo.CurrentCulture, OpenIdStrings.TypeMustImplementX, typeof(IOpenIdMessageExtension).FullName)); - throw new System.NotImplementedException(); - } - - #endregion - } -} diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs index 55d6403..d199985 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs @@ -30,7 +30,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <c>True</c> if the endpoint should be considered. /// <c>False</c> to remove it from the pool of acceptable providers. /// </returns> - public delegate bool EndpointSelector(IXrdsProviderEndpoint endpoint); + public delegate bool EndpointSelector(IProviderEndpoint endpoint); /// <summary> /// Provides the programmatic facilities to act as an OpenId consumer. @@ -49,6 +49,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { private readonly ObservableCollection<IRelyingPartyBehavior> behaviors = new ObservableCollection<IRelyingPartyBehavior>(); /// <summary> + /// Backing field for the <see cref="DiscoveryServices"/> property. + /// </summary> + private readonly IList<IIdentifierDiscoveryService> discoveryServices = new List<IIdentifierDiscoveryService>(2); + + /// <summary> /// Backing field for the <see cref="SecuritySettings"/> property. /// </summary> private RelyingPartySecuritySettings securitySettings; @@ -56,7 +61,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Backing store for the <see cref="EndpointOrder"/> property. /// </summary> - private Comparison<IXrdsProviderEndpoint> endpointOrder = DefaultEndpointOrder; + private Comparison<IdentifierDiscoveryResult> endpointOrder = DefaultEndpointOrder; /// <summary> /// Backing field for the <see cref="Channel"/> property. @@ -90,6 +95,11 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { Contract.Requires<ArgumentException>(associationStore == null || nonceStore != null, OpenIdStrings.AssociationStoreRequiresNonceStore); this.securitySettings = DotNetOpenAuthSection.Configuration.OpenId.RelyingParty.SecuritySettings.CreateSecuritySettings(); + + foreach (var discoveryService in DotNetOpenAuthSection.Configuration.OpenId.RelyingParty.DiscoveryServices.CreateInstances(true)) { + this.discoveryServices.Add(discoveryService); + } + this.behaviors.CollectionChanged += this.OnBehaviorsChanged; foreach (var behavior in DotNetOpenAuthSection.Configuration.OpenId.RelyingParty.Behaviors.CreateInstances(false)) { this.behaviors.Add(behavior); @@ -116,8 +126,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// Endpoints lacking any priority value are sorted to the end of the list. /// </remarks> [EditorBrowsable(EditorBrowsableState.Advanced)] - public static Comparison<IXrdsProviderEndpoint> DefaultEndpointOrder { - get { return ServiceEndpoint.EndpointOrder; } + public static Comparison<IdentifierDiscoveryResult> DefaultEndpointOrder { + get { return IdentifierDiscoveryResult.EndpointOrder; } } /// <summary> @@ -199,7 +209,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// can be set to the value of <see cref="DefaultEndpointOrder"/>. /// </remarks> [EditorBrowsable(EditorBrowsableState.Advanced)] - public Comparison<IXrdsProviderEndpoint> EndpointOrder { + public Comparison<IdentifierDiscoveryResult> EndpointOrder { get { return this.endpointOrder; } @@ -229,6 +239,13 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> + /// Gets the list of services that can perform discovery on identifiers given to this relying party. + /// </summary> + public IList<IIdentifierDiscoveryService> DiscoveryServices { + get { return this.discoveryServices; } + } + + /// <summary> /// Gets a value indicating whether this Relying Party can sign its return_to /// parameter in outgoing authentication requests. /// </summary> @@ -574,6 +591,42 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { } /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to discover services for.</param> + /// <returns>A non-null sequence of services discovered for the identifier.</returns> + internal IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Ensures(Contract.Result<IEnumerable<IdentifierDiscoveryResult>>() != null); + + IEnumerable<IdentifierDiscoveryResult> results = Enumerable.Empty<IdentifierDiscoveryResult>(); + foreach (var discoverer in this.DiscoveryServices) { + bool abortDiscoveryChain; + var discoveryResults = discoverer.Discover(identifier, this.WebRequestHandler, out abortDiscoveryChain).CacheGeneratedResults(); + results = results.Concat(discoveryResults); + if (abortDiscoveryChain) { + Logger.OpenId.InfoFormat("Further discovery on '{0}' was stopped by the {1} discovery service.", identifier, discoverer.GetType().Name); + break; + } + } + + // If any OP Identifier service elements were found, we must not proceed + // to use any Claimed Identifier services, per OpenID 2.0 sections 7.3.2.2 and 11.2. + // For a discussion on this topic, see + // http://groups.google.com/group/dotnetopenid/browse_thread/thread/4b5a8c6b2210f387/5e25910e4d2252c8 + // Sometimes the IIdentifierDiscoveryService will automatically filter this for us, but + // just to be sure, we'll do it here as well. + if (!this.SecuritySettings.AllowDualPurposeIdentifiers) { + results = results.CacheGeneratedResults(); // avoid performing discovery repeatedly + var opIdentifiers = results.Where(result => result.ClaimedIdentifier == result.Protocol.ClaimedIdentifierForOPIdentifier); + var claimedIdentifiers = results.Where(result => result.ClaimedIdentifier != result.Protocol.ClaimedIdentifierForOPIdentifier); + results = opIdentifiers.Any() ? opIdentifiers : claimedIdentifiers; + } + + return results; + } + + /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param> diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs index 0254346..12d676b 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyAjaxControlBase.cs @@ -565,7 +565,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // If the ReturnToUrl was explicitly set, we'll need to reset our first parameter if (string.IsNullOrEmpty(HttpUtility.ParseQueryString(req.ReturnToUrl.Query)[AuthenticationRequest.UserSuppliedIdentifierParameterName])) { - Identifier userSuppliedIdentifier = ((AuthenticationRequest)req).Endpoint.UserSuppliedIdentifier; + Identifier userSuppliedIdentifier = ((AuthenticationRequest)req).DiscoveryResult.UserSuppliedIdentifier; req.SetUntrustedCallbackArgument(AuthenticationRequest.UserSuppliedIdentifierParameterName, userSuppliedIdentifier.OriginalString); } diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs index 02df7a2..a4a60d1 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingPartyControlBase.cs @@ -810,7 +810,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { case PopupBehavior.Always: return true; case PopupBehavior.IfProviderSupported: - return request.Provider.IsExtensionSupported<UIRequest>(); + return request.DiscoveryResult.IsExtensionSupported<UIRequest>(); default: throw ErrorUtilities.ThrowInternal("Unexpected value for Popup property."); } @@ -937,7 +937,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // Inform ourselves in return_to that we're in a popup. req.SetUntrustedCallbackArgument(UIPopupCallbackKey, "1"); - if (req.Provider.IsExtensionSupported<UIRequest>()) { + if (req.DiscoveryResult.IsExtensionSupported<UIRequest>()) { // Inform the OP that we'll be using a popup window consistent with the UI extension. req.AddExtension(new UIRequest()); diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs index 6e7d7ef..5cfa191 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAnonymousResponse.cs @@ -26,7 +26,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Information about the OP endpoint that issued this assertion. /// </summary> - private readonly ProviderEndpointDescription provider; + private readonly IProviderEndpoint provider; /// <summary> /// Initializes a new instance of the <see cref="PositiveAnonymousResponse"/> class. diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs index 0fd034c..6e141ad 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/PositiveAuthenticationResponse.cs @@ -28,7 +28,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { : base(response) { Contract.Requires<ArgumentNullException>(relyingParty != null); - this.Endpoint = ServiceEndpoint.CreateForClaimedIdentifier( + this.Endpoint = IdentifierDiscoveryResult.CreateForClaimedIdentifier( this.Response.ClaimedIdentifier, this.Response.GetReturnToArgument(AuthenticationRequest.UserSuppliedIdentifierParameterName), this.Response.LocalIdentifier, @@ -114,7 +114,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// the claimed identifier to avoid a Provider asserting an Identifier /// for which it has no authority. /// </remarks> - internal ServiceEndpoint Endpoint { get; private set; } + internal IdentifierDiscoveryResult Endpoint { get; private set; } /// <summary> /// Gets the positive assertion response message. @@ -155,7 +155,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { // is signed by the RP before it's considered reliable. In 1.x stateless mode, this RP // doesn't (and can't) sign its own return_to URL, so its cached discovery information // is merely a hint that must be verified by performing discovery again here. - var discoveryResults = claimedId.Discover(relyingParty.WebRequestHandler); + var discoveryResults = relyingParty.Discover(claimedId); ErrorUtilities.VerifyProtocol( discoveryResults.Contains(this.Endpoint), OpenIdStrings.IssuedAssertionFailsIdentifierDiscovery, diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs index ff29498..071a488 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/RelyingPartySecuritySettings.cs @@ -111,11 +111,26 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { public bool RequireAssociation { get; set; } /// <summary> + /// Gets or sets a value indicating whether identifiers that are both OP Identifiers and Claimed Identifiers + /// should ever be recognized as claimed identifiers. + /// </summary> + /// <value> + /// The default value is <c>false</c>, per the OpenID 2.0 spec. + /// </value> + /// <remarks> + /// OpenID 2.0 sections 7.3.2.2 and 11.2 specify that OP Identifiers never be recognized as Claimed Identifiers. + /// However, for some scenarios it may be desirable for an RP to override this behavior and allow this. + /// The security ramifications of setting this property to <c>true</c> have not been fully explored and + /// therefore this setting should only be changed with caution. + /// </remarks> + public bool AllowDualPurposeIdentifiers { get; set; } + + /// <summary> /// Filters out any disallowed endpoints. /// </summary> /// <param name="endpoints">The endpoints discovered on an Identifier.</param> /// <returns>A sequence of endpoints that satisfy all security requirements.</returns> - internal IEnumerable<ServiceEndpoint> FilterEndpoints(IEnumerable<ServiceEndpoint> endpoints) { + internal IEnumerable<IdentifierDiscoveryResult> FilterEndpoints(IEnumerable<IdentifierDiscoveryResult> endpoints) { return endpoints .Where(se => !this.RejectDelegatingIdentifiers || se.ClaimedIdentifier == se.ProviderLocalIdentifier) .Where(se => !this.RequireDirectedIdentity || se.ClaimedIdentifier == se.Protocol.ClaimedIdentifierForOPIdentifier); diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/SimpleXrdsProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/SimpleXrdsProviderEndpoint.cs index 912b8f4..678f69a 100644 --- a/src/DotNetOpenAuth/OpenId/RelyingParty/SimpleXrdsProviderEndpoint.cs +++ b/src/DotNetOpenAuth/OpenId/RelyingParty/SimpleXrdsProviderEndpoint.cs @@ -6,6 +6,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { using System; + using System.Collections.ObjectModel; + using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; /// <summary> @@ -13,7 +15,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// assertions (particularly unsolicited ones) are received from OP endpoints that /// are deemed permissible by the host RP. /// </summary> - internal class SimpleXrdsProviderEndpoint : IXrdsProviderEndpoint { + internal class SimpleXrdsProviderEndpoint : IProviderEndpoint { /// <summary> /// Initializes a new instance of the <see cref="SimpleXrdsProviderEndpoint"/> class. /// </summary> @@ -23,29 +25,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { this.Version = positiveAssertion.Version; } - #region IXrdsProviderEndpoint Properties - - /// <summary> - /// Gets the priority associated with this service that may have been given - /// in the XRDS document. - /// </summary> - public int? ServicePriority { - get { return null; } - } - - /// <summary> - /// Gets the priority associated with the service endpoint URL. - /// </summary> - /// <remarks> - /// When sorting by priority, this property should be considered second after - /// <see cref="ServicePriority"/>. - /// </remarks> - public int? UriPriority { - get { return null; } - } - - #endregion - #region IProviderEndpoint Members /// <summary> @@ -56,7 +35,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// <summary> /// Gets the URL that the OpenID Provider receives authentication requests at. /// </summary> - /// <value></value> public Uri Uri { get; private set; } /// <summary> @@ -73,8 +51,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The only way to be sure of support for a given extension is to include /// the extension in the request and see if a response comes back for that extension. /// </remarks> - public bool IsExtensionSupported<T>() where T : DotNetOpenAuth.OpenId.Messages.IOpenIdMessageExtension, new() { - throw new NotSupportedException(); + bool IProviderEndpoint.IsExtensionSupported<T>() { + throw new NotImplementedException(); } /// <summary> @@ -91,23 +69,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { /// The only way to be sure of support for a given extension is to include /// the extension in the request and see if a response comes back for that extension. /// </remarks> - public bool IsExtensionSupported(Type extensionType) { - throw new NotSupportedException(); - } - - #endregion - - #region IXrdsProviderEndpoint Methods - - /// <summary> - /// Checks for the presence of a given Type URI in an XRDS service. - /// </summary> - /// <param name="typeUri">The type URI to check for.</param> - /// <returns> - /// <c>true</c> if the service type uri is present; <c>false</c> otherwise. - /// </returns> - public bool IsTypeUriPresent(string typeUri) { - throw new NotSupportedException(); + bool IProviderEndpoint.IsExtensionSupported(Type extensionType) { + throw new NotImplementedException(); } #endregion diff --git a/src/DotNetOpenAuth/OpenId/UriDiscoveryService.cs b/src/DotNetOpenAuth/OpenId/UriDiscoveryService.cs new file mode 100644 index 0000000..f017d9f --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/UriDiscoveryService.cs @@ -0,0 +1,138 @@ +//----------------------------------------------------------------------- +// <copyright file="UriDiscoveryService.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using System.Web.UI.HtmlControls; + using System.Xml; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Xrds; + using DotNetOpenAuth.Yadis; + + /// <summary> + /// The discovery service for URI identifiers. + /// </summary> + public class UriDiscoveryService : IIdentifierDiscoveryService { + /// <summary> + /// Initializes a new instance of the <see cref="UriDiscoveryService"/> class. + /// </summary> + public UriDiscoveryService() { + } + + #region IDiscoveryService Members + + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + public IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { + abortDiscoveryChain = false; + var uriIdentifier = identifier as UriIdentifier; + if (uriIdentifier == null) { + return Enumerable.Empty<IdentifierDiscoveryResult>(); + } + + var endpoints = new List<IdentifierDiscoveryResult>(); + + // Attempt YADIS discovery + DiscoveryResult yadisResult = Yadis.Discover(requestHandler, uriIdentifier, identifier.IsDiscoverySecureEndToEnd); + if (yadisResult != null) { + if (yadisResult.IsXrds) { + try { + XrdsDocument xrds = new XrdsDocument(yadisResult.ResponseText); + var xrdsEndpoints = xrds.XrdElements.CreateServiceEndpoints(yadisResult.NormalizedUri, uriIdentifier); + + // Filter out insecure endpoints if high security is required. + if (uriIdentifier.IsDiscoverySecureEndToEnd) { + xrdsEndpoints = xrdsEndpoints.Where(se => se.ProviderEndpoint.IsTransportSecure()); + } + endpoints.AddRange(xrdsEndpoints); + } catch (XmlException ex) { + Logger.Yadis.Error("Error while parsing the XRDS document. Falling back to HTML discovery.", ex); + } + } + + // Failing YADIS discovery of an XRDS document, we try HTML discovery. + if (endpoints.Count == 0) { + var htmlEndpoints = new List<IdentifierDiscoveryResult>(DiscoverFromHtml(yadisResult.NormalizedUri, uriIdentifier, yadisResult.ResponseText)); + if (htmlEndpoints.Any()) { + Logger.Yadis.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count); + Logger.Yadis.Debug(htmlEndpoints.ToStringDeferred(true)); + endpoints.AddRange(htmlEndpoints.Where(ep => !uriIdentifier.IsDiscoverySecureEndToEnd || ep.ProviderEndpoint.IsTransportSecure())); + if (endpoints.Count == 0) { + Logger.Yadis.Info("No HTML discovered endpoints met the security requirements."); + } + } else { + Logger.Yadis.Debug("HTML discovery failed to find any endpoints."); + } + } else { + Logger.Yadis.Debug("Skipping HTML discovery because XRDS contained service endpoints."); + } + } + return endpoints; + } + + #endregion + + /// <summary> + /// Searches HTML for the HEAD META tags that describe OpenID provider services. + /// </summary> + /// <param name="claimedIdentifier">The final URL that provided this HTML document. + /// This may not be the same as (this) userSuppliedIdentifier if the + /// userSuppliedIdentifier pointed to a 301 Redirect.</param> + /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> + /// <param name="html">The HTML that was downloaded and should be searched.</param> + /// <returns> + /// A sequence of any discovered ServiceEndpoints. + /// </returns> + private static IEnumerable<IdentifierDiscoveryResult> DiscoverFromHtml(Uri claimedIdentifier, UriIdentifier userSuppliedIdentifier, string html) { + var linkTags = new List<HtmlLink>(HtmlParser.HeadTags<HtmlLink>(html)); + foreach (var protocol in Protocol.AllPracticalVersions) { + // rel attributes are supposed to be interpreted with case INsensitivity, + // and is a space-delimited list of values. (http://www.htmlhelp.com/reference/html40/values.html#linktypes) + var serverLinkTag = linkTags.WithAttribute("rel").FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryProviderKey) + @"\b", RegexOptions.IgnoreCase)); + if (serverLinkTag == null) { + continue; + } + + Uri providerEndpoint = null; + if (Uri.TryCreate(serverLinkTag.Href, UriKind.Absolute, out providerEndpoint)) { + // See if a LocalId tag of the discovered version exists + Identifier providerLocalIdentifier = null; + var delegateLinkTag = linkTags.WithAttribute("rel").FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryLocalIdKey) + @"\b", RegexOptions.IgnoreCase)); + if (delegateLinkTag != null) { + if (Identifier.IsValid(delegateLinkTag.Href)) { + providerLocalIdentifier = delegateLinkTag.Href; + } else { + Logger.Yadis.WarnFormat("Skipping endpoint data because local id is badly formed ({0}).", delegateLinkTag.Href); + continue; // skip to next version + } + } + + // Choose the TypeURI to match the OpenID version detected. + string[] typeURIs = { protocol.ClaimedIdentifierServiceTypeURI }; + yield return IdentifierDiscoveryResult.CreateForClaimedIdentifier( + claimedIdentifier, + userSuppliedIdentifier, + providerLocalIdentifier, + new ProviderEndpointDescription(providerEndpoint, typeURIs), + (int?)null, + (int?)null); + } + } + } + } +} diff --git a/src/DotNetOpenAuth/OpenId/UriIdentifier.cs b/src/DotNetOpenAuth/OpenId/UriIdentifier.cs index 28d8b37..0b7a0e3 100644 --- a/src/DotNetOpenAuth/OpenId/UriIdentifier.cs +++ b/src/DotNetOpenAuth/OpenId/UriIdentifier.cs @@ -207,54 +207,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Performs discovery on the Identifier. - /// </summary> - /// <param name="requestHandler">The web request handler to use for discovery.</param> - /// <returns> - /// An initialized structure containing the discovered provider endpoint information. - /// </returns> - internal override IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { - List<ServiceEndpoint> endpoints = new List<ServiceEndpoint>(); - - // Attempt YADIS discovery - DiscoveryResult yadisResult = Yadis.Discover(requestHandler, this, IsDiscoverySecureEndToEnd); - if (yadisResult != null) { - if (yadisResult.IsXrds) { - try { - XrdsDocument xrds = new XrdsDocument(yadisResult.ResponseText); - var xrdsEndpoints = xrds.CreateServiceEndpoints(yadisResult.NormalizedUri, this); - - // Filter out insecure endpoints if high security is required. - if (IsDiscoverySecureEndToEnd) { - xrdsEndpoints = xrdsEndpoints.Where(se => se.IsSecure); - } - endpoints.AddRange(xrdsEndpoints); - } catch (XmlException ex) { - Logger.Yadis.Error("Error while parsing the XRDS document. Falling back to HTML discovery.", ex); - } - } - - // Failing YADIS discovery of an XRDS document, we try HTML discovery. - if (endpoints.Count == 0) { - var htmlEndpoints = new List<ServiceEndpoint>(DiscoverFromHtml(yadisResult.NormalizedUri, this, yadisResult.ResponseText)); - if (htmlEndpoints.Any()) { - Logger.Yadis.DebugFormat("Total services discovered in HTML: {0}", htmlEndpoints.Count); - Logger.Yadis.Debug(htmlEndpoints.ToStringDeferred(true)); - endpoints.AddRange(htmlEndpoints.Where(ep => !IsDiscoverySecureEndToEnd || ep.IsSecure)); - if (endpoints.Count == 0) { - Logger.Yadis.Info("No HTML discovered endpoints met the security requirements."); - } - } else { - Logger.Yadis.Debug("HTML discovery failed to find any endpoints."); - } - } else { - Logger.Yadis.Debug("Skipping HTML discovery because XRDS contained service endpoints."); - } - } - return endpoints; - } - - /// <summary> /// Returns an <see cref="Identifier"/> that has no URI fragment. /// Quietly returns the original <see cref="Identifier"/> if it is not /// a <see cref="UriIdentifier"/> or no fragment exists. @@ -318,54 +270,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Searches HTML for the HEAD META tags that describe OpenID provider services. - /// </summary> - /// <param name="claimedIdentifier">The final URL that provided this HTML document. - /// This may not be the same as (this) userSuppliedIdentifier if the - /// userSuppliedIdentifier pointed to a 301 Redirect.</param> - /// <param name="userSuppliedIdentifier">The user supplied identifier.</param> - /// <param name="html">The HTML that was downloaded and should be searched.</param> - /// <returns> - /// A sequence of any discovered ServiceEndpoints. - /// </returns> - private static IEnumerable<ServiceEndpoint> DiscoverFromHtml(Uri claimedIdentifier, UriIdentifier userSuppliedIdentifier, string html) { - var linkTags = new List<HtmlLink>(HtmlParser.HeadTags<HtmlLink>(html)); - foreach (var protocol in Protocol.AllPracticalVersions) { - // rel attributes are supposed to be interpreted with case INsensitivity, - // and is a space-delimited list of values. (http://www.htmlhelp.com/reference/html40/values.html#linktypes) - var serverLinkTag = linkTags.WithAttribute("rel").FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryProviderKey) + @"\b", RegexOptions.IgnoreCase)); - if (serverLinkTag == null) { - continue; - } - - Uri providerEndpoint = null; - if (Uri.TryCreate(serverLinkTag.Href, UriKind.Absolute, out providerEndpoint)) { - // See if a LocalId tag of the discovered version exists - Identifier providerLocalIdentifier = null; - var delegateLinkTag = linkTags.WithAttribute("rel").FirstOrDefault(tag => Regex.IsMatch(tag.Attributes["rel"], @"\b" + Regex.Escape(protocol.HtmlDiscoveryLocalIdKey) + @"\b", RegexOptions.IgnoreCase)); - if (delegateLinkTag != null) { - if (Identifier.IsValid(delegateLinkTag.Href)) { - providerLocalIdentifier = delegateLinkTag.Href; - } else { - Logger.Yadis.WarnFormat("Skipping endpoint data because local id is badly formed ({0}).", delegateLinkTag.Href); - continue; // skip to next version - } - } - - // Choose the TypeURI to match the OpenID version detected. - string[] typeURIs = { protocol.ClaimedIdentifierServiceTypeURI }; - yield return ServiceEndpoint.CreateForClaimedIdentifier( - claimedIdentifier, - userSuppliedIdentifier, - providerLocalIdentifier, - new ProviderEndpointDescription(providerEndpoint, typeURIs), - (int?)null, - (int?)null); - } - } - } - - /// <summary> /// Determines whether the given URI is using a scheme in the list of allowed schemes. /// </summary> /// <param name="uri">The URI whose scheme is to be checked.</param> diff --git a/src/DotNetOpenAuth/OpenId/XriDiscoveryProxyService.cs b/src/DotNetOpenAuth/OpenId/XriDiscoveryProxyService.cs new file mode 100644 index 0000000..e338542 --- /dev/null +++ b/src/DotNetOpenAuth/OpenId/XriDiscoveryProxyService.cs @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------- +// <copyright file="XriDiscoveryProxyService.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Globalization; + using System.Linq; + using System.Text; + using System.Xml; + using DotNetOpenAuth.Configuration; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.RelyingParty; + using DotNetOpenAuth.Xrds; + using DotNetOpenAuth.Yadis; + + /// <summary> + /// The discovery service for XRI identifiers that uses an XRI proxy resolver for discovery. + /// </summary> + public class XriDiscoveryProxyService : IIdentifierDiscoveryService { + /// <summary> + /// The magic URL that will provide us an XRDS document for a given XRI identifier. + /// </summary> + /// <remarks> + /// We use application/xrd+xml instead of application/xrds+xml because it gets + /// xri.net to automatically give us exactly the right XRD element for community i-names + /// automatically, saving us having to choose which one to use out of the result. + /// The ssl=true parameter tells the proxy resolver to accept only SSL connections + /// when resolving community i-names. + /// </remarks> + private const string XriResolverProxyTemplate = "https://{1}/{0}?_xrd_r=application/xrd%2Bxml;sep=false"; + + /// <summary> + /// Initializes a new instance of the <see cref="XriDiscoveryProxyService"/> class. + /// </summary> + public XriDiscoveryProxyService() { + } + + #region IDiscoveryService Members + + /// <summary> + /// Performs discovery on the specified identifier. + /// </summary> + /// <param name="identifier">The identifier to perform discovery on.</param> + /// <param name="requestHandler">The means to place outgoing HTTP requests.</param> + /// <param name="abortDiscoveryChain">if set to <c>true</c>, no further discovery services will be called for this identifier.</param> + /// <returns> + /// A sequence of service endpoints yielded by discovery. Must not be null, but may be empty. + /// </returns> + public IEnumerable<IdentifierDiscoveryResult> Discover(Identifier identifier, IDirectWebRequestHandler requestHandler, out bool abortDiscoveryChain) { + abortDiscoveryChain = false; + var xriIdentifier = identifier as XriIdentifier; + if (xriIdentifier == null) { + return Enumerable.Empty<IdentifierDiscoveryResult>(); + } + + return DownloadXrds(xriIdentifier, requestHandler).XrdElements.CreateServiceEndpoints(xriIdentifier); + } + + #endregion + + /// <summary> + /// Downloads the XRDS document for this XRI. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <param name="requestHandler">The request handler.</param> + /// <returns>The XRDS document.</returns> + private static XrdsDocument DownloadXrds(XriIdentifier identifier, IDirectWebRequestHandler requestHandler) { + Contract.Requires<ArgumentNullException>(identifier != null); + Contract.Requires<ArgumentNullException>(requestHandler != null); + Contract.Ensures(Contract.Result<XrdsDocument>() != null); + XrdsDocument doc; + using (var xrdsResponse = Yadis.Request(requestHandler, GetXrdsUrl(identifier), identifier.IsDiscoverySecureEndToEnd)) { + doc = new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream)); + } + ErrorUtilities.VerifyProtocol(doc.IsXrdResolutionSuccessful, OpenIdStrings.XriResolutionFailed); + return doc; + } + + /// <summary> + /// Gets the URL from which this XRI's XRDS document may be downloaded. + /// </summary> + /// <param name="identifier">The identifier.</param> + /// <returns>The URI to HTTP GET from to get the services.</returns> + private static Uri GetXrdsUrl(XriIdentifier identifier) { + ErrorUtilities.VerifyProtocol(DotNetOpenAuthSection.Configuration.OpenId.XriResolver.Enabled, OpenIdStrings.XriResolutionDisabled); + string xriResolverProxy = XriResolverProxyTemplate; + if (identifier.IsDiscoverySecureEndToEnd) { + // Indicate to xri.net that we require SSL to be used for delegated resolution + // of community i-names. + xriResolverProxy += ";https=true"; + } + + return new Uri( + string.Format( + CultureInfo.InvariantCulture, + xriResolverProxy, + identifier, + DotNetOpenAuthSection.Configuration.OpenId.XriResolver.Proxy.Name)); + } + } +} diff --git a/src/DotNetOpenAuth/OpenId/XriIdentifier.cs b/src/DotNetOpenAuth/OpenId/XriIdentifier.cs index 9bcb9cf..6af41fa 100644 --- a/src/DotNetOpenAuth/OpenId/XriIdentifier.cs +++ b/src/DotNetOpenAuth/OpenId/XriIdentifier.cs @@ -35,23 +35,6 @@ namespace DotNetOpenAuth.OpenId { private const string XriScheme = "xri://"; /// <summary> - /// The magic URL that will provide us an XRDS document for a given XRI identifier. - /// </summary> - /// <remarks> - /// We use application/xrd+xml instead of application/xrds+xml because it gets - /// xri.net to automatically give us exactly the right XRD element for community i-names - /// automatically, saving us having to choose which one to use out of the result. - /// The ssl=true parameter tells the proxy resolver to accept only SSL connections - /// when resolving community i-names. - /// </remarks> - private const string XriResolverProxyTemplate = "https://{1}/{0}?_xrd_r=application/xrd%2Bxml;sep=false"; - - /// <summary> - /// The XRI proxy resolver to use for finding XRDS documents from an XRI. - /// </summary> - private readonly string xriResolverProxy; - - /// <summary> /// Backing store for the <see cref="CanonicalXri"/> property. /// </summary> private readonly string canonicalXri; @@ -79,12 +62,6 @@ namespace DotNetOpenAuth.OpenId { Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(xri)); Contract.Requires<FormatException>(IsValidXri(xri), OpenIdStrings.InvalidXri); Contract.Assume(xri != null); // Proven by IsValidXri - this.xriResolverProxy = XriResolverProxyTemplate; - if (requireSsl) { - // Indicate to xri.net that we require SSL to be used for delegated resolution - // of community i-names. - this.xriResolverProxy += ";https=true"; - } this.OriginalXri = xri; this.canonicalXri = CanonicalizeXri(xri); } @@ -105,21 +82,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Gets the URL from which this XRI's XRDS document may be downloaded. - /// </summary> - private Uri XrdsUrl { - get { - ErrorUtilities.VerifyProtocol(DotNetOpenAuthSection.Configuration.OpenId.XriResolver.Enabled, OpenIdStrings.XriResolutionDisabled); - return new Uri( - string.Format( - CultureInfo.InvariantCulture, - this.xriResolverProxy, - this, - DotNetOpenAuthSection.Configuration.OpenId.XriResolver.Proxy.Name)); - } - } - - /// <summary> /// Tests equality between this XRI and another XRI. /// </summary> /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param> @@ -178,30 +140,6 @@ namespace DotNetOpenAuth.OpenId { } /// <summary> - /// Performs discovery on the Identifier. - /// </summary> - /// <param name="requestHandler">The web request handler to use for discovery.</param> - /// <returns> - /// An initialized structure containing the discovered provider endpoint information. - /// </returns> - internal override IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler) { - return this.DownloadXrds(requestHandler).CreateServiceEndpoints(this); - } - - /// <summary> - /// Performs discovery on THIS identifier, but generates <see cref="ServiceEndpoint"/> - /// instances that treat another given identifier as the user-supplied identifier. - /// </summary> - /// <param name="requestHandler">The request handler to use in discovery.</param> - /// <param name="userSuppliedIdentifier">The user supplied identifier, which may differ from this XRI instance due to multiple discovery steps.</param> - /// <returns>A list of service endpoints offered for this identifier.</returns> - internal IEnumerable<ServiceEndpoint> Discover(IDirectWebRequestHandler requestHandler, XriIdentifier userSuppliedIdentifier) { - Contract.Requires<ArgumentNullException>(requestHandler != null); - Contract.Requires<ArgumentNullException>(userSuppliedIdentifier != null); - return this.DownloadXrds(requestHandler).CreateServiceEndpoints(userSuppliedIdentifier); - } - - /// <summary> /// Returns an <see cref="Identifier"/> that has no URI fragment. /// Quietly returns the original <see cref="Identifier"/> if it is not /// a <see cref="UriIdentifier"/> or no fragment exists. @@ -253,22 +191,6 @@ namespace DotNetOpenAuth.OpenId { return xri; } - /// <summary> - /// Downloads the XRDS document for this XRI. - /// </summary> - /// <param name="requestHandler">The request handler.</param> - /// <returns>The XRDS document.</returns> - private XrdsDocument DownloadXrds(IDirectWebRequestHandler requestHandler) { - Contract.Requires<ArgumentNullException>(requestHandler != null); - Contract.Ensures(Contract.Result<XrdsDocument>() != null); - XrdsDocument doc; - using (var xrdsResponse = Yadis.Request(requestHandler, this.XrdsUrl, this.IsDiscoverySecureEndToEnd)) { - doc = new XrdsDocument(XmlReader.Create(xrdsResponse.ResponseStream)); - } - ErrorUtilities.VerifyProtocol(doc.IsXrdResolutionSuccessful, OpenIdStrings.XriResolutionFailed); - return doc; - } - #if CONTRACTS_FULL /// <summary> /// Verifies conditions that should be true for any valid state of this object. @@ -277,7 +199,6 @@ namespace DotNetOpenAuth.OpenId { [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")] [ContractInvariantMethod] private void ObjectInvariant() { - Contract.Invariant(this.xriResolverProxy != null); Contract.Invariant(this.canonicalXri != null); } #endif diff --git a/src/DotNetOpenAuth/Xrds/XrdElement.cs b/src/DotNetOpenAuth/Xrds/XrdElement.cs index a8cc145..2cdc720 100644 --- a/src/DotNetOpenAuth/Xrds/XrdElement.cs +++ b/src/DotNetOpenAuth/Xrds/XrdElement.cs @@ -133,7 +133,7 @@ namespace DotNetOpenAuth.Xrds { /// </summary> /// <param name="p">A function that selects what element of the OpenID Protocol we're interested in finding.</param> /// <returns>A sequence of service elements that match the search criteria, sorted in XRDS @priority attribute order.</returns> - private IEnumerable<ServiceElement> SearchForServiceTypeUris(Func<Protocol, string> p) { + internal IEnumerable<ServiceElement> SearchForServiceTypeUris(Func<Protocol, string> p) { var xpath = new StringBuilder(); xpath.Append("xrd:Service["); foreach (var protocol in Protocol.AllVersions) { diff --git a/src/DotNetOpenAuth/Xrds/XrdsDocument.cs b/src/DotNetOpenAuth/Xrds/XrdsDocument.cs index dd0e19f..e2c2d72 100644 --- a/src/DotNetOpenAuth/Xrds/XrdsDocument.cs +++ b/src/DotNetOpenAuth/Xrds/XrdsDocument.cs @@ -18,6 +18,16 @@ namespace DotNetOpenAuth.Xrds { /// </summary> internal class XrdsDocument : XrdsNode { /// <summary> + /// The namespace used by XML digital signatures. + /// </summary> + private const string XmlDSigNamespace = "http://www.w3.org/2000/09/xmldsig#"; + + /// <summary> + /// The namespace used by Google Apps for Domains for OpenID URI templates. + /// </summary> + private const string GoogleOpenIdNamespace = "http://namespace.google.com/openid/xmlns"; + + /// <summary> /// Initializes a new instance of the <see cref="XrdsDocument"/> class. /// </summary> /// <param name="xrdsNavigator">The root node of the XRDS document.</param> @@ -26,6 +36,8 @@ namespace DotNetOpenAuth.Xrds { XmlNamespaceResolver.AddNamespace("xrd", XrdsNode.XrdNamespace); XmlNamespaceResolver.AddNamespace("xrds", XrdsNode.XrdsNamespace); XmlNamespaceResolver.AddNamespace("openid10", Protocol.V10.XmlNamespace); + XmlNamespaceResolver.AddNamespace("ds", XmlDSigNamespace); + XmlNamespaceResolver.AddNamespace("google", GoogleOpenIdNamespace); } /// <summary> diff --git a/src/DotNetOpenAuth/Xrds/XrdsNode.cs b/src/DotNetOpenAuth/Xrds/XrdsNode.cs index f8fa0af..39bd9b9 100644 --- a/src/DotNetOpenAuth/Xrds/XrdsNode.cs +++ b/src/DotNetOpenAuth/Xrds/XrdsNode.cs @@ -54,16 +54,16 @@ namespace DotNetOpenAuth.Xrds { /// <summary> /// Gets the node. /// </summary> - protected XPathNavigator Node { get; private set; } + internal XPathNavigator Node { get; private set; } /// <summary> /// Gets the parent node, or null if this is the root node. /// </summary> - protected XrdsNode ParentNode { get; private set; } + protected internal XrdsNode ParentNode { get; private set; } /// <summary> /// Gets the XML namespace resolver to use in XPath expressions. /// </summary> - protected XmlNamespaceManager XmlNamespaceResolver { get; private set; } + protected internal XmlNamespaceManager XmlNamespaceResolver { get; private set; } } } diff --git a/src/version.txt b/src/version.txt index 4772543..1809198 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -3.3.2 +3.4.0 |