diff options
Diffstat (limited to 'src/DotNetOpenAuth.OpenId/OpenId/Provider/Request.cs')
-rw-r--r-- | src/DotNetOpenAuth.OpenId/OpenId/Provider/Request.cs | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/Provider/Request.cs b/src/DotNetOpenAuth.OpenId/OpenId/Provider/Request.cs new file mode 100644 index 0000000..4e54ef9 --- /dev/null +++ b/src/DotNetOpenAuth.OpenId/OpenId/Provider/Request.cs @@ -0,0 +1,210 @@ +//----------------------------------------------------------------------- +// <copyright file="Request.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OpenId.Provider { + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Linq; + using System.Text; + using DotNetOpenAuth.Messaging; + using DotNetOpenAuth.OpenId.Messages; + + /// <summary> + /// Implements the <see cref="IRequest"/> interface for all incoming + /// request messages to an OpenID Provider. + /// </summary> + [Serializable] + [ContractClass(typeof(RequestContract))] + [ContractVerification(true)] + internal abstract class Request : IRequest { + /// <summary> + /// The incoming request message. + /// </summary> + private readonly IDirectedProtocolMessage request; + + /// <summary> + /// The incoming request message cast to its extensible form. + /// Or null if the message does not support extensions. + /// </summary> + private readonly IProtocolMessageWithExtensions extensibleMessage; + + /// <summary> + /// The version of the OpenID protocol to use. + /// </summary> + private readonly Version protocolVersion; + + /// <summary> + /// Backing store for the <see cref="Protocol"/> property. + /// </summary> + [NonSerialized] + private Protocol protocol; + + /// <summary> + /// The list of extensions to add to the response message. + /// </summary> + private List<IOpenIdMessageExtension> responseExtensions = new List<IOpenIdMessageExtension>(); + + /// <summary> + /// Initializes a new instance of the <see cref="Request"/> class. + /// </summary> + /// <param name="request">The incoming request message.</param> + /// <param name="securitySettings">The security settings from the channel.</param> + protected Request(IDirectedProtocolMessage request, ProviderSecuritySettings securitySettings) { + Contract.Requires<ArgumentNullException>(request != null); + Contract.Requires<ArgumentNullException>(securitySettings != null); + + this.request = request; + this.SecuritySettings = securitySettings; + this.protocolVersion = this.request.Version; + this.extensibleMessage = request as IProtocolMessageWithExtensions; + } + + /// <summary> + /// Initializes a new instance of the <see cref="Request"/> class. + /// </summary> + /// <param name="version">The version.</param> + /// <param name="securitySettings">The security settings.</param> + protected Request(Version version, ProviderSecuritySettings securitySettings) { + Contract.Requires<ArgumentNullException>(version != null); + Contract.Requires<ArgumentNullException>(securitySettings != null); + + this.protocolVersion = version; + this.SecuritySettings = securitySettings; + } + + #region IRequest Properties + + /// <summary> + /// Gets a value indicating whether the response is ready to be sent to the user agent. + /// </summary> + /// <remarks> + /// This property returns false if there are properties that must be set on this + /// request instance before the response can be sent. + /// </remarks> + public abstract bool IsResponseReady { get; } + + /// <summary> + /// Gets or sets the security settings that apply to this request. + /// </summary> + /// <value>Defaults to the <see cref="OpenIdProvider.SecuritySettings"/> on the <see cref="OpenIdProvider"/>.</value> + public ProviderSecuritySettings SecuritySettings { get; set; } + + /// <summary> + /// Gets the response to send to the user agent. + /// </summary> + /// <exception cref="InvalidOperationException">Thrown if <see cref="IsResponseReady"/> is <c>false</c>.</exception> + internal IProtocolMessage Response { + get { + Contract.Requires<InvalidOperationException>(this.IsResponseReady, OpenIdStrings.ResponseNotReady); + Contract.Ensures(Contract.Result<IProtocolMessage>() != null); + + if (this.responseExtensions.Count > 0) { + var extensibleResponse = this.ResponseMessage as IProtocolMessageWithExtensions; + ErrorUtilities.VerifyOperation(extensibleResponse != null, MessagingStrings.MessageNotExtensible, this.ResponseMessage.GetType().Name); + foreach (var extension in this.responseExtensions) { + // It's possible that a prior call to this property + // has already added some/all of the extensions to the message. + // We don't have to worry about deleting old ones because + // this class provides no facility for removing extensions + // that are previously added. + if (!extensibleResponse.Extensions.Contains(extension)) { + extensibleResponse.Extensions.Add(extension); + } + } + } + + return this.ResponseMessage; + } + } + + #endregion + + /// <summary> + /// Gets the original request message. + /// </summary> + /// <value>This may be null in the case of an unrecognizable message.</value> + protected internal IDirectedProtocolMessage RequestMessage { + get { return this.request; } + } + + /// <summary> + /// Gets the response message, once <see cref="IsResponseReady"/> is <c>true</c>. + /// </summary> + protected abstract IProtocolMessage ResponseMessage { get; } + + /// <summary> + /// Gets the protocol version used in the request. + /// </summary> + protected Protocol Protocol { + get { + if (this.protocol == null) { + this.protocol = Protocol.Lookup(this.protocolVersion); + } + + return this.protocol; + } + } + + #region IRequest Methods + + /// <summary> + /// Adds an extension to the response to send to the relying party. + /// </summary> + /// <param name="extension">The extension to add to the response message.</param> + public void AddResponseExtension(IOpenIdMessageExtension extension) { + // Because the derived AuthenticationRequest class can swap out + // one response message for another (auth vs. no-auth), and because + // some response messages support extensions while others don't, + // we just add the extensions to a collection here and add them + // to the response on the way out. + this.responseExtensions.Add(extension); + } + + /// <summary> + /// Removes any response extensions previously added using <see cref="AddResponseExtension"/>. + /// </summary> + /// <remarks> + /// This should be called before sending a negative response back to the relying party + /// if extensions were already added, since negative responses cannot carry extensions. + /// </remarks> + public void ClearResponseExtensions() { + this.responseExtensions.Clear(); + } + + /// <summary> + /// Gets an extension sent from the relying party. + /// </summary> + /// <typeparam name="T">The type of the extension.</typeparam> + /// <returns> + /// An instance of the extension initialized with values passed in with the request. + /// </returns> + public T GetExtension<T>() where T : IOpenIdMessageExtension, new() { + if (this.extensibleMessage != null) { + return this.extensibleMessage.Extensions.OfType<T>().SingleOrDefault(); + } else { + return default(T); + } + } + + /// <summary> + /// Gets an extension sent from the relying party. + /// </summary> + /// <param name="extensionType">The type of the extension.</param> + /// <returns> + /// An instance of the extension initialized with values passed in with the request. + /// </returns> + public IOpenIdMessageExtension GetExtension(Type extensionType) { + if (this.extensibleMessage != null) { + return this.extensibleMessage.Extensions.OfType<IOpenIdMessageExtension>().Where(ext => extensionType.IsInstanceOfType(ext)).SingleOrDefault(); + } else { + return null; + } + } + + #endregion + } +} |