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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
|
//-----------------------------------------------------------------------
// <copyright file="NegativeAuthenticationResponse.cs" company="Outercurve Foundation">
// Copyright (c) Outercurve Foundation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OpenId.RelyingParty {
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Messages;
using Validation;
/// <summary>
/// Wraps a negative assertion response in an <see cref="IAuthenticationResponse"/> instance
/// for public consumption by the host web site.
/// </summary>
internal class NegativeAuthenticationResponse : IAuthenticationResponse, ISetupRequiredAuthenticationResponse {
/// <summary>
/// The negative assertion message that was received by the RP that was used
/// to create this instance.
/// </summary>
private readonly NegativeAssertionResponse response;
/// <summary>
/// Initializes a new instance of the <see cref="NegativeAuthenticationResponse"/> class.
/// </summary>
/// <param name="response">The negative assertion response received by the Relying Party.</param>
internal NegativeAuthenticationResponse(NegativeAssertionResponse response) {
Requires.NotNull(response, "response");
this.response = response;
Reporting.RecordEventOccurrence(this, string.Empty);
}
#region IAuthenticationResponse Properties
/// <summary>
/// Gets the Identifier that the end user claims to own. For use with user database storage and lookup.
/// May be null for some failed authentications (i.e. failed directed identity authentications).
/// </summary>
/// <value></value>
/// <remarks>
/// <para>
/// This is the secure identifier that should be used for database storage and lookup.
/// It is not always friendly (i.e. =Arnott becomes =!9B72.7DD1.50A9.5CCD), but it protects
/// user identities against spoofing and other attacks.
/// </para>
/// <para>
/// For user-friendly identifiers to display, use the
/// <see cref="FriendlyIdentifierForDisplay"/> property.
/// </para>
/// </remarks>
public Identifier ClaimedIdentifier {
get { return null; }
}
/// <summary>
/// Gets a user-friendly OpenID Identifier for display purposes ONLY.
/// </summary>
/// <value></value>
/// <remarks>
/// <para>
/// This <i>should</i> be put through <see cref="HttpUtility.HtmlEncode(string)"/> before
/// sending to a browser to secure against javascript injection attacks.
/// </para>
/// <para>
/// This property retains some aspects of the user-supplied identifier that get lost
/// in the <see cref="ClaimedIdentifier"/>. For example, XRIs used as user-supplied
/// identifiers (i.e. =Arnott) become unfriendly unique strings (i.e. =!9B72.7DD1.50A9.5CCD).
/// For display purposes, such as text on a web page that says "You're logged in as ...",
/// this property serves to provide the =Arnott string, or whatever else is the most friendly
/// string close to what the user originally typed in.
/// </para>
/// <para>
/// If the user-supplied identifier is a URI, this property will be the URI after all
/// redirects, and with the protocol and fragment trimmed off.
/// If the user-supplied identifier is an XRI, this property will be the original XRI.
/// If the user-supplied identifier is an OpenID Provider identifier (i.e. yahoo.com),
/// this property will be the Claimed Identifier, with the protocol stripped if it is a URI.
/// </para>
/// <para>
/// It is <b>very</b> important that this property <i>never</i> be used for database storage
/// or lookup to avoid identity spoofing and other security risks. For database storage
/// and lookup please use the <see cref="ClaimedIdentifier"/> property.
/// </para>
/// </remarks>
public string FriendlyIdentifierForDisplay {
get { return null; }
}
/// <summary>
/// Gets the detailed success or failure status of the authentication attempt.
/// </summary>
/// <value></value>
public AuthenticationStatus Status {
get { return this.response.Immediate ? AuthenticationStatus.SetupRequired : AuthenticationStatus.Canceled; }
}
/// <summary>
/// Gets information about the OpenId Provider, as advertised by the
/// OpenID discovery documents found at the <see cref="ClaimedIdentifier"/>
/// location.
/// </summary>
/// <value>
/// The Provider endpoint that issued the positive assertion;
/// or <c>null</c> if information about the Provider is unavailable.
/// </value>
public IProviderEndpoint Provider {
get { return null; }
}
/// <summary>
/// Gets the details regarding a failed authentication attempt, if available.
/// This will be set if and only if <see cref="Status"/> is <see cref="AuthenticationStatus.Failed"/>.
/// </summary>
/// <value></value>
public Exception Exception {
get { return null; }
}
#endregion
#region ISetupRequiredAuthenticationResponse Members
/// <summary>
/// Gets the <see cref="Identifier"/> to pass to <see cref="OpenIdRelyingParty.CreateRequest(Identifier)"/>
/// in a subsequent authentication attempt.
/// </summary>
/// <value></value>
public Identifier UserSuppliedIdentifier {
get {
ErrorUtilities.VerifyOperation(((IAuthenticationResponse)this).Status == AuthenticationStatus.SetupRequired, OpenIdStrings.OperationOnlyValidForSetupRequiredState);
string userSuppliedIdentifier;
this.response.ExtraData.TryGetValue(AuthenticationRequest.UserSuppliedIdentifierParameterName, out userSuppliedIdentifier);
return userSuppliedIdentifier;
}
}
#endregion
#region IAuthenticationResponse Methods
/// <summary>
/// Gets a callback argument's value that was previously added using
/// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.
/// </summary>
/// <param name="key">The name of the parameter whose value is sought.</param>
/// <returns>
/// The value of the argument, or null if the named parameter could not be found.
/// </returns>
/// <remarks>
/// <para>This may return any argument on the querystring that came with the authentication response,
/// which may include parameters not explicitly added using
/// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.</para>
/// <para>Note that these values are NOT protected against tampering in transit.</para>
/// </remarks>
public string GetCallbackArgument(string key) {
return null;
}
/// <summary>
/// Gets a callback argument's value that was previously added using
/// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.
/// </summary>
/// <param name="key">The name of the parameter whose value is sought.</param>
/// <returns>
/// The value of the argument, or null if the named parameter could not be found.
/// </returns>
/// <remarks>
/// Callback parameters are only available even if the RP is in stateless mode,
/// or the callback parameters are otherwise unverifiable as untampered with.
/// Therefore, use this method only when the callback argument is not to be
/// used to make a security-sensitive decision.
/// </remarks>
public string GetUntrustedCallbackArgument(string key) {
return null;
}
/// <summary>
/// Gets all the callback arguments that were previously added using
/// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/> or as a natural part
/// of the return_to URL.
/// </summary>
/// <returns>A name-value dictionary. Never null.</returns>
/// <remarks>
/// <para>This MAY return any argument on the querystring that came with the authentication response,
/// which may include parameters not explicitly added using
/// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/>.</para>
/// <para>Note that these values are NOT protected against tampering in transit.</para>
/// </remarks>
public IDictionary<string, string> GetCallbackArguments() {
return EmptyDictionary<string, string>.Instance;
}
/// <summary>
/// Gets all the callback arguments that were previously added using
/// <see cref="IAuthenticationRequest.AddCallbackArguments(string, string)"/> or as a natural part
/// of the return_to URL.
/// </summary>
/// <returns>A name-value dictionary. Never null.</returns>
/// <remarks>
/// Callback parameters are only available even if the RP is in stateless mode,
/// or the callback parameters are otherwise unverifiable as untampered with.
/// Therefore, use this method only when the callback argument is not to be
/// used to make a security-sensitive decision.
/// </remarks>
public IDictionary<string, string> GetUntrustedCallbackArguments() {
return EmptyDictionary<string, string>.Instance;
}
/// <summary>
/// Tries to get an OpenID extension that may be present in the response.
/// </summary>
/// <typeparam name="T">The type of extension to look for in the response message.</typeparam>
/// <returns>
/// The extension, if it is found. Null otherwise.
/// </returns>
/// <remarks>
/// <para>Extensions are returned only if the Provider signed them.
/// Relying parties that do not care if the values were modified in
/// transit should use the <see cref="GetUntrustedExtension<T>"/> method
/// in order to allow the Provider to not sign the extension. </para>
/// <para>Unsigned extensions are completely unreliable and should be
/// used only to prefill user forms since the user or any other third
/// party may have tampered with the data carried by the extension.</para>
/// <para>Signed extensions are only reliable if the relying party
/// trusts the OpenID Provider that signed them. Signing does not mean
/// the relying party can trust the values -- it only means that the values
/// have not been tampered with since the Provider sent the message.</para>
/// </remarks>
public T GetExtension<T>() where T : IOpenIdMessageExtension {
return default(T);
}
/// <summary>
/// Tries to get an OpenID extension that may be present in the response.
/// </summary>
/// <param name="extensionType">Type of the extension to look for in the response.</param>
/// <returns>
/// The extension, if it is found. Null otherwise.
/// </returns>
/// <remarks>
/// <para>Extensions are returned only if the Provider signed them.
/// Relying parties that do not care if the values were modified in
/// transit should use the <see cref="GetUntrustedExtension"/> method
/// in order to allow the Provider to not sign the extension. </para>
/// <para>Unsigned extensions are completely unreliable and should be
/// used only to prefill user forms since the user or any other third
/// party may have tampered with the data carried by the extension.</para>
/// <para>Signed extensions are only reliable if the relying party
/// trusts the OpenID Provider that signed them. Signing does not mean
/// the relying party can trust the values -- it only means that the values
/// have not been tampered with since the Provider sent the message.</para>
/// </remarks>
public IOpenIdMessageExtension GetExtension(Type extensionType) {
return null;
}
/// <summary>
/// Tries to get an OpenID extension that may be present in the response, without
/// requiring it to be signed by the Provider.
/// </summary>
/// <typeparam name="T">The type of extension to look for in the response message.</typeparam>
/// <returns>
/// The extension, if it is found. Null otherwise.
/// </returns>
/// <remarks>
/// <para>Extensions are returned whether they are signed or not.
/// Use the <see cref="GetExtension<T>"/> method to retrieve
/// extension responses only if they are signed by the Provider to
/// protect against tampering. </para>
/// <para>Unsigned extensions are completely unreliable and should be
/// used only to prefill user forms since the user or any other third
/// party may have tampered with the data carried by the extension.</para>
/// <para>Signed extensions are only reliable if the relying party
/// trusts the OpenID Provider that signed them. Signing does not mean
/// the relying party can trust the values -- it only means that the values
/// have not been tampered with since the Provider sent the message.</para>
/// </remarks>
public T GetUntrustedExtension<T>() where T : IOpenIdMessageExtension {
return this.response.Extensions.OfType<T>().FirstOrDefault();
}
/// <summary>
/// Tries to get an OpenID extension that may be present in the response.
/// </summary>
/// <param name="extensionType">Type of the extension to look for in the response.</param>
/// <returns>
/// The extension, if it is found. Null otherwise.
/// </returns>
/// <remarks>
/// <para>Extensions are returned whether they are signed or not.
/// Use the <see cref="GetExtension"/> method to retrieve
/// extension responses only if they are signed by the Provider to
/// protect against tampering. </para>
/// <para>Unsigned extensions are completely unreliable and should be
/// used only to prefill user forms since the user or any other third
/// party may have tampered with the data carried by the extension.</para>
/// <para>Signed extensions are only reliable if the relying party
/// trusts the OpenID Provider that signed them. Signing does not mean
/// the relying party can trust the values -- it only means that the values
/// have not been tampered with since the Provider sent the message.</para>
/// </remarks>
public IOpenIdMessageExtension GetUntrustedExtension(Type extensionType) {
return this.response.Extensions.OfType<IOpenIdMessageExtension>().Where(ext => extensionType.IsInstanceOfType(ext)).FirstOrDefault();
}
#endregion
}
}
|