summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj2
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/Provider/AnonymousIdentifierProviderBase.cs122
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs38
-rw-r--r--samples/DotNetOpenAuth.ApplicationBlock/Util.cs13
-rw-r--r--samples/OpenIdProviderMvc/App_Data/Users.xml5
-rw-r--r--samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs23
-rw-r--r--samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs9
-rw-r--r--samples/OpenIdProviderMvc/Code/Util.cs17
-rw-r--r--samples/OpenIdProviderMvc/Controllers/HomeController.cs4
-rw-r--r--samples/OpenIdProviderMvc/Controllers/OpenIdController.cs83
-rw-r--r--samples/OpenIdProviderMvc/Controllers/UserController.cs12
-rw-r--r--samples/OpenIdProviderMvc/Global.asax.cs8
-rw-r--r--samples/OpenIdProviderMvc/Models/User.cs20
-rw-r--r--samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj9
-rw-r--r--samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx18
-rw-r--r--samples/OpenIdProviderMvc/Views/Shared/Site.Master2
-rw-r--r--samples/OpenIdProviderMvc/Views/User/Identity.aspx4
-rw-r--r--samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx16
-rw-r--r--samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx13
-rw-r--r--samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs2
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj2
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs8
-rw-r--r--src/DotNetOpenAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs2
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs10
-rw-r--r--src/DotNetOpenAuth/OpenId/OpenIdStrings.resx8
-rw-r--r--src/DotNetOpenAuth/Yadis/Yadis.cs4
26 files changed, 404 insertions, 50 deletions
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
index 976a325..83d3527 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
+++ b/samples/DotNetOpenAuth.ApplicationBlock/DotNetOpenAuth.ApplicationBlock.csproj
@@ -60,6 +60,8 @@
<Compile Include="CustomExtensions\AcmeResponse.cs" />
<Compile Include="GoogleConsumer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Provider\AnonymousIdentifierProviderBase.cs" />
+ <Compile Include="Provider\AuthenticationRequestExtensions.cs" />
<Compile Include="TwitterConsumer.cs" />
<Compile Include="Util.cs" />
</ItemGroup>
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Provider/AnonymousIdentifierProviderBase.cs b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AnonymousIdentifierProviderBase.cs
new file mode 100644
index 0000000..1df7267
--- /dev/null
+++ b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AnonymousIdentifierProviderBase.cs
@@ -0,0 +1,122 @@
+//-----------------------------------------------------------------------
+// <copyright file="AnonymousIdentifierProviderBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.ApplicationBlock.Provider {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId;
+
+ public abstract class AnonymousIdentifierProviderBase {
+ private int newSaltLength = 20;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AnonymousIdentifierProviderBase"/> class.
+ /// </summary>
+ /// <param name="baseIdentifier">The base URI on which to append the anonymous part.</param>
+ public AnonymousIdentifierProviderBase(Uri baseIdentifier) {
+ if (baseIdentifier == null) {
+ throw new ArgumentNullException("baseIdentifier");
+ }
+
+ this.Hasher = HashAlgorithm.Create("SHA256");
+ this.Encoder = Encoding.UTF8;
+ this.BaseIdentifier = baseIdentifier;
+ }
+
+ public Uri BaseIdentifier { get; private set; }
+
+ protected HashAlgorithm Hasher { get; private set; }
+
+ protected Encoding Encoder { get; private set; }
+
+ protected int NewSaltLength {
+ get {
+ return this.newSaltLength;
+ }
+
+ set {
+ if (value <= 0) {
+ throw new ArgumentOutOfRangeException("value");
+ }
+
+ this.newSaltLength = value;
+ }
+ }
+
+ #region IAnonymousIdentifierProvider Members
+
+ public Uri GetAnonymousIdentifier(Identifier localIdentifier, Realm relyingPartyRealm) {
+ byte[] salt = this.GetHashSaltForLocalIdentifier(localIdentifier);
+ string valueToHash = localIdentifier + "#" + (relyingPartyRealm ?? string.Empty);
+ byte[] valueAsBytes = this.Encoder.GetBytes(valueToHash);
+ byte[] bytesToHash = new byte[valueAsBytes.Length + salt.Length];
+ valueAsBytes.CopyTo(bytesToHash, 0);
+ salt.CopyTo(bytesToHash, valueAsBytes.Length);
+ byte[] hash = this.Hasher.ComputeHash(bytesToHash);
+ string base64Hash = Convert.ToBase64String(hash);
+ Uri anonymousIdentifier = this.AppendIdentifiers(this.BaseIdentifier, base64Hash);
+ return anonymousIdentifier;
+ }
+
+ #endregion
+
+ protected virtual byte[] GetNewSalt() {
+ // We COULD use a crypto random function, but for a salt it seems overkill.
+ return Util.GetNonCryptoRandomData(this.NewSaltLength);
+ }
+
+ protected Uri AppendIdentifiers(Uri baseIdentifier, string uriHash) {
+ if (baseIdentifier == null) {
+ throw new ArgumentNullException("baseIdentifier");
+ }
+ if (String.IsNullOrEmpty(uriHash)) {
+ throw new ArgumentNullException("uriHash");
+ }
+
+ if (string.IsNullOrEmpty(baseIdentifier.Query)) {
+ // The uriHash will appear on the path itself.
+ string pathEncoded = Uri.EscapeUriString(uriHash.Replace('/', '_'));
+ return new Uri(baseIdentifier, pathEncoded);
+ } else {
+ // The uriHash will appear on the query string.
+ string dataEncoded = Uri.EscapeDataString(uriHash);
+ return new Uri(baseIdentifier + dataEncoded);
+ }
+ }
+
+ /// <summary>
+ /// Gets the salt to use for generating an anonymous identifier for a given OP local identifier.
+ /// </summary>
+ /// <param name="localIdentifier">The OP local identifier.</param>
+ /// <returns>The salt to use in the hash.</returns>
+ /// <remarks>
+ /// It is important that this method always return the same value for a given
+ /// <paramref name="localIdentifier"/>.
+ /// New salts can be generated for local identifiers without previously assigned salt
+ /// values by calling <see cref="GetNewSalt"/> or by a custom method.
+ /// </remarks>
+ protected abstract byte[] GetHashSaltForLocalIdentifier(Identifier localIdentifier);
+
+#if CONTRACTS_FULL
+ /// <summary>
+ /// Verifies conditions that should be true for any valid state of this object.
+ /// </summary>
+ [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called by code contracts.")]
+ [ContractInvariantMethod]
+ protected void ObjectInvariant() {
+ Contract.Invariant(this.Hasher != null);
+ Contract.Invariant(this.Encoder != null);
+ Contract.Invariant(this.BaseIdentifier != null);
+ Contract.Invariant(this.NewHashLength > 0);
+ }
+#endif
+ }
+}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs
new file mode 100644
index 0000000..a737d30
--- /dev/null
+++ b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs
@@ -0,0 +1,38 @@
+namespace DotNetOpenAuth.ApplicationBlock.Provider {
+ using System;
+ using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Provider;
+
+ public static class AuthenticationRequestExtensions {
+ /// <summary>
+ /// Removes all personally identifiable information from the positive assertion.
+ /// </summary>
+ /// <param name="request">The incoming authentication request.</param>
+ /// <param name="localIdentifier">The OP local identifier, before the anonymous hash is applied to it.</param>
+ /// <param name="anonymousIdentifierProvider">The anonymous identifier provider.</param>
+ /// <param name="pairwiseUnique">if set to <c>true</c> the anonymous identifier will be unique to the requesting relying party's realm.</param>
+ /// <remarks>
+ /// The openid.claimed_id and openid.identity values are hashed.
+ /// </remarks>
+ public static void ScrubPersonallyIdentifiableInformation(this IAuthenticationRequest request, Identifier localIdentifier, AnonymousIdentifierProviderBase anonymousIdentifierProvider, bool pairwiseUnique) {
+ if (request == null) {
+ throw new ArgumentNullException("request");
+ }
+ if (!request.IsDirectedIdentity) {
+ throw new InvalidOperationException("This operation is supported only under identifier select (directed identity) scenarios.");
+ }
+ if (anonymousIdentifierProvider == null) {
+ throw new ArgumentNullException("anonymousIdentifierProvider");
+ }
+ if (localIdentifier == null) {
+ throw new ArgumentNullException("localIdentifier");
+ }
+
+ // When generating the anonymous identifiers, the openid.identity and openid.claimed_id
+ // will always end up with matching values.
+ var anonymousIdentifier = anonymousIdentifierProvider.GetAnonymousIdentifier(localIdentifier, pairwiseUnique ? request.Realm : null);
+ request.ClaimedIdentifier = anonymousIdentifier;
+ request.LocalIdentifier = anonymousIdentifier;
+ }
+ }
+}
diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
index ea7da97..8a188ac 100644
--- a/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
+++ b/samples/DotNetOpenAuth.ApplicationBlock/Util.cs
@@ -5,6 +5,8 @@
using DotNetOpenAuth.Messaging;
internal static class Util {
+ internal static readonly Random NonCryptoRandomDataGenerator = new Random();
+
/// <summary>
/// Enumerates through the individual set bits in a flag enum.
/// </summary>
@@ -28,6 +30,17 @@
}
/// <summary>
+ /// Gets a buffer of random data (not cryptographically strong).
+ /// </summary>
+ /// <param name="length">The length of the sequence to generate.</param>
+ /// <returns>The generated values, which may contain zeros.</returns>
+ internal static byte[] GetNonCryptoRandomData(int length) {
+ byte[] buffer = new byte[length];
+ NonCryptoRandomDataGenerator.NextBytes(buffer);
+ return buffer;
+ }
+
+ /// <summary>
/// Copies the contents of one stream to another.
/// </summary>
/// <param name="copyFrom">The stream to copy from, at the position where copying should begin.</param>
diff --git a/samples/OpenIdProviderMvc/App_Data/Users.xml b/samples/OpenIdProviderMvc/App_Data/Users.xml
index cffe009..7f70bc6 100644
--- a/samples/OpenIdProviderMvc/App_Data/Users.xml
+++ b/samples/OpenIdProviderMvc/App_Data/Users.xml
@@ -3,21 +3,26 @@
<User>
<UserName>bob</UserName>
<Password>test</Password>
+ <Salt>CDI=</Salt>
</User>
<User>
<UserName>bob1</UserName>
<Password>test</Password>
+ <Salt>CAI=</Salt>
</User>
<User>
<UserName>bob2</UserName>
<Password>test</Password>
+ <Salt>hYMC</Salt>
</User>
<User>
<UserName>bob3</UserName>
<Password>test</Password>
+ <Salt>hTKDAg==</Salt>
</User>
<User>
<UserName>bob4</UserName>
<Password>test</Password>
+ <Salt>hTkDAg==</Salt>
</User>
</Users>
diff --git a/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs b/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs
new file mode 100644
index 0000000..2b9e01c
--- /dev/null
+++ b/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs
@@ -0,0 +1,23 @@
+namespace OpenIdProviderMvc.Code {
+ using System;
+ using System.Web.Security;
+ using DotNetOpenAuth.ApplicationBlock.Provider;
+ using DotNetOpenAuth.OpenId;
+ using OpenIdProviderMvc.Models;
+
+ internal class AnonymousIdentifierProvider : AnonymousIdentifierProviderBase {
+ internal AnonymousIdentifierProvider()
+ : base(Util.GetAppPathRootedUri("anon?id=")) {
+ }
+
+ protected override byte[] GetHashSaltForLocalIdentifier(Identifier localIdentifier) {
+ // This is just a sample with no database... a real web app MUST return
+ // a reasonable salt here and have that salt be persistent for each user.
+ var membership = (ReadOnlyXmlMembershipProvider)Membership.Provider;
+ string username = User.GetUserFromClaimedIdentifier(new Uri(localIdentifier));
+ string salt = membership.GetSalt(username);
+ return Convert.FromBase64String(salt);
+ ////return AnonymousIdentifierProviderBase.GetNewSalt(5);
+ }
+ }
+}
diff --git a/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs b/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs
index 3da0f8e..cc5a321 100644
--- a/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs
+++ b/samples/OpenIdProviderMvc/Code/ReadOnlyXmlMembershipProvider.cs
@@ -236,6 +236,11 @@
throw new NotSupportedException();
}
+ internal string GetSalt(string userName) {
+ this.ReadMembershipDataStore();
+ return this.users[userName].Email;
+ }
+
// Helper method
private void ReadMembershipDataStore() {
lock (this) {
@@ -246,11 +251,13 @@
XmlNodeList nodes = doc.GetElementsByTagName("User");
foreach (XmlNode node in nodes) {
+ // Yes, we're misusing some of these fields. A real app would
+ // have the right fields from a database to use.
MembershipUser user = new MembershipUser(
Name, // Provider name
node["UserName"].InnerText, // Username
null, // providerUserKey
- null, // Email
+ node["Salt"].InnerText, // Email
string.Empty, // passwordQuestion
node["Password"].InnerText, // Comment
true, // isApproved
diff --git a/samples/OpenIdProviderMvc/Code/Util.cs b/samples/OpenIdProviderMvc/Code/Util.cs
new file mode 100644
index 0000000..6623952
--- /dev/null
+++ b/samples/OpenIdProviderMvc/Code/Util.cs
@@ -0,0 +1,17 @@
+namespace OpenIdProviderMvc.Code {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Web;
+
+ internal static class Util {
+ internal static Uri GetAppPathRootedUri(string value) {
+ string appPath = HttpContext.Current.Request.ApplicationPath.ToLowerInvariant();
+ if (!appPath.EndsWith("/")) {
+ appPath += "/";
+ }
+
+ return new Uri(HttpContext.Current.Request.Url, appPath + value);
+ }
+ }
+}
diff --git a/samples/OpenIdProviderMvc/Controllers/HomeController.cs b/samples/OpenIdProviderMvc/Controllers/HomeController.cs
index 5ba08b3..346e838 100644
--- a/samples/OpenIdProviderMvc/Controllers/HomeController.cs
+++ b/samples/OpenIdProviderMvc/Controllers/HomeController.cs
@@ -23,5 +23,9 @@
public ActionResult Xrds() {
return View();
}
+
+ public ActionResult PpidXrds() {
+ return View();
+ }
}
}
diff --git a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs
index fff0a62..e353268 100644
--- a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs
+++ b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs
@@ -5,8 +5,11 @@ namespace OpenIdProviderMvc.Controllers {
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
+ using DotNetOpenAuth.ApplicationBlock.Provider;
using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Provider;
+ using OpenIdProviderMvc.Code;
public class OpenIdController : Controller {
internal static OpenIdProvider OpenIdProvider = new OpenIdProvider();
@@ -17,16 +20,67 @@ namespace OpenIdProviderMvc.Controllers {
}
[ValidateInput(false)]
+ public ActionResult PpidProvider() {
+ return this.DoProvider(true);
+ }
+
+ [ValidateInput(false)]
public ActionResult Provider() {
+ return this.DoProvider(false);
+ }
+
+ [Authorize]
+ public ActionResult SendAssertion(bool pseudonymous) {
+ IAuthenticationRequest authReq = PendingAuthenticationRequest;
+ PendingAuthenticationRequest = null;
+ if (authReq == null) {
+ throw new InvalidOperationException();
+ }
+
+ Identifier localIdentifier = Models.User.GetClaimedIdentifierForUser(User.Identity.Name);
+
+ if (pseudonymous) {
+ if (!authReq.IsDirectedIdentity) {
+ throw new InvalidOperationException("Directed identity is the only supported scenario for anonymous identifiers.");
+ }
+
+ var anonProvider = new AnonymousIdentifierProvider();
+ authReq.ScrubPersonallyIdentifiableInformation(localIdentifier, anonProvider, true);
+ authReq.IsAuthenticated = true;
+ } else {
+ if (authReq.IsDirectedIdentity) {
+ authReq.LocalIdentifier = localIdentifier;
+ authReq.ClaimedIdentifier = localIdentifier;
+ authReq.IsAuthenticated = true;
+ } else {
+ if (authReq.LocalIdentifier == localIdentifier) {
+ authReq.IsAuthenticated = true;
+ if (!authReq.IsDelegatedIdentifier) {
+ authReq.ClaimedIdentifier = authReq.LocalIdentifier;
+ }
+ } else {
+ authReq.IsAuthenticated = false;
+ }
+ }
+
+ // TODO: Respond to AX/sreg extension requests here.
+ // We don't want to add these extension responses for anonymous identifiers
+ // because they could leak information about the user's identity.
+ }
+
+ return OpenIdProvider.PrepareResponse(authReq).AsActionResult();
+ }
+
+ private ActionResult DoProvider(bool pseudonymous) {
IRequest request = OpenIdProvider.GetRequest();
if (request != null) {
var authRequest = request as IAuthenticationRequest;
if (authRequest != null) {
PendingAuthenticationRequest = authRequest;
if (User.Identity.IsAuthenticated && (authRequest.IsDirectedIdentity || Models.User.GetClaimedIdentifierForUser(User.Identity.Name) == authRequest.LocalIdentifier)) {
- return this.SendAssertion();
+ return this.SendAssertion(pseudonymous);
} else {
- return RedirectToAction("LogOn", "Account", new { returnUrl = Url.Action("SendAssertion") });
+ return RedirectToAction("LogOn", "Account", new { returnUrl = Url.Action("SendAssertion", new { pseudonymous = pseudonymous }) });
}
}
@@ -39,30 +93,5 @@ namespace OpenIdProviderMvc.Controllers {
return View();
}
}
-
- [Authorize]
- public ActionResult SendAssertion() {
- IAuthenticationRequest authReq = PendingAuthenticationRequest;
- PendingAuthenticationRequest = null;
- if (authReq == null) {
- throw new InvalidOperationException();
- }
-
- if (authReq.IsDirectedIdentity) {
- authReq.LocalIdentifier = Models.User.GetClaimedIdentifierForUser(User.Identity.Name);
- authReq.ClaimedIdentifier = authReq.LocalIdentifier;
- authReq.IsAuthenticated = true;
- } else {
- if (authReq.LocalIdentifier == Models.User.GetClaimedIdentifierForUser(User.Identity.Name)) {
- authReq.IsAuthenticated = true;
- if (!authReq.IsDelegatedIdentifier) {
- authReq.ClaimedIdentifier = authReq.LocalIdentifier;
- }
- } else {
- authReq.IsAuthenticated = false;
- }
- }
- return OpenIdProvider.PrepareResponse(authReq).AsActionResult();
- }
}
}
diff --git a/samples/OpenIdProviderMvc/Controllers/UserController.cs b/samples/OpenIdProviderMvc/Controllers/UserController.cs
index 70bea04..c160fce 100644
--- a/samples/OpenIdProviderMvc/Controllers/UserController.cs
+++ b/samples/OpenIdProviderMvc/Controllers/UserController.cs
@@ -7,6 +7,14 @@ namespace OpenIdProviderMvc.Controllers {
using System.Web.Mvc.Ajax;
public class UserController : Controller {
+ public ActionResult PpidIdentity() {
+ if (Request.AcceptTypes.Contains("application/xrds+xml")) {
+ return View("PpidXrds");
+ }
+
+ return View();
+ }
+
public ActionResult Identity(string id) {
var redirect = this.RedirectIfNotNormalizedRequestUri();
if (redirect != null) {
@@ -25,6 +33,10 @@ namespace OpenIdProviderMvc.Controllers {
return View();
}
+ public ActionResult PpidXrds() {
+ return View();
+ }
+
private ActionResult RedirectIfNotNormalizedRequestUri() {
Uri normalized = Models.User.GetNormalizedClaimedIdentifier(Request.Url);
if (Request.Url != normalized) {
diff --git a/samples/OpenIdProviderMvc/Global.asax.cs b/samples/OpenIdProviderMvc/Global.asax.cs
index b0d1b60..8c57961 100644
--- a/samples/OpenIdProviderMvc/Global.asax.cs
+++ b/samples/OpenIdProviderMvc/Global.asax.cs
@@ -22,6 +22,14 @@
"user/{id}/{action}",
new { controller = "User", action = "Identity", id = string.Empty });
routes.MapRoute(
+ "PPID identifiers",
+ "anon",
+ new { controller = "User", action = "PpidIdentity", id = string.Empty });
+ routes.MapRoute(
+ "PpidXrds",
+ "PpidXrds",
+ new { controller = "Home", action = "PpidXrds" }); // Parameter defaults
+ routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = string.Empty }); // Parameter defaults
diff --git a/samples/OpenIdProviderMvc/Models/User.cs b/samples/OpenIdProviderMvc/Models/User.cs
index 577aa05..443c004 100644
--- a/samples/OpenIdProviderMvc/Models/User.cs
+++ b/samples/OpenIdProviderMvc/Models/User.cs
@@ -5,17 +5,23 @@
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Routing;
+ using OpenIdProviderMvc.Code;
internal class User {
+ internal static Uri PpidClaimedIdentifierBaseUri {
+ get { return Util.GetAppPathRootedUri("anon?id="); }
+ }
+
+ internal static Uri ClaimedIdentifierBaseUri {
+ get { return Util.GetAppPathRootedUri("user/"); }
+ }
+
internal static Uri GetClaimedIdentifierForUser(string username) {
- string appPath = HttpContext.Current.Request.ApplicationPath;
- if (!appPath.EndsWith("/")) {
- appPath += "/";
+ if (String.IsNullOrEmpty(username)) {
+ throw new ArgumentNullException("username");
}
- Uri claimedIdentifier = new Uri(
- HttpContext.Current.Request.Url,
- appPath + "user/" + username);
- return new Uri(claimedIdentifier.AbsoluteUri.ToLowerInvariant());
+
+ return new Uri(ClaimedIdentifierBaseUri, username.ToLowerInvariant());
}
internal static string GetUserFromClaimedIdentifier(Uri claimedIdentifier) {
diff --git a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj
index 80e8e64..5caf26d 100644
--- a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj
+++ b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj
@@ -65,10 +65,12 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Code\AccountMembershipService.cs" />
+ <Compile Include="Code\AnonymousIdentifierProvider.cs" />
<Compile Include="Code\FormsAuthenticationService.cs" />
<Compile Include="Code\IFormsAuthentication.cs" />
<Compile Include="Code\IMembershipService.cs" />
<Compile Include="Code\ReadOnlyXmlMembershipProvider.cs" />
+ <Compile Include="Code\Util.cs" />
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\OpenIdController.cs" />
@@ -90,8 +92,11 @@
<Content Include="Views\Account\ChangePassword.aspx" />
<Content Include="Views\Account\ChangePasswordSuccess.aspx" />
<Content Include="Views\Account\Register.aspx" />
+ <Content Include="Views\Home\PpidXrds.aspx" />
<Content Include="Views\Home\Xrds.aspx" />
<Content Include="Views\OpenId\Provider.aspx" />
+ <Content Include="Views\User\PpidXrds.aspx" />
+ <Content Include="Views\User\PpidIdentity.aspx" />
<Content Include="Views\User\Identity.aspx" />
<Content Include="Views\User\Xrds.aspx" />
<Content Include="Web.config" />
@@ -117,6 +122,10 @@
<Project>{3191B653-F76D-4C1A-9A5A-347BC3AAAAB7}</Project>
<Name>DotNetOpenAuth</Name>
</ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.ApplicationBlock\DotNetOpenAuth.ApplicationBlock.csproj">
+ <Project>{AA78D112-D889-414B-A7D4-467B34C7B663}</Project>
+ <Name>DotNetOpenAuth.ApplicationBlock</Name>
+ </ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v9.0\WebApplications\Microsoft.WebApplication.targets" />
diff --git a/samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx b/samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx
new file mode 100644
index 0000000..990a3df
--- /dev/null
+++ b/samples/OpenIdProviderMvc/Views/Home/PpidXrds.aspx
@@ -0,0 +1,18 @@
+<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?>
+<%--
+This page is a required as part of the service discovery phase of the openid
+protocol (step 1). It simply renders the xml for doing service discovery of
+server.aspx using the xrds mechanism.
+This XRDS doc is discovered via the user.aspx page.
+--%>
+<xrds:XRDS
+ xmlns:xrds="xri://$xrds"
+ xmlns:openid="http://openid.net/xmlns/1.0"
+ xmlns="xri://$xrd*($v*2.0)">
+ <XRD>
+ <Service priority="10">
+ <Type>http://specs.openid.net/auth/2.0/server</Type>
+ <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/PpidProvider"))%></URI>
+ </Service>
+ </XRD>
+</xrds:XRDS>
diff --git a/samples/OpenIdProviderMvc/Views/Shared/Site.Master b/samples/OpenIdProviderMvc/Views/Shared/Site.Master
index 8df2d5f..073908e 100644
--- a/samples/OpenIdProviderMvc/Views/Shared/Site.Master
+++ b/samples/OpenIdProviderMvc/Views/Shared/Site.Master
@@ -13,7 +13,7 @@
<div class="page">
<div id="header">
<div id="title">
- <h1>My MVC Application</h1>
+ <h1>OpenID Provider MVC Application</h1>
</div>
<div id="logindisplay">
<% Html.RenderPartial("LogOnUserControl"); %>
diff --git a/samples/OpenIdProviderMvc/Views/User/Identity.aspx b/samples/OpenIdProviderMvc/Views/User/Identity.aspx
index 632df43..bb50899 100644
--- a/samples/OpenIdProviderMvc/Views/User/Identity.aspx
+++ b/samples/OpenIdProviderMvc/Views/User/Identity.aspx
@@ -3,7 +3,7 @@
<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.Provider"
TagPrefix="op" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
- <%=ViewData["username"]%>
+ <%=Html.Encode(ViewData["username"])%>
identity page
</asp:Content>
<asp:Content runat="server" ContentPlaceHolderID="HeadContent">
@@ -12,7 +12,7 @@
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>This is
- <%=ViewData["username"]%>'s OpenID identity page </h2>
+ <%=Html.Encode(ViewData["username"])%>'s OpenID identity page </h2>
<% if (string.Equals(User.Identity.Name, ViewData["username"])) { %>
<p>This is <b>your</b> identity page. </p>
diff --git a/samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx b/samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx
new file mode 100644
index 0000000..f33a694
--- /dev/null
+++ b/samples/OpenIdProviderMvc/Views/User/PpidIdentity.aspx
@@ -0,0 +1,16 @@
+<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
+
+<%@ Register Assembly="DotNetOpenAuth" Namespace="DotNetOpenAuth.OpenId.Provider"
+ TagPrefix="op" %>
+<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
+ Identity page
+</asp:Content>
+<asp:Content runat="server" ContentPlaceHolderID="HeadContent">
+ <op:IdentityEndpoint ID="IdentityEndpoint11" runat="server" ProviderEndpointUrl="~/OpenId/PpidProvider"
+ ProviderVersion="V11" />
+ <op:IdentityEndpoint ID="IdentityEndpoint20" runat="server" ProviderEndpointUrl="~/OpenId/PpidProvider"
+ XrdsUrl="~/User/all/ppidxrds" XrdsAutoAnswer="false" />
+</asp:Content>
+<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
+ <h2>OpenID identity page </h2>
+</asp:Content>
diff --git a/samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx b/samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx
new file mode 100644
index 0000000..67256bd
--- /dev/null
+++ b/samples/OpenIdProviderMvc/Views/User/PpidXrds.aspx
@@ -0,0 +1,13 @@
+<%@ Page Language="C#" AutoEventWireup="true" ContentType="application/xrds+xml" %><?xml version="1.0" encoding="UTF-8"?>
+<XRDS xmlns="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0">
+ <XRD xmlns="xri://$xrd*($v*2.0)">
+ <Service priority="10">
+ <Type>http://specs.openid.net/auth/2.0/signon</Type>
+ <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/PpidProvider"))%></URI>
+ </Service>
+ <Service priority="20">
+ <Type>http://openid.net/signon/1.0</Type>
+ <URI><%=new Uri(Request.Url, Response.ApplyAppPathModifier("~/OpenId/PpidProvider"))%></URI>
+ </Service>
+ </XRD>
+</XRDS>
diff --git a/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs b/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs
index dd8d897..b14aba1 100644
--- a/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs
+++ b/samples/OpenIdRelyingPartyWebForms/MembersOnly/DisplayGoogleContacts.aspx.cs
@@ -17,7 +17,7 @@
} else {
this.emailLabel.Text = "unavailable";
}
- claimedIdLabel.Text = User.Identity.Name;
+ this.claimedIdLabel.Text = this.User.Identity.Name;
var contactsDocument = GoogleConsumer.GetContacts(Global.GoogleWebConsumer, State.GoogleAccessToken);
this.RenderContacts(contactsDocument);
}
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index e2894cf..a6069b4 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -25,7 +25,7 @@
<DocumentationFile>..\..\bin\Debug\DotNetOpenAuth.xml</DocumentationFile>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeAnalysisRules>-Microsoft.Design#CA1054;-Microsoft.Design#CA1056;-Microsoft.Design#CA1055</CodeAnalysisRules>
- <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
+ <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsCustomRewriterAssembly>
</CodeContractsCustomRewriterAssembly>
<CodeContractsCustomRewriterClass>
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs
index 951d8e8..ff004cb 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/ICombinedOpenIdProviderTokenManager.cs
@@ -7,6 +7,14 @@
namespace DotNetOpenAuth.OAuth.ChannelElements {
using DotNetOpenAuth.OpenId;
+ /// <summary>
+ /// An interface that providers that play a dual role as OpenID Provider
+ /// and OAuth Service Provider should implement on their token manager classes.
+ /// </summary>
+ /// <remarks>
+ /// This interface should be implemented by the same class that implements
+ /// <see cref="ITokenManager"/> in order to enable the OpenID+OAuth extension.
+ /// </remarks>
public interface ICombinedOpenIdProviderTokenManager {
/// <summary>
/// Gets the OAuth consumer key for a given OpenID relying party realm.
diff --git a/src/DotNetOpenAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs b/src/DotNetOpenAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs
index 592bff3..b3ee320 100644
--- a/src/DotNetOpenAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs
+++ b/src/DotNetOpenAuth/OAuth/ChannelElements/IOpenIdOAuthTokenManager.cs
@@ -5,8 +5,8 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OAuth.ChannelElements {
- using DotNetOpenAuth.OpenId.Extensions.OAuth;
using DotNetOpenAuth.OpenId;
+ using DotNetOpenAuth.OpenId.Extensions.OAuth;
/// <summary>
/// Additional methods an <see cref="ITokenManager"/> implementing class
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
index 3c4116a..a6e02fe 100644
--- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:2.0.50727.4912
+// Runtime Version:2.0.50727.4918
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -322,7 +322,7 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
- /// Looks up a localized string similar to The OpenId Provider issued an assertion for an Identifier whose discovery information did not match.
+ /// Looks up a localized string similar to The OpenID Provider issued an assertion for an Identifier whose discovery information did not match.
///Assertion endpoint info:
///{0}
///Discovered endpoint info:
@@ -389,7 +389,7 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
- /// Looks up a localized string similar to No XRDS document containing OpenId relying party endpoint information could be found at {0}..
+ /// Looks up a localized string similar to No XRDS document containing OpenID relying party endpoint information could be found at {0}..
/// </summary>
internal static string NoRelyingPartyEndpointDiscovered {
get {
@@ -416,7 +416,7 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
- /// Looks up a localized string similar to No OpenId endpoint found..
+ /// Looks up a localized string similar to No OpenID endpoint found..
/// </summary>
internal static string OpenIdEndpointNotFound {
get {
@@ -425,7 +425,7 @@ namespace DotNetOpenAuth.OpenId {
}
/// <summary>
- /// Looks up a localized string similar to No OpenId url is provided..
+ /// Looks up a localized string similar to No OpenID url is provided..
/// </summary>
internal static string OpenIdTextBoxEmpty {
get {
diff --git a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
index 7356c10..95fe655 100644
--- a/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
+++ b/src/DotNetOpenAuth/OpenId/OpenIdStrings.resx
@@ -181,7 +181,7 @@
<value>Not a recognized XRI format: '{0}'.</value>
</data>
<data name="IssuedAssertionFailsIdentifierDiscovery" xml:space="preserve">
- <value>The OpenId Provider issued an assertion for an Identifier whose discovery information did not match.
+ <value>The OpenID Provider issued an assertion for an Identifier whose discovery information did not match.
Assertion endpoint info:
{0}
Discovered endpoint info:
@@ -206,7 +206,7 @@ Discovered endpoint info:
<value>Diffie-Hellman session type '{0}' not found for OpenID {1}.</value>
</data>
<data name="OpenIdEndpointNotFound" xml:space="preserve">
- <value>No OpenId endpoint found.</value>
+ <value>No OpenID endpoint found.</value>
</data>
<data name="OperationOnlyValidForSetupRequiredState" xml:space="preserve">
<value>This operation is only allowed when IAuthenticationResponse.State == AuthenticationStatus.SetupRequired.</value>
@@ -266,7 +266,7 @@ Discovered endpoint info:
<value>An authentication request has already been created using CreateRequest().</value>
</data>
<data name="OpenIdTextBoxEmpty" xml:space="preserve">
- <value>No OpenId url is provided.</value>
+ <value>No OpenID url is provided.</value>
</data>
<data name="ClientScriptExtensionPropertyNameCollision" xml:space="preserve">
<value>An extension with this property name ('{0}') has already been registered.</value>
@@ -281,7 +281,7 @@ Discovered endpoint info:
<value>This operation is not supported by serialized authentication responses. Try this operation from the LoggedIn event handler.</value>
</data>
<data name="NoRelyingPartyEndpointDiscovered" xml:space="preserve">
- <value>No XRDS document containing OpenId relying party endpoint information could be found at {0}.</value>
+ <value>No XRDS document containing OpenID relying party endpoint information could be found at {0}.</value>
</data>
<data name="AbsoluteUriRequired" xml:space="preserve">
<value>An absolute URI is required for this value.</value>
diff --git a/src/DotNetOpenAuth/Yadis/Yadis.cs b/src/DotNetOpenAuth/Yadis/Yadis.cs
index 98bffc9..0caffb6 100644
--- a/src/DotNetOpenAuth/Yadis/Yadis.cs
+++ b/src/DotNetOpenAuth/Yadis/Yadis.cs
@@ -27,7 +27,11 @@ namespace DotNetOpenAuth.Yadis {
/// <summary>
/// Gets or sets the cache that can be used for HTTP requests made during identifier discovery.
/// </summary>
+#if DEBUG
+ internal static readonly RequestCachePolicy IdentifierDiscoveryCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.BypassCache);
+#else
internal static readonly RequestCachePolicy IdentifierDiscoveryCachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.CacheIfAvailable);
+#endif
/// <summary>
/// The maximum number of bytes to read from an HTTP response