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); } } }