using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Globalization;
using System.Web;
namespace DotNetOpenId.Provider
{
///
/// Represents any OpenId-protocol request that may come to the provider.
///
[DebuggerDisplay("Mode: {Mode}, OpenId: {Protocol.Version}")]
abstract class Request : IRequest {
protected Request(OpenIdProvider provider) {
if (provider == null) throw new ArgumentNullException("provider");
Provider = provider;
Query = provider.Query;
Protocol = Protocol.Detect(Query);
IncomingExtensions = ExtensionArgumentsManager.CreateIncomingExtensions(Query);
OutgoingExtensions = ExtensionArgumentsManager.CreateOutgoingExtensions(Protocol);
}
///
/// The detected protocol of the calling OpenId relying party.
///
protected internal Protocol Protocol;
protected IDictionary Query { get; private set; }
protected internal OpenIdProvider Provider { get; private set; }
internal abstract string Mode { get; }
///
/// Extension arguments to pass to the Relying Party.
///
protected ExtensionArgumentsManager OutgoingExtensions { get; private set; }
///
/// Extension arguments received from the Relying Party.
///
protected ExtensionArgumentsManager IncomingExtensions { get; private set; }
///
/// Tests whether a given dictionary represents an incoming OpenId request.
///
/// The name/value pairs in the querystring or Form submission. Cannot be null.
/// True if the request is an OpenId request, false otherwise.
internal static bool IsOpenIdRequest(IDictionary query) {
Debug.Assert(query != null);
Protocol protocol = Protocol.Detect(query);
foreach (string key in query.Keys) {
if (key.StartsWith(protocol.openid.Prefix, StringComparison.OrdinalIgnoreCase)) {
return true;
}
}
return false;
}
///
/// Creates the appropriate Request-derived type based on the request dictionary.
///
/// The Provider instance that called this method.
/// A Request-derived type appropriate for this stage in authentication.
internal static Request CreateRequest(OpenIdProvider provider) {
if (provider == null) throw new ArgumentNullException("provider");
Debug.Assert(provider.Protocol != null, "This should have been set already.");
string mode = Util.GetRequiredArg(provider.Query, provider.Protocol.openid.mode);
Request request;
try {
if (mode == provider.Protocol.Args.Mode.checkid_setup ||
mode == provider.Protocol.Args.Mode.checkid_immediate)
request = new CheckIdRequest(provider);
else if (mode == provider.Protocol.Args.Mode.check_authentication)
request = new CheckAuthRequest(provider);
else if (mode == provider.Protocol.Args.Mode.associate)
request = new AssociateRequest(provider);
else
throw new OpenIdException(string.Format(CultureInfo.CurrentCulture,
Strings.InvalidOpenIdQueryParameterValue, provider.Protocol.openid.mode,
mode), provider.Query);
} catch (OpenIdException ex) {
request = new FaultyRequest(provider, ex);
}
return request;
}
///
/// Gets the version of OpenID being used by the relying party that sent the request.
///
public ProtocolVersion RelyingPartyVersion {
get {
return Protocol.Lookup(Protocol.Version).ProtocolVersion;
}
}
///
/// Indicates whether this request has all the information necessary to formulate a response.
///
public abstract bool IsResponseReady { get; }
protected abstract IEncodable CreateResponse();
///
/// Called whenever a property changes that would cause the response to need to be
/// regenerated if it had already been generated.
///
protected void InvalidateResponse() {
response = null;
}
Response response;
///
/// The authentication response to be sent to the user agent or the calling
/// OpenId consumer.
///
public Response Response {
get {
if (!IsResponseReady) throw new InvalidOperationException(Strings.ResponseNotReady);
if (response == null) {
var encodableResponse = CreateResponse();
EncodableResponse extendableResponse = encodableResponse as EncodableResponse;
if (extendableResponse != null) {
foreach (var pair in OutgoingExtensions.GetArgumentsToSend(false)) {
extendableResponse.Fields.Add(pair.Key, pair.Value);
extendableResponse.Signed.Add(pair.Key);
}
}
response = Provider.Encoder.Encode(encodableResponse);
}
return response;
}
}
IResponse IRequest.Response { get { return this.Response; } }
public void AddResponseExtension(DotNetOpenId.Extensions.IExtensionResponse extension) {
OutgoingExtensions.AddExtensionArguments(extension.TypeUri, extension.Serialize(this));
}
///
/// Attempts to load an extension from an OpenId message.
///
/// The extension to attempt to load.
///
/// True if the extension was found in the message and successfully loaded.
/// False otherwise.
///
bool getExtension(DotNetOpenId.Extensions.IExtensionRequest extension) {
var fields = IncomingExtensions.GetExtensionArguments(extension.TypeUri);
if (fields != null) {
// The extension was found using the preferred TypeUri.
return extension.Deserialize(fields, this, extension.TypeUri);
} else {
// The extension may still be found using secondary TypeUris.
if (extension.AdditionalSupportedTypeUris != null) {
foreach (string typeUri in extension.AdditionalSupportedTypeUris) {
fields = IncomingExtensions.GetExtensionArguments(typeUri);
if (fields != null) {
// We found one of the older ones.
return extension.Deserialize(fields, this, typeUri);
}
}
}
}
return false;
}
public T GetExtension() where T : DotNetOpenId.Extensions.IExtensionRequest, new() {
T extension = new T();
return getExtension(extension) ? (T)extension : default(T);
}
public DotNetOpenId.Extensions.IExtensionRequest GetExtension(Type extensionType) {
if (extensionType == null) throw new ArgumentNullException("extensionType");
if (!typeof(DotNetOpenId.Extensions.IExtensionRequest).IsAssignableFrom(extensionType))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
Strings.TypeMustImplementX, typeof(DotNetOpenId.Extensions.IExtensionRequest).FullName),
"extensionType");
var extension = (DotNetOpenId.Extensions.IExtensionRequest)Activator.CreateInstance(extensionType);
return getExtension(extension) ? extension : null;
}
public override string ToString() {
string returnString = @"Request.Mode = {0}";
return string.Format(CultureInfo.CurrentCulture, returnString, Mode);
}
}
}