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
|
//-----------------------------------------------------------------------
// <copyright file="HostProcessedRequest.cs" company="Outercurve Foundation">
// Copyright (c) Outercurve Foundation. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.OpenId.Provider {
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Net;
using System.Text;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId.Messages;
/// <summary>
/// A base class from which identity and non-identity RP requests can derive.
/// </summary>
[Serializable]
internal abstract class HostProcessedRequest : Request, IHostProcessedRequest {
/// <summary>
/// The negative assertion to send, if the host site chooses to send it.
/// </summary>
private readonly NegativeAssertionResponse negativeResponse;
/// <summary>
/// A cache of the result from discovery of the Realm URL.
/// </summary>
private RelyingPartyDiscoveryResult? realmDiscoveryResult;
/// <summary>
/// Initializes a new instance of the <see cref="HostProcessedRequest"/> class.
/// </summary>
/// <param name="provider">The provider that received the request.</param>
/// <param name="request">The incoming request message.</param>
protected HostProcessedRequest(OpenIdProvider provider, SignedResponseRequest request)
: base(request, provider.SecuritySettings) {
Requires.NotNull(provider, "provider");
this.negativeResponse = new NegativeAssertionResponse(request, provider.Channel);
Reporting.RecordEventOccurrence(this, request.Realm);
}
#region IHostProcessedRequest Properties
/// <summary>
/// Gets the version of OpenID being used by the relying party that sent the request.
/// </summary>
public ProtocolVersion RelyingPartyVersion {
get { return Protocol.Lookup(this.RequestMessage.Version).ProtocolVersion; }
}
/// <summary>
/// Gets a value indicating whether the consumer demands an immediate response.
/// If false, the consumer is willing to wait for the identity provider
/// to authenticate the user.
/// </summary>
public bool Immediate {
get { return this.RequestMessage.Immediate; }
}
/// <summary>
/// Gets the URL the consumer site claims to use as its 'base' address.
/// </summary>
public Realm Realm {
get { return this.RequestMessage.Realm; }
}
/// <summary>
/// Gets or sets the provider endpoint.
/// </summary>
/// <value>
/// The default value is the URL that the request came in on from the relying party.
/// </value>
public abstract Uri ProviderEndpoint { get; set; }
#endregion
/// <summary>
/// Gets a value indicating whether realm discovery been performed.
/// </summary>
internal bool HasRealmDiscoveryBeenPerformed {
get { return this.realmDiscoveryResult.HasValue; }
}
/// <summary>
/// Gets the negative response.
/// </summary>
protected NegativeAssertionResponse NegativeResponse {
get { return this.negativeResponse; }
}
/// <summary>
/// Gets the original request message.
/// </summary>
/// <value>This may be null in the case of an unrecognizable message.</value>
protected new SignedResponseRequest RequestMessage {
get { return (SignedResponseRequest)base.RequestMessage; }
}
#region IHostProcessedRequest Methods
/// <summary>
/// Gets a value indicating whether verification of the return URL claimed by the Relying Party
/// succeeded.
/// </summary>
/// <param name="requestHandler">The request handler.</param>
/// <returns>
/// Result of realm discovery.
/// </returns>
/// <remarks>
/// Return URL verification is only attempted if this property is queried.
/// The result of the verification is cached per request so calling this
/// property getter multiple times in one request is not a performance hit.
/// See OpenID Authentication 2.0 spec section 9.2.1.
/// </remarks>
public RelyingPartyDiscoveryResult IsReturnUrlDiscoverable(IDirectWebRequestHandler requestHandler) {
if (!this.realmDiscoveryResult.HasValue) {
this.realmDiscoveryResult = this.IsReturnUrlDiscoverableCore(requestHandler);
}
return this.realmDiscoveryResult.Value;
}
/// <summary>
/// Gets a value indicating whether verification of the return URL claimed by the Relying Party
/// succeeded.
/// </summary>
/// <param name="requestHandler">The request handler.</param>
/// <returns>
/// Result of realm discovery.
/// </returns>
private RelyingPartyDiscoveryResult IsReturnUrlDiscoverableCore(IDirectWebRequestHandler requestHandler) {
Requires.NotNull(requestHandler, "requestHandler");
ErrorUtilities.VerifyInternal(this.Realm != null, "Realm should have been read or derived by now.");
try {
if (this.SecuritySettings.RequireSsl && this.Realm.Scheme != Uri.UriSchemeHttps) {
Logger.OpenId.WarnFormat("RP discovery failed because RequireSsl is true and RP discovery would begin at insecure URL {0}.", this.Realm);
return RelyingPartyDiscoveryResult.NoServiceDocument;
}
var returnToEndpoints = this.Realm.DiscoverReturnToEndpoints(requestHandler, false);
if (returnToEndpoints == null) {
return RelyingPartyDiscoveryResult.NoServiceDocument;
}
foreach (var returnUrl in returnToEndpoints) {
Realm discoveredReturnToUrl = returnUrl.ReturnToEndpoint;
// The spec requires that the return_to URLs given in an RPs XRDS doc
// do not contain wildcards.
if (discoveredReturnToUrl.DomainWildcard) {
Logger.Yadis.WarnFormat("Realm {0} contained return_to URL {1} which contains a wildcard, which is not allowed.", Realm, discoveredReturnToUrl);
continue;
}
// Use the same rules as return_to/realm matching to check whether this
// URL fits the return_to URL we were given.
if (discoveredReturnToUrl.Contains(this.RequestMessage.ReturnTo)) {
// no need to keep looking after we find a match
return RelyingPartyDiscoveryResult.Success;
}
}
} catch (ProtocolException ex) {
// Don't do anything else. We quietly fail at return_to verification and return false.
Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex);
return RelyingPartyDiscoveryResult.NoServiceDocument;
} catch (WebException ex) {
// Don't do anything else. We quietly fail at return_to verification and return false.
Logger.Yadis.InfoFormat("Relying party discovery at URL {0} failed. {1}", Realm, ex);
return RelyingPartyDiscoveryResult.NoServiceDocument;
}
return RelyingPartyDiscoveryResult.NoMatchingReturnTo;
}
#endregion
}
}
|