diff options
13 files changed, 110 insertions, 154 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/src/DotNetOpenAuth/OpenId/Provider/AnonymousIdentifierProviderBase.cs b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AnonymousIdentifierProviderBase.cs index bb3808b..5354093 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/AnonymousIdentifierProviderBase.cs +++ b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AnonymousIdentifierProviderBase.cs @@ -4,26 +4,27 @@ // </copyright> //----------------------------------------------------------------------- -namespace DotNetOpenAuth.OpenId.Provider { +namespace DotNetOpenAuth.ApplicationBlock.Provider { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; - using System.Diagnostics.Contracts; using System.Linq; using System.Security.Cryptography; using System.Text; using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId; - [ContractClass(typeof(AnonymousIdentifierProviderBaseContract))] - public abstract class AnonymousIdentifierProviderBase : IAnonymousIdentifierProvider { + public abstract class AnonymousIdentifierProviderBase { private int newSaltLength = 20; /// <summary> /// Initializes a new instance of the <see cref="StandardAnonymousIdentifierProvider"/> class. /// </summary> public AnonymousIdentifierProviderBase(Uri baseIdentifier) { - Contract.Requires(baseIdentifier != null); - Contract.Ensures(this.BaseIdentifier == baseIdentifier); + if (baseIdentifier == null) { + throw new ArgumentNullException("baseIdentifier"); + } + this.Hasher = HashAlgorithm.Create("SHA256"); this.Encoder = Encoding.UTF8; this.BaseIdentifier = baseIdentifier; @@ -41,8 +42,10 @@ namespace DotNetOpenAuth.OpenId.Provider { } set { - Contract.Requires(value > 0); - ErrorUtilities.VerifyArgumentInRange(value > 0, "value"); + if (value <= 0) { + throw new ArgumentOutOfRangeException("value"); + } + newSaltLength = value; } } @@ -66,12 +69,16 @@ namespace DotNetOpenAuth.OpenId.Provider { protected virtual byte[] GetNewSalt() { // We COULD use a crypto random function, but for a salt it seems overkill. - return MessagingUtilities.GetNonCryptoRandomData(this.NewSaltLength); + return Util.GetNonCryptoRandomData(this.NewSaltLength); } protected Uri AppendIdentifiers(Uri baseIdentifier, string uriHash) { - Contract.Requires(baseIdentifier != null); - Contract.Requires(!String.IsNullOrEmpty(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. diff --git a/samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs new file mode 100644 index 0000000..496b14b --- /dev/null +++ b/samples/DotNetOpenAuth.ApplicationBlock/Provider/AuthenticationRequestExtensions.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using DotNetOpenAuth.OpenId.Provider; +using DotNetOpenAuth.OpenId; + +namespace DotNetOpenAuth.ApplicationBlock.Provider { + public static class AuthenticationRequestExtensions { + /// <summary> + /// Removes all personally identifiable information from the positive assertion. + /// </summary> + /// <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/Code/AnonymousIdentifierProvider.cs b/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs index 5771279..4bda10f 100644 --- a/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs +++ b/samples/OpenIdProviderMvc/Code/AnonymousIdentifierProvider.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using DotNetOpenAuth.OpenId.Provider; -using DotNetOpenAuth.OpenId; -using System.Web.Security; -using OpenIdProviderMvc.Models; +namespace OpenIdProviderMvc.Code { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Web; + using DotNetOpenAuth.OpenId.Provider; + using DotNetOpenAuth.OpenId; + using System.Web.Security; + using OpenIdProviderMvc.Models; + using DotNetOpenAuth.ApplicationBlock.Provider; -namespace OpenIdProviderMvc.Code { internal class AnonymousIdentifierProvider : AnonymousIdentifierProviderBase { internal AnonymousIdentifierProvider() : base(Util.GetAppPathRootedUri("anon?id=")) { diff --git a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs index ebe3e54..bc5b705 100644 --- a/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs +++ b/samples/OpenIdProviderMvc/Controllers/OpenIdController.cs @@ -8,6 +8,8 @@ namespace OpenIdProviderMvc.Controllers { using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Provider; using OpenIdProviderMvc.Code; + using DotNetOpenAuth.ApplicationBlock.Provider; + using DotNetOpenAuth.OpenId; public class OpenIdController : Controller { internal static OpenIdProvider OpenIdProvider = new OpenIdProvider(); @@ -35,26 +37,35 @@ namespace OpenIdProviderMvc.Controllers { throw new InvalidOperationException(); } - if (authReq.IsDirectedIdentity) { - authReq.LocalIdentifier = Models.User.GetClaimedIdentifierForUser(User.Identity.Name); - authReq.ClaimedIdentifier = authReq.LocalIdentifier; + 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.LocalIdentifier == Models.User.GetClaimedIdentifierForUser(User.Identity.Name)) { + if (authReq.IsDirectedIdentity) { + authReq.LocalIdentifier = localIdentifier; + authReq.ClaimedIdentifier = localIdentifier; authReq.IsAuthenticated = true; - if (!authReq.IsDelegatedIdentifier) { - authReq.ClaimedIdentifier = authReq.LocalIdentifier; - } } else { - authReq.IsAuthenticated = false; + if (authReq.LocalIdentifier == localIdentifier) { + authReq.IsAuthenticated = true; + if (!authReq.IsDelegatedIdentifier) { + authReq.ClaimedIdentifier = authReq.LocalIdentifier; + } + } else { + authReq.IsAuthenticated = false; + } } - } - - if (pseudonymous) { - var anonProvider = new AnonymousIdentifierProvider(); - authReq.ScrubPersonallyIdentifiableInformation(anonProvider, true); - } else { - // TODO: Respond to AX/sreg extension requests here + + // 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(); diff --git a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj index 7fa05ca..5caf26d 100644 --- a/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj +++ b/samples/OpenIdProviderMvc/OpenIdProviderMvc.csproj @@ -122,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/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj index dd78f98..a6069b4 100644 --- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj +++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj @@ -368,7 +368,6 @@ <Compile Include="OpenId\Messages\SignedResponseRequest.cs" /> <Compile Include="OpenId\NoDiscoveryIdentifier.cs" /> <Compile Include="OpenId\OpenIdUtilities.cs" /> - <Compile Include="OpenId\Provider\IAnonymousIdentifierProvider.cs" /> <Compile Include="OpenId\Provider\AuthenticationChallengeEventArgs.cs" /> <Compile Include="OpenId\Provider\AuthenticationRequest.cs" /> <Compile Include="OpenId\Provider\AutoResponsiveRequest.cs" /> @@ -381,8 +380,6 @@ <Compile Include="OpenId\Provider\ProviderEndpoint.cs" /> <Compile Include="OpenId\Provider\Request.cs" /> <Compile Include="OpenId\Provider\RequestContract.cs" /> - <Compile Include="OpenId\Provider\AnonymousIdentifierProviderBase.cs" /> - <Compile Include="OpenId\Provider\AnonymousIdentifierProviderBaseContract.cs" /> <Compile Include="OpenId\Provider\StandardProviderApplicationStore.cs" /> <Compile Include="OpenId\Realm.cs" /> <Compile Include="OpenId\RelyingPartyDescription.cs" /> diff --git a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs index bd9aeac..fe1e4e8 100644 --- a/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs +++ b/src/DotNetOpenAuth/Messaging/MessagingUtilities.cs @@ -30,8 +30,6 @@ namespace DotNetOpenAuth.Messaging { /// <remarks>The random number generator is thread-safe.</remarks> internal static readonly RandomNumberGenerator CryptoRandomDataGenerator = new RNGCryptoServiceProvider(); - internal static readonly Random NonCryptoRandomDataGenerator = new Random(); - /// <summary> /// A set of escaping mappings that help secure a string from javscript execution. /// </summary> @@ -160,17 +158,6 @@ namespace DotNetOpenAuth.Messaging { } /// <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> /// Adds a set of HTTP headers to an <see cref="HttpResponse"/> instance, /// taking care to set some headers to the appropriate properties of /// <see cref="HttpResponse" /> diff --git a/src/DotNetOpenAuth/OpenId/Provider/AnonymousIdentifierProviderBaseContract.cs b/src/DotNetOpenAuth/OpenId/Provider/AnonymousIdentifierProviderBaseContract.cs deleted file mode 100644 index 88b31b9..0000000 --- a/src/DotNetOpenAuth/OpenId/Provider/AnonymousIdentifierProviderBaseContract.cs +++ /dev/null @@ -1,23 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="AnonymousIdentifierProviderBaseContract.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Provider { - using System; - using System.Diagnostics.Contracts; - - [ContractClassFor(typeof(AnonymousIdentifierProviderBase))] - internal abstract class AnonymousIdentifierProviderBaseContract : AnonymousIdentifierProviderBase { - private AnonymousIdentifierProviderBaseContract() - : base(null) { - } - - protected override byte[] GetHashSaltForLocalIdentifier(Identifier localIdentifier) { - Contract.Requires(localIdentifier != null); - Contract.Ensures(Contract.Result<byte[]>() != null); - throw new NotImplementedException(); - } - } -} diff --git a/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs index 1c0ac1f..b1eac93 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/AuthenticationRequest.cs @@ -236,28 +236,6 @@ namespace DotNetOpenAuth.OpenId.Provider { } /// <summary> - /// Removes all personally identifiable information from the positive assertion. - /// </summary> - /// <remarks> - /// The openid.claimed_id and openid.identity values are hashed. - /// </remarks> - public void ScrubPersonallyIdentifiableInformation(IAnonymousIdentifierProvider anonymousIdentifierProvider, bool pairwiseUnique) { - ErrorUtilities.VerifyOperation(this.IsDirectedIdentity, OpenIdStrings.DirectedIdentityRequired); - ErrorUtilities.VerifyArgumentNotNull(anonymousIdentifierProvider, "anonymousIdentifierProvider"); - - ErrorUtilities.VerifyOperation( - !(this.GetResponseExtension<ClaimsResponse>().Any() || this.GetResponseExtension<FetchResponse>().Any()), - OpenIdStrings.ExtensionsWithPiiFound); - - // When generating the anonymous identifiers, the openid.identity and openid.claimed_id - // will always end up with matching values. - var anonymousIdentifier = anonymousIdentifierProvider.GetAnonymousIdentifier(this.LocalIdentifier, pairwiseUnique ? this.Realm : null); - Logger.OpenId.InfoFormat("Sending anonymous identifier assertion {0} for local identifier {1}.", anonymousIdentifier, this.LocalIdentifier); - this.positiveResponse.ClaimedIdentifier = anonymousIdentifier; - this.positiveResponse.LocalIdentifier = anonymousIdentifier; - } - - /// <summary> /// Gets a value indicating whether verification of the return URL claimed by the Relying Party /// succeeded. /// </summary> diff --git a/src/DotNetOpenAuth/OpenId/Provider/IAnonymousIdentifierProvider.cs b/src/DotNetOpenAuth/OpenId/Provider/IAnonymousIdentifierProvider.cs deleted file mode 100644 index c865efa..0000000 --- a/src/DotNetOpenAuth/OpenId/Provider/IAnonymousIdentifierProvider.cs +++ /dev/null @@ -1,44 +0,0 @@ -//----------------------------------------------------------------------- -// <copyright file="IAnonymousIdentifierProvider.cs" company="Andrew Arnott"> -// Copyright (c) Andrew Arnott. All rights reserved. -// </copyright> -//----------------------------------------------------------------------- - -namespace DotNetOpenAuth.OpenId.Provider { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; -using System.Diagnostics.Contracts; - - /// <summary> - /// Services for generating and consuming anonymous OpenID identifiers. - /// </summary> - [ContractClass(typeof(IAnonymousIdentifierProviderContract))] - public interface IAnonymousIdentifierProvider { - /// <summary> - /// Gets the anonymous identifier for some user. - /// </summary> - /// <param name="localIdentifier">The OP local identifier for the authenticating user.</param> - /// <param name="relyingPartyRealm">The realm of the relying party requesting authentication. May be null if a pairwise-unique identifier based on the realm is not desired.</param> - /// <returns> - /// A discoverable OpenID Claimed Identifier that gives no hint regarding the real identity of the controlling user. - /// </returns> - Uri GetAnonymousIdentifier(Identifier localIdentifier, Realm relyingPartyRealm); - } - - [ContractClassFor(typeof(IAnonymousIdentifierProvider))] - internal abstract class IAnonymousIdentifierProviderContract : IAnonymousIdentifierProvider { - private IAnonymousIdentifierProviderContract() { - } - - #region IAnonymousIdentifierProvider Members - - Uri IAnonymousIdentifierProvider.GetAnonymousIdentifier(Identifier localIdentifier, Realm relyingPartyRealm) { - Contract.Requires(localIdentifier != null); - Contract.Ensures(Contract.Result<Uri>() != null); - throw new NotImplementedException(); - } - #endregion - } -} diff --git a/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs b/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs index ee32c8e..ca299fc 100644 --- a/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs +++ b/src/DotNetOpenAuth/OpenId/Provider/IAuthenticationRequest.cs @@ -114,14 +114,6 @@ namespace DotNetOpenAuth.OpenId.Provider { void SetClaimedIdentifierFragment(string fragment); /// <summary> - /// Removes all personally identifiable information from the positive assertion. - /// </summary> - /// <remarks> - /// The openid.claimed_id and openid.identity values are hashed. - /// </remarks> - void ScrubPersonallyIdentifiableInformation(IAnonymousIdentifierProvider anonymousIdentifierProvider, bool pairwiseUnique); - - /// <summary> /// Attempts to perform relying party discovery of the return URL claimed by the Relying Party. /// </summary> /// <param name="requestHandler">The request handler to use to perform relying party discovery.</param> @@ -190,12 +182,6 @@ namespace DotNetOpenAuth.OpenId.Provider { throw new NotImplementedException(); } - void IAuthenticationRequest.ScrubPersonallyIdentifiableInformation(IAnonymousIdentifierProvider anonymousIdentifierProvider, bool pairwiseUnique) { - Contract.Requires(((IAuthenticationRequest)this).IsDirectedIdentity); - Contract.Requires(anonymousIdentifierProvider != null); - throw new NotImplementedException(); - } - bool IAuthenticationRequest.IsReturnUrlDiscoverable(IDirectWebRequestHandler requestHandler) { throw new NotImplementedException(); } |