summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2010-10-24 15:56:48 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2010-10-24 15:56:48 -0700
commit9dbb9aab73812202648c4e68d60261dd84d6c8e2 (patch)
tree5de139019a7b2f870f84c57cac36c0e489bd1e41
parent4b27c330fbfb3a260aa3bd6a9b1232ee3b53deb0 (diff)
parente7ce41355c38b3125729a62920231f274b7a2100 (diff)
downloadDotNetOpenAuth-origin/mono2.zip
DotNetOpenAuth-origin/mono2.tar.gz
DotNetOpenAuth-origin/mono2.tar.bz2
Merge branch 'v3.2' into mono2origin/mono2
Conflicts: src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
-rw-r--r--build.proj5
-rw-r--r--doc/Configuration.htm167
-rw-r--r--doc/README.html4
-rw-r--r--doc/WebFarms.htm25
-rw-r--r--lib/DotNetOpenAuth.BuildTasks.dllbin21504 -> 59904 bytes
-rw-r--r--lib/DotNetOpenAuth.BuildTasks.pdbbin60928 -> 155136 bytes
-rw-r--r--lib/DotNetOpenAuth.BuildTasks.targets44
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/Util.cs185
-rw-r--r--samples/InfoCardRelyingParty/Site.Master4
-rw-r--r--samples/OAuthConsumer/Twitter.aspx.cs2
-rw-r--r--samples/OpenIdOfflineProvider/OpenIdOfflineProvider.csproj12
-rw-r--r--samples/OpenIdOfflineProvider/Properties/AssemblyInfo.cs15
-rw-r--r--samples/OpenIdProviderMvc/Views/Shared/Site.Master4
-rw-r--r--samples/OpenIdProviderMvc/Views/Shared/Xrds.aspx8
-rw-r--r--samples/OpenIdProviderWebForms/ProfileFields.ascx.cs18
-rw-r--r--samples/OpenIdProviderWebForms/Site.Master4
-rw-r--r--samples/OpenIdProviderWebForms/Web.config4
-rw-r--r--samples/OpenIdProviderWebForms/server.aspx2
-rw-r--r--samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp2
-rw-r--r--samples/OpenIdRelyingPartyClassicAsp/default.asp2
-rw-r--r--samples/OpenIdRelyingPartyClassicAsp/login.asp2
-rw-r--r--samples/OpenIdRelyingPartyMvc/Controllers/UserController.cs4
-rw-r--r--samples/OpenIdRelyingPartyMvc/Views/Home/Index.aspx2
-rw-r--r--samples/OpenIdRelyingPartyMvc/Views/Shared/Site.Master6
-rw-r--r--samples/OpenIdRelyingPartyMvc/Views/User/LoginPopup.aspx16
-rw-r--r--samples/OpenIdRelyingPartyMvc/Web.config2
-rw-r--r--samples/OpenIdRelyingPartyWebForms/Site.Master4
-rw-r--r--samples/OpenIdRelyingPartyWebForms/Web.config2
-rw-r--r--samples/OpenIdRelyingPartyWebForms/ajaxlogin.aspx.cs2
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx1
-rw-r--r--samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs11
-rw-r--r--samples/README.html12
-rw-r--r--src/DotNetOpenAuth.BuildTasks/AddProjectItems.cs62
-rw-r--r--src/DotNetOpenAuth.BuildTasks/ChangeAssemblyReference.cs47
-rw-r--r--src/DotNetOpenAuth.BuildTasks/ChangeProjectReferenceToAssemblyReference.cs52
-rw-r--r--src/DotNetOpenAuth.BuildTasks/CheckAdminRights.cs30
-rw-r--r--src/DotNetOpenAuth.BuildTasks/CompareFiles.cs112
-rw-r--r--src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs102
-rw-r--r--src/DotNetOpenAuth.BuildTasks/CreateWebApplication.cs95
-rw-r--r--src/DotNetOpenAuth.BuildTasks/DeleteWebApplication.cs66
-rw-r--r--src/DotNetOpenAuth.BuildTasks/DiscoverProjectTemplates.cs63
-rw-r--r--src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.csproj160
-rw-r--r--src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.sln28
-rw-r--r--src/DotNetOpenAuth.BuildTasks/ECMAScriptPacker.cs486
-rw-r--r--src/DotNetOpenAuth.BuildTasks/FilterItems.cs24
-rw-r--r--src/DotNetOpenAuth.BuildTasks/FixupReferenceHintPaths.cs71
-rw-r--r--src/DotNetOpenAuth.BuildTasks/FixupShippingToolSamples.cs64
-rw-r--r--src/DotNetOpenAuth.BuildTasks/GetBuildVersion.cs124
-rw-r--r--src/DotNetOpenAuth.BuildTasks/JsPack.cs75
-rw-r--r--src/DotNetOpenAuth.BuildTasks/MergeProjectWithVSTemplate.cs103
-rw-r--r--src/DotNetOpenAuth.BuildTasks/ParseMaster.cs250
-rw-r--r--src/DotNetOpenAuth.BuildTasks/Properties/AssemblyInfo.cs36
-rw-r--r--src/DotNetOpenAuth.BuildTasks/Purge.cs88
-rw-r--r--src/DotNetOpenAuth.BuildTasks/ReSignDelaySignedAssemblies.cs56
-rw-r--r--src/DotNetOpenAuth.BuildTasks/SetEnvironmentVariable.cs33
-rw-r--r--src/DotNetOpenAuth.BuildTasks/SignatureVerification.cs45
-rw-r--r--src/DotNetOpenAuth.BuildTasks/SnToolTask.cs37
-rw-r--r--src/DotNetOpenAuth.BuildTasks/TaskStrings.Designer.cs117
-rw-r--r--src/DotNetOpenAuth.BuildTasks/TaskStrings.resx138
-rw-r--r--src/DotNetOpenAuth.BuildTasks/Trim.cs79
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs56
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs6
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/Reflection/MessagePartTests.cs7
-rw-r--r--src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs1
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs9
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ConsumerDescription.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OAuth/ServiceProviderDescriptionTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/AttributeExchangeRoundtripTests.cs4
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperOPTests.cs24
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPResponseTests.cs2
-rw-r--r--src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs4
-rw-r--r--src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd521
-rw-r--r--src/DotNetOpenAuth/Configuration/OpenIdElement.cs4
-rw-r--r--src/DotNetOpenAuth/GlobalSuppressions.cs1
-rw-r--r--src/DotNetOpenAuth/InfoCard/ReceivedTokenEventArgs.cs2
-rw-r--r--src/DotNetOpenAuth/InfoCard/ReceivingTokenEventArgs.cs2
-rw-r--r--src/DotNetOpenAuth/InfoCard/Token/TokenDecryptor.cs2
-rw-r--r--src/DotNetOpenAuth/InfoCard/TokenProcessingErrorEventArgs.cs2
-rw-r--r--src/DotNetOpenAuth/Loggers/ILog.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/EmptyDictionary.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/EmptyList.cs3
-rw-r--r--src/DotNetOpenAuth/Messaging/EnumerableCache.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs66
-rw-r--r--src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs4
-rw-r--r--src/DotNetOpenAuth/Messaging/MessageSerializer.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs4
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs4
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs2
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs24
-rw-r--r--src/DotNetOpenAuth/Messaging/StandardWebRequestHandler.cs4
-rw-r--r--src/DotNetOpenAuth/Messaging/UntrustedWebRequestHandler.cs4
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs2
-rw-r--r--src/DotNetOpenAuth/OAuth/ConsumerBase.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs39
-rw-r--r--src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs14
-rw-r--r--src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs1
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs6
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs11
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/IAssociationStore.cs17
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs42
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs19
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs19
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs3
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs9
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.js4
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs5
-rw-r--r--src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs19
-rw-r--r--src/DotNetOpenAuth/Properties/AssemblyInfo.cs42
-rw-r--r--tools/DotNetOpenAuth.Versioning.targets18
-rw-r--r--tools/Publish.targets10
-rw-r--r--tools/sandcastle.targets27
125 files changed, 3793 insertions, 536 deletions
diff --git a/build.proj b/build.proj
index 8e34a8d..b724482 100644
--- a/build.proj
+++ b/build.proj
@@ -21,7 +21,6 @@
<DirtyDirectories Include="
$(ProjectRoot)\bin;
$(ProjectRoot)\**\obj;
- $(ProjectRoot)\doc\api;
$(ProjectRoot)\drops;
$(ProjectRoot)\src\PrecompiledWeb;
" />
@@ -198,6 +197,7 @@
<DropLibFiles Include="@(DropLibSourceFiles->'$(DropLibDirectory)\%(RecurisveDir)%(FileName)%(Extension)')"/>
<DropSamplesFiles Include="@(DropSamplesSourceFiles->'$(DropSamplesDirectory)\%(RecursiveDir)%(FileName)%(Extension)')"/>
<DropSamplesRefreshFiles Include="@(DropSamplesRefreshSourceFiles->'$(DropSamplesDirectory)\%(RecursiveDir)%(FileName).refresh')"/>
+ <DropSamplesToolsProjects Include="$(DropSamplesDirectory)\OpenIdOfflineProvider\OpenIdOfflineProvider.csproj" />
<DropSpecsFiles Include="@(DropSpecsSourceFiles->'$(DropSpecsDirectory)\%(RecursiveDir)%(FileName)%(Extension)')"/>
<AllDropSources Include="
@@ -227,6 +227,9 @@
<ItemGroup>
<SampleProjectTargets Include="$(DropSamplesDirectory)\**\*.csproj" />
</ItemGroup>
+ <FixupShippingToolSamples Projects="@(DropSamplesToolsProjects)"
+ RemoveImportsStartingWith="%24(ProjectRoot)tools\;..\"
+ AddReferences="Microsoft.Contracts"/>
<ChangeProjectReferenceToAssemblyReference Projects="@(SampleProjectTargets)"
ProjectReference="..\..\src\$(ProductName)\$(ProductName).csproj" Reference="..\..\Bin\$(ProductName).dll" />
</Target>
diff --git a/doc/Configuration.htm b/doc/Configuration.htm
deleted file mode 100644
index 9346c9f..0000000
--- a/doc/Configuration.htm
+++ /dev/null
@@ -1,167 +0,0 @@
-<!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>
- <title>Web.config file configuration of DotNetOpenId</title>
-<style>
-#id_text_to_colorize{width:600px;height:120px}
-.linenos {padding-right: 5px;background: #ccc}
-.code {padding-left: 5px;}
-.highlight { background: #ffffff; }
-.highlight .c { color: #408080; font-style: italic } /* Comment */
-.highlight .err { border: 1px solid #FF0000 } /* Error */
-.highlight .k { color: #008000; font-weight: bold } /* Keyword */
-.highlight .o { color: #666666 } /* Operator */
-.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
-.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
-.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
-.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
-.highlight .gd { color: #A00000 } /* Generic.Deleted */
-.highlight .ge { font-style: italic } /* Generic.Emph */
-.highlight .gr { color: #FF0000 } /* Generic.Error */
-.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.highlight .gi { color: #00A000 } /* Generic.Inserted */
-.highlight .go { color: #808080 } /* Generic.Output */
-.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
-.highlight .gs { font-weight: bold } /* Generic.Strong */
-.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.highlight .gt { color: #0040D0 } /* Generic.Traceback */
-.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
-.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
-.highlight .kp { color: #008000 } /* Keyword.Pseudo */
-.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
-.highlight .kt { color: #B00040 } /* Keyword.Type */
-.highlight .m { color: #666666 } /* Literal.Number */
-.highlight .s { color: #BA2121 } /* Literal.String */
-.highlight .na { color: #7D9029 } /* Name.Attribute */
-.highlight .nb { color: #008000 } /* Name.Builtin */
-.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
-.highlight .no { color: #880000 } /* Name.Constant */
-.highlight .nd { color: #AA22FF } /* Name.Decorator */
-.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
-.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
-.highlight .nf { color: #0000FF } /* Name.Function */
-.highlight .nl { color: #A0A000 } /* Name.Label */
-.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
-.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
-.highlight .nv { color: #19177C } /* Name.Variable */
-.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
-.highlight .w { color: #bbbbbb } /* Text.Whitespace */
-.highlight .mf { color: #666666 } /* Literal.Number.Float */
-.highlight .mh { color: #666666 } /* Literal.Number.Hex */
-.highlight .mi { color: #666666 } /* Literal.Number.Integer */
-.highlight .mo { color: #666666 } /* Literal.Number.Oct */
-.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
-.highlight .sc { color: #BA2121 } /* Literal.String.Char */
-.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
-.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
-.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
-.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
-.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
-.highlight .sx { color: #008000 } /* Literal.String.Other */
-.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
-.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
-.highlight .ss { color: #19177C } /* Literal.String.Symbol */
-.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
-.highlight .vc { color: #19177C } /* Name.Variable.Class */
-.highlight .vg { color: #19177C } /* Name.Variable.Global */
-.highlight .vi { color: #19177C } /* Name.Variable.Instance */
-.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
-</style>
-</head>
-<body>
-
- <p>DotNetOpenId can be configured in some aspects inside your web project&#39;s
- web.config file.&nbsp; To do this, add the below &lt;sectionGroup&gt; within the
- &lt;configSections&gt; of your Web.config file:</p>
- <div class="highlight"><pre><span class="nt">&lt;configSections&gt;</span>
- <span class="nt">&lt;sectionGroup</span> <span class="na">name=</span><span
- class="s">&quot;dotNetOpenId&quot;</span><span class="nt">&gt;</span>
- <span class="nt">&lt;section</span> <span class="na">name=</span><span
- class="s">&quot;relyingParty&quot;</span> <span class="na">type=</span><span
- class="s">&quot;DotNetOpenId.Configuration.RelyingPartySection&quot;</span> <span
- class="na">requirePermission=</span><span class="s">&quot;false&quot;</span> <span
- class="na">allowLocation=</span><span class="s">&quot;true&quot;</span><span
- class="nt">/&gt;</span>
- <span class="nt">&lt;section</span> <span class="na">name=</span><span
- class="s">&quot;provider&quot;</span> <span class="na">type=</span><span class="s">&quot;DotNetOpenId.Configuration.ProviderSection&quot;</span> <span
- class="na">requirePermission=</span><span class="s">&quot;false&quot;</span> <span
- class="na">allowLocation=</span><span class="s">&quot;true&quot;</span><span
- class="nt">/&gt;</span>
- <span class="nt">&lt;section</span> <span class="na">name=</span><span
- class="s">&quot;untrustedWebRequest&quot;</span> <span class="na">type=</span><span
- class="s">&quot;DotNetOpenId.Configuration.UntrustedWebRequestSection&quot;</span> <span
- class="na">requirePermission=</span><span class="s">&quot;false&quot;</span> <span
- class="na">allowLocation=</span><span class="s">&quot;false&quot;</span><span
- class="nt">/&gt;</span>
- <span class="nt">&lt;/sectionGroup&gt;</span>
-<span class="nt">&lt;/configSections&gt;</span></pre></div>
- <p>If you do not already have a configSections element in your Web.config file, add
- it at the very top, as the first child of the root &lt;configuration&gt; tag.</p>
- <p>Following is an example of every possible configuration setting, where each
- demonstrate value happens to be the default that would be used if it wasn&#39;t set
- in the .config file.&nbsp; Keep in mind that every setting below is optional, so
- you need only include those elements that you wish to change in your own copy of
- Web.config.&nbsp; The &lt;dotNetOpenId&gt; node below should show up as a peer node to
- system.web in your Web.config file.</p>
- <div class="highlight"><pre><span class="nt">&lt;dotNetOpenId&gt;</span>
- <span class="nt">&lt;relyingParty&gt;</span>
- <span class="nt">&lt;security</span> <span class="na">minimumHashBitLength=</span><span
- class="s">&quot;160&quot;</span> <span class="na">maximumHashBitLength=</span><span
- class="s">&quot;256&quot;</span>
- <span class="na">requireSsl=</span><span class="s">&quot;false&quot;</span> <span
- class="na">minimumRequiredOpenIdVersion=</span><span class="s">&quot;V10&quot;</span> <span
- class="nt">/&gt;</span>
- <span class="nt">&lt;store</span> <span class="na">type=</span><span class="s">&quot;SomeSite.CustomRPStore, SomeSite&quot;</span> <span
- class="nt">/&gt;</span>
- <span class="nt">&lt;/relyingParty&gt;</span>
- <span class="nt">&lt;provider&gt;</span>
- <span class="nt">&lt;security</span> <span class="na">minimumHashBitLength=</span><span
- class="s">&quot;160&quot;</span> <span class="na">maximumHashBitLength=</span><span
- class="s">&quot;256&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;store</span> <span class="na">type=</span><span class="s">&quot;SomeSite.CustomProviderStore, SomeSite&quot;</span> <span
- class="nt">/&gt;</span>
- <span class="nt">&lt;/provider&gt;</span>
- <span class="nt">&lt;untrustedWebRequest</span> <span class="na">readWriteTimeout=</span><span
- class="s">&quot;00:00:00.800&quot;</span> <span class="na">timeout=</span><span
- class="s">&quot;00:00:10&quot;</span> <span class="na">maximumBytesToRead=</span><span
- class="s">&quot;1048576&quot;</span> <span class="na">maximumRedirections=</span><span
- class="s">&quot;10&quot;</span><span class="nt">&gt;</span>
- <span class="nt">&lt;whitelistHosts&gt;</span>
- <span class="nt">&lt;add</span> <span class="na">name=</span><span
- class="s">&quot;localhost&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;add</span> <span class="na">name=</span><span
- class="s">&quot;127.0.0.1&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;/whitelistHosts&gt;</span>
- <span class="nt">&lt;whitelistHostsRegex&gt;</span>
- <span class="nt">&lt;add</span> <span class="na">name=</span><span
- class="s">&quot;^(.*\.)?goodsite.com&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;/whitelistHostsRegex&gt;</span>
- <span class="nt">&lt;blacklistHosts&gt;</span>
- <span class="nt">&lt;add</span> <span class="na">name=</span><span
- class="s">&quot;internalfinancialserver&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;add</span> <span class="na">name=</span><span
- class="s">&quot;www.evilsite.com&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;/blacklistHosts&gt;</span>
- <span class="nt">&lt;blacklistHostsRegex&gt;</span>
- <span class="nt">&lt;add</span> <span class="na">name=</span><span
- class="s">&quot;^(.*\.)?evilsite.com&quot;</span> <span class="nt">/&gt;</span>
- <span class="nt">&lt;/blacklistHostsRegex&gt;</span>
- <span class="nt">&lt;/untrustedWebRequest&gt;</span>
-<span class="nt">&lt;/dotNetOpenId&gt;</span>
-</pre></div>
-
- <p>All these configuration values are also configurable at runtime using the object
- model of the library.&nbsp; Using the Web.config file allows changes to be made
- without recompiling the web site.&nbsp; In the case of OpenIdRelyingParty and
- OpenIdProvider, it also allows you to setup your configuration just once, in
- your .config file, and have it apply to every instance of OpenIdRelyingParty or
- OpenIdProvider instead of you having to set up that configuration everywhere you
- instantiate these types.</p>
- <p>By using the ASP.NET &lt;location&gt; element, you can set some configuration settings
- for OpenIdRelyingParty or OpenIdProvider based on which directory or web page in
- your project is instantiating them.&nbsp; This would allow you to, for example,
- use enhanced SSL security requirements at just the administrator log in screen
- while allowing non-SSL OpenIDs for ordinary users.</p>
-
-</body>
-</html>
diff --git a/doc/README.html b/doc/README.html
index 7877d72..a82d848 100644
--- a/doc/README.html
+++ b/doc/README.html
@@ -4,8 +4,8 @@
<p>DotNetOpenAuth is a .NET library that enables OpenID, OAuth and InfoCard support
to be easily added to your web and/or desktop applications.&nbsp; </p>
<p>The project site for this library is hosted at
- <a href="http://dotnetopenid.googlecode.com/">
- http://dotnetopenid.googlecode.com/</a>.&nbsp; Please visit that web site for
+ <a href="http://dotnetopenauth.net/">
+ http://dotnetopenauth.net/</a>.&nbsp; Please visit that web site for
documentation, support and maintenance releases.</p>
<p>As with any library that is used for security-sensitive purposes such as
authentication and authorization, you should periodically check the project web
diff --git a/doc/WebFarms.htm b/doc/WebFarms.htm
index 44447e7..5ae924d 100644
--- a/doc/WebFarms.htm
+++ b/doc/WebFarms.htm
@@ -7,21 +7,26 @@
<h3>
Non-ASP.NET web servers</h3>
<p>
- DotNetOpenId works without being a part of an ASP.NET web site.&nbsp; The
- ASP.NET controls may not be used in this context, but the programmatic access to
- the OpenIdProvider and OpenIdRelyingParty classes will work correctly if you
- call the method overloads that do not require a current ASP.NET context.&nbsp;
- The xml doc comments indicate which methods require an ASP.NET context and which
- methods may be used without one.</p>
+ DotNetOpenAuth works without being a part of an ASP.NET web site.&nbsp; The ASP.NET
+ controls may not be used in this context, but the programmatic access to the OpenIdProvider
+ and OpenIdRelyingParty classes will work correctly if you call the method overloads
+ that do not require a current ASP.NET context.&nbsp; The xml doc comments indicate
+ which methods require an ASP.NET context and which methods may be used without one.</p>
<h3>
Proxy servers</h3>
<p>
- If your web servers need to use proxy servers to make outbound requests, you
- will need to configure your .NET AppDomain to default to the proxy server you
- require so that DotNetOpenId will use it.&nbsp;
+ If your web servers need to use proxy servers to make outbound requests, you will
+ need to configure your .NET AppDomain to default to the proxy server you require
+ so that DotNetOpenAuth will use it.&nbsp;
</p>
<p>
- To set the default web proxy, set the System.Net.WebRequest.DefaultWebProxy
+ To set the default web proxy programmatically, set the System.Net.WebRequest.DefaultWebProxy
property.</p>
+ <p>
+ To use the default proxy using your web.config file, add this section:<br />
+ <pre>&lt;system.net&gt;
+ &lt;defaultProxy enabled=&quot;true&quot; /&gt;
+&lt;/system.net&gt;</pre>
+ </p>
</body>
</html>
diff --git a/lib/DotNetOpenAuth.BuildTasks.dll b/lib/DotNetOpenAuth.BuildTasks.dll
index d11865f..3db458c 100644
--- a/lib/DotNetOpenAuth.BuildTasks.dll
+++ b/lib/DotNetOpenAuth.BuildTasks.dll
Binary files differ
diff --git a/lib/DotNetOpenAuth.BuildTasks.pdb b/lib/DotNetOpenAuth.BuildTasks.pdb
index dda205e..24a5292 100644
--- a/lib/DotNetOpenAuth.BuildTasks.pdb
+++ b/lib/DotNetOpenAuth.BuildTasks.pdb
Binary files differ
diff --git a/lib/DotNetOpenAuth.BuildTasks.targets b/lib/DotNetOpenAuth.BuildTasks.targets
index 024b43a..e57ec97 100644
--- a/lib/DotNetOpenAuth.BuildTasks.targets
+++ b/lib/DotNetOpenAuth.BuildTasks.targets
@@ -1,19 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
- <PropertyGroup>
- <ProjectRoot Condition="'$(ProjectRoot)' == ''">$(MSBuildProjectDirectory)\..\..</ProjectRoot>
- </PropertyGroup>
-
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="GetBuildVersion" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="SetEnvironmentVariable" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="ChangeProjectReferenceToAssemblyReference" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="CompareFiles" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="ReSignDelaySignedAssemblies" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="SignatureVerification" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="CheckAdminRights" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="CreateWebApplication" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="DeleteWebApplication" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="Trim" />
- <UsingTask AssemblyFile="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.dll" TaskName="FilterItems" />
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+ <ItemGroup>
+ <VsTemplateParameterReplaceExtensions Include=".cs;.csproj;.sql;.config;.Master;.aspx;.ascx;.vb;.asax;.ashx" />
+ <VsTemplateProjectItemTypes Include="Compile;EmbeddedResource;EntityDeploy;Content;None" />
+ </ItemGroup>
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="GetBuildVersion" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="SetEnvironmentVariable" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="ChangeProjectReferenceToAssemblyReference" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="CompareFiles" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="ReSignDelaySignedAssemblies" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="SignatureVerification" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="CheckAdminRights" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="CreateWebApplication" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="DeleteWebApplication" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="Trim" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="FilterItems" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="JsPack" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="CopyWithTokenSubstitution" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="MergeProjectWithVSTemplate" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="DiscoverProjectTemplates" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="FixupReferenceHintPaths" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="AddProjectItems" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="Purge" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="FixupShippingToolSamples" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="Publicize" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="DowngradeProjects" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="HardLinkCopy" />
+ <UsingTask AssemblyFile="DotNetOpenAuth.BuildTasks.dll" TaskName="PrepareOhlohRelease" />
</Project>
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
index ea7da97..65505b6 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
@@ -1,10 +1,44 @@
namespace DotNetOpenAuth.ApplicationBlock {
using System;
using System.Collections.Generic;
+ using System.Diagnostics;
using System.IO;
+ using System.Net;
using DotNetOpenAuth.Messaging;
- internal static class Util {
+ public static class Util {
+ /// <summary>
+ /// Pseudo-random data generator.
+ /// </summary>
+ internal static readonly Random NonCryptoRandomDataGenerator = new Random();
+
+ /// <summary>
+ /// Sets the channel's outgoing HTTP requests to use default network credentials.
+ /// </summary>
+ /// <param name="channel">The channel to modify.</param>
+ public static void UseDefaultNetworkCredentialsOnOutgoingHttpRequests(this Channel channel)
+ {
+ Debug.Assert(!(channel.WebRequestHandler is WrappingWebRequestHandler), "Wrapping an already wrapped web request handler. This is legal, but highly suspect of a bug as you don't want to wrap the same channel repeatedly to apply the same effect.");
+ AddOutgoingHttpRequestTransform(channel, http => http.Credentials = CredentialCache.DefaultNetworkCredentials);
+ }
+
+ /// <summary>
+ /// Adds some action to any outgoing HTTP request on this channel.
+ /// </summary>
+ /// <param name="channel">The channel's whose outgoing HTTP requests should be modified.</param>
+ /// <param name="action">The action to perform on outgoing HTTP requests.</param>
+ internal static void AddOutgoingHttpRequestTransform(this Channel channel, Action<HttpWebRequest> action) {
+ if (channel == null) {
+ throw new ArgumentNullException("channel");
+ }
+
+ if (action == null) {
+ throw new ArgumentNullException("action");
+ }
+
+ channel.WebRequestHandler = new WrappingWebRequestHandler(channel.WebRequestHandler, action);
+ }
+
/// <summary>
/// Enumerates through the individual set bits in a flag enum.
/// </summary>
@@ -72,5 +106,154 @@
return totalCopiedBytes;
}
+
+ /// <summary>
+ /// Wraps some instance of a web request handler in order to perform some extra operation on all
+ /// outgoing HTTP requests.
+ /// </summary>
+ private class WrappingWebRequestHandler : IDirectWebRequestHandler
+ {
+ /// <summary>
+ /// The handler being wrapped.
+ /// </summary>
+ private readonly IDirectWebRequestHandler wrappedHandler;
+
+ /// <summary>
+ /// The action to perform on outgoing HTTP requests.
+ /// </summary>
+ private readonly Action<HttpWebRequest> action;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="WrappingWebRequestHandler"/> class.
+ /// </summary>
+ /// <param name="wrappedHandler">The HTTP handler to wrap.</param>
+ /// <param name="action">The action to perform on outgoing HTTP requests.</param>
+ internal WrappingWebRequestHandler(IDirectWebRequestHandler wrappedHandler, Action<HttpWebRequest> action)
+ {
+ if (wrappedHandler == null) {
+ throw new ArgumentNullException("wrappedHandler");
+ }
+
+ if (action == null) {
+ throw new ArgumentNullException("action");
+ }
+
+ this.wrappedHandler = wrappedHandler;
+ this.action = action;
+ }
+
+ #region Implementation of IDirectWebRequestHandler
+
+ /// <summary>
+ /// Determines whether this instance can support the specified options.
+ /// </summary>
+ /// <param name="options">The set of options that might be given in a subsequent web request.</param>
+ /// <returns>
+ /// <c>true</c> if this instance can support the specified options; otherwise, <c>false</c>.
+ /// </returns>
+ public bool CanSupport(DirectWebRequestOptions options)
+ {
+ return this.wrappedHandler.CanSupport(options);
+ }
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>
+ /// The stream the caller should write out the entity data to.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
+ /// and any other appropriate properties <i>before</i> calling this method.
+ /// Callers <i>must</i> close and dispose of the request stream when they are done
+ /// writing to it to avoid taking up the connection too long and causing long waits on
+ /// subsequent requests.</para>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch.</para>
+ /// </remarks>
+ public Stream GetRequestStream(HttpWebRequest request)
+ {
+ this.action(request);
+ return wrappedHandler.GetRequestStream(request);
+ }
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <param name="options">The options to apply to this web request.</param>
+ /// <returns>
+ /// The stream the caller should write out the entity data to.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
+ /// and any other appropriate properties <i>before</i> calling this method.
+ /// Callers <i>must</i> close and dispose of the request stream when they are done
+ /// writing to it to avoid taking up the connection too long and causing long waits on
+ /// subsequent requests.</para>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch.</para>
+ /// </remarks>
+ public Stream GetRequestStream(HttpWebRequest request, DirectWebRequestOptions options)
+ {
+ this.action(request);
+ return wrappedHandler.GetRequestStream(request, options);
+ }
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>An instance of <see cref="IncomingWebResponse"/> describing the response.</returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
+ /// value, if set, should be Closed before throwing.</para>
+ /// </remarks>
+ public IncomingWebResponse GetResponse(HttpWebRequest request)
+ {
+ // If the request has an entity, the action would have already been processed in GetRequestStream.
+ if (request.Method == "GET")
+ {
+ this.action(request);
+ }
+
+ return wrappedHandler.GetResponse(request);
+ }
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <param name="options">The options to apply to this web request.</param>
+ /// <returns>An instance of <see cref="IncomingWebResponse"/> describing the response.</returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
+ /// value, if set, should be Closed before throwing.</para>
+ /// </remarks>
+ public IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options)
+ {
+ // If the request has an entity, the action would have already been processed in GetRequestStream.
+ if (request.Method == "GET") {
+ this.action(request);
+ }
+
+ return wrappedHandler.GetResponse(request, options);
+ }
+
+ #endregion
+ }
}
}
diff --git a/samples/InfoCardRelyingParty/Site.Master b/samples/InfoCardRelyingParty/Site.Master
index 7d3dae7..508f62c 100644
--- a/samples/InfoCardRelyingParty/Site.Master
+++ b/samples/InfoCardRelyingParty/Site.Master
@@ -19,9 +19,9 @@
<asp:LoginStatus ID="LoginStatus1" runat="server" />
</span>
<div>
- <a href="http://dotnetopenid.googlecode.com">
+ <a href="http://dotnetopenauth.net">
<img runat="server" src="~/images/dotnetopenid_tiny.gif" title="Jump to the project web site."
- alt="DotNetOpenId" border='0' /></a>
+ alt="DotNetOpenAuth" border='0' /></a>
</div>
<div>
<asp:ContentPlaceHolder ID="Main" runat="server" />
diff --git a/samples/OAuthConsumer/Twitter.aspx.cs b/samples/OAuthConsumer/Twitter.aspx.cs
index a4fb0cb..9b9eced 100644
--- a/samples/OAuthConsumer/Twitter.aspx.cs
+++ b/samples/OAuthConsumer/Twitter.aspx.cs
@@ -54,7 +54,7 @@ public partial class Twitter : System.Web.UI.Page {
protected void downloadUpdates_Click(object sender, EventArgs e) {
var twitter = new WebConsumer(TwitterConsumer.ServiceDescription, this.TokenManager);
- XPathDocument updates = new XPathDocument(TwitterConsumer.GetUpdates(twitter, AccessToken).CreateReader());
+ XPathDocument updates = new XPathDocument(TwitterConsumer.GetUpdates(twitter, this.AccessToken).CreateReader());
XPathNavigator nav = updates.CreateNavigator();
var parsedUpdates = from status in nav.Select("/statuses/status").OfType<XPathNavigator>()
where !status.SelectSingleNode("user/protected").ValueAsBoolean
diff --git a/samples/OpenIdOfflineProvider/OpenIdOfflineProvider.csproj b/samples/OpenIdOfflineProvider/OpenIdOfflineProvider.csproj
index 1bb2367..be1e9c3 100644
--- a/samples/OpenIdOfflineProvider/OpenIdOfflineProvider.csproj
+++ b/samples/OpenIdOfflineProvider/OpenIdOfflineProvider.csproj
@@ -15,6 +15,8 @@
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<UICulture>en-US</UICulture>
+ <OutputPath Condition=" '$(OutputPath)' == '' ">bin\$(Configuration)\</OutputPath>
+ <TargetFrameworkVersion Condition=" '$(TargetFrameworkVersion)' == '' ">v3.5</TargetFrameworkVersion>
<ApplicationIcon>openid.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@@ -161,11 +163,5 @@
<Resource Include="openid.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>
- -->
-</Project> \ No newline at end of file
+ <Import Project="..\..\tools\DotNetOpenAuth.Versioning.targets" />
+</Project>
diff --git a/samples/OpenIdOfflineProvider/Properties/AssemblyInfo.cs b/samples/OpenIdOfflineProvider/Properties/AssemblyInfo.cs
index adaded3..77d7464 100644
--- a/samples/OpenIdOfflineProvider/Properties/AssemblyInfo.cs
+++ b/samples/OpenIdOfflineProvider/Properties/AssemblyInfo.cs
@@ -10,6 +10,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
+// We DON'T put an AssemblyVersionAttribute in here because it is generated in the build.
+
// 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.
@@ -36,16 +38,3 @@ using System.Windows;
ResourceDictionaryLocation.SourceAssembly)] // where the generic resource dictionary is located
// (used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
-
-// 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 Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/samples/OpenIdProviderMvc/Views/Shared/Site.Master b/samples/OpenIdProviderMvc/Views/Shared/Site.Master
index 073908e..49f6a7f 100644
--- a/samples/OpenIdProviderMvc/Views/Shared/Site.Master
+++ b/samples/OpenIdProviderMvc/Views/Shared/Site.Master
@@ -2,11 +2,11 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
-<head runat="server">
+<head>
<title>
<asp:ContentPlaceHolder ID="TitleContent" runat="server" />
</title>
- <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
+ <link href='<%= Url.Content("~/Content/Site.css") %>' rel="stylesheet" type="text/css" />
<asp:ContentPlaceHolder ID="HeadContent" runat="server" />
</head>
<body>
diff --git a/samples/OpenIdProviderMvc/Views/Shared/Xrds.aspx b/samples/OpenIdProviderMvc/Views/Shared/Xrds.aspx
index 7aad102..0d73909 100644
--- a/samples/OpenIdProviderMvc/Views/Shared/Xrds.aspx
+++ b/samples/OpenIdProviderMvc/Views/Shared/Xrds.aspx
@@ -27,5 +27,13 @@ for all XRDS discovery.
<Type>http://specs.openid.net/extensions/ui/1.0/icon</Type>--%>
<URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/Provider"))%></URI>
</Service>
+<% if (ViewData["OPIdentifier"] == null) { %>
+ <Service priority="20">
+ <Type>http://openid.net/signon/1.0</Type>
+ <Type>http://openid.net/extensions/sreg/1.1</Type>
+ <Type>http://axschema.org/contact/email</Type>
+ <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/Provider"))%></URI>
+ </Service>
+<% } %>
</XRD>
</xrds:XRDS>
diff --git a/samples/OpenIdProviderWebForms/ProfileFields.ascx.cs b/samples/OpenIdProviderWebForms/ProfileFields.ascx.cs
index 893830f..6954aa6 100644
--- a/samples/OpenIdProviderWebForms/ProfileFields.ascx.cs
+++ b/samples/OpenIdProviderWebForms/ProfileFields.ascx.cs
@@ -76,15 +76,15 @@ namespace OpenIdProviderWebForms {
this.privacyLink.Visible = false;
}
- this.dobRequiredLabel.Visible = (requestFields.BirthDate == DemandLevel.Require);
- this.countryRequiredLabel.Visible = (requestFields.Country == DemandLevel.Require);
- this.emailRequiredLabel.Visible = (requestFields.Email == DemandLevel.Require);
- this.fullnameRequiredLabel.Visible = (requestFields.FullName == DemandLevel.Require);
- this.genderRequiredLabel.Visible = (requestFields.Gender == DemandLevel.Require);
- this.languageRequiredLabel.Visible = (requestFields.Language == DemandLevel.Require);
- this.nicknameRequiredLabel.Visible = (requestFields.Nickname == DemandLevel.Require);
- this.postcodeRequiredLabel.Visible = (requestFields.PostalCode == DemandLevel.Require);
- this.timezoneRequiredLabel.Visible = (requestFields.TimeZone == DemandLevel.Require);
+ this.dobRequiredLabel.Visible = requestFields.BirthDate == DemandLevel.Require;
+ this.countryRequiredLabel.Visible = requestFields.Country == DemandLevel.Require;
+ this.emailRequiredLabel.Visible = requestFields.Email == DemandLevel.Require;
+ this.fullnameRequiredLabel.Visible = requestFields.FullName == DemandLevel.Require;
+ this.genderRequiredLabel.Visible = requestFields.Gender == DemandLevel.Require;
+ this.languageRequiredLabel.Visible = requestFields.Language == DemandLevel.Require;
+ this.nicknameRequiredLabel.Visible = requestFields.Nickname == DemandLevel.Require;
+ this.postcodeRequiredLabel.Visible = requestFields.PostalCode == DemandLevel.Require;
+ this.timezoneRequiredLabel.Visible = requestFields.TimeZone == DemandLevel.Require;
this.dateOfBirthRow.Visible = !(requestFields.BirthDate == DemandLevel.NoRequest);
this.countryRow.Visible = !(requestFields.Country == DemandLevel.NoRequest);
diff --git a/samples/OpenIdProviderWebForms/Site.Master b/samples/OpenIdProviderWebForms/Site.Master
index 8780550..4df9e0a 100644
--- a/samples/OpenIdProviderWebForms/Site.Master
+++ b/samples/OpenIdProviderWebForms/Site.Master
@@ -9,9 +9,9 @@
</head>
<body>
<form id="form1" runat="server">
- <div><a href="http://dotnetopenid.googlecode.com">
+ <div><a href="http://dotnetopenauth.net">
<img runat="server" src="~/images/dotnetopenid_tiny.gif" title="Jump to the project web site."
- alt="DotNetOpenId" border='0' /></a> </div>
+ alt="DotNetOpenAuth" border='0' /></a> </div>
<div>
<asp:ContentPlaceHolder ID="Main" runat="server" />
</div>
diff --git a/samples/OpenIdProviderWebForms/Web.config b/samples/OpenIdProviderWebForms/Web.config
index 5db477c..cd070ba 100644
--- a/samples/OpenIdProviderWebForms/Web.config
+++ b/samples/OpenIdProviderWebForms/Web.config
@@ -43,7 +43,7 @@
</settings>
</system.net>
- <!-- this is an optional configuration section where aspects of dotnetopenid can be customized -->
+ <!-- this is an optional configuration section where aspects of DotNetOpenAuth can be customized -->
<dotNetOpenAuth>
<openid>
<provider>
@@ -125,7 +125,7 @@
</authorization>
</system.web>
</location>
- <!-- log4net is a 3rd party (free) logger library that dotnetopenid will use if present but does not require. -->
+ <!-- log4net is a 3rd party (free) logger library that DotNetOpenAuth will use if present but does not require. -->
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="Provider.log"/>
diff --git a/samples/OpenIdProviderWebForms/server.aspx b/samples/OpenIdProviderWebForms/server.aspx
index d3ce78d..a874ccd 100644
--- a/samples/OpenIdProviderWebForms/server.aspx
+++ b/samples/OpenIdProviderWebForms/server.aspx
@@ -25,7 +25,7 @@
<table>
<tr>
<td>
- <a href="http://dotnetopenid.googlecode.com/">http://dotnetopenid.googlecode.com/</a>
+ <a href="http://dotnetopenauth.net/">http://dotnetopenauth.net/</a>
</td>
<td>
Home of this library
diff --git a/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp b/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp
index 741a3e7..da6c18b 100644
--- a/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp
+++ b/samples/OpenIdRelyingPartyClassicAsp/MembersOnly.asp
@@ -11,7 +11,7 @@ End If
</head>
<body>
<div>
- <a href="http://DotNetOpenId.googlecode.com">
+ <a href="http://dotnetopenauth.net">
<img runat="server" src="images/DotNetOpenId_tiny.gif" title="Jump to the project web site."
alt="DotNetOpenAuth" border='0' /></a>
</div>
diff --git a/samples/OpenIdRelyingPartyClassicAsp/default.asp b/samples/OpenIdRelyingPartyClassicAsp/default.asp
index bdddbcc..f4d1d1d 100644
--- a/samples/OpenIdRelyingPartyClassicAsp/default.asp
+++ b/samples/OpenIdRelyingPartyClassicAsp/default.asp
@@ -6,7 +6,7 @@
</head>
<body>
<div>
- <a href="http://DotNetOpenId.googlecode.com">
+ <a href="http://dotnetopenauth.net">
<img runat="server" src="images/DotNetOpenId_tiny.gif" title="Jump to the project web site."
alt="DotNetOpenAuth" border='0' /></a>
</div>
diff --git a/samples/OpenIdRelyingPartyClassicAsp/login.asp b/samples/OpenIdRelyingPartyClassicAsp/login.asp
index d222e57..449af3e 100644
--- a/samples/OpenIdRelyingPartyClassicAsp/login.asp
+++ b/samples/OpenIdRelyingPartyClassicAsp/login.asp
@@ -6,7 +6,7 @@
</head>
<body>
<div>
- <a href="http://DotNetOpenId.googlecode.com">
+ <a href="http://dotnetopenauth.net">
<img runat="server" src="images/DotNetOpenId_tiny.gif" title="Jump to the project web site."
alt="DotNetOpenAuth" border='0' /></a>
</div>
diff --git a/samples/OpenIdRelyingPartyMvc/Controllers/UserController.cs b/samples/OpenIdRelyingPartyMvc/Controllers/UserController.cs
index fd22389..b3698bb 100644
--- a/samples/OpenIdRelyingPartyMvc/Controllers/UserController.cs
+++ b/samples/OpenIdRelyingPartyMvc/Controllers/UserController.cs
@@ -14,7 +14,7 @@
public ActionResult Index() {
if (!User.Identity.IsAuthenticated) {
- Response.Redirect("/User/Login?ReturnUrl=Index");
+ Response.Redirect("~/User/Login?ReturnUrl=Index");
}
return View("Index");
@@ -26,7 +26,7 @@
public ActionResult Logout() {
FormsAuthentication.SignOut();
- return Redirect("/Home");
+ return Redirect("~/Home");
}
public ActionResult Login() {
diff --git a/samples/OpenIdRelyingPartyMvc/Views/Home/Index.aspx b/samples/OpenIdRelyingPartyMvc/Views/Home/Index.aspx
index 8535c7c..be4bd20 100644
--- a/samples/OpenIdRelyingPartyMvc/Views/Home/Index.aspx
+++ b/samples/OpenIdRelyingPartyMvc/Views/Home/Index.aspx
@@ -2,7 +2,7 @@
<asp:Content ID="indexContent" ContentPlaceHolderID="MainContentPlaceHolder" runat="server">
<h1>OpenID Relying Party </h1>
- <h2>Provided by <a href="http://dotnetopenid.googlecode.com">DotNetOpenAuth</a> </h2>
+ <h2>Provided by <a href="http://dotnetopenauth.net">DotNetOpenAuth</a> </h2>
<% if (User.Identity.IsAuthenticated) { %>
<p><b>You are already logged in!</b> Try visiting the
<%=Html.ActionLink("Members Only", "Index", "User") %>
diff --git a/samples/OpenIdRelyingPartyMvc/Views/Shared/Site.Master b/samples/OpenIdRelyingPartyMvc/Views/Shared/Site.Master
index d9b759c..35c101d 100644
--- a/samples/OpenIdRelyingPartyMvc/Views/Shared/Site.Master
+++ b/samples/OpenIdRelyingPartyMvc/Views/Shared/Site.Master
@@ -2,10 +2,10 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
-<head runat="server">
+<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>DotNetOpenAuth ASP.NET MVC Login sample</title>
- <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
+ <link href='<%= Url.Content("~/Content/Site.css") %>' rel="stylesheet" type="text/css" />
<asp:ContentPlaceHolder ID="HeadContentPlaceHolder" runat="server" />
</head>
<body>
@@ -26,7 +26,7 @@
<div class="leftColumn">
<h2>External OpenID Links</h2>
<ul>
- <li><a href="http://dotnetopenid.googlecode.com">DotNetOpenAuth</a></li>
+ <li><a href="http://dotnetopenauth.net">DotNetOpenAuth</a></li>
<li><a href="http://openid.net">About OpenID</a></li>
</ul>
</div>
diff --git a/samples/OpenIdRelyingPartyMvc/Views/User/LoginPopup.aspx b/samples/OpenIdRelyingPartyMvc/Views/User/LoginPopup.aspx
index e7bc18a..2f4b276 100644
--- a/samples/OpenIdRelyingPartyMvc/Views/User/LoginPopup.aspx
+++ b/samples/OpenIdRelyingPartyMvc/Views/User/LoginPopup.aspx
@@ -7,10 +7,10 @@
<head>
<title>OpenID login demo</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
- <link type="text/css" href="../../Content/theme/ui.all.css" rel="Stylesheet" />
- <link type="text/css" href="../../Content/css/openidlogin.css" rel="stylesheet" />
- <script type="text/javascript" src="../../Content/scripts/jquery-1.3.1.js"></script>
- <script type="text/javascript" src="../../Content/scripts/jquery-ui-personalized-1.6rc6.js"></script>
+ <link type="text/css" href='<%= Url.Content("~/Content/theme/ui.all.css") %>' rel="Stylesheet" />
+ <link type="text/css" href='<%= Url.Content("~/Content/css/openidlogin.css") %>' rel="stylesheet" />
+ <script type="text/javascript" src='<%= Url.Content("~/Content/scripts/jquery-1.3.1.js") %>'></script>
+ <script type="text/javascript" src='<%= Url.Content("~/Content/scripts/jquery-ui-personalized-1.6rc6.js") %>'></script>
<script>
$(function() {
$('#openidlogin').dialog({
@@ -171,10 +171,10 @@
<div id="openidlogin" class="ui-widget-content">
<p>Log in with an account you already use:</p>
<div class="large buttons">
- <div class="provider" onclick="document.selectProvider(this, 'https://www.google.com/accounts/o8/id')"><div><img src="../../Content/images/google.gif"/></div></div>
- <div class="provider" onclick="document.selectProvider(this, 'https://me.yahoo.com/')"><div><img src="../../Content/images/yahoo.gif"/></div></div>
- <div class="provider" onclick="document.selectProvider(this, 'http://openid.aol.com/{username}')"><div><img src="../../Content/images/aol.gif"/></div></div>
- <div class="provider" onclick="document.selectProvider(this, '')"><div><img src="../../Content/images/openid.gif"/></div></div>
+ <div class="provider" onclick="document.selectProvider(this, 'https://www.google.com/accounts/o8/id')"><div><img src='<%= Url.Content("~/Content/images/google.gif") %>'/></div></div>
+ <div class="provider" onclick="document.selectProvider(this, 'https://me.yahoo.com/')"><div><img src='<%= Url.Content("~/Content/images/yahoo.gif") %>'/></div></div>
+ <div class="provider" onclick="document.selectProvider(this, 'http://openid.aol.com/{username}')"><div><img src='<%= Url.Content("~/Content/images/aol.gif") %>'/></div></div>
+ <div class="provider" onclick="document.selectProvider(this, '')"><div><img src='<%= Url.Content("~/Content/images/openid.gif") %>'/></div></div>
</div>
<div class="small buttons">
<div class="provider" onclick="document.selectProvider(this, 'http://www.flickr.com/photos/{username}')"><div><img src="http://flickr.com/favicon.ico"/></div></div>
diff --git a/samples/OpenIdRelyingPartyMvc/Web.config b/samples/OpenIdRelyingPartyMvc/Web.config
index da36d72..bf37616 100644
--- a/samples/OpenIdRelyingPartyMvc/Web.config
+++ b/samples/OpenIdRelyingPartyMvc/Web.config
@@ -117,7 +117,7 @@
ASP.NET to identify an incoming user.
-->
<authentication mode="Forms">
- <forms defaultUrl="/Home" loginUrl="/User/Login" name="OpenIdRelyingPartyMvcSession"/>
+ <forms defaultUrl="~/Home" loginUrl="~/User/Login" name="OpenIdRelyingPartyMvcSession"/>
<!-- named cookie prevents conflicts with other samples -->
</authentication>
<!--
diff --git a/samples/OpenIdRelyingPartyWebForms/Site.Master b/samples/OpenIdRelyingPartyWebForms/Site.Master
index 9630f78..cf8c507 100644
--- a/samples/OpenIdRelyingPartyWebForms/Site.Master
+++ b/samples/OpenIdRelyingPartyWebForms/Site.Master
@@ -27,9 +27,9 @@
<asp:LoginStatus ID="LoginStatus1" runat="server" OnLoggedOut="LoginStatus1_LoggedOut" />
</span>
<div>
- <a href="http://dotnetopenid.googlecode.com">
+ <a href="http://dotnetopenauth.net">
<img runat="server" src="~/images/dotnetopenid_tiny.gif" title="Jump to the project web site."
- alt="DotNetOpenId" border='0' /></a>
+ alt="DotNetOpenAuth" border='0' /></a>
</div>
<div>
<asp:ContentPlaceHolder ID="Main" runat="server" />
diff --git a/samples/OpenIdRelyingPartyWebForms/Web.config b/samples/OpenIdRelyingPartyWebForms/Web.config
index 536294a..7c35f74 100644
--- a/samples/OpenIdRelyingPartyWebForms/Web.config
+++ b/samples/OpenIdRelyingPartyWebForms/Web.config
@@ -73,7 +73,7 @@
<trust level="Medium" originUrl=".*"/>
</system.web>
- <!-- log4net is a 3rd party (free) logger library that dotnetopenid will use if present but does not require. -->
+ <!-- log4net is a 3rd party (free) logger library that DotNetOpenAuth will use if present but does not require. -->
<log4net>
<appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="RelyingParty.log" />
diff --git a/samples/OpenIdRelyingPartyWebForms/ajaxlogin.aspx.cs b/samples/OpenIdRelyingPartyWebForms/ajaxlogin.aspx.cs
index ffaf6f0..de44e35 100644
--- a/samples/OpenIdRelyingPartyWebForms/ajaxlogin.aspx.cs
+++ b/samples/OpenIdRelyingPartyWebForms/ajaxlogin.aspx.cs
@@ -18,7 +18,7 @@
}
protected void OpenIdAjaxTextBox1_LoggedIn(object sender, OpenIdEventArgs e) {
- Label label = ((Label)this.commentSubmitted.FindControl("emailLabel"));
+ Label label = (Label)this.commentSubmitted.FindControl("emailLabel");
label.Text = e.Response.FriendlyIdentifierForDisplay;
// We COULD get the sreg extension response here for the email, but since we let the user
diff --git a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx
index 78179f7..a00eccd 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx
+++ b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx
@@ -12,5 +12,4 @@
Visible="False" />
<asp:Label ID="loginCanceledLabel" runat="server" EnableViewState="False" Text="Login canceled"
Visible="False" />
- <asp:CheckBox ID="noLoginCheckBox" runat="server" Text="Extensions only (no login) -- most OPs don't yet support this" />
</asp:Content> \ No newline at end of file
diff --git a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs
index 239d7b8..088e305 100644
--- a/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs
+++ b/samples/OpenIdRelyingPartyWebForms/loginProgrammatic.aspx.designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.4918
+// Runtime Version:2.0.50727.4927
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -66,14 +66,5 @@ namespace OpenIdRelyingPartyWebForms {
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.Label loginCanceledLabel;
-
- /// <summary>
- /// noLoginCheckBox 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.CheckBox noLoginCheckBox;
}
}
diff --git a/samples/README.html b/samples/README.html
index 287942a..10e0f8c 100644
--- a/samples/README.html
+++ b/samples/README.html
@@ -94,22 +94,22 @@
<h3>Interesting classes and methods</h3>
<h4>Relying party</h4>
<ul>
- <li>DotNetOpenId.RelyingParty.<b>OpenIdRelyingParty</b> - programmatic access to everything
+ <li>DotNetOpenAuth.OpenId.RelyingParty.<b>OpenIdRelyingParty</b> - programmatic access to everything
a relying party web site needs.</li>
- <li>DotNetOpenId.RelyingParty.<b>OpenIdTextBox</b> - An ASP.NET control that is a bare-bones
+ <li>DotNetOpenAuth.OpenId.RelyingParty.<b>OpenIdTextBox</b> - An ASP.NET control that is a bare-bones
text input box with a LogOn method that automatically does all the OpenId stuff
for you.</li>
- <li>DotNetOpenId.RelyingParty.<b>OpenIdLogin</b> - Like the OpenIdTextBox, but has a
+ <li>DotNetOpenAuth.OpenId.RelyingParty.<b>OpenIdLogin</b> - Like the OpenIdTextBox, but has a
Login button and some other end user-friendly UI built-in.&nbsp; Drop this onto
your web form and you&#39;re all done!</li>
</ul>
<h4>Provider</h4>
<ul>
- <li>DotNetOpenId.Provider.<b>OpenIdProvider</b> - programmatic access to everything
+ <li>DotNetOpenAuth.OpenId.Provider.<b>OpenIdProvider</b> - programmatic access to everything
a provider web site needs.</li>
- <li>DotNetOpenId.Provider.<b>ProviderEndpoint</b> - An ASP.NET control that you can
+ <li>DotNetOpenAuth.OpenId.Provider.<b>ProviderEndpoint</b> - An ASP.NET control that you can
drop in and have an instant provider endpoint on your page.</li>
- <li>DotNetOpenId.Provider.<b>IdentityEndpoint</b> - An ASP.NET control that you can
+ <li>DotNetOpenAuth.OpenId.Provider.<b>IdentityEndpoint</b> - An ASP.NET control that you can
drop onto the page for your own or your customers&#39; individual identity pages
for discovery by Relying Parties.</li>
</ul>
diff --git a/src/DotNetOpenAuth.BuildTasks/AddProjectItems.cs b/src/DotNetOpenAuth.BuildTasks/AddProjectItems.cs
new file mode 100644
index 0000000..30fa284
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/AddProjectItems.cs
@@ -0,0 +1,62 @@
+//-----------------------------------------------------------------------
+// <copyright file="AddProjectItems.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.BuildEngine;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+ using System.Collections;
+
+ public class AddProjectItems : Task {
+ /// <summary>
+ /// Gets or sets the projects to add items to.
+ /// </summary>
+ /// <value>The projects.</value>
+ [Required]
+ public ITaskItem[] Projects { get; set; }
+
+ /// <summary>
+ /// Gets or sets the items to add to each project.
+ /// </summary>
+ /// <value>The items.</value>
+ /// <remarks>
+ /// Use the metadata "ItemType" on each item to specify the item type to use for the new
+ /// project item. If the metadata is absent, "None" is used as the item type.
+ /// </remarks>
+ [Required]
+ public ITaskItem[] Items { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ public override bool Execute() {
+ foreach (var projectTaskItem in this.Projects) {
+ var project = new Project();
+ project.Load(projectTaskItem.ItemSpec);
+
+ foreach (var projectItem in this.Items) {
+ string itemType = projectItem.GetMetadata("ItemType");
+ if (string.IsNullOrEmpty(itemType)) {
+ itemType = "None";
+ }
+ BuildItem newItem = project.AddNewItem(itemType, projectItem.ItemSpec, false);
+ var customMetadata = projectItem.CloneCustomMetadata();
+ foreach (DictionaryEntry entry in customMetadata) {
+ newItem.SetMetadata((string)entry.Key, (string)entry.Value);
+ }
+ }
+
+ project.Save(projectTaskItem.ItemSpec);
+ }
+
+ return !this.Log.HasLoggedErrors;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/ChangeAssemblyReference.cs b/src/DotNetOpenAuth.BuildTasks/ChangeAssemblyReference.cs
new file mode 100644
index 0000000..3ad5eb0
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/ChangeAssemblyReference.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Linq;
+using System.IO;
+using System.Xml;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.BuildEngine;
+
+namespace DotNetOpenAuth.BuildTasks {
+ /// <summary>
+ /// Replaces Reference items HintPaths in a set of projects.
+ /// </summary>
+ public class ChangeAssemblyReference : Task {
+ /// <summary>
+ /// The projects to alter.
+ /// </summary>
+ [Required]
+ public ITaskItem[] Projects { get; set; }
+ /// <summary>
+ /// The project reference to remove.
+ /// </summary>
+ [Required]
+ public string OldReference { get; set; }
+ /// <summary>
+ /// The assembly reference to add.
+ /// </summary>
+ [Required]
+ public string NewReference { get; set; }
+
+ const string msbuildNamespace = "http://schemas.microsoft.com/developer/msbuild/2003";
+ public override bool Execute() {
+ foreach (var project in Projects) {
+ Project doc = new Project();
+ doc.Load(project.ItemSpec);
+
+ var reference = doc.GetEvaluatedItemsByName("Reference").OfType<BuildItem>().
+ Where(item => string.Equals(item.GetMetadata("HintPath"), OldReference, StringComparison.OrdinalIgnoreCase)).Single();
+ reference.SetMetadata("HintPath", NewReference);
+
+ doc.Save(project.ItemSpec);
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/ChangeProjectReferenceToAssemblyReference.cs b/src/DotNetOpenAuth.BuildTasks/ChangeProjectReferenceToAssemblyReference.cs
new file mode 100644
index 0000000..4b103b4
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/ChangeProjectReferenceToAssemblyReference.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Linq;
+using System.IO;
+using System.Xml;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.BuildEngine;
+
+namespace DotNetOpenAuth.BuildTasks {
+ /// <summary>
+ /// Replaces ProjectReference items in a set of projects with Reference items.
+ /// </summary>
+ public class ChangeProjectReferenceToAssemblyReference : Task {
+ /// <summary>
+ /// The projects to alter.
+ /// </summary>
+ [Required]
+ public ITaskItem[] Projects { get; set; }
+ /// <summary>
+ /// The project reference to remove.
+ /// </summary>
+ [Required]
+ public string ProjectReference { get; set; }
+ /// <summary>
+ /// The assembly reference to add.
+ /// </summary>
+ [Required]
+ public string Reference { get; set; }
+
+ const string msbuildNamespace = "http://schemas.microsoft.com/developer/msbuild/2003";
+ public override bool Execute() {
+ foreach (var project in Projects) {
+ Log.LogMessage(MessageImportance.Normal, "Changing P2P references to assembly references in \"{0}\".", project.ItemSpec);
+
+ Project doc = new Project();
+ doc.Load(project.ItemSpec, ProjectLoadSettings.IgnoreMissingImports);
+
+ var projectReference = doc.EvaluatedItems.OfType<BuildItem>().Where(
+ item => item.Name == "ProjectReference" && item.Include == ProjectReference).Single();
+ doc.RemoveItem(projectReference);
+
+ var newReference = doc.AddNewItem("Reference", Path.GetFileNameWithoutExtension(Reference), true);
+ newReference.SetMetadata("HintPath", Reference);
+
+ doc.Save(project.ItemSpec);
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/CheckAdminRights.cs b/src/DotNetOpenAuth.BuildTasks/CheckAdminRights.cs
new file mode 100644
index 0000000..9cfd35d
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/CheckAdminRights.cs
@@ -0,0 +1,30 @@
+//-----------------------------------------------------------------------
+// <copyright file="CheckAdminRights.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System.Security.Principal;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public class CheckAdminRights : Task {
+ /// <summary>
+ /// Gets or sets a value indicating whether this process has elevated permissions.
+ /// </summary>
+ [Output]
+ public bool IsElevated { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ public override bool Execute() {
+ WindowsIdentity id = WindowsIdentity.GetCurrent();
+ WindowsPrincipal p = new WindowsPrincipal(id);
+ this.IsElevated = p.IsInRole(WindowsBuiltInRole.Administrator);
+
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs b/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs
new file mode 100644
index 0000000..51fcee4
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/CompareFiles.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.Framework;
+using System.IO;
+
+namespace DotNetOpenAuth.BuildTasks {
+ public class CompareFiles : Task {
+ /// <summary>
+ /// One set of items to compare.
+ /// </summary>
+ [Required]
+ public ITaskItem[] OriginalItems { get; set; }
+
+ /// <summary>
+ /// The other set of items to compare.
+ /// </summary>
+ [Required]
+ public ITaskItem[] NewItems { get; set; }
+
+ /// <summary>
+ /// Gets whether the items lists contain items that are identical going down the list.
+ /// </summary>
+ [Output]
+ public bool AreSame { get; private set; }
+
+ /// <summary>
+ /// Same as <see cref="AreSame"/>, but opposite.
+ /// </summary>
+ [Output]
+ public bool AreChanged { get { return !AreSame; } }
+
+ public override bool Execute() {
+ AreSame = AreFilesIdentical();
+ return true;
+ }
+
+ private bool AreFilesIdentical() {
+ if (OriginalItems.Length != NewItems.Length) {
+ return false;
+ }
+
+ for (int i = 0; i < OriginalItems.Length; i++) {
+ if (!IsContentOfFilesTheSame(OriginalItems[i].ItemSpec, NewItems[i].ItemSpec)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private bool IsContentOfFilesTheSame(string file1, string file2) {
+ // If exactly one file is missing, that's different.
+ if (File.Exists(file1) ^ File.Exists(file2)) return false;
+ // If both are missing, that's the same.
+ if (!File.Exists(file1)) return true;
+ // If both are present, we need to do a content comparison.
+ using (FileStream fileStream1 = File.OpenRead(file1)) {
+ using (FileStream fileStream2 = File.OpenRead(file2)) {
+ if (fileStream1.Length != fileStream2.Length) return false;
+ byte[] buffer1 = new byte[4096];
+ byte[] buffer2 = new byte[buffer1.Length];
+ int bytesRead;
+ do {
+ bytesRead = fileStream1.Read(buffer1, 0, buffer1.Length);
+ if (fileStream2.Read(buffer2, 0, buffer2.Length) != bytesRead) {
+ // We should never get here since we compared file lengths, but
+ // this is a sanity check.
+ return false;
+ }
+ for (int i = 0; i < bytesRead; i++) {
+ if (buffer1[i] != buffer2[i]) {
+ return false;
+ }
+ }
+ } while (bytesRead == buffer1.Length);
+ }
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Tests whether a file is up to date with respect to another,
+ /// based on existence, last write time and file size.
+ /// </summary>
+ /// <param name="sourcePath">The source path.</param>
+ /// <param name="destPath">The dest path.</param>
+ /// <returns><c>true</c> if the files are the same; <c>false</c> if the files are different</returns>
+ internal static bool FastFileEqualityCheck(string sourcePath, string destPath) {
+ FileInfo sourceInfo = new FileInfo(sourcePath);
+ FileInfo destInfo = new FileInfo(destPath);
+
+ if (sourceInfo.Exists ^ destInfo.Exists) {
+ // Either the source file or the destination file is missing.
+ return false;
+ }
+
+ if (!sourceInfo.Exists) {
+ // Neither file exists.
+ return true;
+ }
+
+ // We'll say the files are the same if their modification date and length are the same.
+ return
+ sourceInfo.LastWriteTimeUtc == destInfo.LastWriteTimeUtc &&
+ sourceInfo.Length == destInfo.Length;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs b/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs
new file mode 100644
index 0000000..e17d8f2
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/CopyWithTokenSubstitution.cs
@@ -0,0 +1,102 @@
+//-----------------------------------------------------------------------
+// <copyright file="CopyWithTokenSubstitution.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ /// <summary>
+ /// Copies files and performs a search and replace for given tokens in their contents during the process.
+ /// </summary>
+ public class CopyWithTokenSubstitution : Task {
+ /// <summary>
+ /// Gets or sets the files to copy.
+ /// </summary>
+ /// <value>The files to copy.</value>
+ [Required]
+ public ITaskItem[] SourceFiles { get; set; }
+
+ /// <summary>
+ /// Gets or sets a list of files to copy the source files to.
+ /// </summary>
+ /// <value>The list of files to copy the source files to.</value>
+ [Required]
+ public ITaskItem[] DestinationFiles { get; set; }
+
+ /// <summary>
+ /// Gets or sets the destination files actually copied to.
+ /// </summary>
+ /// <remarks>
+ /// In the case of error partway through, or files not copied due to already being up to date,
+ /// this can be a subset of the <see cref="DestinationFiles"/> array.
+ /// </remarks>
+ [Output]
+ public ITaskItem[] CopiedFiles { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ /// <returns><c>true</c> if the operation was successful.</returns>
+ public override bool Execute() {
+ if (this.SourceFiles.Length != this.DestinationFiles.Length) {
+ Log.LogError("{0} inputs and {1} outputs given.", this.SourceFiles.Length, this.DestinationFiles.Length);
+ return false;
+ }
+
+ var copiedFiles = new List<ITaskItem>(this.DestinationFiles.Length);
+
+ for (int i = 0; i < this.SourceFiles.Length; i++) {
+ string sourcePath = this.SourceFiles[i].ItemSpec;
+ string destPath = this.DestinationFiles[i].ItemSpec;
+ bool skipUnchangedFiles = bool.Parse(this.SourceFiles[i].GetMetadata("SkipUnchangedFiles"));
+
+ // We deliberably consider newer destination files to be up-to-date rather than
+ // requiring equality because this task modifies the destination file while copying.
+ if (skipUnchangedFiles && File.GetLastWriteTimeUtc(sourcePath) < File.GetLastWriteTimeUtc(destPath)) {
+ Log.LogMessage(MessageImportance.Low, "Skipping \"{0}\" -> \"{1}\" because the destination is up to date.", sourcePath, destPath);
+ continue;
+ }
+
+ Log.LogMessage(MessageImportance.Normal, "Transforming \"{0}\" -> \"{1}\"", sourcePath, destPath);
+
+ string[] beforeTokens = this.SourceFiles[i].GetMetadata("BeforeTokens").Split(';');
+ string[] afterTokens = this.SourceFiles[i].GetMetadata("AfterTokens").Split(';');
+ if (beforeTokens.Length != afterTokens.Length) {
+ Log.LogError("Unequal number of before and after tokens. Before: \"{0}\". After \"{1}\".", beforeTokens, afterTokens);
+ return false;
+ }
+
+ using (StreamReader sr = File.OpenText(sourcePath)) {
+ if (!Directory.Exists(Path.GetDirectoryName(destPath))) {
+ Directory.CreateDirectory(Path.GetDirectoryName(destPath));
+ }
+ using (StreamWriter sw = File.CreateText(destPath)) {
+ StringBuilder line = new StringBuilder();
+ while (!sr.EndOfStream) {
+ line.Length = 0;
+ line.Append(sr.ReadLine());
+ for (int j = 0; j < beforeTokens.Length; j++) {
+ line.Replace(beforeTokens[j], afterTokens[j]);
+ }
+
+ sw.WriteLine(line);
+ }
+ }
+ }
+
+ copiedFiles.Add(this.DestinationFiles[i]);
+ }
+
+ this.CopiedFiles = copiedFiles.ToArray();
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/CreateWebApplication.cs b/src/DotNetOpenAuth.BuildTasks/CreateWebApplication.cs
new file mode 100644
index 0000000..4980898
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/CreateWebApplication.cs
@@ -0,0 +1,95 @@
+//-----------------------------------------------------------------------
+// <copyright file="CreateWebApplication.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Linq;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+ using Microsoft.Web.Administration;
+
+ /// <summary>
+ /// Creates or updates web applications within an existing web site in IIS.
+ /// </summary>
+ public class CreateWebApplication : Task {
+ /// <summary>
+ /// Gets or sets the name of the application pool that should host the web application.
+ /// </summary>
+ /// <value>The name of an existing application pool.</value>
+ public string ApplicationPoolName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the web site under which to create the web application.
+ /// </summary>
+ /// <value>The name of the existing web site.</value>
+ [Required]
+ public string WebSiteName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the virtual paths within the web site that will access these applications.
+ /// </summary>
+ /// <value>The virtual path, which must start with '/'.</value>
+ [Required]
+ public ITaskItem[] VirtualPaths { get; set; }
+
+ /// <summary>
+ /// Gets or sets the full file system paths to the web applications.
+ /// </summary>
+ /// <value>The physical path.</value>
+ [Required]
+ public ITaskItem[] PhysicalPaths { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ /// <returns>A value indicating whether the task completed successfully.</returns>
+ public override bool Execute() {
+ var serverManager = new ServerManager();
+
+ if (this.PhysicalPaths.Length != this.VirtualPaths.Length) {
+ Log.LogError(TaskStrings.MismatchingArrayLengths, "PhysicalPath", "VirtualPath");
+ return false;
+ }
+
+ if (this.VirtualPaths.Length == 0) {
+ // Nothing to do.
+ return true;
+ }
+
+ // Find the root web site that this web application will be created under.
+ var site = serverManager.Sites.FirstOrDefault(s => string.Equals(s.Name, this.WebSiteName, StringComparison.OrdinalIgnoreCase));
+ if (site == null) {
+ Log.LogError(TaskStrings.NoMatchingWebSiteFound, this.WebSiteName);
+ return false;
+ }
+
+ Log.LogMessage(MessageImportance.Normal, "Creating web applications under web site: {0}", site.Name);
+
+ for (int i = 0; i < this.PhysicalPaths.Length; i++) {
+ string physicalPath = this.PhysicalPaths[i].ItemSpec;
+ string virtualPath = this.VirtualPaths[i].ItemSpec;
+
+ Log.LogMessage(MessageImportance.Normal, "\t{0} -> {1}", virtualPath, physicalPath);
+
+ var app = site.Applications.FirstOrDefault(a => string.Equals(a.Path, virtualPath, StringComparison.OrdinalIgnoreCase));
+ if (app == null) {
+ app = site.Applications.Add(virtualPath, physicalPath);
+ } else {
+ // Ensure physical path is set correctly.
+ var appRoot = app.VirtualDirectories.First(vd => vd.Path == "/");
+ appRoot.PhysicalPath = physicalPath;
+ }
+
+ if (!string.IsNullOrEmpty(this.ApplicationPoolName)) {
+ app.ApplicationPoolName = this.ApplicationPoolName;
+ }
+ }
+
+ serverManager.CommitChanges();
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/DeleteWebApplication.cs b/src/DotNetOpenAuth.BuildTasks/DeleteWebApplication.cs
new file mode 100644
index 0000000..930a8c4
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/DeleteWebApplication.cs
@@ -0,0 +1,66 @@
+//-----------------------------------------------------------------------
+// <copyright file="DeleteWebApplication.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Linq;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+ using Microsoft.Web.Administration;
+
+ /// <summary>
+ /// Deletes a web application from IIS.
+ /// </summary>
+ public class DeleteWebApplication : Task {
+ /// <summary>
+ /// Gets or sets the name of the web site under which to create the web application.
+ /// </summary>
+ /// <value>The name of the existing web site.</value>
+ [Required]
+ public string WebSiteName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the virtual paths within the web site that will access these applications.
+ /// </summary>
+ /// <value>The virtual path, which must start with '/'.</value>
+ [Required]
+ public ITaskItem[] VirtualPaths { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ /// <returns>A value indicating whether the task completed successfully.</returns>
+ public override bool Execute() {
+ var serverManager = new ServerManager();
+
+ // Find the root web site that this web application will be created under.
+ var site = serverManager.Sites.FirstOrDefault(s => string.Equals(s.Name, this.WebSiteName, StringComparison.OrdinalIgnoreCase));
+ if (site == null) {
+ Log.LogMessage(MessageImportance.Low, TaskStrings.NoMatchingWebSiteFound, this.WebSiteName);
+ return true;
+ }
+
+ if (this.VirtualPaths.Length == 0) {
+ // Nothing to do.
+ return true;
+ }
+
+ foreach (ITaskItem path in this.VirtualPaths) {
+ var app = site.Applications.FirstOrDefault(a => string.Equals(a.Path, path.ItemSpec, StringComparison.OrdinalIgnoreCase));
+ if (app != null) {
+ site.Applications.Remove(app);
+ Log.LogMessage(MessageImportance.Normal, TaskStrings.DeletedWebApplication, app.Path);
+ } else {
+ Log.LogMessage(MessageImportance.Low, TaskStrings.WebApplicationNotFoundSoNotDeleted, path.ItemSpec);
+ }
+ }
+
+ serverManager.CommitChanges();
+
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/DiscoverProjectTemplates.cs b/src/DotNetOpenAuth.BuildTasks/DiscoverProjectTemplates.cs
new file mode 100644
index 0000000..0162c16
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/DiscoverProjectTemplates.cs
@@ -0,0 +1,63 @@
+//-----------------------------------------------------------------------
+// <copyright file="DiscoverProjectTemplates.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using System.Xml.Linq;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public class DiscoverProjectTemplates : Task {
+ public ITaskItem[] TopLevelTemplates { get; set; }
+
+ [Output]
+ public ITaskItem[] ProjectTemplates { get; set; }
+
+ [Output]
+ public ITaskItem[] ProjectTemplateContents { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ public override bool Execute() {
+ List<ITaskItem> projectTemplates = new List<ITaskItem>();
+ List<ITaskItem> projectTemplateContents = new List<ITaskItem>();
+ foreach (ITaskItem topLevelTemplate in this.TopLevelTemplates) {
+ var vsTemplate = XElement.Load(topLevelTemplate.ItemSpec);
+ var templateContent = vsTemplate.Element(XName.Get("TemplateContent", MergeProjectWithVSTemplate.VSTemplateNamespace));
+ var projectCollection = templateContent.Element(XName.Get("ProjectCollection", MergeProjectWithVSTemplate.VSTemplateNamespace));
+ var links = projectCollection.Elements(XName.Get("ProjectTemplateLink", MergeProjectWithVSTemplate.VSTemplateNamespace));
+ var subTemplates = links.Select(
+ link => (ITaskItem)new TaskItem(
+ link.Value,
+ new Dictionary<string, string> {
+ { "TopLevelTemplate", topLevelTemplate.ItemSpec },
+ { "TopLevelTemplateFileName", Path.GetFileNameWithoutExtension(topLevelTemplate.ItemSpec) },
+ }));
+ projectTemplates.AddRange(subTemplates);
+
+ foreach (var link in links.Select(link => link.Value)) {
+ string[] files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(topLevelTemplate.ItemSpec), Path.GetDirectoryName(link)), "*.*", SearchOption.AllDirectories);
+ projectTemplateContents.AddRange(files.Select(file => (ITaskItem)new TaskItem(
+ file,
+ new Dictionary<string, string> {
+ { "TopLevelTemplate", topLevelTemplate.ItemSpec },
+ { "TopLevelTemplateFileName", Path.GetFileNameWithoutExtension(topLevelTemplate.ItemSpec) },
+ })));
+ }
+ }
+
+ this.ProjectTemplates = projectTemplates.ToArray();
+ this.ProjectTemplateContents = projectTemplateContents.ToArray();
+
+ return !this.Log.HasLoggedErrors;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.csproj b/src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.csproj
new file mode 100644
index 0000000..038e7f8
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.csproj
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="utf-8"?>
+<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>{AC231A51-EF60-437C-A33F-AF8ADEB8EB74}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>DotNetOpenAuth.BuildTasks</RootNamespace>
+ <AssemblyName>DotNetOpenAuth.BuildTasks</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>..\..\lib\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>False</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly>
+ </CodeContractsCustomRewriterAssembly>
+ <CodeContractsCustomRewriterClass>
+ </CodeContractsCustomRewriterClass>
+ <CodeContractsLibPaths>
+ </CodeContractsLibPaths>
+ <CodeContractsPlatformPath>
+ </CodeContractsPlatformPath>
+ <CodeContractsExtraAnalysisOptions>
+ </CodeContractsExtraAnalysisOptions>
+ <CodeContractsBaseLineFile>
+ </CodeContractsBaseLineFile>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
+ <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
+ <CodeContractsExtraRewriteOptions>
+ </CodeContractsExtraRewriteOptions>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>..\..\lib\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
+ <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
+ <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
+ <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
+ <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
+ <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
+ <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
+ <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
+ <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
+ <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
+ <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
+ <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
+ <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
+ <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
+ <CodeContractsCustomRewriterAssembly>
+ </CodeContractsCustomRewriterAssembly>
+ <CodeContractsCustomRewriterClass>
+ </CodeContractsCustomRewriterClass>
+ <CodeContractsLibPaths>
+ </CodeContractsLibPaths>
+ <CodeContractsExtraRewriteOptions>
+ </CodeContractsExtraRewriteOptions>
+ <CodeContractsExtraAnalysisOptions>
+ </CodeContractsExtraAnalysisOptions>
+ <CodeContractsBaseLineFile>
+ </CodeContractsBaseLineFile>
+ <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
+ <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="Microsoft.Build.Engine" />
+ <Reference Include="Microsoft.Build.Framework" />
+ <Reference Include="Microsoft.Build.Utilities.v3.5">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="Microsoft.Contracts, Version=1.0.0.0, Culture=neutral, PublicKeyToken=736440c9b414ea16, processorArchitecture=MSIL">
+ <Private>False</Private>
+ </Reference>
+ <Reference Include="Microsoft.Web.Administration, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>$(SystemRoot)\System32\inetsrv\Microsoft.Web.Administration.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="AddProjectItems.cs" />
+ <Compile Include="ChangeProjectReferenceToAssemblyReference.cs" />
+ <Compile Include="CompareFiles.cs" />
+ <Compile Include="ChangeAssemblyReference.cs" />
+ <Compile Include="CopyWithTokenSubstitution.cs" />
+ <Compile Include="CreateWebApplication.cs" />
+ <Compile Include="DeleteWebApplication.cs" />
+ <Compile Include="DiscoverProjectTemplates.cs" />
+ <Compile Include="ECMAScriptPacker.cs" />
+ <Compile Include="FilterItems.cs" />
+ <Compile Include="FixupReferenceHintPaths.cs" />
+ <Compile Include="FixupShippingToolSamples.cs" />
+ <Compile Include="MergeProjectWithVSTemplate.cs" />
+ <Compile Include="GetBuildVersion.cs" />
+ <Compile Include="CheckAdminRights.cs" />
+ <Compile Include="JsPack.cs" />
+ <Compile Include="ParseMaster.cs" />
+ <Compile Include="Purge.cs" />
+ <Compile Include="ReSignDelaySignedAssemblies.cs" />
+ <Compile Include="SetEnvironmentVariable.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="SignatureVerification.cs" />
+ <Compile Include="SnToolTask.cs" />
+ <Compile Include="TaskStrings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>TaskStrings.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Trim.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="TaskStrings.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>TaskStrings.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>
+ -->
+</Project> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.sln b/src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.sln
new file mode 100644
index 0000000..fca41e8
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/DotNetOpenAuth.BuildTasks.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetOpenAuth.BuildTasks", "DotNetOpenAuth.BuildTasks.csproj", "{AC231A51-EF60-437C-A33F-AF8ADEB8EB74}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ABBE14A3-0404-4123-9093-E598C3DD3E9B}"
+ ProjectSection(SolutionItems) = preProject
+ ..\..\build.proj = ..\..\build.proj
+ ..\..\lib\DotNetOpenAuth.BuildTasks.targets = ..\..\lib\DotNetOpenAuth.BuildTasks.targets
+ ..\..\tools\DotNetOpenAuth.Common.Settings.targets = ..\..\tools\DotNetOpenAuth.Common.Settings.targets
+ ..\..\tools\DotNetOpenAuth.Versioning.targets = ..\..\tools\DotNetOpenAuth.Versioning.targets
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AC231A51-EF60-437C-A33F-AF8ADEB8EB74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AC231A51-EF60-437C-A33F-AF8ADEB8EB74}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AC231A51-EF60-437C-A33F-AF8ADEB8EB74}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AC231A51-EF60-437C-A33F-AF8ADEB8EB74}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/src/DotNetOpenAuth.BuildTasks/ECMAScriptPacker.cs b/src/DotNetOpenAuth.BuildTasks/ECMAScriptPacker.cs
new file mode 100644
index 0000000..d63d5b4
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/ECMAScriptPacker.cs
@@ -0,0 +1,486 @@
+using System;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Web;
+using System.IO;
+
+/*
+ packer, version 2.0 (beta) (2005/02/01)
+ Copyright 2004-2005, Dean Edwards
+ Web: http://dean.edwards.name/
+
+ This software is licensed under the CC-GNU LGPL
+ Web: http://creativecommons.org/licenses/LGPL/2.1/
+
+ Ported to C# by Jesse Hansen, twindagger2k@msn.com
+ modified slightly by Andrew Arnott
+*/
+
+// http://dean.edwards.name/packer/
+
+namespace Dean.Edwards
+{
+ /// <summary>
+ /// Packs a javascript file into a smaller area, removing unnecessary characters from the output.
+ /// </summary>
+ internal class ECMAScriptPacker
+ {
+ /// <summary>
+ /// The encoding level to use. See http://dean.edwards.name/packer/usage/ for more info.
+ /// </summary>
+ public enum PackerEncoding { None = 0, Numeric = 10, Mid = 36, Normal = 62, HighAscii = 95 };
+
+ private PackerEncoding encoding = PackerEncoding.Normal;
+ private bool fastDecode = true;
+ private bool specialChars = false;
+ private bool enabled = true;
+
+ string IGNORE = "$1";
+
+ /// <summary>
+ /// The encoding level for this instance
+ /// </summary>
+ public PackerEncoding Encoding
+ {
+ get { return encoding; }
+ set { encoding = value; }
+ }
+
+ /// <summary>
+ /// Adds a subroutine to the output to speed up decoding
+ /// </summary>
+ public bool FastDecode
+ {
+ get { return fastDecode; }
+ set { fastDecode = value; }
+ }
+
+ /// <summary>
+ /// Replaces special characters
+ /// </summary>
+ public bool SpecialChars
+ {
+ get { return specialChars; }
+ set { specialChars = value; }
+ }
+
+ /// <summary>
+ /// Packer enabled
+ /// </summary>
+ public bool Enabled
+ {
+ get { return enabled; }
+ set { enabled = value; }
+ }
+
+ public ECMAScriptPacker()
+ {
+ Encoding = PackerEncoding.Normal;
+ FastDecode = true;
+ SpecialChars = false;
+ }
+
+ /// <summary>
+ /// Constructor
+ /// </summary>
+ /// <param name="encoding">The encoding level for this instance</param>
+ /// <param name="fastDecode">Adds a subroutine to the output to speed up decoding</param>
+ /// <param name="specialChars">Replaces special characters</param>
+ public ECMAScriptPacker(PackerEncoding encoding, bool fastDecode, bool specialChars)
+ {
+ Encoding = encoding;
+ FastDecode = fastDecode;
+ SpecialChars = specialChars;
+ }
+
+ /// <summary>
+ /// Packs the script
+ /// </summary>
+ /// <param name="script">the script to pack</param>
+ /// <returns>the packed script</returns>
+ public string Pack(string script)
+ {
+ if (enabled)
+ {
+ script += "\n";
+ script = basicCompression(script);
+ if (SpecialChars)
+ script = encodeSpecialChars(script);
+ if (Encoding != PackerEncoding.None)
+ script = encodeKeywords(script);
+ }
+ return script;
+ }
+
+ //zero encoding - just removal of whitespace and comments
+ private string basicCompression(string script)
+ {
+ ParseMaster parser = new ParseMaster();
+ // make safe
+ parser.EscapeChar = '\\';
+ // protect strings
+ parser.Add("'[^'\\n\\r]*'", IGNORE);
+ parser.Add("\"[^\"\\n\\r]*\"", IGNORE);
+ // remove comments
+ parser.Add("\\/\\/[^\\n\\r]*[\\n\\r]");
+ parser.Add("\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\/");
+ // protect regular expressions
+ parser.Add("\\s+(\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?)", "$2");
+ parser.Add("[^\\w\\$\\/'\"*)\\?:]\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?", IGNORE);
+ // remove: ;;; doSomething();
+ if (specialChars)
+ parser.Add(";;[^\\n\\r]+[\\n\\r]");
+ // remove redundant semi-colons
+ parser.Add(";+\\s*([};])", "$2");
+ // remove white-space
+ parser.Add("(\\b|\\$)\\s+(\\b|\\$)", "$2 $3");
+ parser.Add("([+\\-])\\s+([+\\-])", "$2 $3");
+ parser.Add("\\s+");
+ // done
+ return parser.Exec(script);
+ }
+
+ WordList encodingLookup;
+ private string encodeSpecialChars(string script)
+ {
+ ParseMaster parser = new ParseMaster();
+ // replace: $name -> n, $$name -> na
+ parser.Add("((\\$+)([a-zA-Z\\$_]+))(\\d*)",
+ new ParseMaster.MatchGroupEvaluator(encodeLocalVars));
+
+ // replace: _name -> _0, double-underscore (__name) is ignored
+ Regex regex = new Regex("\\b_[A-Za-z\\d]\\w*");
+
+ // build the word list
+ encodingLookup = analyze(script, regex, new EncodeMethod(encodePrivate));
+
+ parser.Add("\\b_[A-Za-z\\d]\\w*", new ParseMaster.MatchGroupEvaluator(encodeWithLookup));
+
+ script = parser.Exec(script);
+ return script;
+ }
+
+ private string encodeKeywords(string script)
+ {
+ // escape high-ascii values already in the script (i.e. in strings)
+ if (Encoding == PackerEncoding.HighAscii) script = escape95(script);
+ // create the parser
+ ParseMaster parser = new ParseMaster();
+ EncodeMethod encode = getEncoder(Encoding);
+
+ // for high-ascii, don't encode single character low-ascii
+ Regex regex = new Regex(
+ (Encoding == PackerEncoding.HighAscii) ? "\\w\\w+" : "\\w+"
+ );
+ // build the word list
+ encodingLookup = analyze(script, regex, encode);
+
+ // encode
+ parser.Add((Encoding == PackerEncoding.HighAscii) ? "\\w\\w+" : "\\w+",
+ new ParseMaster.MatchGroupEvaluator(encodeWithLookup));
+
+ // if encoded, wrap the script in a decoding function
+ return (script == string.Empty) ? "" : bootStrap(parser.Exec(script), encodingLookup);
+ }
+
+ private string bootStrap(string packed, WordList keywords)
+ {
+ // packed: the packed script
+ packed = "'" + escape(packed) + "'";
+
+ // ascii: base for encoding
+ int ascii = Math.Min(keywords.Sorted.Count, (int) Encoding);
+ if (ascii == 0)
+ ascii = 1;
+
+ // count: number of words contained in the script
+ int count = keywords.Sorted.Count;
+
+ // keywords: list of words contained in the script
+ foreach (object key in keywords.Protected.Keys)
+ {
+ keywords.Sorted[(int) key] = "";
+ }
+ // convert from a string to an array
+ StringBuilder sbKeywords = new StringBuilder("'");
+ foreach (string word in keywords.Sorted)
+ sbKeywords.Append(word + "|");
+ sbKeywords.Remove(sbKeywords.Length-1, 1);
+ string keywordsout = sbKeywords.ToString() + "'.split('|')";
+
+ string encode;
+ string inline = "c";
+
+ switch (Encoding)
+ {
+ case PackerEncoding.Mid:
+ encode = "function(c){return c.toString(36)}";
+ inline += ".toString(a)";
+ break;
+ case PackerEncoding.Normal:
+ encode = "function(c){return(c<a?\"\":e(parseInt(c/a)))+" +
+ "((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))}";
+ inline += ".toString(a)";
+ break;
+ case PackerEncoding.HighAscii:
+ encode = "function(c){return(c<a?\"\":e(c/a))+" +
+ "String.fromCharCode(c%a+161)}";
+ inline += ".toString(a)";
+ break;
+ default:
+ encode = "function(c){return c}";
+ break;
+ }
+
+ // decode: code snippet to speed up decoding
+ string decode = "";
+ if (fastDecode)
+ {
+ decode = "if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\\\w+'};c=1;}";
+ if (Encoding == PackerEncoding.HighAscii)
+ decode = decode.Replace("\\\\w", "[\\xa1-\\xff]");
+ else if (Encoding == PackerEncoding.Numeric)
+ decode = decode.Replace("e(c)", inline);
+ if (count == 0)
+ decode = decode.Replace("c=1", "c=0");
+ }
+
+ // boot function
+ string unpack = "function(p,a,c,k,e,d){while(c--)if(k[c])p=p.replace(new RegExp('\\\\b'+e(c)+'\\\\b','g'),k[c]);return p;}";
+ Regex r;
+ if (fastDecode)
+ {
+ //insert the decoder
+ r = new Regex("\\{");
+ unpack = r.Replace(unpack, "{" + decode + ";", 1);
+ }
+
+ if (Encoding == PackerEncoding.HighAscii)
+ {
+ // get rid of the word-boundries for regexp matches
+ r = new Regex("'\\\\\\\\b'\\s*\\+|\\+\\s*'\\\\\\\\b'");
+ unpack = r.Replace(unpack, "");
+ }
+ if (Encoding == PackerEncoding.HighAscii || ascii > (int) PackerEncoding.Normal || fastDecode)
+ {
+ // insert the encode function
+ r = new Regex("\\{");
+ unpack = r.Replace(unpack, "{e=" + encode + ";", 1);
+ }
+ else
+ {
+ r = new Regex("e\\(c\\)");
+ unpack = r.Replace(unpack, inline);
+ }
+ // no need to pack the boot function since i've already done it
+ string _params = "" + packed + "," + ascii + "," + count + "," + keywordsout;
+ if (fastDecode)
+ {
+ //insert placeholders for the decoder
+ _params += ",0,{}";
+ }
+ // the whole thing
+ return "eval(" + unpack + "(" + _params + "))\n";
+ }
+
+ private string escape(string input)
+ {
+ Regex r = new Regex("([\\\\'])");
+ return r.Replace(input, "\\$1");
+ }
+
+ private EncodeMethod getEncoder(PackerEncoding encoding)
+ {
+ switch (encoding)
+ {
+ case PackerEncoding.Mid:
+ return new EncodeMethod(encode36);
+ case PackerEncoding.Normal:
+ return new EncodeMethod(encode62);
+ case PackerEncoding.HighAscii:
+ return new EncodeMethod(encode95);
+ default:
+ return new EncodeMethod(encode10);
+ }
+ }
+
+ private string encode10(int code)
+ {
+ return code.ToString();
+ }
+
+ //lookups seemed like the easiest way to do this since
+ // I don't know of an equivalent to .toString(36)
+ private static string lookup36 = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+ private string encode36(int code)
+ {
+ string encoded = "";
+ int i = 0;
+ do
+ {
+ int digit = (code / (int) Math.Pow(36, i)) % 36;
+ encoded = lookup36[digit] + encoded;
+ code -= digit * (int) Math.Pow(36, i++);
+ } while (code > 0);
+ return encoded;
+ }
+
+ private static string lookup62 = lookup36 + "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ private string encode62(int code)
+ {
+ string encoded = "";
+ int i = 0;
+ do
+ {
+ int digit = (code / (int) Math.Pow(62, i)) % 62;
+ encoded = lookup62[digit] + encoded;
+ code -= digit * (int) Math.Pow(62, i++);
+ } while (code > 0);
+ return encoded;
+ }
+
+ private static string lookup95 = "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
+
+ private string encode95(int code)
+ {
+ string encoded = "";
+ int i = 0;
+ do
+ {
+ int digit = (code / (int) Math.Pow(95, i)) % 95;
+ encoded = lookup95[digit] + encoded;
+ code -= digit * (int) Math.Pow(95, i++);
+ } while (code > 0);
+ return encoded;
+ }
+
+ private string escape95(string input)
+ {
+ Regex r = new Regex("[\xa1-\xff]");
+ return r.Replace(input, new MatchEvaluator(escape95Eval));
+ }
+
+ private string escape95Eval(Match match)
+ {
+ return "\\x" + ((int) match.Value[0]).ToString("x"); //return hexadecimal value
+ }
+
+ private string encodeLocalVars(Match match, int offset)
+ {
+ int length = match.Groups[offset + 2].Length;
+ int start = length - Math.Max(length - match.Groups[offset + 3].Length, 0);
+ return match.Groups[offset + 1].Value.Substring(start, length) +
+ match.Groups[offset + 4].Value;
+ }
+
+ private string encodeWithLookup(Match match, int offset)
+ {
+ return (string) encodingLookup.Encoded[match.Groups[offset].Value];
+ }
+
+ private delegate string EncodeMethod(int code);
+
+ private string encodePrivate(int code)
+ {
+ return "_" + code;
+ }
+
+ private WordList analyze(string input, Regex regex, EncodeMethod encodeMethod)
+ {
+ // analyse
+ // retreive all words in the script
+ MatchCollection all = regex.Matches(input);
+ WordList rtrn;
+ rtrn.Sorted = new StringCollection(); // list of words sorted by frequency
+ rtrn.Protected = new HybridDictionary(); // dictionary of word->encoding
+ rtrn.Encoded = new HybridDictionary(); // instances of "protected" words
+ if (all.Count > 0)
+ {
+ StringCollection unsorted = new StringCollection(); // same list, not sorted
+ HybridDictionary Protected = new HybridDictionary(); // "protected" words (dictionary of word->"word")
+ HybridDictionary values = new HybridDictionary(); // dictionary of charCode->encoding (eg. 256->ff)
+ HybridDictionary count = new HybridDictionary(); // word->count
+ int i = all.Count, j = 0;
+ string word;
+ // count the occurrences - used for sorting later
+ do
+ {
+ word = "$" + all[--i].Value;
+ if (count[word] == null)
+ {
+ count[word] = 0;
+ unsorted.Add(word);
+ // make a dictionary of all of the protected words in this script
+ // these are words that might be mistaken for encoding
+ Protected["$" + (values[j] = encodeMethod(j))] = j++;
+ }
+ // increment the word counter
+ count[word] = (int) count[word] + 1;
+ } while (i > 0);
+ /* prepare to sort the word list, first we must protect
+ words that are also used as codes. we assign them a code
+ equivalent to the word itself.
+ e.g. if "do" falls within our encoding range
+ then we store keywords["do"] = "do";
+ this avoids problems when decoding */
+ i = unsorted.Count;
+ string[] sortedarr = new string[unsorted.Count];
+ do
+ {
+ word = unsorted[--i];
+ if (Protected[word] != null)
+ {
+ sortedarr[(int) Protected[word]] = word.Substring(1);
+ rtrn.Protected[(int) Protected[word]] = true;
+ count[word] = 0;
+ }
+ } while (i > 0);
+ string[] unsortedarr = new string[unsorted.Count];
+ unsorted.CopyTo(unsortedarr, 0);
+ // sort the words by frequency
+ Array.Sort(unsortedarr, (IComparer) new CountComparer(count));
+ j = 0;
+ /*because there are "protected" words in the list
+ we must add the sorted words around them */
+ do
+ {
+ if (sortedarr[i] == null)
+ sortedarr[i] = unsortedarr[j++].Substring(1);
+ rtrn.Encoded[sortedarr[i]] = values[i];
+ } while (++i < unsortedarr.Length);
+ rtrn.Sorted.AddRange(sortedarr);
+ }
+ return rtrn;
+ }
+
+ private struct WordList
+ {
+ public StringCollection Sorted;
+ public HybridDictionary Encoded;
+ public HybridDictionary Protected;
+ }
+
+ private class CountComparer : IComparer
+ {
+ HybridDictionary count;
+
+ public CountComparer(HybridDictionary count)
+ {
+ this.count = count;
+ }
+
+ #region IComparer Members
+
+ public int Compare(object x, object y)
+ {
+ return (int) count[y] - (int) count[x];
+ }
+
+ #endregion
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/FilterItems.cs b/src/DotNetOpenAuth.BuildTasks/FilterItems.cs
new file mode 100644
index 0000000..97631c6
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/FilterItems.cs
@@ -0,0 +1,24 @@
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.Utilities;
+ using Microsoft.Build.Framework;
+
+ public class FilterItems : Task {
+ [Required]
+ public ITaskItem[] InputItems { get; set; }
+
+ [Required]
+ public ITaskItem[] StartsWithAny { get; set; }
+
+ [Output]
+ public ITaskItem[] FilteredItems { get; set; }
+
+ public override bool Execute() {
+ FilteredItems = InputItems.Where(item => StartsWithAny.Any(filter => item.ItemSpec.StartsWith(filter.ItemSpec, StringComparison.OrdinalIgnoreCase))).ToArray();
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/FixupReferenceHintPaths.cs b/src/DotNetOpenAuth.BuildTasks/FixupReferenceHintPaths.cs
new file mode 100644
index 0000000..13a4b8f
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/FixupReferenceHintPaths.cs
@@ -0,0 +1,71 @@
+//-----------------------------------------------------------------------
+// <copyright file="FixupReferenceHintPaths.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using System.Text;
+ using Microsoft.Build.BuildEngine;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public class FixupReferenceHintPaths : Task {
+ /// <summary>
+ /// Gets or sets the projects to fixup references for.
+ /// </summary>
+ [Required]
+ public ITaskItem[] Projects { get; set; }
+
+ /// <summary>
+ /// Gets or sets the set of full paths to assemblies that may be found in any of the <see cref="Projects"/>.
+ /// </summary>
+ [Required]
+ public ITaskItem[] References { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ public override bool Execute() {
+ if (this.References.Length == 0 || this.Projects.Length == 0) {
+ this.Log.LogMessage(MessageImportance.Low, "Skipping reference hintpath fixup because no projects or no references were supplied.");
+ return !this.Log.HasLoggedErrors;
+ }
+
+ // Figure out what the assembly names are of the references that are available.
+ AssemblyName[] availableReferences = new AssemblyName[this.References.Length];
+ for (int i = 0; i < this.References.Length; i++) {
+ availableReferences[i] = AssemblyName.GetAssemblyName(this.References[i].ItemSpec);
+ }
+
+ foreach (var projectTaskItem in this.Projects) {
+ var project = new Project();
+ Uri projectUri = new Uri(projectTaskItem.GetMetadata("FullPath"));
+ project.Load(projectTaskItem.ItemSpec);
+
+ foreach (BuildItem referenceItem in project.GetEvaluatedItemsByName("Reference")) {
+ var referenceAssemblyName = new AssemblyName(referenceItem.Include);
+ var matchingReference = availableReferences.FirstOrDefault(r => string.Equals(r.Name, referenceAssemblyName.Name, StringComparison.OrdinalIgnoreCase));
+ if (matchingReference != null) {
+ var originalSuppliedReferenceItem = this.References[Array.IndexOf(availableReferences, matchingReference)];
+ string hintPath = originalSuppliedReferenceItem.GetMetadata("HintPath");
+ if (string.IsNullOrEmpty(hintPath)) {
+ hintPath = projectUri.MakeRelativeUri(new Uri(matchingReference.CodeBase)).OriginalString.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
+ }
+ this.Log.LogMessage("Fixing up HintPath to \"{0}\" in project \"{1}\".", referenceAssemblyName.Name, projectTaskItem.ItemSpec);
+ referenceItem.SetMetadata("HintPath", hintPath);
+ }
+ }
+
+ project.Save(projectTaskItem.ItemSpec);
+ }
+
+ return !this.Log.HasLoggedErrors;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/FixupShippingToolSamples.cs b/src/DotNetOpenAuth.BuildTasks/FixupShippingToolSamples.cs
new file mode 100644
index 0000000..6c71740
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/FixupShippingToolSamples.cs
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------
+// <copyright file="FixupShippingToolSamples.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.BuildEngine;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ /// <summary>
+ /// Removes imports that only apply when a shipping tool sample builds as part of
+ /// the entire project, but not when it's part of a source code sample.
+ /// </summary>
+ public class FixupShippingToolSamples : Task {
+ [Required]
+ public ITaskItem[] Projects { get; set; }
+
+ public string[] RemoveImportsStartingWith { get; set; }
+
+ public ITaskItem[] AddReferences { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ /// <returns></returns>
+ public override bool Execute() {
+ foreach (ITaskItem projectTaskItem in this.Projects) {
+ this.Log.LogMessage("Fixing up the {0} sample for shipping as source code.", Path.GetFileNameWithoutExtension(projectTaskItem.ItemSpec));
+
+ var project = new Project();
+ Uri projectUri = new Uri(projectTaskItem.GetMetadata("FullPath"));
+ project.Load(projectTaskItem.ItemSpec, ProjectLoadSettings.IgnoreMissingImports);
+
+ if (this.RemoveImportsStartingWith != null && this.RemoveImportsStartingWith.Length > 0) {
+ project.Imports.Cast<Import>()
+ .Where(import => this.RemoveImportsStartingWith.Any(start => import.ProjectPath.StartsWith(start, StringComparison.OrdinalIgnoreCase)))
+ .ToList()
+ .ForEach(import => project.Imports.RemoveImport(import));
+ }
+
+ if (this.AddReferences != null) {
+ foreach (var reference in this.AddReferences) {
+ BuildItem item = project.AddNewItem("Reference", reference.ItemSpec);
+ foreach (DictionaryEntry metadata in reference.CloneCustomMetadata()) {
+ item.SetMetadata((string)metadata.Key, (string)metadata.Value);
+ }
+ }
+ }
+
+ project.Save(projectTaskItem.ItemSpec);
+ }
+
+ return !this.Log.HasLoggedErrors;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/GetBuildVersion.cs b/src/DotNetOpenAuth.BuildTasks/GetBuildVersion.cs
new file mode 100644
index 0000000..2068a6b
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/GetBuildVersion.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace DotNetOpenAuth.BuildTasks {
+ public class GetBuildVersion : Task {
+
+ /// <summary>
+ /// Gets the version string to use in the compiled assemblies.
+ /// </summary>
+ [Output]
+ public string Version { get; private set; }
+
+ /// <summary>
+ /// Gets the Git revision control commit id for HEAD (the current source code version).
+ /// </summary>
+ [Output]
+ public string GitCommitId { get; private set; }
+
+ /// <summary>
+ /// The file that contains the version base (Major.Minor.Build) to use.
+ /// </summary>
+ [Required]
+ public string VersionFile { get; set; }
+
+ /// <summary>
+ /// Gets or sets the parent directory of the .git directory.
+ /// </summary>
+ public string GitRepoRoot { get; set; }
+
+ public override bool Execute() {
+ try {
+ Version typedVersion = ReadVersionFromFile();
+ typedVersion = new Version(typedVersion.Major, typedVersion.Minor, typedVersion.Build, CalculateJDate(DateTime.Now));
+ Version = typedVersion.ToString();
+
+ this.GitCommitId = GetGitHeadCommitId();
+ } catch (ArgumentOutOfRangeException ex) {
+ Log.LogErrorFromException(ex);
+ return false;
+ }
+
+ return true;
+ }
+
+ private string GetGitHeadCommitId() {
+ if (string.IsNullOrEmpty(this.GitRepoRoot)) {
+ return string.Empty;
+ }
+
+ string commitId = string.Empty;
+
+ // First try asking Git for the HEAD commit id
+ try {
+ string cmdPath = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe");
+ var psi = new ProcessStartInfo(cmdPath, "/c git rev-parse HEAD") {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ CreateNoWindow = true,
+ RedirectStandardOutput = true,
+ UseShellExecute = false
+ };
+ var git = Process.Start(psi);
+ commitId = git.StandardOutput.ReadLine();
+ git.WaitForExit();
+ if (git.ExitCode != 0) {
+ commitId = string.Empty;
+ }
+ if (commitId != null) {
+ commitId = commitId.Trim();
+ if (commitId.Length == 40) {
+ return commitId;
+ }
+ }
+ } catch (InvalidOperationException) {
+ } catch (Win32Exception) {
+ }
+
+ // Failing being able to use the git command to figure out the HEAD commit ID, try the filesystem directly.
+ try {
+ string headContent = File.ReadAllText(Path.Combine(this.GitRepoRoot, @".git/HEAD")).Trim();
+ if (headContent.StartsWith("ref:", StringComparison.Ordinal)) {
+ string refName = headContent.Substring(5).Trim();
+ string refPath = Path.Combine(this.GitRepoRoot, ".git/" + refName);
+ if (File.Exists(refPath)) {
+ commitId = File.ReadAllText(refPath).Trim();
+ } else {
+ string packedRefPath = Path.Combine(this.GitRepoRoot, ".git/packed-refs");
+ string matchingLine = File.ReadAllLines(packedRefPath).FirstOrDefault(line => line.EndsWith(refName));
+ if (matchingLine != null) {
+ commitId = matchingLine.Substring(0, matchingLine.IndexOf(' '));
+ }
+ }
+ } else {
+ commitId = headContent;
+ }
+ } catch (FileNotFoundException) {
+ } catch (DirectoryNotFoundException) {
+ }
+
+ commitId = commitId ?? String.Empty; // doubly-be sure it's not null, since in some error cases it can be.
+ return commitId.Trim();
+ }
+
+ private Version ReadVersionFromFile() {
+ string[] lines = File.ReadAllLines(VersionFile);
+ string versionLine = lines[0];
+ return new Version(versionLine);
+ }
+
+ private int CalculateJDate(DateTime date) {
+ int yearLastDigit = date.Year - 2000; // can actually be two digits in or after 2010
+ DateTime firstOfYear = new DateTime(date.Year, 1, 1);
+ int dayOfYear = (date - firstOfYear).Days + 1;
+ int jdate = yearLastDigit * 1000 + dayOfYear;
+ return jdate;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/JsPack.cs b/src/DotNetOpenAuth.BuildTasks/JsPack.cs
new file mode 100644
index 0000000..fa8c7f0
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/JsPack.cs
@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------
+// <copyright file="JsPack.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ /// <summary>
+ /// Compresses .js files.
+ /// </summary>
+ public class JsPack : Task {
+ /// <summary>
+ /// The Javascript packer to use.
+ /// </summary>
+ private Dean.Edwards.ECMAScriptPacker packer = new Dean.Edwards.ECMAScriptPacker();
+
+ /// <summary>
+ /// Gets or sets the set of javascript files to compress.
+ /// </summary>
+ /// <value>The inputs.</value>
+ [Required]
+ public ITaskItem[] Inputs { get; set; }
+
+ /// <summary>
+ /// Gets or sets the paths where the packed javascript files should be saved.
+ /// </summary>
+ /// <value>The outputs.</value>
+ [Required]
+ public ITaskItem[] Outputs { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ /// <returns>A value indicating whether the packing was successful.</returns>
+ public override bool Execute() {
+ if (this.Inputs.Length != this.Outputs.Length) {
+ Log.LogError("{0} inputs and {1} outputs given.", this.Inputs.Length, this.Outputs.Length);
+ return false;
+ }
+
+ for (int i = 0; i < this.Inputs.Length; i++) {
+ if (!File.Exists(this.Outputs[i].ItemSpec) || File.GetLastWriteTime(this.Outputs[i].ItemSpec) < File.GetLastWriteTime(this.Inputs[i].ItemSpec)) {
+ Log.LogMessage(MessageImportance.Normal, TaskStrings.PackingJsFile, this.Inputs[i].ItemSpec, this.Outputs[i].ItemSpec);
+ string input = File.ReadAllText(this.Inputs[i].ItemSpec);
+ string output = this.packer.Pack(input);
+ if (!Directory.Exists(Path.GetDirectoryName(this.Outputs[i].ItemSpec))) {
+ Directory.CreateDirectory(Path.GetDirectoryName(this.Outputs[i].ItemSpec));
+ }
+
+ // Minification removes all comments, including copyright notices
+ // that must remain. So if there's metadata on this item with
+ // a copyright notice on it, stick it on the front of the file.
+ string copyright = this.Inputs[i].GetMetadata("Copyright");
+ if (!string.IsNullOrEmpty(copyright)) {
+ output = "/*" + copyright + "*/" + output;
+ }
+
+ File.WriteAllText(this.Outputs[i].ItemSpec, output, Encoding.UTF8);
+ } else {
+ Log.LogMessage(MessageImportance.Low, TaskStrings.SkipPackingJsFile, this.Inputs[i].ItemSpec);
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/MergeProjectWithVSTemplate.cs b/src/DotNetOpenAuth.BuildTasks/MergeProjectWithVSTemplate.cs
new file mode 100644
index 0000000..1a8a17d
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/MergeProjectWithVSTemplate.cs
@@ -0,0 +1,103 @@
+//-----------------------------------------------------------------------
+// <copyright file="MergeProjectWithVSTemplate.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+ using System.Xml.Linq;
+ using System.IO;
+ using Microsoft.Build.BuildEngine;
+ using System.Diagnostics.Contracts;
+
+ public class MergeProjectWithVSTemplate : Task {
+ internal const string VSTemplateNamespace = "http://schemas.microsoft.com/developer/vstemplate/2005";
+
+ [Required]
+ public string[] ProjectItemTypes { get; set; }
+
+ [Required]
+ public string[] ReplaceParametersExtensions { get; set; }
+
+ [Required]
+ public ITaskItem[] Templates { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ public override bool Execute() {
+ foreach(ITaskItem sourceTemplateTaskItem in this.Templates) {
+ var template = XElement.Load(sourceTemplateTaskItem.ItemSpec);
+ var templateContentElement = template.Element(XName.Get("TemplateContent", VSTemplateNamespace));
+ var projectElement = templateContentElement.Element(XName.Get("Project", VSTemplateNamespace));
+ if (projectElement == null) {
+ Log.LogMessage("Skipping merge of \"{0}\" with a project because no project was referenced from the template.", sourceTemplateTaskItem.ItemSpec);
+ continue;
+ }
+
+ var projectPath = Path.Combine(Path.GetDirectoryName(sourceTemplateTaskItem.ItemSpec), projectElement.Attribute("File").Value);
+ Log.LogMessage("Merging project \"{0}\" with \"{1}\".", projectPath, sourceTemplateTaskItem.ItemSpec);
+ var sourceProject = new Project();
+ sourceProject.Load(projectPath);
+
+ // Collect the project items from the project that are appropriate
+ // to include in the .vstemplate file.
+ var itemsByFolder = from item in sourceProject.EvaluatedItems.Cast<BuildItem>()
+ where this.ProjectItemTypes.Contains(item.Name)
+ orderby item.Include
+ group item by Path.GetDirectoryName(item.Include);
+ foreach (var folder in itemsByFolder) {
+ XElement parentNode = FindOrCreateParent(folder.Key, projectElement);
+
+ foreach (var item in folder) {
+ bool replaceParameters = this.ReplaceParametersExtensions.Contains(Path.GetExtension(item.Include));
+ var itemName = XName.Get("ProjectItem", VSTemplateNamespace);
+ var projectItem = parentNode.Elements(itemName).FirstOrDefault(el => string.Equals(el.Value, Path.GetFileName(item.Include), StringComparison.OrdinalIgnoreCase));
+ if (projectItem == null) {
+ projectItem = new XElement(itemName, Path.GetFileName(item.Include));
+ parentNode.Add(projectItem);
+ }
+ if (replaceParameters) {
+ projectItem.SetAttributeValue("ReplaceParameters", "true");
+ }
+ }
+ }
+
+ template.Save(sourceTemplateTaskItem.ItemSpec);
+ }
+
+ return !Log.HasLoggedErrors;
+ }
+
+ private static XElement FindOrCreateParent(string directoryName, XElement projectElement) {
+ Contract.Requires<ArgumentNullException>(projectElement != null);
+
+ if (string.IsNullOrEmpty(directoryName)) {
+ return projectElement;
+ }
+
+ string[] segments = directoryName.Split(Path.DirectorySeparatorChar);
+ XElement parent = projectElement;
+ for (int i = 0; i < segments.Length; i++) {
+ var candidateName = XName.Get("Folder", VSTemplateNamespace);
+ var candidate = parent.Elements(XName.Get("Folder", VSTemplateNamespace)).FirstOrDefault(n => n.Attribute("Name").Value == segments[i]);
+ if (candidate == null) {
+ candidate = new XElement(
+ candidateName,
+ new XAttribute("Name", segments[i]));
+ parent.Add(candidate);
+ }
+
+ parent = candidate;
+ }
+
+ return parent;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/ParseMaster.cs b/src/DotNetOpenAuth.BuildTasks/ParseMaster.cs
new file mode 100644
index 0000000..7edba29
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/ParseMaster.cs
@@ -0,0 +1,250 @@
+using System;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Collections;
+using System.Collections.Specialized;
+
+/*
+ ParseMaster, version 1.0 (pre-release) (2005/02/01) x4
+ Copyright 2005, Dean Edwards
+ Web: http://dean.edwards.name/
+
+ This software is licensed under the CC-GNU LGPL
+ Web: http://creativecommons.org/licenses/LGPL/2.1/
+
+ Ported to C# by Jesse Hansen, twindagger2k@msn.com
+*/
+
+namespace Dean.Edwards
+{
+ /// <summary>
+ /// a multi-pattern parser
+ /// </summary>
+ internal class ParseMaster
+ {
+ // used to determine nesting levels
+ Regex GROUPS = new Regex("\\("),
+ SUB_REPLACE = new Regex("\\$"),
+ INDEXED = new Regex("^\\$\\d+$"),
+ ESCAPE = new Regex("\\\\."),
+ QUOTE = new Regex("'"),
+ DELETED = new Regex("\\x01[^\\x01]*\\x01");
+
+ /// <summary>
+ /// Delegate to call when a regular expression is found.
+ /// Use match.Groups[offset + &lt;group number&gt;].Value to get
+ /// the correct subexpression
+ /// </summary>
+ public delegate string MatchGroupEvaluator(Match match, int offset);
+
+ private string DELETE(Match match, int offset)
+ {
+ return "\x01" + match.Groups[offset].Value + "\x01";
+ }
+
+ private bool ignoreCase = false;
+ private char escapeChar = '\0';
+
+ /// <summary>
+ /// Ignore Case?
+ /// </summary>
+ public bool IgnoreCase
+ {
+ get { return ignoreCase; }
+ set { ignoreCase = value; }
+ }
+
+ /// <summary>
+ /// Escape Character to use
+ /// </summary>
+ public char EscapeChar
+ {
+ get { return escapeChar; }
+ set { escapeChar = value; }
+ }
+
+ /// <summary>
+ /// Add an expression to be deleted
+ /// </summary>
+ /// <param name="expression">Regular Expression String</param>
+ public void Add(string expression)
+ {
+ Add(expression, string.Empty);
+ }
+
+ /// <summary>
+ /// Add an expression to be replaced with the replacement string
+ /// </summary>
+ /// <param name="expression">Regular Expression String</param>
+ /// <param name="replacement">Replacement String. Use $1, $2, etc. for groups</param>
+ public void Add(string expression, string replacement)
+ {
+ if (replacement == string.Empty)
+ add(expression, new MatchGroupEvaluator(DELETE));
+
+ add(expression, replacement);
+ }
+
+ /// <summary>
+ /// Add an expression to be replaced using a callback function
+ /// </summary>
+ /// <param name="expression">Regular expression string</param>
+ /// <param name="replacement">Callback function</param>
+ public void Add(string expression, MatchGroupEvaluator replacement)
+ {
+ add(expression, replacement);
+ }
+
+ /// <summary>
+ /// Executes the parser
+ /// </summary>
+ /// <param name="input">input string</param>
+ /// <returns>parsed string</returns>
+ public string Exec(string input)
+ {
+ return DELETED.Replace(unescape(getPatterns().Replace(escape(input), new MatchEvaluator(replacement))), string.Empty);
+ //long way for debugging
+ /*input = escape(input);
+ Regex patterns = getPatterns();
+ input = patterns.Replace(input, new MatchEvaluator(replacement));
+ input = DELETED.Replace(input, string.Empty);
+ return input;*/
+ }
+
+ ArrayList patterns = new ArrayList();
+ private void add(string expression, object replacement)
+ {
+ Pattern pattern = new Pattern();
+ pattern.expression = expression;
+ pattern.replacement = replacement;
+ //count the number of sub-expressions
+ // - add 1 because each group is itself a sub-expression
+ pattern.length = GROUPS.Matches(internalEscape(expression)).Count + 1;
+
+ //does the pattern deal with sup-expressions?
+ if (replacement is string && SUB_REPLACE.IsMatch((string) replacement))
+ {
+ string sreplacement = (string) replacement;
+ // a simple lookup (e.g. $2)
+ if (INDEXED.IsMatch(sreplacement))
+ {
+ pattern.replacement = int.Parse(sreplacement.Substring(1)) - 1;
+ }
+ }
+
+ patterns.Add(pattern);
+ }
+
+ /// <summary>
+ /// builds the patterns into a single regular expression
+ /// </summary>
+ /// <returns></returns>
+ private Regex getPatterns()
+ {
+ StringBuilder rtrn = new StringBuilder(string.Empty);
+ foreach (object pattern in patterns)
+ {
+ rtrn.Append(((Pattern) pattern).ToString() + "|");
+ }
+ rtrn.Remove(rtrn.Length - 1, 1);
+ return new Regex(rtrn.ToString(), ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None );
+ }
+
+ /// <summary>
+ /// Global replacement function. Called once for each match found
+ /// </summary>
+ /// <param name="match">Match found</param>
+ private string replacement(Match match)
+ {
+ int i = 1, j = 0;
+ Pattern pattern;
+ //loop through the patterns
+ while (!((pattern = (Pattern) patterns[j++]) == null))
+ {
+ //do we have a result?
+ if (match.Groups[i].Value != string.Empty)
+ {
+ object replacement = pattern.replacement;
+ if (replacement is MatchGroupEvaluator)
+ {
+ return ((MatchGroupEvaluator) replacement)(match, i);
+ }
+ else if (replacement is int)
+ {
+ return match.Groups[(int) replacement + i].Value;
+ }
+ else
+ {
+ //string, send to interpreter
+ return replacementString(match, i, (string) replacement, pattern.length);
+ }
+ }
+ else //skip over references to sub-expressions
+ i += pattern.length;
+ }
+ return match.Value; //should never be hit, but you never know
+ }
+
+ /// <summary>
+ /// Replacement function for complicated lookups (e.g. Hello $3 $2)
+ /// </summary>
+ private string replacementString(Match match, int offset, string replacement, int length)
+ {
+ while (length > 0)
+ {
+ replacement = replacement.Replace("$" + length--, match.Groups[offset + length].Value);
+ }
+ return replacement;
+ }
+
+ private StringCollection escaped = new StringCollection();
+
+ //encode escaped characters
+ private string escape(string str)
+ {
+ if (escapeChar == '\0')
+ return str;
+ Regex escaping = new Regex("\\\\(.)");
+ return escaping.Replace(str, new MatchEvaluator(escapeMatch));
+ }
+
+ private string escapeMatch(Match match)
+ {
+ escaped.Add(match.Groups[1].Value);
+ return "\\";
+ }
+
+ //decode escaped characters
+ private int unescapeIndex = 0;
+ private string unescape(string str)
+ {
+ if (escapeChar == '\0')
+ return str;
+ Regex unescaping = new Regex("\\" + escapeChar);
+ return unescaping.Replace(str, new MatchEvaluator(unescapeMatch));
+ }
+
+ private string unescapeMatch(Match match)
+ {
+ return "\\" + escaped[unescapeIndex++];
+ }
+
+ private string internalEscape(string str)
+ {
+ return ESCAPE.Replace(str, "");
+ }
+
+ //subclass for each pattern
+ private class Pattern
+ {
+ public string expression;
+ public object replacement;
+ public int length;
+
+ public override string ToString()
+ {
+ return "(" + expression + ")";
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.BuildTasks/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..6fdcc21
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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("CustomMsBuildTasks")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CustomMsBuildTasks")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[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("952e3aaa-5dc6-4b71-8c9c-6b485263be19")]
+
+// 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 Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/src/DotNetOpenAuth.BuildTasks/Purge.cs b/src/DotNetOpenAuth.BuildTasks/Purge.cs
new file mode 100644
index 0000000..e19e485
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/Purge.cs
@@ -0,0 +1,88 @@
+//-----------------------------------------------------------------------
+// <copyright file="Purge.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Microsoft.Build.Utilities;
+ using Microsoft.Build.Framework;
+ using System.IO;
+ using System.Text.RegularExpressions;
+
+ /// <summary>
+ /// Purges directory trees of all directories and files that are not on a whitelist.
+ /// </summary>
+ /// <remarks>
+ /// This task performs a function similar to robocopy's /MIR switch, except that
+ /// this task does not require that an entire directory tree be used as the source
+ /// in order to purge old files from the destination.
+ /// </remarks>
+ public class Purge : Task {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Purge"/> class.
+ /// </summary>
+ public Purge() {
+ this.PurgeEmptyDirectories = true;
+ }
+
+ /// <summary>
+ /// Gets or sets the root directories to purge.
+ /// </summary>
+ /// <value>The directories.</value>
+ [Required]
+ public string[] Directories { get; set; }
+
+ /// <summary>
+ /// Gets or sets the files that should be NOT be purged.
+ /// </summary>
+ public ITaskItem[] IntendedFiles { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether empty directories will be deleted.
+ /// </summary>
+ /// <value>
+ /// The default value is <c>true</c>.
+ /// </value>
+ public bool PurgeEmptyDirectories { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ public override bool Execute() {
+ HashSet<string> intendedFiles = new HashSet<string>(this.IntendedFiles.Select(file => file.GetMetadata("FullPath")), StringComparer.OrdinalIgnoreCase);
+
+ foreach (string directory in this.Directories.Select(dir => NormalizePath(dir)).Where(dir => Directory.Exists(dir))) {
+ foreach (string existingFile in Directory.GetFiles(directory, "*", SearchOption.AllDirectories)) {
+ if (!intendedFiles.Contains(existingFile)) {
+ this.Log.LogWarning("Purging file \"{0}\".", existingFile);
+ File.Delete(existingFile);
+ }
+ }
+
+ if (this.PurgeEmptyDirectories) {
+ foreach (string subdirectory in Directory.GetDirectories(directory, "*", SearchOption.AllDirectories)) {
+ // We have to check for the existance of the directory because it MAY be
+ // a descendent of a directory we already deleted in this loop.
+ if (Directory.Exists(subdirectory)) {
+ if (Directory.GetDirectories(subdirectory).Length == 0 && Directory.GetFiles(subdirectory).Length == 0) {
+ this.Log.LogWarning("Purging empty directory \"{0}\".", subdirectory);
+ Directory.Delete(subdirectory);
+ }
+ }
+ }
+ }
+ }
+
+ return !this.Log.HasLoggedErrors;
+ }
+
+ private static string NormalizePath(string path) {
+ return Regex.Replace(path, @"\\+", @"\");
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/ReSignDelaySignedAssemblies.cs b/src/DotNetOpenAuth.BuildTasks/ReSignDelaySignedAssemblies.cs
new file mode 100644
index 0000000..a0ba386
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/ReSignDelaySignedAssemblies.cs
@@ -0,0 +1,56 @@
+//-----------------------------------------------------------------------
+// <copyright file="ReSignDelaySignedAssemblies.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ public class ReSignDelaySignedAssemblies : SnToolTask {
+ /// <summary>
+ /// Gets or sets the key file to use for signing.
+ /// </summary>
+ public ITaskItem KeyFile { get; set; }
+
+ /// <summary>
+ /// Gets or sets the key container.
+ /// </summary>
+ public ITaskItem KeyContainer { get; set; }
+
+ /// <summary>
+ /// Gets or sets the assemblies to re-sign.
+ /// </summary>
+ public ITaskItem[] Assemblies { get; set; }
+
+ /// <summary>
+ /// Generates the command line commands.
+ /// </summary>
+ protected override string GenerateCommandLineCommands() {
+ ////if (this.Assemblies.Length != 1) {
+ //// throw new NotSupportedException("Exactly 1 assembly for signing is supported.");
+ ////}
+ CommandLineBuilder args = new CommandLineBuilder();
+ args.AppendSwitch("-q");
+
+ if (this.KeyFile != null) {
+ args.AppendSwitch("-R");
+ } else if (this.KeyContainer != null) {
+ args.AppendSwitch("-Rc");
+ } else {
+ throw new InvalidOperationException("Either KeyFile or KeyContainer must be set.");
+ }
+
+ args.AppendFileNameIfNotNull(this.Assemblies[0]);
+ if (this.KeyFile != null) {
+ args.AppendFileNameIfNotNull(this.KeyFile);
+ } else {
+ args.AppendFileNameIfNotNull(this.KeyContainer);
+ }
+
+ return args.ToString();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/SetEnvironmentVariable.cs b/src/DotNetOpenAuth.BuildTasks/SetEnvironmentVariable.cs
new file mode 100644
index 0000000..2de5976
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/SetEnvironmentVariable.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Microsoft.Build.Utilities;
+using Microsoft.Build.Framework;
+
+namespace DotNetOpenAuth.BuildTasks {
+ public class SetEnvironmentVariable : Task {
+ public SetEnvironmentVariable() {
+ Scope = EnvironmentVariableTarget.Process;
+ }
+
+ /// <summary>
+ /// The name of the environment variable to set or clear.
+ /// </summary>
+ [Required]
+ public string Name { get; set; }
+ /// <summary>
+ /// The value of the environment variable, or the empty string to clear it.
+ /// </summary>
+ [Required]
+ public string Value { get; set; }
+ /// <summary>
+ /// The target environment for the variable. Machine, User, or Process.
+ /// </summary>
+ public EnvironmentVariableTarget Scope { get; set; }
+
+ public override bool Execute() {
+ Environment.SetEnvironmentVariable(Name, Value, Scope);
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/SignatureVerification.cs b/src/DotNetOpenAuth.BuildTasks/SignatureVerification.cs
new file mode 100644
index 0000000..2e69926
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/SignatureVerification.cs
@@ -0,0 +1,45 @@
+//-----------------------------------------------------------------------
+// <copyright file="SignatureVerification.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using Microsoft.Build.Utilities;
+
+ public class SignatureVerification : SnToolTask {
+ /// <summary>
+ /// Gets or sets a value indicating whether to register the given assembly and public key token
+ /// for skip verification or clear any pre-existing skip verification entry.
+ /// </summary>
+ public bool SkipVerification { get; set; }
+
+ /// <summary>
+ /// Gets or sets the name of the assembly.
+ /// </summary>
+ /// <value>The name of the assembly.</value>
+ public string AssemblyName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the public key token.
+ /// </summary>
+ /// <value>The public key token.</value>
+ public string PublicKeyToken { get; set; }
+
+ /// <summary>
+ /// Generates the command line commands.
+ /// </summary>
+ protected override string GenerateCommandLineCommands() {
+ CommandLineBuilder builder = new CommandLineBuilder();
+ builder.AppendSwitch("-q");
+ if (this.SkipVerification) {
+ builder.AppendSwitch("-Vr");
+ } else {
+ builder.AppendSwitch("-Vu");
+ }
+
+ builder.AppendFileNameIfNotNull(this.AssemblyName + "," + this.PublicKeyToken);
+ return builder.ToString();
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/SnToolTask.cs b/src/DotNetOpenAuth.BuildTasks/SnToolTask.cs
new file mode 100644
index 0000000..29896fe
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/SnToolTask.cs
@@ -0,0 +1,37 @@
+//-----------------------------------------------------------------------
+// <copyright file="SnToolTask.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using System;
+ using System.IO;
+ using Microsoft.Build.Utilities;
+
+ public abstract class SnToolTask : ToolTask {
+ /// <summary>
+ /// Gets the name of the tool.
+ /// </summary>
+ /// <value>The name of the tool.</value>
+ protected override string ToolName {
+ get { return "sn.exe"; }
+ }
+
+ /// <summary>
+ /// Generates the full path to tool.
+ /// </summary>
+ protected override string GenerateFullPathToTool() {
+ string[] versions = new[] { "v6.0A", "v6.1", "v7.0a" };
+ string fullPath = null;
+ foreach (string version in versions) {
+ fullPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), @"Microsoft SDKs\Windows\" + version + @"\bin\" + this.ToolName);
+ if (File.Exists(fullPath)) {
+ return fullPath;
+ }
+ }
+
+ throw new FileNotFoundException("Unable to find sn.exe tool.", fullPath);
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/TaskStrings.Designer.cs b/src/DotNetOpenAuth.BuildTasks/TaskStrings.Designer.cs
new file mode 100644
index 0000000..17647fd
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/TaskStrings.Designer.cs
@@ -0,0 +1,117 @@
+//------------------------------------------------------------------------------
+// <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 DotNetOpenAuth.BuildTasks {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class TaskStrings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal TaskStrings() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DotNetOpenAuth.BuildTasks.TaskStrings", typeof(TaskStrings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Web application &apos;{0}&apos; deleted..
+ /// </summary>
+ internal static string DeletedWebApplication {
+ get {
+ return ResourceManager.GetString("DeletedWebApplication", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to The {0} and {1} properties must be set to arrays of equal length..
+ /// </summary>
+ internal static string MismatchingArrayLengths {
+ get {
+ return ResourceManager.GetString("MismatchingArrayLengths", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to No web site with the name &apos;{0}&apos; found..
+ /// </summary>
+ internal static string NoMatchingWebSiteFound {
+ get {
+ return ResourceManager.GetString("NoMatchingWebSiteFound", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Packing javascript resource &quot;{0}&quot; into &quot;{1}&quot;..
+ /// </summary>
+ internal static string PackingJsFile {
+ get {
+ return ResourceManager.GetString("PackingJsFile", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Skip packing &quot;{0}&quot; because its packed version is up to date..
+ /// </summary>
+ internal static string SkipPackingJsFile {
+ get {
+ return ResourceManager.GetString("SkipPackingJsFile", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Web application &apos;{0}&apos; was not found, so it was not deleted..
+ /// </summary>
+ internal static string WebApplicationNotFoundSoNotDeleted {
+ get {
+ return ResourceManager.GetString("WebApplicationNotFoundSoNotDeleted", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.BuildTasks/TaskStrings.resx b/src/DotNetOpenAuth.BuildTasks/TaskStrings.resx
new file mode 100644
index 0000000..50e1592
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/TaskStrings.resx
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="DeletedWebApplication" xml:space="preserve">
+ <value>Web application '{0}' deleted.</value>
+ </data>
+ <data name="MismatchingArrayLengths" xml:space="preserve">
+ <value>The {0} and {1} properties must be set to arrays of equal length.</value>
+ </data>
+ <data name="NoMatchingWebSiteFound" xml:space="preserve">
+ <value>No web site with the name '{0}' found.</value>
+ </data>
+ <data name="PackingJsFile" xml:space="preserve">
+ <value>Packing javascript resource "{0}" into "{1}".</value>
+ </data>
+ <data name="SkipPackingJsFile" xml:space="preserve">
+ <value>Skip packing "{0}" because its packed version is up to date.</value>
+ </data>
+ <data name="WebApplicationNotFoundSoNotDeleted" xml:space="preserve">
+ <value>Web application '{0}' was not found, so it was not deleted.</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.BuildTasks/Trim.cs b/src/DotNetOpenAuth.BuildTasks/Trim.cs
new file mode 100644
index 0000000..972b87d
--- /dev/null
+++ b/src/DotNetOpenAuth.BuildTasks/Trim.cs
@@ -0,0 +1,79 @@
+//-----------------------------------------------------------------------
+// <copyright file="Trim.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.BuildTasks {
+ using Microsoft.Build.Framework;
+ using Microsoft.Build.Utilities;
+
+ /// <summary>
+ /// Trims item identities or metadata.
+ /// </summary>
+ public class Trim : Task {
+ /// <summary>
+ /// Gets or sets the name of the metadata to trim. Leave empty or null to operate on itemspec.
+ /// </summary>
+ /// <value>The name of the metadata.</value>
+ public string MetadataName { get; set; }
+
+ /// <summary>
+ /// Gets or sets the characters that should be trimmed off if found at the start of items' ItemSpecs.
+ /// </summary>
+ public string StartCharacters { get; set; }
+
+ /// <summary>
+ /// Gets or sets the characters that should be trimmed off if found at the end of items' ItemSpecs.
+ /// </summary>
+ public string EndCharacters { get; set; }
+
+ /// <summary>
+ /// Gets or sets the substring that should be trimmed along with everything that appears after it.
+ /// </summary>
+ public string AllAfter { get; set; }
+
+ /// <summary>
+ /// Gets or sets the items with ItemSpec's to be trimmed.
+ /// </summary>
+ [Required]
+ public ITaskItem[] Inputs { get; set; }
+
+ /// <summary>
+ /// Gets or sets the items with trimmed ItemSpec strings.
+ /// </summary>
+ [Output]
+ public ITaskItem[] Outputs { get; set; }
+
+ /// <summary>
+ /// Executes this instance.
+ /// </summary>
+ /// <returns>A value indicating whether the task completed successfully.</returns>
+ public override bool Execute() {
+ this.Outputs = new ITaskItem[this.Inputs.Length];
+ for (int i = 0; i < this.Inputs.Length; i++) {
+ this.Outputs[i] = new TaskItem(this.Inputs[i]);
+ string value = string.IsNullOrEmpty(this.MetadataName) ? this.Outputs[i].ItemSpec : this.Outputs[i].GetMetadata(this.MetadataName);
+ if (!string.IsNullOrEmpty(this.StartCharacters)) {
+ value = value.TrimStart(this.StartCharacters.ToCharArray());
+ }
+ if (!string.IsNullOrEmpty(this.EndCharacters)) {
+ value = value.TrimEnd(this.EndCharacters.ToCharArray());
+ }
+ if (!string.IsNullOrEmpty(this.AllAfter)) {
+ int index = value.IndexOf(this.AllAfter);
+ if (index >= 0) {
+ value = value.Substring(0, index);
+ }
+ }
+ if (string.IsNullOrEmpty(this.MetadataName)) {
+ this.Outputs[i].ItemSpec = value;
+ } else {
+ this.Outputs[i].SetMetadata(this.MetadataName, value);
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs b/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs
index 05ac306..fd77746 100644
--- a/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/HttpRequestInfoTests.cs
@@ -5,6 +5,8 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Test.Messaging {
+ using System;
+ using System.Collections.Specialized;
using System.Web;
using DotNetOpenAuth.Messaging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -92,5 +94,59 @@ namespace DotNetOpenAuth.Test.Messaging {
HttpRequestInfo info = new HttpRequestInfo();
Assert.IsNull(info.QueryString["hi"]);
}
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply X_FORWARDED_PROTO and HOST
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder1() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_X_FORWARDED_PROTO"] = "https";
+ serverVariables["HTTP_HOST"] = "somehost";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("https://somehost/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply X_FORWARDED_PROTO and HOST:port
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder2() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_X_FORWARDED_PROTO"] = "https";
+ serverVariables["HTTP_HOST"] = "somehost:999";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("https://somehost:999/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply just HOST
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder3() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_HOST"] = "somehost";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("http://somehost/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
+
+ /// <summary>
+ /// Verifies SSL forwarders are correctly handled when they supply just HOST:port
+ /// </summary>
+ [TestMethod]
+ public void GetPublicFacingUrlSSLForwarder4() {
+ HttpRequest req = new HttpRequest("a.aspx", "http://someinternalhost/a.aspx?a=b", "a=b");
+ var serverVariables = new NameValueCollection();
+ serverVariables["HTTP_HOST"] = "somehost:79";
+ Uri actual = HttpRequestInfo.GetPublicFacingUrl(req, serverVariables);
+ Uri expected = new Uri("http://somehost:79/a.aspx?a=b");
+ Assert.AreEqual(expected, actual);
+ }
}
}
diff --git a/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs b/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs
index 24171e1..b9e7436 100644
--- a/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/Reflection/MessageDictionaryTests.cs
@@ -300,7 +300,7 @@ namespace DotNetOpenAuth.Test.Messaging.Reflection {
[TestMethod]
public void CopyTo() {
ICollection<KeyValuePair<string, string>> target = this.MessageDescriptions.GetAccessor(this.message);
- IDictionary<string, string> targetAsDictionary = ((IDictionary<string, string>)target);
+ IDictionary<string, string> targetAsDictionary = (IDictionary<string, string>)target;
KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[target.Count + 1];
int arrayIndex = 1;
target.CopyTo(array, arrayIndex);
@@ -317,7 +317,7 @@ namespace DotNetOpenAuth.Test.Messaging.Reflection {
[TestMethod]
public void ContainsKeyValuePair() {
ICollection<KeyValuePair<string, string>> target = this.MessageDescriptions.GetAccessor(this.message);
- IDictionary<string, string> targetAsDictionary = ((IDictionary<string, string>)target);
+ IDictionary<string, string> targetAsDictionary = (IDictionary<string, string>)target;
Assert.IsFalse(target.Contains(new KeyValuePair<string, string>("age", "1")));
Assert.IsTrue(target.Contains(new KeyValuePair<string, string>("age", "0")));
@@ -333,7 +333,7 @@ namespace DotNetOpenAuth.Test.Messaging.Reflection {
[TestMethod]
public void ClearValues() {
MessageDictionary target = this.MessageDescriptions.GetAccessor(this.message);
- IDictionary<string, string> targetAsDictionary = ((IDictionary<string, string>)target);
+ IDictionary<string, string> targetAsDictionary = (IDictionary<string, string>)target;
this.message.Name = "Andrew";
this.message.Age = 15;
targetAsDictionary["extra"] = "value";
diff --git a/src/DotNetOpenAuth.Test/Messaging/Reflection/MessagePartTests.cs b/src/DotNetOpenAuth.Test/Messaging/Reflection/MessagePartTests.cs
index 19e6a82..9deaecd 100644
--- a/src/DotNetOpenAuth.Test/Messaging/Reflection/MessagePartTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/Reflection/MessagePartTests.cs
@@ -28,7 +28,12 @@ namespace DotNetOpenAuth.Test.Messaging.Reflection {
[TestMethod]
public void OptionalNullableStruct() {
- this.ParameterizedMessageTypeTest(typeof(MessageWithNullableOptionalStruct));
+ var message = new MessageWithNullableOptionalStruct();
+ var part = this.ParameterizedMessageTypeTest(message.GetType());
+
+ Assert.IsNull(part.GetValue(message));
+ part.SetValue(message, "3");
+ Assert.AreEqual("3", part.GetValue(message));
}
[TestMethod]
diff --git a/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs b/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
index 48547b7..aae119d 100644
--- a/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
+++ b/src/DotNetOpenAuth.Test/Mocks/InMemoryTokenManager.cs
@@ -12,6 +12,7 @@ namespace DotNetOpenAuth.Test.Mocks {
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
+ using DotNetOpenAuth.Test.OAuth;
internal class InMemoryTokenManager : IConsumerTokenManager, IServiceProviderTokenManager {
private KeyedCollectionDelegate<string, ConsumerInfo> consumers = new KeyedCollectionDelegate<string, ConsumerInfo>(c => c.Key);
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs
index fcdb5e8..6477510 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/HmacSha1SigningBindingElementTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.ChannelElements {
+namespace DotNetOpenAuth.Test.OAuth.ChannelElements {
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
using DotNetOpenAuth.Test.Mocks;
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs
index 856f164..e215bc1 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/OAuthChannelTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.ChannelElements {
+namespace DotNetOpenAuth.Test.OAuth.ChannelElements {
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
@@ -356,6 +356,7 @@ namespace DotNetOpenAuth.Test.ChannelElements {
{ "Name", "Andrew" },
{ "Location", "http://hostb/pathB" },
{ "Timestamp", XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.Utc) },
+ { "realm" , "someValue" },
};
IProtocolMessage requestMessage = this.channel.ReadFromRequest(CreateHttpRequestInfo(scheme, fields));
Assert.IsNotNull(requestMessage);
@@ -364,6 +365,12 @@ namespace DotNetOpenAuth.Test.ChannelElements {
Assert.AreEqual(15, testMessage.Age);
Assert.AreEqual("Andrew", testMessage.Name);
Assert.AreEqual("http://hostb/pathB", testMessage.Location.AbsoluteUri);
+ if (scheme == HttpDeliveryMethods.AuthorizationHeaderRequest) {
+ // The realm value should be ignored in the authorization header
+ Assert.IsFalse(((IMessage)testMessage).ExtraData.ContainsKey("realm"));
+ } else {
+ Assert.AreEqual("someValue", ((IMessage)testMessage).ExtraData["realm"]);
+ }
}
}
}
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs
index 627db8f..80a1c01 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/PlaintextSigningBindingElementTest.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.ChannelElements {
+namespace DotNetOpenAuth.Test.OAuth.ChannelElements {
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;
diff --git a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
index 6e566c8..49549f5 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ChannelElements/SigningBindingElementBaseTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.ChannelElements {
+namespace DotNetOpenAuth.Test.OAuth.ChannelElements {
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Reflection;
using DotNetOpenAuth.OAuth;
diff --git a/src/DotNetOpenAuth.Test/OAuth/ConsumerDescription.cs b/src/DotNetOpenAuth.Test/OAuth/ConsumerDescription.cs
index 625f416..89105ef 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ConsumerDescription.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ConsumerDescription.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test {
+namespace DotNetOpenAuth.Test.OAuth {
/// <summary>
/// Information necessary to initialize a <see cref="Consumer"/>,
/// and to tell a <see cref="ServiceProvider"/> about it.
diff --git a/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs b/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs
index ce548a9..c3ef6c2 100644
--- a/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/OAuthCoordinator.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test {
+namespace DotNetOpenAuth.Test.OAuth {
using System;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
diff --git a/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs b/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs
index ce8070b..e60a9e2 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ProtocolTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test {
+namespace DotNetOpenAuth.Test.OAuth {
using DotNetOpenAuth.OAuth;
using Microsoft.VisualStudio.TestTools.UnitTesting;
diff --git a/src/DotNetOpenAuth.Test/OAuth/ServiceProviderDescriptionTests.cs b/src/DotNetOpenAuth.Test/OAuth/ServiceProviderDescriptionTests.cs
index 760a9e9..3430103 100644
--- a/src/DotNetOpenAuth.Test/OAuth/ServiceProviderDescriptionTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth/ServiceProviderDescriptionTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test {
+namespace DotNetOpenAuth.Test.OAuth {
using System;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/AttributeExchangeRoundtripTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/AttributeExchangeRoundtripTests.cs
index 1051092..fa05e94 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/AttributeExchangeRoundtripTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/AttributeExchange/AttributeExchangeRoundtripTests.cs
@@ -34,8 +34,8 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
var request = new StoreRequest();
var newAttribute = new AttributeValues(
IncrementingAttribute,
- "val" + (incrementingAttributeValue++).ToString(),
- "val" + (incrementingAttributeValue++).ToString());
+ "val" + (this.incrementingAttributeValue++).ToString(),
+ "val" + (this.incrementingAttributeValue++).ToString());
request.Attributes.Add(newAttribute);
var successResponse = new StoreResponse();
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperOPTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperOPTests.cs
index 9f849ea..1fb3160 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperOPTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperOPTests.cs
@@ -42,6 +42,8 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
Assert.IsNull(sreg);
// Make sure we're still able to send an sreg response.
+ // (not really a valid scenario, since OPs don't have public access
+ // to directly create a response without a request.
var sregResponse = new ClaimsResponse();
this.request.AddResponseExtension(sregResponse);
ExtensionsInteropHelper.ConvertSregToMatchRequest(this.request);
@@ -49,12 +51,18 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
Assert.AreSame(sregResponse, extensions.Single());
}
+ [TestMethod]
+ public void NegativeResponse() {
+ this.request.IsAuthenticated = false;
+ ExtensionsInteropHelper.ConvertSregToMatchRequest(this.request);
+ }
+
/// <summary>
/// Verifies sreg coming in is seen as sreg.
/// </summary>
[TestMethod]
public void UnifyExtensionsAsSregWithSreg() {
- var sregInjected = new ClaimsRequest {
+ var sregInjected = new ClaimsRequest(DotNetOpenAuth.OpenId.Extensions.SimpleRegistration.Constants.sreg_ns) {
Nickname = DemandLevel.Request,
};
this.extensions.Add(sregInjected);
@@ -63,7 +71,7 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
Assert.AreEqual(DemandLevel.Request, sreg.Nickname);
Assert.AreEqual(DemandLevel.NoRequest, sreg.FullName);
- var sregResponse = new ClaimsResponse();
+ var sregResponse = sreg.CreateResponse();
this.request.AddResponseExtension(sregResponse);
ExtensionsInteropHelper.ConvertSregToMatchRequest(this.request);
var extensions = this.GetResponseExtensions();
@@ -91,7 +99,7 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
/// </summary>
[TestMethod]
public void UnifyExtensionsAsSregWithBothSregAndAX() {
- var sregInjected = new ClaimsRequest {
+ var sregInjected = new ClaimsRequest(DotNetOpenAuth.OpenId.Extensions.SimpleRegistration.Constants.sreg_ns) {
Nickname = DemandLevel.Request,
};
this.extensions.Add(sregInjected);
@@ -103,9 +111,8 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
Assert.AreEqual(DemandLevel.Request, sreg.Nickname);
Assert.AreEqual(DemandLevel.NoRequest, sreg.Email);
- var sregResponseInjected = new ClaimsResponse {
- Nickname = "andy",
- };
+ var sregResponseInjected = sreg.CreateResponse();
+ sregResponseInjected.Nickname = "andy";
this.request.AddResponseExtension(sregResponseInjected);
var axResponseInjected = new FetchResponse();
axResponseInjected.Attributes.Add(WellKnownAttributes.Contact.Email, "a@b.com");
@@ -134,9 +141,8 @@ namespace DotNetOpenAuth.Test.OpenId.Extensions {
Assert.AreEqual(DemandLevel.Require, sreg.FullName);
Assert.AreEqual(DemandLevel.NoRequest, sreg.Language);
- var sregResponse = new ClaimsResponse {
- Nickname = "andy",
- };
+ var sregResponse = sreg.CreateResponse();
+ sregResponse.Nickname = "andy";
this.request.AddResponseExtension(sregResponse);
ExtensionsInteropHelper.ConvertSregToMatchRequest(this.request);
var extensions = this.GetResponseExtensions();
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs
index ba5e335..7edec09 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPRequestTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.OpenId {
+namespace DotNetOpenAuth.Test.OpenId.Extensions {
using System.Linq;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions;
diff --git a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPResponseTests.cs b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPResponseTests.cs
index 5fe05c1..655e616 100644
--- a/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPResponseTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/Extensions/ExtensionsInteropHelperRPResponseTests.cs
@@ -4,7 +4,7 @@
// </copyright>
//-----------------------------------------------------------------------
-namespace DotNetOpenAuth.Test.OpenId {
+namespace DotNetOpenAuth.Test.OpenId.Extensions {
using System.Collections.Generic;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
diff --git a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs
index 10497b2..0ddc76b 100644
--- a/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs
+++ b/src/DotNetOpenAuth.Test/OpenId/RelyingParty/AuthenticationRequestTests.cs
@@ -112,11 +112,11 @@ namespace DotNetOpenAuth.Test.OpenId.RelyingParty {
var rp = CreateRelyingParty();
// First verify that delegating identifiers work
- Assert.IsTrue(AuthenticationRequest.Create(id, rp, realm, returnTo, false).Any(), "The delegating identifier should have not generated any results.");
+ Assert.IsTrue(AuthenticationRequest.Create(id, rp, this.realm, this.returnTo, false).Any(), "The delegating identifier should have not generated any results.");
// Now disable them and try again.
rp.SecuritySettings.RejectDelegatingIdentifiers = true;
- Assert.IsFalse(AuthenticationRequest.Create(id, rp, realm, returnTo, false).Any(), "The delegating identifier should have not generated any results.");
+ Assert.IsFalse(AuthenticationRequest.Create(id, rp, this.realm, this.returnTo, false).Any(), "The delegating identifier should have not generated any results.");
}
/// <summary>
diff --git a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd
index a637d1f..d2b5f14 100644
--- a/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd
+++ b/src/DotNetOpenAuth/Configuration/DotNetOpenAuth.xsd
@@ -4,28 +4,68 @@
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="dotNetOpenAuth">
+ <xs:annotation>
+ <xs:documentation>
+ Customizations and configuration of DotNetOpenAuth behavior.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="messaging">
+ <xs:annotation>
+ <xs:documentation>
+ Options for general messaging protocols, such as whitelist/blacklist hosts and maximum message age.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="untrustedWebRequest">
+ <xs:annotation>
+ <xs:documentation>
+ Restrictions and settings to apply to outgoing HTTP requests to hosts that are not
+ trusted by this web site. Useful for OpenID-supporting hosts because HTTP connections
+ are initiated based on user input to arbitrary servers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="whitelistHosts">
+ <xs:annotation>
+ <xs:documentation>
+ A set of host names (including domain names) to allow outgoing connections to
+ that would otherwise not be allowed based on security restrictions.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="name" type="xs:string" use="required" />
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name to trust. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="remove">
<xs:complexType>
- <xs:attribute name="name" type="xs:string" use="required" />
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name to NOT trust. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="clear">
+ <xs:annotation>
+ <xs:documentation>
+ Clears all hosts from the whitelist.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<!--tag is empty-->
</xs:complexType>
@@ -55,19 +95,42 @@
</xs:complexType>
</xs:element>
<xs:element name="blacklistHosts">
+ <xs:annotation>
+ <xs:documentation>
+ A set of host names (including domain names) to disallow outgoing connections to
+ that would otherwise be allowed based on security restrictions.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="name" type="xs:string" use="required" />
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name known to add to the blacklist. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="remove">
<xs:complexType>
- <xs:attribute name="name" type="xs:string" use="required" />
+ <xs:attribute name="name" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The host name known to remove to the blacklist. For example: "localhost" or "www.mypartners.com".
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="clear">
+ <xs:annotation>
+ <xs:documentation>
+ Clears all hosts from the blacklist.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<!--tag is empty-->
</xs:complexType>
@@ -97,27 +160,92 @@
</xs:complexType>
</xs:element>
</xs:choice>
- <xs:attribute name="timeout" type="xs:string" />
- <xs:attribute name="readWriteTimeout" type="xs:string" />
- <xs:attribute name="maximumBytesToRead" type="xs:int" />
- <xs:attribute name="maximumRedirections" type="xs:int" />
+ <xs:attribute name="timeout" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time to allow for an outgoing HTTP request to complete before giving up.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="readWriteTimeout" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time to allow for an outgoing HTTP request to either send or receive data before giving up.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumBytesToRead" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum bytes to read from an untrusted server during an outgoing HTTP request before cutting off the response.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumRedirections" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum redirection instructions to follow before giving up.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
- <xs:attribute name="lifetime" type="xs:string" />
- <xs:attribute name="clockSkew" type="xs:string" />
+ <xs:attribute name="lifetime" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time allowed between a message being sent to when it is received before
+ it is considered expired.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="clockSkew" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time to consider a safe difference in server clocks.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="openid">
+ <xs:annotation>
+ <xs:documentation>
+ Configuration for OpenID authentication (relying parties and providers).
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="relyingParty">
+ <xs:annotation>
+ <xs:documentation>
+ Configuration specific for OpenID relying parties.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings that apply to OpenID relying parties.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
- <xs:attribute name="requireSsl" type="xs:boolean" default="false" />
+ <xs:attribute name="requireSsl" type="xs:boolean" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Restricts OpenID logins to identifiers that use HTTPS throughout the discovery process,
+ and only uses HTTPS OpenID Provider endpoints.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="minimumRequiredOpenIdVersion">
+ <xs:annotation>
+ <xs:documentation>
+ Optionally restricts interoperability with remote parties that
+ implement older versions of OpenID.
+ </xs:documentation>
+ </xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="V10" />
@@ -126,28 +254,103 @@
</xs:restriction>
</xs:simpleType>
</xs:attribute>
- <xs:attribute name="minimumHashBitLength" type="xs:int" />
- <xs:attribute name="maximumHashBitLength" type="xs:int" />
- <xs:attribute name="privateSecretMaximumAge" type="xs:string" />
- <xs:attribute name="requireDirectedIdentity" type="xs:boolean" />
- <xs:attribute name="requireAssociation" type="xs:boolean" />
- <xs:attribute name="rejectUnsolicitedAssertions" type="xs:boolean" />
- <xs:attribute name="rejectDelegatingIdentifiers" type="xs:boolean" />
- <xs:attribute name="ignoreUnsignedExtensions" type="xs:boolean" />
+ <xs:attribute name="minimumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ Shared associations with OpenID Providers will only be formed or used if they
+ are willing to form associations equal to or greater than a given level of protection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ Shared associaitons with OpenID Providers will only be formed or used if they
+ are willing to form associations equal to or less than a given level of protection.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="privateSecretMaximumAge" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum age of a secret used for private signing before it is renewed.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requireDirectedIdentity" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that OpenID identifiers upon which authentication requests are created
+ are to be OP Identifiers. Claimed Identifiers are not allowed.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="requireAssociation" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that the relying party can form a shared association with an
+ OpenID Provider before creating an authentication request for it.
+ Note that this does not require that the Provider actually use a
+ shared association in its response.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="rejectUnsolicitedAssertions" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that users begin their login experience at the relying party
+ rather than at a Provider or using other forms of unsolicited assertions.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="rejectDelegatingIdentifiers" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that the claimed identifiers used to log into the relying party
+ be the same ones that are originally issued by the Provider.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="ignoreUnsignedExtensions" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Makes it impossible for the relying party to read authentication response
+ extensions that are not signed by the Provider.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="behaviors">
+ <xs:annotation>
+ <xs:documentation>
+ Manipulates the set of custom behaviors that are automatically applied
+ to incoming and outgoing OpenID messages.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="optional" />
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IRelyingPartyBehavior interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="xaml" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="remove">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="required" />
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IRelyingPartyBehavior interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="clear">
@@ -159,31 +362,76 @@
</xs:complexType>
</xs:element>
<xs:element name="store">
+ <xs:annotation>
+ <xs:documentation>
+ A custom implementation of IRelyingPartyApplicationStore to use by default for new
+ instances of OpenIdRelyingParty.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
- <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ A fully-qualified type name of the custom implementation of IRelyingPartyApplicationStore.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="provider">
+ <xs:annotation>
+ <xs:documentation>
+ Configuration specific for OpenID providers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings that apply to OpenID providers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="associations">
+ <xs:annotation>
+ <xs:documentation>
+ Sets maximum ages for shared associations of various strengths.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="required" />
- <xs:attribute name="lifetime" type="xs:string" use="required" />
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The OpenID association type (i.e. HMAC-SHA1 or HMAC-SHA256)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="lifetime" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The lifetime a shared association of this type will be used for.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="remove">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="required" />
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The OpenID association type (i.e. HMAC-SHA1 or HMAC-SHA256)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="clear">
@@ -195,27 +443,92 @@
</xs:complexType>
</xs:element>
</xs:choice>
- <xs:attribute name="requireSsl" type="xs:boolean" default="false" />
- <xs:attribute name="protectDownlevelReplayAttacks" type="xs:boolean" />
+ <xs:attribute name="requireSsl" type="xs:boolean" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ Requires that relying parties' realm URLs be protected by HTTPS,
+ ensuring that the RP discovery step is not vulnerable to DNS poisoning attacks.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="protectDownlevelReplayAttacks" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Provides automatic security protections to OpenID 1.x relying parties
+ so security is comparable to OpenID 2.0 relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="unsolicitedAssertionVerification">
+ <xs:annotation>
+ <xs:documentation>
+ The level of verification done on a claimed identifier before an unsolicited
+ assertion for that identifier is issued by this Provider.
+ </xs:documentation>
+ </xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
- <xs:enumeration value="RequireSuccess" />
- <xs:enumeration value="LogWarningOnFailure" />
- <xs:enumeration value="NeverVerify" />
+ <xs:enumeration value="RequireSuccess">
+ <xs:annotation>
+ <xs:documentation>
+ The claimed identifier being asserted must delegate to this Provider
+ and this must be verifiable by the Provider to send the assertion.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="LogWarningOnFailure">
+ <xs:annotation>
+ <xs:documentation>
+ The claimed identifier being asserted is checked for delegation to this Provider
+ and an warning is logged, but the assertion is allowed to go through.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="NeverVerify">
+ <xs:annotation>
+ <xs:documentation>
+ The claimed identifier being asserted is not checked to see that this Provider
+ has authority to assert its identity.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
- <xs:attribute name="minimumHashBitLength" type="xs:int" />
- <xs:attribute name="maximumHashBitLength" type="xs:int" />
+ <xs:attribute name="minimumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The minimum shared association strength to form with relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximumHashBitLength" type="xs:int">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum shared association strength to form with relying parties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="behaviors">
+ <xs:annotation>
+ <xs:documentation>
+ Manipulates the set of custom behaviors that are automatically applied
+ to incoming and outgoing OpenID messages.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="optional" />
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements the IRelyingPartyBehavior interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="xaml" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
@@ -233,25 +546,54 @@
</xs:complexType>
</xs:element>
<xs:element name="store">
+ <xs:annotation>
+ <xs:documentation>
+ A custom implementation of IProviderApplicationStore to use by default for new
+ instances of OpenIdRelyingParty.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
- <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ A fully-qualified type name of the custom implementation of IProviderApplicationStore.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="extensionFactories">
+ <xs:annotation>
+ <xs:documentation>
+ Adjusts the list of known OpenID extensions via the registration of extension factories.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="add">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="optional" />
+ <xs:attribute name="type" type="xs:string" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements IOpenIdExtensionFactory.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
<xs:attribute name="xaml" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
<xs:element name="remove">
<xs:complexType>
- <xs:attribute name="type" type="xs:string" use="required" />
+ <xs:attribute name="type" type="xs:string" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ The fully-qualified name of the type that implements IOpenIdExtensionFactory.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="clear">
@@ -263,22 +605,69 @@
</xs:complexType>
</xs:element>
<xs:element name="xriResolver">
+ <xs:annotation>
+ <xs:documentation>
+ Controls XRI resolution to XRDS documents.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
- <xs:attribute name="enabled" type="xs:boolean" />
- <xs:attribute name="proxy" type="xs:string" />
+ <xs:attribute name="enabled" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Controls whether XRI identifiers are allowed at all.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="proxy" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The XRI proxy resolver to use for obtaining XRDS documents from an XRI.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
- <xs:attribute name="maxAuthenticationTime" type="xs:string" />
+ <xs:attribute name="maxAuthenticationTime" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time a user can take at the Provider while logging in before a relying party considers
+ the authentication lost.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="cacheDiscovery" type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ Whether the results of identifier discovery should be cached for a short time to improve performance
+ on subsequent requests, at the potential risk of reading stale data.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="oauth">
+ <xs:annotation>
+ <xs:documentation>
+ Settings for OAuth consumers and service providers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="consumer">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth Consumers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings applicable to OAuth Consumers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
</xs:complexType>
@@ -287,24 +676,70 @@
</xs:complexType>
</xs:element>
<xs:element name="serviceProvider">
+ <xs:annotation>
+ <xs:documentation>
+ Settings applicable to OAuth Service Providers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="security">
+ <xs:annotation>
+ <xs:documentation>
+ Security settings applicable to OAuth Service Providers.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
<xs:attribute name="minimumRequiredOAuthVersion" default="V10">
+ <xs:annotation>
+ <xs:documentation>
+ Optionally restricts interoperability with OAuth consumers that implement
+ older versions of OAuth.
+ </xs:documentation>
+ </xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
- <xs:enumeration value="V10" />
- <xs:enumeration value="V10a" />
+ <xs:enumeration value="V10">
+ <xs:annotation>
+ <xs:documentation>
+ The initial version of OAuth, now known to be vulnerable to certain social engineering attacks.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="V10a">
+ <xs:annotation>
+ <xs:documentation>
+ The OAuth version that protects against social engineering attacks by introducing
+ the oauth_verifier parameter.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
- <xs:attribute name="maxAuthorizationTime" type="xs:string" default="0:05" />
+ <xs:attribute name="maxAuthorizationTime" type="xs:string" default="0:05">
+ <xs:annotation>
+ <xs:documentation>
+ The maximum time allowed for users to authorize a consumer before request tokens expire.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="store">
+ <xs:annotation>
+ <xs:documentation>
+ Sets the custom type that implements the INonceStore interface to use for nonce checking.
+ </xs:documentation>
+ </xs:annotation>
<xs:complexType>
- <xs:attribute name="type" type="xs:string"/>
+ <xs:attribute name="type" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ A fully-qualified type name of the custom implementation of INonceStore.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
</xs:complexType>
</xs:element>
</xs:choice>
diff --git a/src/DotNetOpenAuth/Configuration/OpenIdElement.cs b/src/DotNetOpenAuth/Configuration/OpenIdElement.cs
index 58a8276..385185a 100644
--- a/src/DotNetOpenAuth/Configuration/OpenIdElement.cs
+++ b/src/DotNetOpenAuth/Configuration/OpenIdElement.cs
@@ -104,10 +104,10 @@ namespace DotNetOpenAuth.Configuration {
}
/// <summary>
- /// Gets or sets the registered OpenID extensions.
+ /// Gets or sets the registered OpenID extension factories.
/// </summary>
[ConfigurationProperty(ExtensionFactoriesElementName, IsDefaultCollection = false)]
- [ConfigurationCollection(typeof(TypeConfigurationCollection<IOpenIdMessageExtension>))]
+ [ConfigurationCollection(typeof(TypeConfigurationCollection<IOpenIdExtensionFactory>))]
internal TypeConfigurationCollection<IOpenIdExtensionFactory> ExtensionFactories {
get { return (TypeConfigurationCollection<IOpenIdExtensionFactory>)this[ExtensionFactoriesElementName] ?? new TypeConfigurationCollection<IOpenIdExtensionFactory>(); }
set { this[ExtensionFactoriesElementName] = value; }
diff --git a/src/DotNetOpenAuth/GlobalSuppressions.cs b/src/DotNetOpenAuth/GlobalSuppressions.cs
index d0e0d05..56daae9 100644
--- a/src/DotNetOpenAuth/GlobalSuppressions.cs
+++ b/src/DotNetOpenAuth/GlobalSuppressions.cs
@@ -48,3 +48,4 @@
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "icam", Scope = "resource", Target = "DotNetOpenAuth.OpenId.Behaviors.BehaviorStrings.resources")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "idmanagement", Scope = "resource", Target = "DotNetOpenAuth.OpenId.Behaviors.BehaviorStrings.resources")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1703:ResourceStringsShouldBeSpelledCorrectly", MessageId = "no-pii", Scope = "resource", Target = "DotNetOpenAuth.OpenId.Behaviors.BehaviorStrings.resources")]
+[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly")]
diff --git a/src/DotNetOpenAuth/InfoCard/ReceivedTokenEventArgs.cs b/src/DotNetOpenAuth/InfoCard/ReceivedTokenEventArgs.cs
index 1511e2d..b91b82f 100644
--- a/src/DotNetOpenAuth/InfoCard/ReceivedTokenEventArgs.cs
+++ b/src/DotNetOpenAuth/InfoCard/ReceivedTokenEventArgs.cs
@@ -33,7 +33,7 @@ namespace DotNetOpenAuth.InfoCard {
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
[ContractInvariantMethod]
- protected void ObjectInvariant() {
+ private void ObjectInvariant() {
Contract.Invariant(this.Token != null);
}
#endif
diff --git a/src/DotNetOpenAuth/InfoCard/ReceivingTokenEventArgs.cs b/src/DotNetOpenAuth/InfoCard/ReceivingTokenEventArgs.cs
index f3722d7..d78329f 100644
--- a/src/DotNetOpenAuth/InfoCard/ReceivingTokenEventArgs.cs
+++ b/src/DotNetOpenAuth/InfoCard/ReceivingTokenEventArgs.cs
@@ -83,7 +83,7 @@ namespace DotNetOpenAuth.InfoCard {
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
[ContractInvariantMethod]
- protected void ObjectInvariant() {
+ private void ObjectInvariant() {
Contract.Invariant(this.TokenXml != null);
Contract.Invariant(this.DecryptingTokens != null);
}
diff --git a/src/DotNetOpenAuth/InfoCard/Token/TokenDecryptor.cs b/src/DotNetOpenAuth/InfoCard/Token/TokenDecryptor.cs
index 1038ad7..15330e9 100644
--- a/src/DotNetOpenAuth/InfoCard/Token/TokenDecryptor.cs
+++ b/src/DotNetOpenAuth/InfoCard/Token/TokenDecryptor.cs
@@ -150,7 +150,7 @@ namespace DotNetOpenAuth.InfoCard {
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
[ContractInvariantMethod]
- protected void ObjectInvariant() {
+ private void ObjectInvariant() {
Contract.Invariant(this.Tokens != null);
}
#endif
diff --git a/src/DotNetOpenAuth/InfoCard/TokenProcessingErrorEventArgs.cs b/src/DotNetOpenAuth/InfoCard/TokenProcessingErrorEventArgs.cs
index 1132ac0..fa72c98 100644
--- a/src/DotNetOpenAuth/InfoCard/TokenProcessingErrorEventArgs.cs
+++ b/src/DotNetOpenAuth/InfoCard/TokenProcessingErrorEventArgs.cs
@@ -40,7 +40,7 @@ namespace DotNetOpenAuth.InfoCard {
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
[ContractInvariantMethod]
- protected void ObjectInvariant() {
+ private void ObjectInvariant() {
Contract.Invariant(this.TokenXml != null);
Contract.Invariant(this.Exception != null);
}
diff --git a/src/DotNetOpenAuth/Loggers/ILog.cs b/src/DotNetOpenAuth/Loggers/ILog.cs
index 4ddbd49..8094296 100644
--- a/src/DotNetOpenAuth/Loggers/ILog.cs
+++ b/src/DotNetOpenAuth/Loggers/ILog.cs
@@ -21,7 +21,7 @@
// This interface is designed to look like log4net's ILog interface.
// We have this as a facade in front of it to avoid crashing if the
// hosting web site chooses not to deploy log4net.dll along with
-// dotnetopenid.dll.
+// DotNetOpenAuth.dll.
namespace DotNetOpenAuth.Loggers
{
diff --git a/src/DotNetOpenAuth/Messaging/EmptyDictionary.cs b/src/DotNetOpenAuth/Messaging/EmptyDictionary.cs
index 22c947a..0418d21 100644
--- a/src/DotNetOpenAuth/Messaging/EmptyDictionary.cs
+++ b/src/DotNetOpenAuth/Messaging/EmptyDictionary.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.Messaging {
using System;
using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
using System.Linq;
/// <summary>
@@ -153,6 +154,7 @@ namespace DotNetOpenAuth.Messaging {
/// <exception cref="T:System.NotSupportedException">
/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </exception>
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Code Contracts ccrewrite does this.")]
public void Add(KeyValuePair<TKey, TValue> item) {
throw new NotSupportedException();
}
diff --git a/src/DotNetOpenAuth/Messaging/EmptyList.cs b/src/DotNetOpenAuth/Messaging/EmptyList.cs
index b418623..afe2c89 100644
--- a/src/DotNetOpenAuth/Messaging/EmptyList.cs
+++ b/src/DotNetOpenAuth/Messaging/EmptyList.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.Messaging {
using System;
using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
/// <summary>
/// An empty, read-only list.
@@ -98,6 +99,7 @@ namespace DotNetOpenAuth.Messaging {
/// <exception cref="T:System.NotSupportedException">
/// The <see cref="T:System.Collections.Generic.IList`1"/> is read-only.
/// </exception>
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Code Contracts ccrewrite does this.")]
public void RemoveAt(int index) {
throw new ArgumentOutOfRangeException("index");
}
@@ -113,6 +115,7 @@ namespace DotNetOpenAuth.Messaging {
/// <exception cref="T:System.NotSupportedException">
/// The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
/// </exception>
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Code Contracts ccrewrite does this.")]
public void Add(T item) {
throw new NotSupportedException();
}
diff --git a/src/DotNetOpenAuth/Messaging/EnumerableCache.cs b/src/DotNetOpenAuth/Messaging/EnumerableCache.cs
index d343410..b64491b 100644
--- a/src/DotNetOpenAuth/Messaging/EnumerableCache.cs
+++ b/src/DotNetOpenAuth/Messaging/EnumerableCache.cs
@@ -136,7 +136,7 @@ namespace DotNetOpenAuth.Messaging {
private int cachePosition = -1;
/// <summary>
- /// Initializes a new instance of the <see cref="EnumerableCache&lt;T&gt;.EnumeratorCache"/> class.
+ /// Initializes a new instance of the <see cref="EnumeratorCache"/> class.
/// </summary>
/// <param name="parent">The parent cached enumerable whose GetEnumerator method is calling this constructor.</param>
internal EnumeratorCache(EnumerableCache<T> parent) {
diff --git a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
index 5acd589..09edc01 100644
--- a/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
+++ b/src/DotNetOpenAuth/Messaging/HttpRequestInfo.cs
@@ -294,28 +294,24 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
- /// Gets the query or form data from the original request (before any URL rewriting has occurred.)
- /// </summary>
- /// <returns>A set of name=value pairs.</returns>
- [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Expensive call")]
- internal NameValueCollection GetQueryOrFormFromContext() {
- NameValueCollection query;
- if (this.HttpMethod == "GET") {
- query = this.QueryStringBeforeRewriting;
- } else {
- query = this.Form;
- }
- return query;
- }
-
- /// <summary>
/// Gets the public facing URL for the given incoming HTTP request.
/// </summary>
/// <param name="request">The request.</param>
- /// <returns>The URI that the outside world used to create this request.</returns>
- private static Uri GetPublicFacingUrl(HttpRequest request) {
+ /// <param name="serverVariables">The server variables to consider part of the request.</param>
+ /// <returns>
+ /// The URI that the outside world used to create this request.
+ /// </returns>
+ /// <remarks>
+ /// Although the <paramref name="serverVariables"/> value can be obtained from
+ /// <see cref="HttpRequest.ServerVariables"/>, it's useful to be able to pass them
+ /// in so we can simulate injected values from our unit tests since the actual property
+ /// is a read-only kind of <see cref="NameValueCollection"/>.
+ /// </remarks>
+ internal static Uri GetPublicFacingUrl(HttpRequest request, NameValueCollection serverVariables) {
Contract.Requires(request != null);
+ Contract.Requires(serverVariables != null);
ErrorUtilities.VerifyArgumentNotNull(request, "request");
+ ErrorUtilities.VerifyArgumentNotNull(serverVariables, "serverVariables");
// Due to URL rewriting, cloud computing (i.e. Azure)
// and web farms, etc., we have to be VERY careful about what
@@ -325,15 +321,14 @@ namespace DotNetOpenAuth.Messaging {
// So we use a variable that (at least from what I can tell) gives us
// the public URL:
#if !Mono // In ASP.NET MVC, Mono adds UrlRouting.axd to the URL here, which breaks OpenID return_to verification.
- if (request.ServerVariables["HTTP_HOST"] != null) {
+ if (serverVariables["HTTP_HOST"] != null) {
ErrorUtilities.VerifySupported(request.Url.Scheme == Uri.UriSchemeHttps || request.Url.Scheme == Uri.UriSchemeHttp, "Only HTTP and HTTPS are supported protocols.");
+ string scheme = serverVariables["HTTP_X_FORWARDED_PROTO"] ?? request.Url.Scheme;
+ Uri hostAndPort = new Uri(scheme + Uri.SchemeDelimiter + serverVariables["HTTP_HOST"]);
UriBuilder publicRequestUri = new UriBuilder(request.Url);
- Uri hostAndPort = new Uri(request.Url.Scheme + Uri.SchemeDelimiter + request.ServerVariables["HTTP_HOST"]);
+ publicRequestUri.Scheme = scheme;
publicRequestUri.Host = hostAndPort.Host;
publicRequestUri.Port = hostAndPort.Port;
- if (request.ServerVariables["HTTP_X_FORWARDED_PROTO"] != null) {
- publicRequestUri.Scheme = request.ServerVariables["HTTP_X_FORWARDED_PROTO"];
- }
return publicRequestUri.Uri;
} else {
#endif
@@ -352,6 +347,33 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Gets the query or form data from the original request (before any URL rewriting has occurred.)
+ /// </summary>
+ /// <returns>A set of name=value pairs.</returns>
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Expensive call")]
+ internal NameValueCollection GetQueryOrFormFromContext() {
+ NameValueCollection query;
+ if (this.HttpMethod == "GET") {
+ query = this.QueryStringBeforeRewriting;
+ } else {
+ query = this.Form;
+ }
+ return query;
+ }
+
+ /// <summary>
+ /// Gets the public facing URL for the given incoming HTTP request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>The URI that the outside world used to create this request.</returns>
+ private static Uri GetPublicFacingUrl(HttpRequest request) {
+ Contract.Requires(request != null);
+ ErrorUtilities.VerifyArgumentNotNull(request, "request");
+
+ return GetPublicFacingUrl(request, request.ServerVariables);
+ }
+
+ /// <summary>
/// Makes up a reasonable guess at the raw URL from the possibly rewritten URL.
/// </summary>
/// <param name="url">A full URL.</param>
diff --git a/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs b/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs
index 380e2d5..0f88247 100644
--- a/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs
+++ b/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs
@@ -78,7 +78,7 @@ namespace DotNetOpenAuth.Messaging {
/// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
/// <see cref="ProtocolException"/> to abstract away the transport and provide
/// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, shoud be Closed before throwing.</para>
+ /// value, if set, should be Closed before throwing.</para>
/// </remarks>
IncomingWebResponse GetResponse(HttpWebRequest request);
@@ -94,7 +94,7 @@ namespace DotNetOpenAuth.Messaging {
/// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
/// <see cref="ProtocolException"/> to abstract away the transport and provide
/// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, shoud be Closed before throwing.</para>
+ /// value, if set, should be Closed before throwing.</para>
/// </remarks>
IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options);
}
diff --git a/src/DotNetOpenAuth/Messaging/MessageSerializer.cs b/src/DotNetOpenAuth/Messaging/MessageSerializer.cs
index 1aafc11..63b639b 100644
--- a/src/DotNetOpenAuth/Messaging/MessageSerializer.cs
+++ b/src/DotNetOpenAuth/Messaging/MessageSerializer.cs
@@ -126,7 +126,7 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
[ContractInvariantMethod]
- protected void ObjectInvariant() {
+ private void ObjectInvariant() {
Contract.Invariant(this.messageType != null);
}
#endif
diff --git a/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs b/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs
index 147cd66..c013fae 100644
--- a/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs
+++ b/src/DotNetOpenAuth/Messaging/OutgoingWebResponse.cs
@@ -120,7 +120,7 @@ namespace DotNetOpenAuth.Messaging {
/// Automatically sends the appropriate response to the user agent
/// and ends execution on the current page or handler.
/// </summary>
- /// <exception cref="ThreadAbortException">Thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
+ /// <exception cref="ThreadAbortException">Typically thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
/// <remarks>
/// Requires a current HttpContext.
/// </remarks>
@@ -137,7 +137,7 @@ namespace DotNetOpenAuth.Messaging {
/// </summary>
/// <param name="context">The context of the HTTP request whose response should be set.
/// Typically this is <see cref="HttpContext.Current"/>.</param>
- /// <exception cref="ThreadAbortException">Thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
+ /// <exception cref="ThreadAbortException">Typically thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
public virtual void Send(HttpContext context) {
Contract.Requires(context != null);
ErrorUtilities.VerifyArgumentNotNull(context, "context");
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
index cadce44..8979693 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
@@ -136,7 +136,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
/// <param name="keys">The names of all parameters included in a message.</param>
/// <exception cref="ProtocolException">Thrown when required parts of a message are not in <paramref name="keys"/></exception>
private void EnsureRequiredMessagePartsArePresent(IEnumerable<string> keys) {
- var missingKeys = (from part in Mapping.Values
+ var missingKeys = (from part in this.Mapping.Values
where part.IsRequired && !keys.Contains(part.Name)
select part.Name).ToArray();
if (missingKeys.Length > 0) {
@@ -155,7 +155,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
/// <param name="partValues">A dictionary of key/value pairs that make up the serialized message.</param>
private void EnsureRequiredProtocolMessagePartsAreNotEmpty(IDictionary<string, string> partValues) {
string value;
- var emptyValuedKeys = (from part in Mapping.Values
+ var emptyValuedKeys = (from part in this.Mapping.Values
where !part.AllowEmpty && partValues.TryGetValue(part.Name, out value) && value != null && value.Length == 0
select part.Name).ToArray();
if (emptyValuedKeys.Length > 0) {
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs
index 0b5b6d0..db5903e 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDictionary.cs
@@ -9,6 +9,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
/// <summary>
@@ -270,6 +271,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
/// Sets a named value in the message.
/// </summary>
/// <param name="item">The name-value pair to add. The name is the serialized form of the key.</param>
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Code Contracts ccrewrite does this.")]
public void Add(KeyValuePair<string, string> item) {
this.Add(item.Key, item.Value);
}
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
index f4bc3fe..26c0526 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
@@ -114,9 +114,25 @@ namespace DotNetOpenAuth.Messaging.Reflection {
if (attribute.Encoder == null) {
if (!converters.TryGetValue(this.memberDeclaredType, out this.converter)) {
- this.converter = new ValueMapping(
- obj => obj != null ? obj.ToString() : null,
- str => str != null ? Convert.ChangeType(str, this.memberDeclaredType, CultureInfo.InvariantCulture) : null);
+ if (this.memberDeclaredType.IsGenericType &&
+ this.memberDeclaredType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
+ // It's a nullable type. Try again to look up an appropriate converter for the underlying type.
+ Type underlyingType = Nullable.GetUnderlyingType(this.memberDeclaredType);
+ ValueMapping underlyingMapping;
+ if (converters.TryGetValue(underlyingType, out underlyingMapping)) {
+ this.converter = new ValueMapping(
+ underlyingMapping.ValueToString,
+ str => str != null ? underlyingMapping.StringToValue(str) : null);
+ } else {
+ this.converter = new ValueMapping(
+ obj => obj != null ? obj.ToString() : null,
+ str => str != null ? Convert.ChangeType(str, underlyingType, CultureInfo.InvariantCulture) : null);
+ }
+ } else {
+ this.converter = new ValueMapping(
+ obj => obj != null ? obj.ToString() : null,
+ str => str != null ? Convert.ChangeType(str, this.memberDeclaredType, CultureInfo.InvariantCulture) : null);
+ }
}
} else {
this.converter = new ValueMapping(GetEncoder(attribute.Encoder));
@@ -239,7 +255,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
}
/// <summary>
- /// Adds a pair of type conversion functions to the static converstion map.
+ /// Adds a pair of type conversion functions to the static conversion map.
/// </summary>
/// <typeparam name="T">The custom type to convert to and from strings.</typeparam>
/// <param name="toString">The function to convert the custom type to a string.</param>
diff --git a/src/DotNetOpenAuth/Messaging/StandardWebRequestHandler.cs b/src/DotNetOpenAuth/Messaging/StandardWebRequestHandler.cs
index cc991cd..0ed0b5c 100644
--- a/src/DotNetOpenAuth/Messaging/StandardWebRequestHandler.cs
+++ b/src/DotNetOpenAuth/Messaging/StandardWebRequestHandler.cs
@@ -95,7 +95,7 @@ namespace DotNetOpenAuth.Messaging {
/// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
/// <see cref="ProtocolException"/> to abstract away the transport and provide
/// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, shoud be Closed before throwing.</para>
+ /// value, if set, should be Closed before throwing.</para>
/// </remarks>
public IncomingWebResponse GetResponse(HttpWebRequest request) {
return this.GetResponse(request, DirectWebRequestOptions.None);
@@ -115,7 +115,7 @@ namespace DotNetOpenAuth.Messaging {
/// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
/// <see cref="ProtocolException"/> to abstract away the transport and provide
/// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, shoud be Closed before throwing.</para>
+ /// value, if set, should be Closed before throwing.</para>
/// </remarks>
public IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options) {
ErrorUtilities.VerifyArgumentNotNull(request, "request");
diff --git a/src/DotNetOpenAuth/Messaging/UntrustedWebRequestHandler.cs b/src/DotNetOpenAuth/Messaging/UntrustedWebRequestHandler.cs
index 1656155..f68ac73 100644
--- a/src/DotNetOpenAuth/Messaging/UntrustedWebRequestHandler.cs
+++ b/src/DotNetOpenAuth/Messaging/UntrustedWebRequestHandler.cs
@@ -230,7 +230,7 @@ namespace DotNetOpenAuth.Messaging {
/// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
/// <see cref="ProtocolException"/> to abstract away the transport and provide
/// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, shoud be Closed before throwing.</para>
+ /// value, if set, should be Closed before throwing.</para>
/// </remarks>
[SuppressMessage("Microsoft.Usage", "CA2234:PassSystemUriObjectsInsteadOfStrings", Justification = "Uri(Uri, string) accepts second arguments that Uri(Uri, new Uri(string)) does not that we must support.")]
public IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options) {
@@ -299,7 +299,7 @@ namespace DotNetOpenAuth.Messaging {
/// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
/// <see cref="ProtocolException"/> to abstract away the transport and provide
/// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
- /// value, if set, shoud be Closed before throwing.</para>
+ /// value, if set, should be Closed before throwing.</para>
/// </remarks>
IncomingWebResponse IDirectWebRequestHandler.GetResponse(HttpWebRequest request) {
return this.GetResponse(request, DirectWebRequestOptions.None);
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
index d325825..a4be672 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/OAuthChannel.cs
@@ -139,6 +139,8 @@ namespace DotNetOpenAuth.OAuth.ChannelElements {
}
}
}
+
+ fields.Remove("realm"); // ignore the realm parameter, since we don't use it, and it must be omitted from signature base string.
}
// Scrape the entity
diff --git a/src/DotNetOpenAuth/OAuth/ConsumerBase.cs b/src/DotNetOpenAuth/OAuth/ConsumerBase.cs
index 55b40ac..bc78c63 100644
--- a/src/DotNetOpenAuth/OAuth/ConsumerBase.cs
+++ b/src/DotNetOpenAuth/OAuth/ConsumerBase.cs
@@ -208,7 +208,7 @@ namespace DotNetOpenAuth.OAuth {
// Fine-tune our understanding of the SP's supported OAuth version if it's wrong.
if (this.ServiceProvider.Version != requestTokenResponse.Version) {
- Logger.OAuth.WarnFormat("Expected OAuth service provider at endpoint {0} to use OAuth {1} but {2} was detected. Adjusting service description to new version.", this.ServiceProvider.RequestTokenEndpoint, this.ServiceProvider.Version, requestTokenResponse.Version);
+ Logger.OAuth.WarnFormat("Expected OAuth service provider at endpoint {0} to use OAuth {1} but {2} was detected. Adjusting service description to new version.", this.ServiceProvider.RequestTokenEndpoint.Location, this.ServiceProvider.Version, requestTokenResponse.Version);
this.ServiceProvider.ProtocolVersion = Protocol.Lookup(requestTokenResponse.Version).ProtocolVersion;
}
diff --git a/src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs b/src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs
index 13633b4..7a20fd5 100644
--- a/src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs
+++ b/src/DotNetOpenAuth/OpenId/AssociationMemoryStore.cs
@@ -20,12 +20,22 @@ namespace DotNetOpenAuth.OpenId {
/// </remarks>
internal class AssociationMemoryStore<TKey> : IAssociationStore<TKey> {
/// <summary>
+ /// How many association store requests should occur between each spring cleaning.
+ /// </summary>
+ private const int PeriodicCleaningFrequency = 10;
+
+ /// <summary>
/// For Relying Parties, this maps OP Endpoints to a set of associations with that endpoint.
/// For Providers, this keeps smart and dumb associations in two distinct pools.
/// </summary>
private Dictionary<TKey, Associations> serverAssocsTable = new Dictionary<TKey, Associations>();
/// <summary>
+ /// A counter to track how close we are to an expired association cleaning run.
+ /// </summary>
+ private int periodicCleaning;
+
+ /// <summary>
/// Stores a given association for later recall.
/// </summary>
/// <param name="distinguishingFactor">The distinguishing factor, either an OP Endpoint or smart/dumb mode.</param>
@@ -38,6 +48,13 @@ namespace DotNetOpenAuth.OpenId {
Associations server_assocs = this.serverAssocsTable[distinguishingFactor];
server_assocs.Set(association);
+
+ unchecked {
+ this.periodicCleaning++;
+ }
+ if (this.periodicCleaning % PeriodicCleaningFrequency == 0) {
+ this.ClearExpiredAssociations();
+ }
}
}
@@ -88,17 +105,6 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
- /// Clears all expired associations from the store.
- /// </summary>
- public void ClearExpiredAssociations() {
- lock (this) {
- foreach (Associations assocs in this.serverAssocsTable.Values) {
- assocs.ClearExpired();
- }
- }
- }
-
- /// <summary>
/// Gets the server associations for a given OP Endpoint or dumb/smart mode.
/// </summary>
/// <param name="distinguishingFactor">The distinguishing factor, either an OP Endpoint (for relying parties) or smart/dumb (for providers).</param>
@@ -112,5 +118,16 @@ namespace DotNetOpenAuth.OpenId {
return this.serverAssocsTable[distinguishingFactor];
}
}
+
+ /// <summary>
+ /// Clears all expired associations from the store.
+ /// </summary>
+ private void ClearExpiredAssociations() {
+ lock (this) {
+ foreach (Associations assocs in this.serverAssocsTable.Values) {
+ assocs.ClearExpired();
+ }
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs b/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs
index d7dca9a..01b74a1 100644
--- a/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs
+++ b/src/DotNetOpenAuth/OpenId/Behaviors/AXFetchAsSregTransform.cs
@@ -23,7 +23,7 @@ namespace DotNetOpenAuth.OpenId.Behaviors {
/// to the originally requested extension and format.
/// </summary>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Sreg", Justification = "Abbreviation")]
- public class AXFetchAsSregTransform : IRelyingPartyBehavior, IProviderBehavior {
+ public sealed class AXFetchAsSregTransform : IRelyingPartyBehavior, IProviderBehavior {
/// <summary>
/// Initializes static members of the <see cref="AXFetchAsSregTransform"/> class.
/// </summary>
@@ -65,7 +65,10 @@ namespace DotNetOpenAuth.OpenId.Behaviors {
/// without malfunctioning.
/// </remarks>
void IRelyingPartyBehavior.OnOutgoingAuthenticationRequest(RelyingParty.IAuthenticationRequest request) {
- request.SpreadSregToAX(AXFormats);
+ // Don't create AX extensions for OpenID 1.x messages, since AX requires OpenID 2.0.
+ if (request.Provider.Version.Major >= 2) {
+ request.SpreadSregToAX(AXFormats);
+ }
}
/// <summary>
@@ -112,12 +115,7 @@ namespace DotNetOpenAuth.OpenId.Behaviors {
bool IProviderBehavior.OnIncomingRequest(IRequest request) {
var extensionRequest = request as Provider.HostProcessedRequest;
if (extensionRequest != null) {
- if (extensionRequest.GetExtension<ClaimsRequest>() == null) {
- ClaimsRequest sreg = extensionRequest.UnifyExtensionsAsSreg();
- if (sreg != null) {
- ((IProtocolMessageWithExtensions)extensionRequest.RequestMessage).Extensions.Add(sreg);
- }
- }
+ extensionRequest.UnifyExtensionsAsSreg();
}
return false;
diff --git a/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs b/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs
index 9c4c46d..6dbc455 100644
--- a/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs
+++ b/src/DotNetOpenAuth/OpenId/ChannelElements/ReturnToNonceBindingElement.cs
@@ -209,7 +209,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
}
/// <summary>
- /// A special DotNetOpenId-only nonce used by the RP when talking to 1.0 OPs in order
+ /// A special DotNetOpenAuth-only nonce used by the RP when talking to 1.0 OPs in order
/// to protect against replay attacks.
/// </summary>
private class CustomNonce {
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs
index e508233..42393f5 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeRequest.cs
@@ -14,6 +14,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
/// the Attribute Exchange extension.
/// </summary>
[Serializable]
+ [DebuggerDisplay("{TypeUri} (required: {IsRequired}) ({Count})")]
public class AttributeRequest {
/// <summary>
/// Backing field for the <see cref="Count"/> property.
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs
index e87e188..9047b68 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/AttributeValues.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
using System;
using System.Collections.Generic;
+ using System.Diagnostics;
using DotNetOpenAuth.Messaging;
/// <summary>
@@ -15,6 +16,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
/// a fetch request, or by a relying party as part of a store request.
/// </summary>
[Serializable]
+ [DebuggerDisplay("{TypeUri}")]
public class AttributeValues {
/// <summary>
/// Initializes a new instance of the <see cref="AttributeValues"/> class.
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs
index a69e226..124a18c 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchRequest.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
+ using System.Diagnostics.Contracts;
using System.Globalization;
using System.Linq;
using DotNetOpenAuth.Messaging;
@@ -67,7 +68,10 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
/// <value>A collection where the keys are the attribute type URIs, and the value
/// is all the attribute request details.</value>
public KeyedCollection<string, AttributeRequest> Attributes {
- get { return this.attributes; }
+ get {
+ Contract.Ensures(Contract.Result<KeyedCollection<string, AttributeRequest>>() != null);
+ return this.attributes;
+ }
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs
index 758b20c..14b1caa 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/AttributeExchange/FetchResponse.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
using System;
using System.Collections.ObjectModel;
+ using System.Diagnostics.Contracts;
using System.Linq;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Messages;
@@ -52,7 +53,10 @@ namespace DotNetOpenAuth.OpenId.Extensions.AttributeExchange {
/// Gets a sequence of the attributes whose values are provided by the OpenID Provider.
/// </summary>
public KeyedCollection<string, AttributeValues> Attributes {
- get { return this.attributesProvided; }
+ get {
+ Contract.Ensures(Contract.Result<KeyedCollection<string, AttributeValues>>() != null);
+ return this.attributesProvided;
+ }
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs
index 36358a7..8cfe0b7 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/ExtensionsInteropHelper.cs
@@ -132,7 +132,8 @@ namespace DotNetOpenAuth.OpenId.Extensions {
/// <summary>
/// Looks for Simple Registration and Attribute Exchange (all known formats)
- /// request extensions and returns them as a Simple Registration extension.
+ /// request extensions and returns them as a Simple Registration extension,
+ /// and adds the new extension to the original request message if it was absent.
/// </summary>
/// <param name="request">The authentication request.</param>
/// <returns>
@@ -143,7 +144,7 @@ namespace DotNetOpenAuth.OpenId.Extensions {
Contract.Requires(request != null);
ErrorUtilities.VerifyArgumentNotNull(request, "request");
- var req = (Provider.AuthenticationRequest)request;
+ var req = (Provider.HostProcessedRequest)request;
var sreg = req.GetExtension<ClaimsRequest>();
if (sreg != null) {
return sreg;
@@ -151,7 +152,7 @@ namespace DotNetOpenAuth.OpenId.Extensions {
var ax = req.GetExtension<FetchRequest>();
if (ax != null) {
- sreg = new ClaimsRequest();
+ sreg = new ClaimsRequest(SimpleRegistration.Constants.sreg_ns);
sreg.Synthesized = true;
((IProtocolMessageWithExtensions)req.RequestMessage).Extensions.Add(sreg);
sreg.BirthDate = GetDemandLevelFor(ax, WellKnownAttributes.BirthDate.WholeBirthDate);
@@ -179,9 +180,9 @@ namespace DotNetOpenAuth.OpenId.Extensions {
/// </remarks>
internal static void ConvertSregToMatchRequest(this Provider.IHostProcessedRequest request) {
var req = (Provider.HostProcessedRequest)request;
- var response = (IProtocolMessageWithExtensions)req.Response;
+ var response = req.Response as IProtocolMessageWithExtensions; // negative responses don't support extensions.
var sregRequest = request.GetExtension<ClaimsRequest>();
- if (sregRequest != null) {
+ if (sregRequest != null && response != null) {
if (sregRequest.Synthesized) {
var axRequest = request.GetExtension<FetchRequest>();
ErrorUtilities.VerifyInternal(axRequest != null, "How do we have a synthesized Sreg request without an AX request?");
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs b/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs
index 0a3147a..3031aad 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/ProviderAuthenticationPolicy/NistAssuranceLevel.cs
@@ -18,7 +18,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.ProviderAuthenticationPolicy {
/// <remarks>
/// <para>One using this enum should review the following publication for details
/// before asserting or interpreting what these levels signify, notwithstanding
- /// the brief summaries attached to each level in DotNetOpenId documentation.
+ /// the brief summaries attached to each level in DotNetOpenAuth documentation.
/// http://csrc.nist.gov/publications/nistpubs/800-63/SP800-63V1_0_2.pdf</para>
/// <para>
/// See PAPE spec Appendix A.1.2 (NIST Assurance Levels) for high-level example classifications of authentication methods within the defined levels.
diff --git a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs
index bee675d..ae483a6 100644
--- a/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/Extensions/UI/UIRequest.cs
@@ -31,6 +31,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI {
/// <see cref="IProviderEndpoint.IsExtensionSupported"/> method on the <see cref="DotNetOpenAuth.OpenId.RelyingParty.IAuthenticationRequest.Provider"/>
/// object.</para>
/// </remarks>
+ [Serializable]
public sealed class UIRequest : IOpenIdMessageExtension, IMessageWithEvents {
/// <summary>
/// The factory method that may be used in deserialization of this message.
@@ -71,6 +72,7 @@ namespace DotNetOpenAuth.OpenId.Extensions.UI {
/// <remarks>
/// The user's preferred languages as a [BCP 47] language priority list, represented as a comma-separated list of BCP 47 basic language ranges in descending priority order. For instance, the value "fr-CA,fr-FR,en-CA" represents the preference for French spoken in Canada, French spoken in France, followed by English spoken in Canada.
/// </remarks>
+ [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays", Justification = "By design.")]
[MessagePart("lang", AllowEmpty = false)]
public CultureInfo[] LanguagePreference { get; set; }
diff --git a/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs b/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
index 4c31100..36a874d 100644
--- a/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
+++ b/src/DotNetOpenAuth/OpenId/HmacShaAssociation.cs
@@ -136,7 +136,7 @@ namespace DotNetOpenAuth.OpenId {
/// Creates a new association of a given type.
/// </summary>
/// <param name="protocol">The protocol.</param>
- /// <param name="associationType">Type of the association.</param>
+ /// <param name="associationType">Type of the association (i.e. HMAC-SHA1 or HMAC-SHA256)</param>
/// <param name="associationUse">A value indicating whether the new association will be used privately by the Provider for "dumb mode" authentication
/// or shared with the Relying Party for "smart mode" authentication.</param>
/// <param name="securitySettings">The security settings of the Provider.</param>
diff --git a/src/DotNetOpenAuth/OpenId/IAssociationStore.cs b/src/DotNetOpenAuth/OpenId/IAssociationStore.cs
index 2376b0d..a3c5305 100644
--- a/src/DotNetOpenAuth/OpenId/IAssociationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/IAssociationStore.cs
@@ -33,6 +33,12 @@ namespace DotNetOpenAuth.OpenId {
/// <see cref="System.Uri"/> for consumers (to distinguish associations across servers) or
/// <see cref="AssociationRelyingPartyType"/> for providers (to distinguish dumb and smart client associations).
/// </typeparam>
+ /// <remarks>
+ /// Expired associations should be periodically cleared out of an association store.
+ /// This should be done frequently enough to avoid a memory leak, but sparingly enough
+ /// to not be a performance drain. Because this balance can vary by host, it is the
+ /// responsibility of the host to initiate this cleaning.
+ /// </remarks>
public interface IAssociationStore<TKey> {
/// <summary>
/// Saves an <see cref="Association"/> for later recall.
@@ -80,16 +86,5 @@ namespace DotNetOpenAuth.OpenId {
/// before this call.
/// </remarks>
bool RemoveAssociation(TKey distinguishingFactor, string handle);
-
- /// <summary>
- /// Clears all expired associations from the store.
- /// </summary>
- /// <remarks>
- /// If another algorithm is in place to periodically clear out expired associations,
- /// this method call may be ignored.
- /// This should be done frequently enough to avoid a memory leak, but sparingly enough
- /// to not be a performance drain.
- /// </remarks>
- void ClearExpiredAssociations();
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs b/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs
index 399a84f..e5e89bd 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/PrivatePersonalIdentifierProviderBase.cs
@@ -220,7 +220,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
[ContractInvariantMethod]
- protected void ObjectInvariant() {
+ private void ObjectInvariant() {
Contract.Invariant(this.Hasher != null);
Contract.Invariant(this.Encoder != null);
Contract.Invariant(this.BaseIdentifier != null);
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
index 49d18e0..a87b0f6 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderEndpoint.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
using System;
using System.Collections.Generic;
using System.ComponentModel;
+ using System.Diagnostics.Contracts;
using System.Text;
using System.Web;
using System.Web.UI;
@@ -42,7 +43,12 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <summary>
/// Backing field for the <see cref="Provider"/> property.
/// </summary>
- private static OpenIdProvider provider = CreateProvider();
+ private static OpenIdProvider provider;
+
+ /// <summary>
+ /// The lock that must be obtained when initializing the provider field.
+ /// </summary>
+ private static object providerInitializerLock = new object();
/// <summary>
/// Fired when an incoming OpenID request is an authentication challenge
@@ -63,6 +69,15 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// <value>The default value is an <see cref="OpenIdProvider"/> instance initialized according to the web.config file.</value>
public static OpenIdProvider Provider {
get {
+ Contract.Ensures(Contract.Result<OpenIdProvider>() != null);
+ if (provider == null) {
+ lock (providerInitializerLock) {
+ if (provider == null) {
+ provider = CreateProvider();
+ }
+ }
+ }
+
return provider;
}
@@ -82,8 +97,14 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// before responding to the relying party's authentication request.
/// </remarks>
public static IAuthenticationRequest PendingAuthenticationRequest {
- get { return HttpContext.Current.Session[PendingRequestKey] as IAuthenticationRequest; }
- set { HttpContext.Current.Session[PendingRequestKey] = value; }
+ get {
+ Contract.Ensures(Contract.Result<IAuthenticationRequest>() == null || PendingRequest != null);
+ return HttpContext.Current.Session[PendingRequestKey] as IAuthenticationRequest;
+ }
+
+ set {
+ HttpContext.Current.Session[PendingRequestKey] = value;
+ }
}
/// <summary>
@@ -96,8 +117,14 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// before responding to the relying party's request.
/// </remarks>
public static IAnonymousRequest PendingAnonymousRequest {
- get { return HttpContext.Current.Session[PendingRequestKey] as IAnonymousRequest; }
- set { HttpContext.Current.Session[PendingRequestKey] = value; }
+ get {
+ Contract.Ensures(Contract.Result<IAnonymousRequest>() == null || PendingRequest != null);
+ return HttpContext.Current.Session[PendingRequestKey] as IAnonymousRequest;
+ }
+
+ set {
+ HttpContext.Current.Session[PendingRequestKey] = value;
+ }
}
/// <summary>
@@ -158,7 +185,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
// Then try the configuration file specified one. Finally, use the default
// in-memory one that's built into OpenIdProvider.
// determine what incoming message was received
- IRequest request = provider.GetRequest();
+ IRequest request = Provider.GetRequest();
if (request != null) {
PendingRequest = null;
@@ -178,7 +205,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
}
}
if (request.IsResponseReady) {
- provider.SendResponse(request);
+ Provider.SendResponse(request);
Page.Response.End();
PendingAuthenticationRequest = null;
}
@@ -217,6 +244,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
/// <returns>The new instance of OpenIdProvider.</returns>
private static OpenIdProvider CreateProvider() {
+ Contract.Ensures(Contract.Result<OpenIdProvider>() != null);
return new OpenIdProvider(DotNetOpenAuthSection.Configuration.OpenId.Provider.ApplicationStore.CreateInstance(OpenIdProvider.HttpApplicationStore));
}
}
diff --git a/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs b/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs
index 9590033..d5fa4a9 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/ProviderSecuritySettings.cs
@@ -9,6 +9,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
+ using System.Diagnostics.CodeAnalysis;
using System.Linq;
using DotNetOpenAuth.Messaging;
@@ -51,6 +52,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// The behavior a Provider takes when verifying that it is authoritative for an
/// identifier it is about to send an unsolicited assertion for.
/// </summary>
+ [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "By design")]
public enum UnsolicitedAssertionVerificationLevel {
/// <summary>
/// Always verify that the Provider is authoritative for an identifier before
diff --git a/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs b/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs
index 7085e72..4fa2d64 100644
--- a/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/Provider/StandardProviderApplicationStore.cs
@@ -100,19 +100,6 @@ namespace DotNetOpenAuth.OpenId.Provider {
return this.associationStore.RemoveAssociation(distinguishingFactor, handle);
}
- /// <summary>
- /// Clears all expired associations from the store.
- /// </summary>
- /// <remarks>
- /// If another algorithm is in place to periodically clear out expired associations,
- /// this method call may be ignored.
- /// This should be done frequently enough to avoid a memory leak, but sparingly enough
- /// to not be a performance drain.
- /// </remarks>
- public void ClearExpiredAssociations() {
- this.associationStore.ClearExpiredAssociations();
- }
-
#endregion
#region INonceStore Members
@@ -122,7 +109,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// </summary>
/// <param name="context">The context, or namespace, within which the <paramref name="nonce"/> must be unique.</param>
/// <param name="nonce">A series of random characters.</param>
- /// <param name="timestamp">The timestamp that together with the nonce string make it unique.
+ /// <param name="timestampUtc">The timestamp that together with the nonce string make it unique.
/// The timestamp may also be used by the data store to clear out old nonces.</param>
/// <returns>
/// True if the nonce+timestamp (combination) was not previously in the database.
@@ -135,8 +122,8 @@ namespace DotNetOpenAuth.OpenId.Provider {
/// is retrieved or set using the
/// <see cref="StandardExpirationBindingElement.MaximumMessageAge"/> property.
/// </remarks>
- public bool StoreNonce(string context, string nonce, DateTime timestamp) {
- return this.nonceStore.StoreNonce(context, nonce, timestamp);
+ public bool StoreNonce(string context, string nonce, DateTime timestampUtc) {
+ return this.nonceStore.StoreNonce(context, nonce, timestampUtc);
}
#endregion
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs
index 85c0096..9af947a 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AssociationManager.cs
@@ -9,6 +9,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
using System.Collections.Generic;
using System.Linq;
using System.Net;
+ using System.Security;
using System.Text;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.ChannelElements;
@@ -147,10 +148,20 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
return null;
}
- var associateRequest = AssociateRequest.Create(this.securitySettings, provider);
-
- const int RenegotiateRetries = 1;
- return this.CreateNewAssociation(provider, associateRequest, RenegotiateRetries);
+ try {
+ var associateRequest = AssociateRequest.Create(this.securitySettings, provider);
+
+ const int RenegotiateRetries = 1;
+ return this.CreateNewAssociation(provider, associateRequest, RenegotiateRetries);
+ } catch (VerificationException ex) {
+ // See Trac ticket #163. In partial trust host environments, the
+ // Diffie-Hellman implementation we're using for HTTP OP endpoints
+ // sometimes causes the CLR to throw:
+ // "VerificationException: Operation could destabilize the runtime."
+ // Just give up and use dumb mode in this case.
+ Logger.OpenId.ErrorFormat("VerificationException occurred while trying to create an association with {0}. {1}", provider.Endpoint, ex);
+ return null;
+ }
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
index cea7d21..30ecfc9 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/AuthenticationRequest.cs
@@ -4,6 +4,8 @@
// </copyright>
//-----------------------------------------------------------------------
+using System.Threading;
+
namespace DotNetOpenAuth.OpenId.RelyingParty {
using System;
using System.Collections.Generic;
@@ -247,6 +249,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// <remarks>
/// This method requires an ASP.NET HttpContext.
/// </remarks>
+ /// <exception cref="ThreadAbortException">Typically thrown by ASP.NET in order to prevent additional data from the page being sent to the client and corrupting the response.</exception>
public void RedirectToProvider() {
this.RedirectingResponse.Send();
}
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs
index 6a4413f..5d7df71 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.cs
@@ -5,7 +5,6 @@
//-----------------------------------------------------------------------
[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdAjaxTextBox.EmbeddedScriptResourceName, "text/javascript")]
-[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdAjaxTextBox.EmbeddedDotNetOpenIdLogoResourceName, "image/gif")]
[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdAjaxTextBox.EmbeddedSpinnerResourceName, "image/gif")]
[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdAjaxTextBox.EmbeddedLoginSuccessResourceName, "image/png")]
[assembly: System.Web.UI.WebResource(DotNetOpenAuth.OpenId.RelyingParty.OpenIdAjaxTextBox.EmbeddedLoginFailureResourceName, "image/png")]
@@ -45,11 +44,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
internal const string EmbeddedScriptResourceName = Util.DefaultNamespace + ".OpenId.RelyingParty.OpenIdAjaxTextBox.js";
/// <summary>
- /// The name of the manifest stream containing the dotnetopenid_16x16.gif file.
- /// </summary>
- internal const string EmbeddedDotNetOpenIdLogoResourceName = Util.DefaultNamespace + ".OpenId.RelyingParty.dotnetopenid_16x16.gif";
-
- /// <summary>
/// The name of the manifest stream containing the spinner.gif file.
/// </summary>
internal const string EmbeddedSpinnerResourceName = Util.DefaultNamespace + ".OpenId.RelyingParty.spinner.gif";
@@ -1191,9 +1185,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
}
startupScript.AppendFormat(
CultureInfo.InvariantCulture,
- "initAjaxOpenId(box, {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, {17}, function({18}, {19}, {20}) {{{21}}});{22}",
+ "initAjaxOpenId(box, {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, function({17}, {18}, {19}) {{{20}}});{21}",
MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), OpenIdTextBox.EmbeddedLogoResourceName)),
- MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedDotNetOpenIdLogoResourceName)),
MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedSpinnerResourceName)),
MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedLoginSuccessResourceName)),
MessagingUtilities.GetSafeJavascriptValue(this.Page.ClientScript.GetWebResourceUrl(this.GetType(), EmbeddedLoginFailureResourceName)),
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.js b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.js
index 1078003..ec600b7 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.js
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdAjaxTextBox.js
@@ -38,7 +38,7 @@ Array.prototype.remove = function(element) {
}
};
-function initAjaxOpenId(box, openid_logo_url, dotnetopenid_logo_url, spinner_url, success_icon_url, failure_icon_url,
+function initAjaxOpenId(box, openid_logo_url, spinner_url, success_icon_url, failure_icon_url,
throttle, timeout, assertionReceivedCode,
loginButtonText, loginButtonToolTip, retryButtonText, retryButtonToolTip, busyToolTip,
identifierRequiredMessage, loginInProgressMessage,
@@ -221,8 +221,6 @@ function initAjaxOpenId(box, openid_logo_url, dotnetopenid_logo_url, spinner_url
box.dnoi_internal.success_icon = box.dnoi_internal.constructIcon(success_icon_url, authenticatedAsToolTip, true);
//box.dnoi_internal.failure_icon = box.dnoi_internal.constructIcon(failure_icon_url, authenticationFailedToolTip, true);
- // Disable the display of the DotNetOpenId logo
- //box.dnoi_internal.dnoi_logo = box.dnoi_internal.constructIcon(dotnetopenid_logo_url);
box.dnoi_internal.dnoi_logo = box.dnoi_internal.openid_logo;
box.dnoi_internal.setVisualCue = function(state, authenticatedBy, authenticatedAs) {
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
index 1fe6521..ff17410 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/OpenIdRelyingParty.cs
@@ -100,7 +100,10 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
// replay attacks. But only 2.0+ Providers can be expected to provide
// replay protection.
if (nonceStore == null) {
- this.SecuritySettings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20;
+ if (this.SecuritySettings.MinimumRequiredOpenIdVersion < ProtocolVersion.V20) {
+ Logger.OpenId.Warn("Raising minimum OpenID version requirement for Providers to 2.0 to protect this stateless RP from replay attacks.");
+ this.SecuritySettings.MinimumRequiredOpenIdVersion = ProtocolVersion.V20;
+ }
}
this.channel = new OpenIdChannel(associationStore, nonceStore, this.SecuritySettings);
diff --git a/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs b/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs
index 8499178..fdb6931 100644
--- a/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs
+++ b/src/DotNetOpenAuth/OpenId/RelyingParty/StandardRelyingPartyApplicationStore.cs
@@ -84,19 +84,6 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
return this.associationStore.RemoveAssociation(distinguishingFactor, handle);
}
- /// <summary>
- /// Clears all expired associations from the store.
- /// </summary>
- /// <remarks>
- /// If another algorithm is in place to periodically clear out expired associations,
- /// this method call may be ignored.
- /// This should be done frequently enough to avoid a memory leak, but sparingly enough
- /// to not be a performance drain.
- /// </remarks>
- public void ClearExpiredAssociations() {
- this.associationStore.ClearExpiredAssociations();
- }
-
#endregion
#region INonceStore Members
@@ -106,7 +93,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// </summary>
/// <param name="context">The context, or namespace, within which the <paramref name="nonce"/> must be unique.</param>
/// <param name="nonce">A series of random characters.</param>
- /// <param name="timestamp">The timestamp that together with the nonce string make it unique.
+ /// <param name="timestampUtc">The timestamp that together with the nonce string make it unique.
/// The timestamp may also be used by the data store to clear out old nonces.</param>
/// <returns>
/// True if the nonce+timestamp (combination) was not previously in the database.
@@ -119,8 +106,8 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// is retrieved or set using the
/// <see cref="StandardExpirationBindingElement.MaximumMessageAge"/> property.
/// </remarks>
- public bool StoreNonce(string context, string nonce, DateTime timestamp) {
- return this.nonceStore.StoreNonce(context, nonce, timestamp);
+ public bool StoreNonce(string context, string nonce, DateTime timestampUtc) {
+ return this.nonceStore.StoreNonce(context, nonce, timestampUtc);
}
#endregion
diff --git a/src/DotNetOpenAuth/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth/Properties/AssemblyInfo.cs
index 69d4dc4..0ffd104 100644
--- a/src/DotNetOpenAuth/Properties/AssemblyInfo.cs
+++ b/src/DotNetOpenAuth/Properties/AssemblyInfo.cs
@@ -4,18 +4,6 @@
// </copyright>
//-----------------------------------------------------------------------
-// Uncomment this line to build a partially trusted assembly.
-// This has some security bonuses in that if there was a way to
-// hijack this assembly to do something it is not designed to do,
-// it will fail before doing much damage.
-// But a partially trusted assembly's events, handled by the hosting
-// web site, will also be under the partial trust restriction.
-// Also note that http://support.microsoft.com/kb/839300 states a
-// strong-name signed assembly must use AllowPartiallyTrustedCallers
-// to be called from a web page, but defining PARTIAL_TRUST below also
-// accomplishes this.
-////#define PARTIAL_TRUST
-
// We DON'T put an AssemblyVersionAttribute in here because it is generated in the build.
using System;
@@ -69,33 +57,3 @@ using System.Web.UI;
#else
[assembly: InternalsVisibleTo("DotNetOpenAuth.Test")]
#endif
-
-// Specify what permissions are required and optional for the assembly.
-// In order for CAS to remove unnecessary privileges from this assembly (which is desirable
-// for security), we need at least one RequestMinimum and at least one RequestOptional.
-// These permissions were determined using PermCalc.exe
-
-// We need to be allowed to execute code. Besides, it gives a good baseline RequestMinimum permission.
-[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)]
-
-// Allows the consumer to call out to the web server. This is unnecessary in provider-only scenarios.
-// Note: we don't use a single demand for https?://.* because the regex pattern must exactly
-// match the one used by hosting providers. Listing them individually seems to be more common.
-[assembly: WebPermission(SecurityAction.RequestMinimum, ConnectPattern = @"http://.*")]
-[assembly: WebPermission(SecurityAction.RequestMinimum, ConnectPattern = @"https://.*")]
-
-#if PARTIAL_TRUST
-// Allows hosting this assembly in an ASP.NET setting. Not all applications
-// will host this using ASP.NET, so this is optional. Besides, we need at least
-// one optional permission to activate CAS permission shrinking.
-[assembly: AspNetHostingPermission(SecurityAction.RequestOptional, Level = AspNetHostingPermissionLevel.Medium)]
-
-// The following are only required for diagnostic logging (Trace.Write, Debug.Assert, etc.).
-#if TRACE || DEBUG
-[assembly: KeyContainerPermission(SecurityAction.RequestOptional, Unrestricted = true)]
-[assembly: ReflectionPermission(SecurityAction.RequestOptional, MemberAccess = true)]
-[assembly: RegistryPermission(SecurityAction.RequestOptional, Unrestricted = true)]
-[assembly: SecurityPermission(SecurityAction.RequestOptional, ControlEvidence = true, UnmanagedCode = true, ControlThread = true)]
-[assembly: FileIOPermission(SecurityAction.RequestOptional, AllFiles = FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read)]
-#endif
-#endif
diff --git a/tools/DotNetOpenAuth.Versioning.targets b/tools/DotNetOpenAuth.Versioning.targets
index f4b12b0..9ba295d 100644
--- a/tools/DotNetOpenAuth.Versioning.targets
+++ b/tools/DotNetOpenAuth.Versioning.targets
@@ -5,16 +5,26 @@
<PropertyGroup>
<ProjectRoot Condition="'$(ProjectRoot)' == ''">$(MSBuildProjectDirectory)\..\..</ProjectRoot>
<VersionCsFile>$(ProjectRoot)\obj\$(Configuration)\$(AssemblyName).Version.cs</VersionCsFile>
+ <NoWarn>$(NoWarn);1607</NoWarn>
</PropertyGroup>
<Import Project="$(ProjectRoot)\lib\DotNetOpenAuth.BuildTasks.targets" />
<UsingTask AssemblyFile="$(ProjectRoot)\lib\MSBuild.Community.Tasks.dll" TaskName="AssemblyInfo"/>
<Target Name="GetBuildVersion">
- <GetBuildVersion VersionFile="$(ProjectRoot)\src\version.txt" Condition=" '$(BuildVersion)' == '' ">
+ <GetBuildVersion Condition=" '$(BuildVersion)' == '' "
+ VersionFile="$(ProjectRoot)\src\version.txt"
+ GitRepoRoot="$(ProjectRoot)\">
<Output TaskParameter="Version" PropertyName="BuildVersion" />
+ <Output TaskParameter="GitCommitId" PropertyName="AssemblyInformationalVersion" />
</GetBuildVersion>
- <Message Text="Building version $(BuildVersion)"/>
+ <PropertyGroup>
+ <!-- In TeamCity, the build agent doesn't get the .git directory, but the commit id is available by other means. -->
+ <AssemblyInformationalVersion Condition=" '$(AssemblyInformationalVersion)' == '' ">$(BUILD_VCS_NUMBER)</AssemblyInformationalVersion>
+ </PropertyGroup>
+ <Warning Condition=" '$(AssemblyInformationalVersion)' == '' " Text="Unable to determine the git HEAD commit ID to use for informational version number." />
+ <Message Condition=" '$(AssemblyInformationalVersion)' != '' " Text="Building version $(BuildVersion) from commit $(AssemblyInformationalVersion)"/>
+ <Message Condition=" '$(AssemblyInformationalVersion)' == '' " Text="Building version $(BuildVersion)"/>
</Target>
<Target Name="BeforeBuild" DependsOnTargets="GetBuildVersion">
@@ -22,7 +32,9 @@
<NewVersionCsFile>$(VersionCsFile).new</NewVersionCsFile>
</PropertyGroup>
<MakeDir Directories="$(ProjectRoot)\obj\$(Configuration)"/>
- <AssemblyInfo OutputFile="$(NewVersionCsFile)" CodeLanguage="C#" AssemblyVersion="$(BuildVersion)" />
+ <AssemblyInfo OutputFile="$(NewVersionCsFile)" CodeLanguage="C#"
+ AssemblyVersion="$(BuildVersion)"
+ AssemblyInformationalVersion="$(AssemblyInformationalVersion)" />
<!-- Avoid applying the newly generated AssemblyInfo.cs file to the build
unless it has changed in order to allow for incremental building. -->
<CompareFiles OriginalItems="$(VersionCsFile)" NewItems="$(NewVersionCsFile)">
diff --git a/tools/Publish.targets b/tools/Publish.targets
index 036e751..a4d2bfa 100644
--- a/tools/Publish.targets
+++ b/tools/Publish.targets
@@ -67,6 +67,11 @@
<Copy SourceFiles="@(PublishableWebSampleSources)" DestinationFiles="@(PublishableWebSampleTargets)" SkipUnchangedFiles="true" />
</Target>
+ <Target Name="UnpublishSamples"
+ DependsOnTargets="DeleteSampleSitesOnIis"
+ Condition=" '$(SampleWebRoot)' != '' ">
+ </Target>
+
<Target Name="PrepareForPublishDocumentation" DependsOnTargets="Documentation">
<ItemGroup>
<DocSources Include="$(ProjectRoot)\doc\api\**\*" />
@@ -84,6 +89,11 @@
<Copy SourceFiles="@(DocSources)" DestinationFiles="@(DocTargets)" SkipUnchangedFiles="true" />
</Target>
+ <Target Name="UnpublishDocumentation"
+ DependsOnTargets="DeleteDocumentationSiteOnIis"
+ Condition=" '$(DocWebRoot)' != '' ">
+ </Target>
+
<Target Name="CreateSampleSitesOnIis" DependsOnTargets="PrepareForIIS;PrepareForPublishSamples">
<Error Text="The PublishSamplesWebSiteName property must be set." Condition=" '$(PublishSamplesWebSiteName)' == '' "/>
<Error Text="The SampleWebRoot property must be set." Condition=" '$(SampleWebRoot)' == '' " />
diff --git a/tools/sandcastle.targets b/tools/sandcastle.targets
index 8103a21..d76698e 100644
--- a/tools/sandcastle.targets
+++ b/tools/sandcastle.targets
@@ -40,10 +40,31 @@
</ItemGroup>
<Target Name="CleanDocumentation">
- <Delete Files="$(ReflectionFile);$(ManifestFile);$(ReflectionBaseFile);$(ChmFile)" TreatErrorsAsWarnings="true"/>
- <RemoveDir Directories="$(DocOutputApiPath);$(DocIntermediatePath);$(ChmDir)" ContinueOnError="true"/>
- <RemoveDir Directories="$(FxReflectionIntermediatePath)" ContinueOnError="true" />
+ <ItemGroup>
+ <_DirtyFiles Include="
+ $(DocOutputApiPath)\**;
+ $(ReflectionFile);
+ $(ManifestFile);
+ $(ReflectionBaseFile);
+ $(ChmFile)
+ "
+ Exclude="
+ $(DocOutputApiPath)\Web.config;
+ $(DocOutputApiPath)\Default.aspx;
+ " />
+ <_DirtyDirectories Include="
+ $(DocIntermediatePath);
+ $(ChmDir);
+ $(FxReflectionIntermediatePath)
+ " />
+ </ItemGroup>
+ <Delete Files="@(_DirtyFiles)" TreatErrorsAsWarnings="true"/>
+ <RemoveDir Directories="@(_DirtyDirectories)" ContinueOnError="true"/>
<!--<RemoveDir Directories="$(FxReflectionOutputPath)" ContinueOnError="true" />-->
+ <ItemGroup>
+ <_DirtyFiles Remove="@(_DirtyFiles)" />
+ <_DirtyDirectories Remove="@(_DirtyDirectories)" />
+ </ItemGroup>
</Target>
<Target Name="CreateIntermediatePath">