Several hundred StyleCop fixes.
[dotnetoauth.git] / src / DotNetOpenAuth / OpenId / RelyingParty / ServiceEndpoint.cs
blob9d79e82164c74ef529f5fc6cf2a70c043acee098
1 namespace DotNetOpenAuth.OpenId.RelyingParty {
2 using System;
3 using System.Collections.Generic;
4 using System.Diagnostics;
5 using System.Globalization;
6 using System.IO;
7 using System.Text;
8 using DotNetOpenAuth.Messaging;
10 /// <summary>
11 /// Represents information discovered about a user-supplied Identifier.
12 /// </summary>
13 [DebuggerDisplay("ClaimedIdentifier: {ClaimedIdentifier}, ProviderEndpoint: {ProviderEndpoint}, OpenId: {Protocol.Version}")]
14 internal class ServiceEndpoint : IXrdsProviderEndpoint {
15 private string friendlyIdentifierForDisplay;
16 private Protocol protocol;
17 private int? uriPriority;
18 private int? servicePriority;
20 private ServiceEndpoint(Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Uri providerEndpoint, Identifier providerLocalIdentifier, string[] providerSupportedServiceTypeUris, int? servicePriority, int? uriPriority) {
21 ErrorUtilities.VerifyArgumentNotNull(claimedIdentifier, "claimedIdentifier");
22 ErrorUtilities.VerifyArgumentNotNull(providerEndpoint, "providerEndpoint");
23 ErrorUtilities.VerifyArgumentNotNull(providerSupportedServiceTypeUris, "providerSupportedServiceTypeUris");
24 this.ClaimedIdentifier = claimedIdentifier;
25 this.UserSuppliedIdentifier = userSuppliedIdentifier;
26 this.ProviderEndpoint = providerEndpoint;
27 this.ProviderLocalIdentifier = providerLocalIdentifier ?? claimedIdentifier;
28 this.ProviderSupportedServiceTypeUris = providerSupportedServiceTypeUris;
29 this.servicePriority = servicePriority;
30 this.uriPriority = uriPriority;
33 /// <summary>
34 /// Used for deserializing <see cref="ServiceEndpoint"/> from authentication responses.
35 /// </summary>
36 private ServiceEndpoint(Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Uri providerEndpoint, Identifier providerLocalIdentifier, Protocol protocol) {
37 this.ClaimedIdentifier = claimedIdentifier;
38 this.UserSuppliedIdentifier = userSuppliedIdentifier;
39 this.ProviderEndpoint = providerEndpoint;
40 this.ProviderLocalIdentifier = providerLocalIdentifier ?? claimedIdentifier;
41 this.protocol = protocol;
44 Uri IProviderEndpoint.Uri { get { return this.ProviderEndpoint; } }
46 /// <summary>
47 /// Gets the URL which accepts OpenID Authentication protocol messages.
48 /// </summary>
49 /// <remarks>
50 /// Obtained by performing discovery on the User-Supplied Identifier.
51 /// This value MUST be an absolute HTTP or HTTPS URL.
52 /// </remarks>
53 public Uri ProviderEndpoint { get; private set; }
55 /// <summary>
56 /// Returns true if the <see cref="ProviderEndpoint"/> is using an encrypted channel.
57 /// </summary>
59 /// <summary>
60 /// An Identifier for an OpenID Provider.
61 /// </summary>
62 public Identifier ProviderIdentifier { get; private set; }
64 /// <summary>
65 /// Gets the Identifier that was presented by the end user to the Relying Party,
66 /// or selected by the user at the OpenID Provider.
67 /// During the initiation phase of the protocol, an end user may enter
68 /// either their own Identifier or an OP Identifier. If an OP Identifier
69 /// is used, the OP may then assist the end user in selecting an Identifier
70 /// to share with the Relying Party.
71 /// </summary>
72 public Identifier UserSuppliedIdentifier { get; private set; }
74 /// <summary>
75 /// Gets the Identifier that the end user claims to own.
76 /// </summary>
77 public Identifier ClaimedIdentifier { get; private set; }
79 /// <summary>
80 /// Gets an alternate Identifier for an end user that is local to a
81 /// particular OP and thus not necessarily under the end user's
82 /// control.
83 /// </summary>
84 public Identifier ProviderLocalIdentifier { get; private set; }
86 /// <summary>
87 /// Gets the value for the <see cref="IAuthenticationResponse.FriendlyIdentifierForDisplay"/> property.
88 /// </summary>
89 public string FriendlyIdentifierForDisplay {
90 get {
91 if (this.friendlyIdentifierForDisplay == null) {
92 XriIdentifier xri = this.ClaimedIdentifier as XriIdentifier;
93 UriIdentifier uri = this.ClaimedIdentifier as UriIdentifier;
94 if (xri != null) {
95 if (UserSuppliedIdentifier == null || String.Equals(UserSuppliedIdentifier, ClaimedIdentifier, StringComparison.OrdinalIgnoreCase)) {
96 this.friendlyIdentifierForDisplay = this.ClaimedIdentifier;
97 } else {
98 this.friendlyIdentifierForDisplay = this.UserSuppliedIdentifier;
100 } else if (uri != null) {
101 if (uri != this.Protocol.ClaimedIdentifierForOPIdentifier) {
102 string displayUri = uri.Uri.Authority + uri.Uri.PathAndQuery;
103 displayUri = displayUri.TrimEnd('/');
104 // Multi-byte unicode characters get encoded by the Uri class for transit.
105 // Since this is for display purposes, we want to reverse this and display a readable
106 // representation of these foreign characters.
107 friendlyIdentifierForDisplay = Uri.UnescapeDataString(displayUri);
109 } else {
110 Debug.Fail("Doh! We never should have reached here.");
111 this.friendlyIdentifierForDisplay = this.ClaimedIdentifier;
114 return this.friendlyIdentifierForDisplay;
118 /// <summary>
119 /// Gets the list of services available at this OP Endpoint for the
120 /// claimed Identifier. May be null.
121 /// </summary>
122 public string[] ProviderSupportedServiceTypeUris { get; private set; }
124 /// <summary>
125 /// Gets the OpenID protocol used by the Provider.
126 /// </summary>
127 public Protocol Protocol {
128 get {
129 if (this.protocol == null) {
130 this.protocol = Protocol.Detect(ProviderSupportedServiceTypeUris);
132 if (this.protocol != null) {
133 return this.protocol;
135 throw new InvalidOperationException("Unable to determine the version of OpenID the Provider supports.");
139 #region IXrdsProviderEndpoint Members
141 /// <summary>
142 /// Gets the priority associated with this service that may have been given
143 /// in the XRDS document.
144 /// </summary>
145 int? IXrdsProviderEndpoint.ServicePriority {
146 get { return this.servicePriority; }
149 /// <summary>
150 /// Gets the priority associated with the service endpoint URL.
151 /// </summary>
152 int? IXrdsProviderEndpoint.UriPriority {
153 get { return this.uriPriority; }
156 #endregion
158 internal bool IsSecure {
159 get { return string.Equals(this.ProviderEndpoint.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase); }
162 public static bool operator ==(ServiceEndpoint se1, ServiceEndpoint se2) {
163 return se1.EqualsNullSafe(se2);
166 public static bool operator !=(ServiceEndpoint se1, ServiceEndpoint se2) {
167 return !(se1 == se2);
170 public bool IsTypeUriPresent(string typeUri) {
171 return IsExtensionSupported(typeUri);
174 public bool IsExtensionSupported(string extensionUri) {
175 if (this.ProviderSupportedServiceTypeUris == null) {
176 throw new InvalidOperationException("Cannot lookup extension support on a rehydrated ServiceEndpoint.");
178 return Array.IndexOf(this.ProviderSupportedServiceTypeUris, extensionUri) >= 0;
181 ////public bool IsExtensionSupported(IExtension extension) {
182 //// if (extension == null) throw new ArgumentNullException("extension");
184 //// // Consider the primary case.
185 //// if (IsExtensionSupported(extension.TypeUri)) {
186 //// return true;
187 //// }
188 //// // Consider the secondary cases.
189 //// if (extension.AdditionalSupportedTypeUris != null) {
190 //// foreach (string extensionTypeUri in extension.AdditionalSupportedTypeUris) {
191 //// if (IsExtensionSupported(extensionTypeUri)) {
192 //// return true;
193 //// }
194 //// }
195 //// }
196 //// return false;
197 ////}
199 ////public bool IsExtensionSupported<T>() where T : Extensions.IExtension, new() {
200 //// T extension = new T();
201 //// return IsExtensionSupported(extension);
202 ////}
204 ////public bool IsExtensionSupported(Type extensionType) {
205 //// if (extensionType == null) throw new ArgumentNullException("extensionType");
206 //// if (!typeof(Extensions.IExtension).IsAssignableFrom(extensionType))
207 //// throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
208 //// Strings.TypeMustImplementX, typeof(Extensions.IExtension).FullName),
209 //// "extensionType");
210 //// var extension = (Extensions.IExtension)Activator.CreateInstance(extensionType);
211 //// return IsExtensionSupported(extension);
212 ////}
214 Version IProviderEndpoint.Version { get { return Protocol.Version; } }
216 public override bool Equals(object obj) {
217 ServiceEndpoint other = obj as ServiceEndpoint;
218 if (other == null) {
219 return false;
221 // We specifically do not check our ProviderSupportedServiceTypeUris array
222 // or the priority field
223 // as that is not persisted in our tokens, and it is not part of the
224 // important assertion validation that is part of the spec.
225 return
226 this.ClaimedIdentifier == other.ClaimedIdentifier &&
227 this.ProviderEndpoint == other.ProviderEndpoint &&
228 this.ProviderLocalIdentifier == other.ProviderLocalIdentifier &&
229 this.Protocol == other.Protocol;
232 public override int GetHashCode() {
233 return ClaimedIdentifier.GetHashCode();
236 public override string ToString() {
237 StringBuilder builder = new StringBuilder();
238 builder.AppendLine("ClaimedIdentifier: " + ClaimedIdentifier);
239 builder.AppendLine("ProviderLocalIdentifier: " + ProviderLocalIdentifier);
240 builder.AppendLine("ProviderEndpoint: " + ProviderEndpoint.AbsoluteUri);
241 builder.AppendLine("OpenID version: " + Protocol.Version);
242 builder.AppendLine("Service Type URIs:");
243 if (ProviderSupportedServiceTypeUris != null) {
244 foreach (string serviceTypeUri in ProviderSupportedServiceTypeUris) {
245 builder.Append("\t");
246 // TODO: uncomment when we support extensions
247 ////var matchingExtension = Util.FirstOrDefault(ExtensionManager.RequestExtensions, ext => ext.Key.TypeUri == serviceTypeUri);
248 ////if (matchingExtension.Key != null) {
249 //// builder.AppendLine(string.Format(CultureInfo.CurrentCulture, "{0} ({1})", serviceTypeUri, matchingExtension.Value));
250 ////} else {
251 //// builder.AppendLine(serviceTypeUri);
252 ////}
254 } else {
255 builder.AppendLine("\t(unavailable)");
257 builder.Length -= Environment.NewLine.Length; // trim last newline
258 return builder.ToString();
261 /// <summary>
262 /// Reads previously discovered information about an endpoint
263 /// from a solicited authentication assertion for validation.
264 /// </summary>
265 /// <returns>
266 /// A <see cref="ServiceEndpoint"/> object that has everything
267 /// except the <see cref="ProviderSupportedServiceTypeUris"/>
268 /// deserialized.
269 /// </returns>
270 internal static ServiceEndpoint Deserialize(TextReader reader) {
271 var claimedIdentifier = Identifier.Parse(reader.ReadLine());
272 var providerLocalIdentifier = Identifier.Parse(reader.ReadLine());
273 string userSuppliedIdentifier = reader.ReadLine();
274 if (userSuppliedIdentifier.Length == 0) {
275 userSuppliedIdentifier = null;
277 var providerEndpoint = new Uri(reader.ReadLine());
278 var protocol = Protocol.FindBestVersion(p => p.Version, new[] { new Version(reader.ReadLine()) });
279 return new ServiceEndpoint(claimedIdentifier, userSuppliedIdentifier, providerEndpoint, providerLocalIdentifier, protocol);
282 internal static ServiceEndpoint CreateForProviderIdentifier(
283 Identifier providerIdentifier, Uri providerEndpoint,
284 string[] providerSupportedServiceTypeUris, int? servicePriority, int? uriPriority) {
285 Protocol protocol = Protocol.Detect(providerSupportedServiceTypeUris);
287 return new ServiceEndpoint(protocol.ClaimedIdentifierForOPIdentifier, providerIdentifier,
288 providerEndpoint, protocol.ClaimedIdentifierForOPIdentifier,
289 providerSupportedServiceTypeUris, servicePriority, uriPriority);
292 internal static ServiceEndpoint CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier providerLocalIdentifier, Uri providerEndpoint, string[] providerSupportedServiceTypeUris, int? servicePriority, int? uriPriority) {
293 return CreateForClaimedIdentifier(claimedIdentifier, null, providerLocalIdentifier, providerEndpoint, providerSupportedServiceTypeUris, servicePriority, uriPriority);
296 internal static ServiceEndpoint CreateForClaimedIdentifier(Identifier claimedIdentifier, Identifier userSuppliedIdentifier, Identifier providerLocalIdentifier, Uri providerEndpoint, string[] providerSupportedServiceTypeUris, int? servicePriority, int? uriPriority) {
297 return new ServiceEndpoint(claimedIdentifier, userSuppliedIdentifier, providerEndpoint, providerLocalIdentifier, providerSupportedServiceTypeUris, servicePriority, uriPriority);
300 /// <summary>
301 /// Saves the discovered information about this endpoint
302 /// for later comparison to validate assertions.
303 /// </summary>
304 internal void Serialize(TextWriter writer) {
305 writer.WriteLine(this.ClaimedIdentifier);
306 writer.WriteLine(this.ProviderLocalIdentifier);
307 writer.WriteLine(this.UserSuppliedIdentifier);
308 writer.WriteLine(this.ProviderEndpoint);
309 writer.WriteLine(this.Protocol.Version);
310 // No reason to serialize priority. We only needed priority to decide whether to use this endpoint.