summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenId/Provider/CheckAuthRequest.cs
blob: bda4918fa504b0b4e0fb831502371b295ad0cf3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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 {
	/// <summary>
	/// A request to verify the validity of a previous response.
	/// </summary>
	internal class CheckAuthRequest : AssociatedRequest {
		string signature;
		IDictionary<string, string> signedFields;
		IList<string> 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<string, string>();
			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; }
		}

		/// <summary>
		/// Gets the string "check_authentication".
		/// </summary>
		internal override string Mode {
			get { return Protocol.Args.Mode.check_authentication; }
		}

		/// <summary>
		/// Respond to this request.
		/// </summary>
		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);
		}

	}
}