//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OAuth2 { using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics.Contracts; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using DotNetOpenAuth.Messaging; /// /// A WinForms control that hosts a mini-browser for hosting by native applications to /// allow the user to authorize the client without leaving the application. /// public partial class ClientAuthorizationView : UserControl { /// /// Initializes a new instance of the class. /// public ClientAuthorizationView() { this.InitializeComponent(); this.Authorization = new AuthorizationState(); } /// /// Occurs when the authorization flow has completed. /// public event EventHandler Completed; /// /// Gets the authorization tracking object. /// public IAuthorizationState Authorization { get; private set; } /// /// Gets or sets the client used to coordinate the authorization flow. /// public UserAgentClient Client { get; set; } /// /// Gets the set of scopes that describe the requested level of access. /// public HashSet Scope { get { return this.Authorization.Scope; } } /// /// Gets or sets the callback URL used to indicate the flow has completed. /// public Uri Callback { get { return this.Authorization.Callback; } set { this.Authorization.Callback = value; } } /// /// Gets a value indicating whether the authorization flow has been completed. /// public bool IsCompleted { get { return this.Authorization == null || this.Authorization.AccessToken != null; } } /// /// Gets a value indicating whether authorization has been granted. /// /// Null if is false public bool? IsGranted { get { if (this.Authorization == null) { return false; } return this.Authorization.AccessToken != null ? (bool?)true : null; } } /// /// Gets a value indicating whether authorization has been rejected. /// /// Null if is false public bool? IsRejected { get { bool? granted = this.IsGranted; return granted.HasValue ? (bool?)(!granted.Value) : null; } } /// /// Called when the authorization flow has been completed. /// protected virtual void OnCompleted() { var completed = this.Completed; if (completed != null) { completed(this, new ClientAuthorizationCompleteEventArgs(this.Authorization)); } } /// /// Raises the event. /// /// An that contains the event data. protected override void OnLoad(EventArgs e) { base.OnLoad(e); Uri authorizationUrl = this.Client.RequestUserAuthorization(this.Authorization); this.webBrowser1.Navigate(authorizationUrl.AbsoluteUri); // use AbsoluteUri to workaround bug in WebBrowser that calls Uri.ToString instead of Uri.AbsoluteUri leading to escaping errors. } /// /// Tests whether two URLs are equal for purposes of detecting the conclusion of authorization. /// /// The first location. /// The second location. /// The components to compare. /// true if the given components are equal. private static bool SignificantlyEqual(Uri location1, Uri location2, UriComponents components) { string value1 = location1.GetComponents(components, UriFormat.Unescaped); string value2 = location2.GetComponents(components, UriFormat.Unescaped); return string.Equals(value1, value2, StringComparison.Ordinal); } /// /// Handles the Navigating event of the webBrowser1 control. /// /// The source of the event. /// The instance containing the event data. private void WebBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e) { this.ProcessLocationChanged(e.Url); } /// /// Processes changes in the URL the browser has navigated to. /// /// The location. private void ProcessLocationChanged(Uri location) { if (SignificantlyEqual(location, this.Authorization.Callback, UriComponents.SchemeAndServer | UriComponents.Path)) { try { this.Client.ProcessUserAuthorization(location, this.Authorization); } catch (ProtocolException ex) { MessageBox.Show(ex.ToStringDescriptive()); } finally { this.OnCompleted(); } } } /// /// Handles the Navigated event of the webBrowser1 control. /// /// The source of the event. /// The instance containing the event data. private void WebBrowser1_Navigated(object sender, WebBrowserNavigatedEventArgs e) { this.ProcessLocationChanged(e.Url); } /// /// Handles the LocationChanged event of the webBrowser1 control. /// /// The source of the event. /// The instance containing the event data. private void WebBrowser1_LocationChanged(object sender, EventArgs e) { this.ProcessLocationChanged(this.webBrowser1.Url); } /// /// Describes the results of a completed authorization flow. /// public class ClientAuthorizationCompleteEventArgs : EventArgs { /// /// Initializes a new instance of the class. /// /// The authorization. public ClientAuthorizationCompleteEventArgs(IAuthorizationState authorization) { Requires.NotNull(authorization, "authorization"); this.Authorization = authorization; } /// /// Gets the authorization tracking object. /// /// Null if authorization was rejected by the user. public IAuthorizationState Authorization { get; private set; } } } }