using System;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace DotNetOpenId.Provider {
///
/// A request to verify the validity of a previous response.
///
internal class CheckAuthRequest : AssociatedRequest {
string signature;
IDictionary signedFields;
IList signedKeyOrder;
public CheckAuthRequest(OpenIdProvider provider)
: base(provider) {
AssociationHandle = Util.GetRequiredArg(Query, Protocol.openid.assoc_handle);
signature = Util.GetRequiredArg(Query, Protocol.openid.sig);
signedKeyOrder = Util.GetRequiredArg(Query, Protocol.openid.signed).Split(',');
signedFields = new Dictionary();
Debug.Assert(!signedKeyOrder.Contains(Protocol.openidnp.mode), "openid.mode must not be included in signature because it necessarily changes in checkauth requests.");
foreach (string key in signedKeyOrder) {
signedFields.Add(key, Util.GetRequiredArgAllowEmptyValue(Query, Protocol.openid.Prefix + key));
}
}
public override bool IsResponseReady {
// This type of request can always be responded to immediately.
get { return true; }
}
///
/// Gets the string "check_authentication".
///
internal override string Mode {
get { return Protocol.Args.Mode.check_authentication; }
}
///
/// Respond to this request.
///
internal EncodableResponse Answer() {
EncodableResponse response = EncodableResponse.PrepareDirectMessage(Protocol);
bool validSignature = Provider.Signatory.Verify(AssociationHandle, signature, signedFields, signedKeyOrder);
response.Fields[Protocol.openidnp.is_valid] = validSignature ?
Protocol.Args.IsValid.True : Protocol.Args.IsValid.False;
// By invalidating our dumb association, we make it impossible to
// verify the same authentication again, making a response_nonce check
// to protect against replay attacks unnecessary.
Provider.Signatory.Invalidate(AssociationHandle, AssociationRelyingPartyType.Dumb);
// The RP may be asking for confirmation that an association should
// be invalidated. If so, double-check and send a reply in our response.
string invalidate_handle = Util.GetOptionalArg(Query, Protocol.openid.invalidate_handle);
if (invalidate_handle != null) {
Association assoc = Provider.Signatory.GetAssociation(invalidate_handle, AssociationRelyingPartyType.Smart);
if (assoc == null) {
Logger.Warn("No matching association found. Returning invalidate_handle. ");
response.Fields[Protocol.openidnp.invalidate_handle] = invalidate_handle;
}
}
return response;
}
protected override IEncodable CreateResponse() {
return Answer();
}
public override string ToString() {
string returnString = @"
CheckAuthRequest._sig = '{0}'
CheckAuthRequest.AssocHandle = '{1}'";
return base.ToString() + string.Format(CultureInfo.CurrentCulture,
returnString, signature, AssociationHandle);
}
}
}