diff options
21 files changed, 288 insertions, 156 deletions
diff --git a/src/DotNetOpenAuth.OpenId.Provider/DotNetOpenAuth.OpenId.Provider.csproj b/src/DotNetOpenAuth.OpenId.Provider/DotNetOpenAuth.OpenId.Provider.csproj index 775bf26..13ef7a8 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/DotNetOpenAuth.OpenId.Provider.csproj +++ b/src/DotNetOpenAuth.OpenId.Provider/DotNetOpenAuth.OpenId.Provider.csproj @@ -23,13 +23,17 @@ <Compile Include="OpenId\Behaviors\AXFetchAsSregTransform.cs" /> <Compile Include="OpenId\Behaviors\GsaIcamProviderProfile.cs" /> <Compile Include="OpenId\Behaviors\PpidGeneration.cs" /> + <Compile Include="OpenId\ChannelElements\AssociateUnencryptedProviderRequest.cs" /> <Compile Include="OpenId\ChannelElements\OpenIdProviderChannel.cs" /> + <Compile Include="OpenId\ChannelElements\OpenIdProviderMessageFactory.cs" /> <Compile Include="OpenId\ChannelElements\ProviderSigningBindingElement.cs" /> <Compile Include="OpenId\Extensions\ExtensionsInteropProviderHelper.cs" /> <Compile Include="OpenId\Extensions\UI\UIRequestProvider.cs" /> <Compile Include="OpenId\HmacShaAssociationProvider.cs" /> + <Compile Include="OpenId\Messages\AssociateDiffieHellmanProviderRequest.cs" /> <Compile Include="OpenId\Messages\AssociateDiffieHellmanProviderResponse.cs" /> - <Compile Include="OpenId\Messages\AssociateRequestProvider.cs" /> + <Compile Include="OpenId\Messages\IAssociateRequestProvider.cs" /> + <Compile Include="OpenId\Messages\AssociateRequestProviderTools.cs" /> <Compile Include="OpenId\Messages\AssociateSuccessfulResponseProvider.cs" /> <Compile Include="OpenId\Messages\AssociateSuccessfulResponseProviderContract.cs" /> <Compile Include="OpenId\Messages\AssociateUnencryptedResponseProvider.cs" /> diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/AssociateUnencryptedProviderRequest.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/AssociateUnencryptedProviderRequest.cs new file mode 100644 index 0000000..883df2c --- /dev/null +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/AssociateUnencryptedProviderRequest.cs @@ -0,0 +1,37 @@ +//----------------------------------------------------------------------- +// <copyright file="AssociateUnencryptedProviderRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.ChannelElements { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OpenId.Messages; + using DotNetOpenAuth.Messaging; + + internal class AssociateUnencryptedProviderRequest : AssociateUnencryptedRequest, IAssociateRequestProvider { + /// <summary> + /// Initializes a new instance of the <see cref="AssociateUnencryptedProviderRequest"/> class. + /// </summary> + /// <param name="version">The OpenID version this message must comply with.</param> + /// <param name="providerEndpoint">The OpenID Provider endpoint.</param> + internal AssociateUnencryptedProviderRequest(Version version, Uri providerEndpoint) + : base(version, providerEndpoint) { + } + + /// <summary> + /// Creates a Provider's response to an incoming association request. + /// </summary> + /// <returns> + /// The appropriate association response message. + /// </returns> + public IProtocolMessage CreateResponseCore() { + var response = new AssociateUnencryptedResponseProvider(this.Version, this); + response.AssociationType = this.AssociationType; + return response; + } + } +} diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/OpenIdProviderChannel.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/OpenIdProviderChannel.cs index fa9b928..ab3b993 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/OpenIdProviderChannel.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/OpenIdProviderChannel.cs @@ -26,7 +26,7 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// <param name="nonceStore">The nonce store to use.</param> /// <param name="securitySettings">The security settings.</param> internal OpenIdProviderChannel(IProviderAssociationStore cryptoKeyStore, INonceStore nonceStore, ProviderSecuritySettings securitySettings) - : this(cryptoKeyStore, nonceStore, new OpenIdMessageFactory(), securitySettings) { + : this(cryptoKeyStore, nonceStore, new OpenIdProviderMessageFactory(), securitySettings) { Contract.Requires<ArgumentNullException>(cryptoKeyStore != null); Contract.Requires<ArgumentNullException>(securitySettings != null); } diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdMessageFactory.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/OpenIdProviderMessageFactory.cs index e73baa0..c633cbf 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/OpenIdMessageFactory.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/ChannelElements/OpenIdProviderMessageFactory.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// <copyright file="OpenIdMessageFactory.cs" company="Andrew Arnott"> +// <copyright file="OpenIdProviderMessageFactory.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- @@ -7,18 +7,15 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { using System; using System.Collections.Generic; - using System.Diagnostics.Contracts; using System.Linq; using System.Text; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; /// <summary> - /// Distinguishes the various OpenID message types for deserialization purposes. + /// OpenID Provider message factory. /// </summary> - internal class OpenIdMessageFactory : IMessageFactory { - #region IMessageFactory Members - + internal class OpenIdProviderMessageFactory : IMessageFactory { /// <summary> /// Analyzes an incoming request message payload to discover what kind of /// message is embedded in it and returns the type, or null if no match is found. @@ -44,9 +41,9 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { if (fields.TryGetValue(protocol.openid.mode, out mode)) { if (string.Equals(mode, protocol.Args.Mode.associate)) { if (fields.ContainsKey(protocol.openid.dh_consumer_public)) { - message = new AssociateDiffieHellmanRequest(protocol.Version, recipient.Location); + message = new AssociateDiffieHellmanProviderRequest(protocol.Version, recipient.Location); } else { - message = new AssociateUnencryptedRequest(protocol.Version, recipient.Location); + message = new AssociateUnencryptedProviderRequest(protocol.Version, recipient.Location); } } else if (string.Equals(mode, protocol.Args.Mode.checkid_setup) || string.Equals(mode, protocol.Args.Mode.checkid_immediate)) { @@ -57,20 +54,6 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent); message = new SignedResponseRequest(protocol.Version, recipient.Location, authMode); } - } else if (string.Equals(mode, protocol.Args.Mode.cancel) || - (string.Equals(mode, protocol.Args.Mode.setup_needed) && (protocol.Version.Major >= 2 || fields.ContainsKey(protocol.openid.user_setup_url)))) { - message = new NegativeAssertionResponse(protocol.Version, recipient.Location, mode); - } else if (string.Equals(mode, protocol.Args.Mode.id_res)) { - if (fields.ContainsKey(protocol.openid.identity)) { - message = new PositiveAssertionResponse(protocol.Version, recipient.Location); - } else { - ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent); - message = new IndirectSignedResponse(protocol.Version, recipient.Location); - } - } else if (string.Equals(mode, protocol.Args.Mode.check_authentication)) { - message = new CheckAuthenticationRequest(protocol.Version, recipient.Location); - } else if (string.Equals(mode, protocol.Args.Mode.error)) { - message = new IndirectErrorResponse(protocol.Version, recipient.Location); } else { ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessagePartValue, protocol.openid.mode, mode); } @@ -93,10 +76,9 @@ namespace DotNetOpenAuth.OpenId.ChannelElements { /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can /// deserialize to. Null if the request isn't recognized as a valid protocol message. /// </returns> - public virtual IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { - return null; + public IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { + // OpenID Providers make no outbound requests, and thus receive no direct response messages. + throw new NotImplementedException(); } - - #endregion } } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderRequest.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderRequest.cs new file mode 100644 index 0000000..0cf70d5 --- /dev/null +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderRequest.cs @@ -0,0 +1,34 @@ +//----------------------------------------------------------------------- +// <copyright file="AssociateDiffieHellmanProviderRequest.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Messages { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + + internal class AssociateDiffieHellmanProviderRequest : AssociateDiffieHellmanRequest, IAssociateRequestProvider { + /// <summary> + /// Initializes a new instance of the <see cref="AssociateDiffieHellmanProviderRequest"/> class. + /// </summary> + /// <param name="version">The OpenID version this message must comply with.</param> + /// <param name="providerEndpoint">The OpenID Provider endpoint.</param> + internal AssociateDiffieHellmanProviderRequest(Version version, Uri providerEndpoint) + : base(version, providerEndpoint) { + } + + /// <summary> + /// Creates a Provider's response to an incoming association request. + /// </summary> + /// <returns> + /// The appropriate association response message. + /// </returns> + public IProtocolMessage CreateResponseCore() { + return new AssociateDiffieHellmanProviderResponse(this.Version, this); + } + } +} diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderResponse.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderResponse.cs index 2e0a4e1..2cb3ab5 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderResponse.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateDiffieHellmanProviderResponse.cs @@ -19,7 +19,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <remarks> /// Association response messages are described in OpenID 2.0 section 8.2. This type covers section 8.2.3. /// </remarks> - internal class AssociateDiffieHellmanProviderResponse : AssociateDiffieHellmanResponse { + internal class AssociateDiffieHellmanProviderResponse : AssociateDiffieHellmanResponse, IAssociateSuccessfulResponseProvider { /// <summary> /// Initializes a new instance of the <see cref="AssociateDiffieHellmanProviderResponse"/> class. /// </summary> @@ -29,6 +29,16 @@ namespace DotNetOpenAuth.OpenId.Messages { : base(responseVersion, originatingRequest) { } + long IAssociateSuccessfulResponseProvider.ExpiresIn { + get { return this.ExpiresIn; } + set { this.ExpiresIn = value; } + } + + string IAssociateSuccessfulResponseProvider.AssociationHandle { + get { return this.AssociationHandle; } + set { this.AssociationHandle = value; } + } + /// <summary> /// Creates the association at the provider side after the association request has been received. /// </summary> @@ -42,7 +52,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// The response message is updated to include the details of the created association by this method, /// but the resulting association is <i>not</i> added to the association store and must be done by the caller. /// </remarks> - protected Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { + public Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { var diffieHellmanRequest = request as AssociateDiffieHellmanRequest; ErrorUtilities.VerifyInternal(diffieHellmanRequest != null, "Expected a DH request type."); diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateRequestProvider.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateRequestProviderTools.cs index 032106f..7537ab6 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateRequestProvider.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateRequestProviderTools.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// <copyright file="AssociateRequestProvider.cs" company="Andrew Arnott"> +// <copyright file="AssociateRequestProviderTools.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- @@ -7,25 +7,13 @@ namespace DotNetOpenAuth.OpenId.Messages { using System; using System.Collections.Generic; - using System.Diagnostics.Contracts; using System.Linq; using System.Text; + using System.Diagnostics.Contracts; using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Provider; - /// <summary> - /// The openid.mode=associate message as it is received at the OpenID Provider. - /// </summary> - internal abstract class AssociateRequestProvider : AssociateRequest { - /// <summary> - /// Initializes a new instance of the <see cref="AssociateRequestProvider"/> class. - /// </summary> - /// <param name="version">The OpenID version this message must comply with.</param> - /// <param name="providerEndpoint">The OpenID Provider endpoint.</param> - internal AssociateRequestProvider(Version version, Uri providerEndpoint) - : base(version, providerEndpoint) { - } - + internal static class AssociateRequestProviderTools { /// <summary> /// Creates a Provider's response to an incoming association request. /// </summary> @@ -40,72 +28,63 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> /// </remarks> - internal IProtocolMessage CreateResponse(IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { + internal static IProtocolMessage CreateResponse(IAssociateRequestProvider requestMessage, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { + Contract.Requires<ArgumentNullException>(requestMessage != null, "requestMessage"); Contract.Requires<ArgumentNullException>(associationStore != null); Contract.Requires<ArgumentNullException>(securitySettings != null); + AssociateRequest request = (AssociateRequest)requestMessage; IProtocolMessage response; - if (securitySettings.IsAssociationInPermittedRange(Protocol, this.AssociationType) && - HmacShaAssociation.IsDHSessionCompatible(Protocol, this.AssociationType, this.SessionType)) { - response = this.CreateResponseCore(); + var protocol = requestMessage.GetProtocol(); + if (securitySettings.IsAssociationInPermittedRange(protocol, request.AssociationType) && + HmacShaAssociation.IsDHSessionCompatible(protocol, request.AssociationType, request.SessionType)) { + response = requestMessage.CreateResponseCore(); // Create and store the association if this is a successful response. - var successResponse = response as AssociateSuccessfulResponseProvider; + var successResponse = response as IAssociateSuccessfulResponseProvider; if (successResponse != null) { - successResponse.CreateAssociationAtProvider(this, associationStore, securitySettings); + OpenIdProviderUtilities.CreateAssociation(request, successResponse, associationStore, securitySettings); } } else { - response = this.CreateUnsuccessfulResponse(securitySettings); + response = CreateUnsuccessfulResponse(requestMessage, securitySettings); } return response; } /// <summary> - /// Creates a Provider's response to an incoming association request. - /// </summary> - /// <returns> - /// The appropriate association response message. - /// </returns> - /// <remarks> - /// <para>If an association can be successfully created, the - /// AssociateSuccessfulResponse.CreateAssociation method must not be - /// called by this method.</para> - /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. - /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> - /// </remarks> - protected abstract IProtocolMessage CreateResponseCore(); - - /// <summary> /// Creates a response that notifies the Relying Party that the requested /// association type is not supported by this Provider, and offers /// an alternative association type, if possible. /// </summary> /// <param name="securitySettings">The security settings that apply to this Provider.</param> /// <returns>The response to send to the Relying Party.</returns> - private AssociateUnsuccessfulResponse CreateUnsuccessfulResponse(ProviderSecuritySettings securitySettings) { + private static AssociateUnsuccessfulResponse CreateUnsuccessfulResponse(IAssociateRequestProvider requestMessage, ProviderSecuritySettings securitySettings) { + Contract.Requires<ArgumentNullException>(requestMessage != null, "requestMessage"); Contract.Requires<ArgumentNullException>(securitySettings != null); - var unsuccessfulResponse = new AssociateUnsuccessfulResponse(this.Version, this); + var unsuccessfulResponse = new AssociateUnsuccessfulResponse(requestMessage.Version, (AssociateRequest)requestMessage); // The strategy here is to suggest that the RP try again with the lowest // permissible security settings, giving the RP the best chance of being // able to match with a compatible request. - bool unencryptedAllowed = this.Recipient.IsTransportSecure(); + bool unencryptedAllowed = requestMessage.Recipient.IsTransportSecure(); bool useDiffieHellman = !unencryptedAllowed; + var request = (AssociateRequest)requestMessage; + var protocol = requestMessage.GetProtocol(); string associationType, sessionType; - if (HmacShaAssociation.TryFindBestAssociation(Protocol, false, securitySettings, useDiffieHellman, out associationType, out sessionType)) { - ErrorUtilities.VerifyInternal(this.AssociationType != associationType, "The RP asked for an association that should have been allowed, but the OP is trying to suggest the same one as an alternative!"); + if (HmacShaAssociation.TryFindBestAssociation(protocol, false, securitySettings, useDiffieHellman, out associationType, out sessionType)) { + ErrorUtilities.VerifyInternal(request.AssociationType != associationType, "The RP asked for an association that should have been allowed, but the OP is trying to suggest the same one as an alternative!"); unsuccessfulResponse.AssociationType = associationType; unsuccessfulResponse.SessionType = sessionType; Logger.OpenId.InfoFormat( "Association requested of type '{0}' and session '{1}', which the Provider does not support. Sending back suggested alternative of '{0}' with session '{1}'.", - this.AssociationType, - this.SessionType, + request.AssociationType, + request.SessionType, unsuccessfulResponse.AssociationType, unsuccessfulResponse.SessionType); } else { - Logger.OpenId.InfoFormat("Association requested of type '{0}' and session '{1}', which the Provider does not support. No alternative association type qualified for suggesting back to the Relying Party.", this.AssociationType, this.SessionType); + Logger.OpenId.InfoFormat("Association requested of type '{0}' and session '{1}', which the Provider does not support. No alternative association type qualified for suggesting back to the Relying Party.", request.AssociationType, request.SessionType); } return unsuccessfulResponse; diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProvider.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProvider.cs index f46ace1..3db33c9 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProvider.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProvider.cs @@ -11,20 +11,16 @@ namespace DotNetOpenAuth.OpenId.Messages { using System.Linq; using System.Text; using DotNetOpenAuth.OpenId.Provider; +using DotNetOpenAuth.Messaging; /// <summary> /// An outgoing successful association response from the OpenID Provider. /// </summary> - [ContractClass(typeof(AssociateSuccessfulResponseProviderContract))] - internal abstract class AssociateSuccessfulResponseProvider : AssociateSuccessfulResponse { - /// <summary> - /// Initializes a new instance of the <see cref="AssociateSuccessfulResponseProvider"/> class. - /// </summary> - /// <param name="version">The version.</param> - /// <param name="request">The request.</param> - internal AssociateSuccessfulResponseProvider(Version version, AssociateRequest request) : - base(version, request) { - } + [ContractClass(typeof(IAssociateSuccessfulResponseProviderContract))] + internal interface IAssociateSuccessfulResponseProvider : IProtocolMessage { + long ExpiresIn { get; set; } + + string AssociationHandle { get; set; } /// <summary> /// Called to create the Association based on a request previously given by the Relying Party. @@ -42,6 +38,6 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <para>The response message is updated to include the details of the created association by this method, /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para> /// </remarks> - protected internal abstract Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings); + Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings); } } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProviderContract.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProviderContract.cs index a6d067e..0b34e1f 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProviderContract.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateSuccessfulResponseProviderContract.cs @@ -15,17 +15,8 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary> /// Code contract for the <see cref="AssociateSuccessfulResponseProvider"/> class. /// </summary> - [ContractClassFor(typeof(AssociateSuccessfulResponseProvider))] - internal abstract class AssociateSuccessfulResponseProviderContract : AssociateSuccessfulResponseProvider { - /// <summary> - /// Initializes a new instance of the <see cref="AssociateSuccessfulResponseProviderContract"/> class. - /// </summary> - /// <param name="version">The version.</param> - /// <param name="request">The request.</param> - private AssociateSuccessfulResponseProviderContract(Version version, AssociateRequest request) - : base(version, request) { - } - + [ContractClassFor(typeof(IAssociateSuccessfulResponseProvider))] + internal abstract class IAssociateSuccessfulResponseProviderContract : IAssociateSuccessfulResponseProvider { /// <summary> /// Called to create the Association based on a request previously given by the Relying Party. /// </summary> @@ -35,11 +26,41 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <returns> /// The created association. /// </returns> - protected internal override Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { + Association IAssociateSuccessfulResponseProvider.CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { Contract.Requires<ArgumentNullException>(request != null); Contract.Requires<ArgumentNullException>(associationStore != null); Contract.Requires<ArgumentNullException>(securitySettings != null); throw new NotImplementedException(); } + + long IAssociateSuccessfulResponseProvider.ExpiresIn { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + string IAssociateSuccessfulResponseProvider.AssociationHandle { + get { throw new NotImplementedException(); } + set { throw new NotImplementedException(); } + } + + Messaging.MessageProtections Messaging.IProtocolMessage.RequiredProtection { + get { throw new NotImplementedException(); } + } + + Messaging.MessageTransport Messaging.IProtocolMessage.Transport { + get { throw new NotImplementedException(); } + } + + Version Messaging.IMessage.Version { + get { throw new NotImplementedException(); } + } + + IDictionary<string, string> Messaging.IMessage.ExtraData { + get { throw new NotImplementedException(); } + } + + void Messaging.IMessage.EnsureValidMessage() { + throw new NotImplementedException(); + } } } diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateUnencryptedResponseProvider.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateUnencryptedResponseProvider.cs index 120d2c4..166e125 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateUnencryptedResponseProvider.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/AssociateUnencryptedResponseProvider.cs @@ -14,7 +14,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary> /// An unencrypted association response as it is sent by the Provider. /// </summary> - internal class AssociateUnencryptedResponseProvider : AssociateUnencryptedResponse { + internal class AssociateUnencryptedResponseProvider : AssociateUnencryptedResponse, IAssociateSuccessfulResponseProvider { /// <summary> /// Initializes a new instance of the <see cref="AssociateUnencryptedResponseProvider"/> class. /// </summary> @@ -24,6 +24,16 @@ namespace DotNetOpenAuth.OpenId.Messages { : base(version, request) { } + long IAssociateSuccessfulResponseProvider.ExpiresIn { + get { return this.ExpiresIn; } + set { this.ExpiresIn = value; } + } + + string IAssociateSuccessfulResponseProvider.AssociationHandle { + get { return this.AssociationHandle; } + set { this.AssociationHandle = value; } + } + /// <summary> /// Called to create the Association based on a request previously given by the Relying Party. /// </summary> @@ -42,7 +52,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <para>The response message is updated to include the details of the created association by this method, /// but the resulting association is <i>not</i> added to the association store and must be done by the caller.</para> /// </remarks> - protected Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { + public Association CreateAssociationAtProvider(AssociateRequest request, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { Association association = HmacShaAssociationProvider.Create(Protocol, this.AssociationType, AssociationRelyingPartyType.Smart, associationStore, securitySettings); this.MacKey = association.SecretKey; return association; diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/IAssociateRequestProvider.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/IAssociateRequestProvider.cs new file mode 100644 index 0000000..ed7c2d4 --- /dev/null +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Messages/IAssociateRequestProvider.cs @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------- +// <copyright file="IAssociateRequestProvider.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Messages { + using DotNetOpenAuth.Messaging; + + /// <summary> + /// The openid.mode=associate message as it is received at the OpenID Provider. + /// </summary> + internal interface IAssociateRequestProvider : IDirectedProtocolMessage{ + /// <summary> + /// Creates a Provider's response to an incoming association request. + /// </summary> + /// <returns> + /// The appropriate association response message. + /// </returns> + /// <remarks> + /// <para>If an association can be successfully created, the + /// AssociateSuccessfulResponse.CreateAssociation method must not be + /// called by this method.</para> + /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. + /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> + /// </remarks> + IProtocolMessage CreateResponseCore(); + } +} diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/OpenIdProviderUtilities.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/OpenIdProviderUtilities.cs index 73e404c..5468ab2 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/OpenIdProviderUtilities.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/OpenIdProviderUtilities.cs @@ -33,7 +33,7 @@ namespace DotNetOpenAuth.OpenId { /// This method is called by both the Provider and the Relying Party, but actually performs /// quite different operations in either scenario. /// </remarks> - internal static Association CreateAssociation(AssociateRequest request, AssociateSuccessfulResponseProvider response, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { + internal static Association CreateAssociation(AssociateRequest request, IAssociateSuccessfulResponseProvider response, IProviderAssociationStore associationStore, ProviderSecuritySettings securitySettings) { Contract.Requires<ArgumentNullException>(request != null); Contract.Requires<ArgumentNullException>(response != null, "response"); Contract.Requires<ArgumentNullException>(securitySettings != null, "securitySettings"); diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs index 6f06024..e794433 100644 --- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs +++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/OpenIdProvider.cs @@ -286,9 +286,9 @@ namespace DotNetOpenAuth.OpenId.Provider { } if (result == null) { - var associateMessage = incomingMessage as AssociateRequestProvider; + var associateMessage = incomingMessage as IAssociateRequestProvider; if (associateMessage != null) { - result = new AutoResponsiveRequest(incomingMessage, associateMessage.CreateResponse(this.AssociationStore, this.SecuritySettings), this.SecuritySettings); + result = new AutoResponsiveRequest(incomingMessage, AssociateRequestProviderTools.CreateResponse(associateMessage, this.AssociationStore, this.SecuritySettings), this.SecuritySettings); } } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/OpenIdRelyingPartyMessageFactory.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/OpenIdRelyingPartyMessageFactory.cs index aaa375f..ce9abda 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/OpenIdRelyingPartyMessageFactory.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/ChannelElements/OpenIdRelyingPartyMessageFactory.cs @@ -6,7 +6,54 @@ using DotNetOpenAuth.Messaging; using DotNetOpenAuth.OpenId.Messages; - internal class OpenIdRelyingPartyMessageFactory : OpenIdMessageFactory { + internal class OpenIdRelyingPartyMessageFactory : IMessageFactory { + /// <summary> + /// Analyzes an incoming request message payload to discover what kind of + /// message is embedded in it and returns the type, or null if no match is found. + /// </summary> + /// <param name="recipient">The intended or actual recipient of the request message.</param> + /// <param name="fields">The name/value pairs that make up the message payload.</param> + /// <returns> + /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can + /// deserialize to. Null if the request isn't recognized as a valid protocol message. + /// </returns> + public IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { + RequestBase message = null; + + // Discern the OpenID version of the message. + Protocol protocol = Protocol.V11; + string ns; + if (fields.TryGetValue(Protocol.V20.openid.ns, out ns)) { + ErrorUtilities.VerifyProtocol(string.Equals(ns, Protocol.OpenId2Namespace, StringComparison.Ordinal), MessagingStrings.UnexpectedMessagePartValue, Protocol.V20.openid.ns, ns); + protocol = Protocol.V20; + } + + string mode; + if (fields.TryGetValue(protocol.openid.mode, out mode)) { + if (string.Equals(mode, protocol.Args.Mode.cancel) || + (string.Equals(mode, protocol.Args.Mode.setup_needed) && (protocol.Version.Major >= 2 || fields.ContainsKey(protocol.openid.user_setup_url)))) { + message = new NegativeAssertionResponse(protocol.Version, recipient.Location, mode); + } else if (string.Equals(mode, protocol.Args.Mode.id_res)) { + if (fields.ContainsKey(protocol.openid.identity)) { + message = new PositiveAssertionResponse(protocol.Version, recipient.Location); + } else { + ErrorUtilities.VerifyProtocol(!fields.ContainsKey(protocol.openid.claimed_id), OpenIdStrings.IdentityAndClaimedIdentifierMustBeBothPresentOrAbsent); + message = new IndirectSignedResponse(protocol.Version, recipient.Location); + } + } else if (string.Equals(mode, protocol.Args.Mode.error)) { + message = new IndirectErrorResponse(protocol.Version, recipient.Location); + } else { + ErrorUtilities.ThrowProtocol(MessagingStrings.UnexpectedMessagePartValue, protocol.openid.mode, mode); + } + } + + if (message != null) { + message.SetAsIncoming(); + } + + return message; + } + /// <summary> /// Analyzes an incoming request message payload to discover what kind of /// message is embedded in it and returns the type, or null if no match is found. @@ -17,7 +64,7 @@ /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can /// deserialize to. Null if the request isn't recognized as a valid protocol message. /// </returns> - public override IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { + public IDirectResponseProtocolMessage GetNewResponseMessage(IDirectedProtocolMessage request, IDictionary<string, string> fields) { DirectResponseBase message = null; // Discern the OpenID version of the message. @@ -47,7 +94,7 @@ } if (associateUnencryptedRequest != null) { - message = new AssociateUnencryptedResponse(protocol.Version, associateUnencryptedRequest); + message = new AssociateUnencryptedResponseRelyingParty(protocol.Version, associateUnencryptedRequest); } } } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateDiffieHellmanRelyingPartyResponse.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateDiffieHellmanRelyingPartyResponse.cs index cb44c7c..2112288 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateDiffieHellmanRelyingPartyResponse.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateDiffieHellmanRelyingPartyResponse.cs @@ -18,7 +18,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <remarks> /// Association response messages are described in OpenID 2.0 section 8.2. This type covers section 8.2.3. /// </remarks> - internal class AssociateDiffieHellmanRelyingPartyResponse : AssociateDiffieHellmanResponse { + internal class AssociateDiffieHellmanRelyingPartyResponse : AssociateDiffieHellmanResponse, IAssociateSuccessfulResponseRelyingParty { /// <summary> /// Initializes a new instance of the <see cref="AssociateDiffieHellmanRelyingPartyResponse"/> class. /// </summary> @@ -36,7 +36,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <remarks> /// The resulting association is <i>not</i> added to the association store and must be done by the caller. /// </remarks> - protected Association CreateAssociationAtRelyingParty(AssociateRequest request) { + public Association CreateAssociationAtRelyingParty(AssociateRequest request) { var diffieHellmanRequest = request as AssociateDiffieHellmanRequest; ErrorUtilities.VerifyArgument(diffieHellmanRequest != null, OpenIdStrings.DiffieHellmanAssociationRequired); diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingParty.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingParty.cs index 717fa27..a3eef44 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingParty.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingParty.cs @@ -1,5 +1,5 @@ //----------------------------------------------------------------------- -// <copyright file="AssociateSuccessfulResponseRelyingParty.cs" company="Andrew Arnott"> +// <copyright file="IAssociateSuccessfulResponseRelyingParty.cs" company="Andrew Arnott"> // Copyright (c) Andrew Arnott. All rights reserved. // </copyright> //----------------------------------------------------------------------- @@ -10,26 +10,18 @@ namespace DotNetOpenAuth.OpenId.Messages { using System.Diagnostics.Contracts; using System.Linq; using System.Text; + using DotNetOpenAuth.Messaging; /// <summary> /// A successful association response as it is received by the relying party. /// </summary> - [ContractClass(typeof(AssociateSuccessfulResponseRelyingPartyContract))] - internal abstract class AssociateSuccessfulResponseRelyingParty : AssociateSuccessfulResponse { - /// <summary> - /// Initializes a new instance of the <see cref="AssociateSuccessfulResponseRelyingParty"/> class. - /// </summary> - /// <param name="version">The version.</param> - /// <param name="request">The request.</param> - internal AssociateSuccessfulResponseRelyingParty(Version version, AssociateRequest request) - : base(version, request) { - } - + [ContractClass(typeof(IAssociateSuccessfulResponseRelyingPartyContract))] + internal interface IAssociateSuccessfulResponseRelyingParty : IProtocolMessage { /// <summary> /// Called to create the Association based on a request previously given by the Relying Party. /// </summary> /// <param name="request">The prior request for an association.</param> /// <returns>The created association.</returns> - protected internal abstract Association CreateAssociationAtRelyingParty(AssociateRequest request); + Association CreateAssociationAtRelyingParty(AssociateRequest request); } } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingPartyContract.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingPartyContract.cs index 4a9a8f4..35cb928 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingPartyContract.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateSuccessfulResponseRelyingPartyContract.cs @@ -16,17 +16,8 @@ namespace DotNetOpenAuth { /// <summary> /// Code contract for the <see cref="AssociateSuccessfulResponseRelyingParty"/> class. /// </summary> - [ContractClassFor(typeof(AssociateSuccessfulResponseRelyingParty))] - internal abstract class AssociateSuccessfulResponseRelyingPartyContract : AssociateSuccessfulResponseRelyingParty { - /// <summary> - /// Initializes a new instance of the <see cref="AssociateSuccessfulResponseRelyingPartyContract"/> class. - /// </summary> - /// <param name="version">The version.</param> - /// <param name="request">The request.</param> - private AssociateSuccessfulResponseRelyingPartyContract(Version version, AssociateRequest request) - : base(version, request) { - } - + [ContractClassFor(typeof(IAssociateSuccessfulResponseRelyingParty))] + internal abstract class IAssociateSuccessfulResponseRelyingPartyContract : IAssociateSuccessfulResponseRelyingParty { /// <summary> /// Called to create the Association based on a request previously given by the Relying Party. /// </summary> @@ -34,9 +25,29 @@ namespace DotNetOpenAuth { /// <returns> /// The created association. /// </returns> - protected internal override Association CreateAssociationAtRelyingParty(AssociateRequest request) { + Association IAssociateSuccessfulResponseRelyingParty.CreateAssociationAtRelyingParty(AssociateRequest request) { Contract.Requires<ArgumentNullException>(request != null); throw new NotImplementedException(); } + + Messaging.MessageProtections Messaging.IProtocolMessage.RequiredProtection { + get { throw new NotImplementedException(); } + } + + Messaging.MessageTransport Messaging.IProtocolMessage.Transport { + get { throw new NotImplementedException(); } + } + + Version Messaging.IMessage.Version { + get { throw new NotImplementedException(); } + } + + IDictionary<string, string> Messaging.IMessage.ExtraData { + get { throw new NotImplementedException(); } + } + + void Messaging.IMessage.EnsureValidMessage() { + throw new NotImplementedException(); + } } } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateUnencryptedResponseRelyingParty.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateUnencryptedResponseRelyingParty.cs index d2561d4..b2a5e11 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateUnencryptedResponseRelyingParty.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/Messages/AssociateUnencryptedResponseRelyingParty.cs @@ -13,7 +13,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// <summary> /// A response to an unencrypted assocation request, as it is received by the relying party. /// </summary> - internal class AssociateUnencryptedResponseRelyingParty : AssociateUnencryptedResponse { + internal class AssociateUnencryptedResponseRelyingParty : AssociateUnencryptedResponse, IAssociateSuccessfulResponseRelyingParty { /// <summary> /// Initializes a new instance of the <see cref="AssociateUnencryptedResponseRelyingParty"/> class. /// </summary> @@ -28,7 +28,7 @@ namespace DotNetOpenAuth.OpenId.Messages { /// </summary> /// <param name="request">The prior request for an association.</param> /// <returns>The created association.</returns> - protected Association CreateAssociationAtRelyingParty(AssociateRequest request) { + public Association CreateAssociationAtRelyingParty(AssociateRequest request) { Association association = HmacShaAssociation.Create(Protocol, this.AssociationType, this.AssociationHandle, this.MacKey, TimeSpan.FromSeconds(this.ExpiresIn)); return association; } diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs index b0c543c..d8b8840 100644 --- a/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs +++ b/src/DotNetOpenAuth.OpenId.RelyingParty/OpenId/RelyingParty/AssociationManager.cs @@ -193,7 +193,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty { try { var associateResponse = this.channel.Request(associateRequest); - var associateSuccessfulResponse = associateResponse as AssociateSuccessfulResponseRelyingParty; + var associateSuccessfulResponse = associateResponse as IAssociateSuccessfulResponseRelyingParty; var associateUnsuccessfulResponse = associateResponse as AssociateUnsuccessfulResponse; if (associateSuccessfulResponse != null) { Association association = associateSuccessfulResponse.CreateAssociationAtRelyingParty(associateRequest); diff --git a/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj b/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj index 62fc620..a215cb9 100644 --- a/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj +++ b/src/DotNetOpenAuth.OpenId/DotNetOpenAuth.OpenId.csproj @@ -47,7 +47,6 @@ <Compile Include="OpenId\ChannelElements\SigningBindingElement.cs" /> <Compile Include="OpenId\ChannelElements\KeyValueFormEncoding.cs" /> <Compile Include="OpenId\ChannelElements\OpenIdChannel.cs" /> - <Compile Include="OpenId\ChannelElements\OpenIdMessageFactory.cs" /> <Compile Include="OpenId\ChannelElements\ReturnToSignatureBindingElement.cs" /> <Compile Include="OpenId\ChannelElements\SkipSecurityBindingElement.cs" /> <Compile Include="OpenId\AssociationContract.cs" /> diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Messages/AssociateUnencryptedRequest.cs b/src/DotNetOpenAuth.OpenId/OpenId/Messages/AssociateUnencryptedRequest.cs index 78a912c..eda8cf3 100644 --- a/src/DotNetOpenAuth.OpenId/OpenId/Messages/AssociateUnencryptedRequest.cs +++ b/src/DotNetOpenAuth.OpenId/OpenId/Messages/AssociateUnencryptedRequest.cs @@ -46,24 +46,5 @@ namespace DotNetOpenAuth.OpenId.Messages { Protocol.Args.SessionType.NoEncryption, SessionType); } - - /// <summary> - /// Creates a Provider's response to an incoming association request. - /// </summary> - /// <returns> - /// The appropriate association response message. - /// </returns> - /// <remarks> - /// <para>If an association can be successfully created, the - /// AssociateSuccessfulResponse.CreateAssociation method must not be - /// called by this method.</para> - /// <para>Successful association response messages will derive from <see cref="AssociateSuccessfulResponse"/>. - /// Failed association response messages will derive from <see cref="AssociateUnsuccessfulResponse"/>.</para> - /// </remarks> - protected /*override */IProtocolMessage CreateResponseCore() { - var response = new AssociateUnencryptedResponse(this.Version, this); - response.AssociationType = this.AssociationType; - return response; - } } } |