//-----------------------------------------------------------------------
//
// 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; }
}
}
}