summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs')
-rw-r--r--src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs b/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs
new file mode 100644
index 0000000..d0dee75
--- /dev/null
+++ b/src/DotNetOpenAuth.OpenId.Provider.UI/OpenId/Provider/ProviderEndpoint.cs
@@ -0,0 +1,267 @@
+//-----------------------------------------------------------------------
+// <copyright file="ProviderEndpoint.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OpenId.Provider {
+ using System;
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using System.Diagnostics.Contracts;
+ using System.Text;
+ using System.Web;
+ using System.Web.UI;
+ using System.Web.UI.WebControls;
+ using DotNetOpenAuth.Configuration;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OpenId.Messages;
+
+ /// <summary>
+ /// An OpenID Provider control that automatically responds to certain
+ /// automated OpenID messages, and routes authentication requests to
+ /// custom code via an event handler.
+ /// </summary>
+ [DefaultEvent("AuthenticationChallenge")]
+ [ToolboxData("<{0}:ProviderEndpoint runat='server' />")]
+ public class ProviderEndpoint : Control {
+ /// <summary>
+ /// The key used to store the pending authentication request in the ASP.NET session.
+ /// </summary>
+ private const string PendingRequestKey = "pendingRequest";
+
+ /// <summary>
+ /// The default value for the <see cref="Enabled"/> property.
+ /// </summary>
+ private const bool EnabledDefault = true;
+
+ /// <summary>
+ /// The view state key in which to store the value of the <see cref="Enabled"/> property.
+ /// </summary>
+ private const string EnabledViewStateKey = "Enabled";
+
+ /// <summary>
+ /// Backing field for the <see cref="Provider"/> property.
+ /// </summary>
+ private static OpenIdProvider provider;
+
+ /// <summary>
+ /// The lock that must be obtained when initializing the provider field.
+ /// </summary>
+ private static object providerInitializerLock = new object();
+
+ /// <summary>
+ /// Fired when an incoming OpenID request is an authentication challenge
+ /// that must be responded to by the Provider web site according to its
+ /// own user database and policies.
+ /// </summary>
+ public event EventHandler<AuthenticationChallengeEventArgs> AuthenticationChallenge;
+
+ /// <summary>
+ /// Fired when an incoming OpenID message carries extension requests
+ /// but is not regarding any OpenID identifier.
+ /// </summary>
+ public event EventHandler<AnonymousRequestEventArgs> AnonymousRequest;
+
+ /// <summary>
+ /// Gets or sets the <see cref="OpenIdProvider"/> instance to use for all instances of this control.
+ /// </summary>
+ /// <value>The default value is an <see cref="OpenIdProvider"/> instance initialized according to the web.config file.</value>
+ public static OpenIdProvider Provider {
+ get {
+ Contract.Ensures(Contract.Result<OpenIdProvider>() != null);
+ if (provider == null) {
+ lock (providerInitializerLock) {
+ if (provider == null) {
+ provider = CreateProvider();
+ }
+ }
+ }
+
+ return provider;
+ }
+
+ set {
+ Requires.NotNull(value, "value");
+ provider = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets an incoming OpenID authentication request that has not yet been responded to.
+ /// </summary>
+ /// <remarks>
+ /// This request is stored in the ASP.NET Session state, so it will survive across
+ /// redirects, postbacks, and transfers. This allows you to authenticate the user
+ /// yourself, and confirm his/her desire to authenticate to the relying party site
+ /// before responding to the relying party's authentication request.
+ /// </remarks>
+ public static IAuthenticationRequest PendingAuthenticationRequest {
+ get {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ Requires.ValidState(HttpContext.Current.Session != null, MessagingStrings.SessionRequired);
+ Contract.Ensures(Contract.Result<IAuthenticationRequest>() == null || PendingRequest != null);
+ return HttpContext.Current.Session[PendingRequestKey] as IAuthenticationRequest;
+ }
+
+ set {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ Requires.ValidState(HttpContext.Current.Session != null, MessagingStrings.SessionRequired);
+ HttpContext.Current.Session[PendingRequestKey] = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets an incoming OpenID anonymous request that has not yet been responded to.
+ /// </summary>
+ /// <remarks>
+ /// This request is stored in the ASP.NET Session state, so it will survive across
+ /// redirects, postbacks, and transfers. This allows you to authenticate the user
+ /// yourself, and confirm his/her desire to provide data to the relying party site
+ /// before responding to the relying party's request.
+ /// </remarks>
+ public static IAnonymousRequest PendingAnonymousRequest {
+ get {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ Requires.ValidState(HttpContext.Current.Session != null, MessagingStrings.SessionRequired);
+ Contract.Ensures(Contract.Result<IAnonymousRequest>() == null || PendingRequest != null);
+ return HttpContext.Current.Session[PendingRequestKey] as IAnonymousRequest;
+ }
+
+ set {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ Requires.ValidState(HttpContext.Current.Session != null, MessagingStrings.SessionRequired);
+ HttpContext.Current.Session[PendingRequestKey] = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets an incoming OpenID request that has not yet been responded to.
+ /// </summary>
+ /// <remarks>
+ /// This request is stored in the ASP.NET Session state, so it will survive across
+ /// redirects, postbacks, and transfers. This allows you to authenticate the user
+ /// yourself, and confirm his/her desire to provide data to the relying party site
+ /// before responding to the relying party's request.
+ /// </remarks>
+ public static IHostProcessedRequest PendingRequest {
+ get {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ Requires.ValidState(HttpContext.Current.Session != null, MessagingStrings.SessionRequired);
+ return HttpContext.Current.Session[PendingRequestKey] as IHostProcessedRequest;
+ }
+
+ set {
+ Requires.ValidState(HttpContext.Current != null, MessagingStrings.HttpContextRequired);
+ Requires.ValidState(HttpContext.Current.Session != null, MessagingStrings.SessionRequired);
+ HttpContext.Current.Session[PendingRequestKey] = value;
+ }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether or not this control should
+ /// be listening for and responding to incoming OpenID requests.
+ /// </summary>
+ [Category("Behavior"), DefaultValue(EnabledDefault)]
+ public bool Enabled {
+ get {
+ return ViewState[EnabledViewStateKey] == null ?
+ EnabledDefault : (bool)ViewState[EnabledViewStateKey];
+ }
+
+ set {
+ ViewState[EnabledViewStateKey] = value;
+ }
+ }
+
+ /// <summary>
+ /// Sends the response for the <see cref="PendingAuthenticationRequest"/> and clears the property.
+ /// </summary>
+ public static void SendResponse() {
+ var pendingRequest = PendingRequest;
+ PendingRequest = null;
+ Provider.SendResponse(pendingRequest);
+ }
+
+ /// <summary>
+ /// Checks for incoming OpenID requests, responds to ones it can
+ /// respond to without policy checks, and fires events for custom
+ /// handling of the ones it cannot decide on automatically.
+ /// </summary>
+ /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
+ protected override void OnLoad(EventArgs e) {
+ base.OnLoad(e);
+
+ // There is the unusual scenario that this control is hosted by
+ // an ASP.NET web page that has other UI on it to that the user
+ // might see, including controls that cause a postback to occur.
+ // We definitely want to ignore postbacks, since any openid messages
+ // they contain will be old.
+ if (this.Enabled && !this.Page.IsPostBack) {
+ // Use the explicitly given state store on this control if there is one.
+ // Then try the configuration file specified one. Finally, use the default
+ // in-memory one that's built into OpenIdProvider.
+ // determine what incoming message was received
+ IRequest request = Provider.GetRequest();
+ if (request != null) {
+ PendingRequest = null;
+
+ // process the incoming message appropriately and send the response
+ IAuthenticationRequest idrequest;
+ IAnonymousRequest anonRequest;
+ if ((idrequest = request as IAuthenticationRequest) != null) {
+ PendingAuthenticationRequest = idrequest;
+ this.OnAuthenticationChallenge(idrequest);
+ } else if ((anonRequest = request as IAnonymousRequest) != null) {
+ PendingAnonymousRequest = anonRequest;
+ if (!this.OnAnonymousRequest(anonRequest)) {
+ // This is a feature not supported by the OP, so
+ // go ahead and set disapproved so we can send a response.
+ Logger.OpenId.Warn("An incoming anonymous OpenID request message was detected, but the ProviderEndpoint.AnonymousRequest event is not handled, so returning cancellation message to relying party.");
+ anonRequest.IsApproved = false;
+ }
+ }
+ if (request.IsResponseReady) {
+ PendingAuthenticationRequest = null;
+ Provider.SendResponse(request);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Fires the <see cref="AuthenticationChallenge"/> event.
+ /// </summary>
+ /// <param name="request">The request to include in the event args.</param>
+ protected virtual void OnAuthenticationChallenge(IAuthenticationRequest request) {
+ var authenticationChallenge = this.AuthenticationChallenge;
+ if (authenticationChallenge != null) {
+ authenticationChallenge(this, new AuthenticationChallengeEventArgs(request));
+ }
+ }
+
+ /// <summary>
+ /// Fires the <see cref="AnonymousRequest"/> event.
+ /// </summary>
+ /// <param name="request">The request to include in the event args.</param>
+ /// <returns><c>true</c> if there were any anonymous request handlers.</returns>
+ protected virtual bool OnAnonymousRequest(IAnonymousRequest request) {
+ var anonymousRequest = this.AnonymousRequest;
+ if (anonymousRequest != null) {
+ anonymousRequest(this, new AnonymousRequestEventArgs(request));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /// <summary>
+ /// Creates the default OpenIdProvider to use.
+ /// </summary>
+ /// <returns>The new instance of OpenIdProvider.</returns>
+ private static OpenIdProvider CreateProvider() {
+ Contract.Ensures(Contract.Result<OpenIdProvider>() != null);
+ return new OpenIdProvider(OpenIdElement.Configuration.Provider.ApplicationStore.CreateInstance(OpenIdProvider.HttpApplicationStore));
+ }
+ }
+}