summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2010-05-17 22:22:05 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2010-05-17 22:22:05 -0700
commit18c5c8fd2a715086674654e461608fa6fc33ba1a (patch)
treea08b37e5e12bf0146f976136cd8c8aa64f9efc4b /src
parent4013c20c2f2dbcd4ba93179c075b7edd1cc1f75e (diff)
downloadDotNetOpenAuth-18c5c8fd2a715086674654e461608fa6fc33ba1a.zip
DotNetOpenAuth-18c5c8fd2a715086674654e461608fa6fc33ba1a.tar.gz
DotNetOpenAuth-18c5c8fd2a715086674654e461608fa6fc33ba1a.tar.bz2
Work toward an auth server side of the web server flow in OAuth 2.0
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj3
-rw-r--r--src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs.orig222
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs38
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs32
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx3
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs106
7 files changed, 414 insertions, 1 deletions
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index bd38345..dd95d3a 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -306,7 +306,9 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="Mvc\OpenIdHelper.cs" />
<Compile Include="Mvc\OpenIdAjaxOptions.cs" />
<Compile Include="Messaging\StandardMessageFactory.cs" />
+ <Compile Include="OAuthWrap\AuthorizationServerBase.cs" />
<Compile Include="OAuthWrap\AuthorizationState.cs" />
+ <Compile Include="OAuthWrap\IAuthorizationServer.cs" />
<Compile Include="OAuthWrap\IAuthorizationState.cs" />
<Compile Include="OAuthWrap\IClientTokenManager.cs" />
<Compile Include="OAuthWrap\Messages\Assertion\AssertionRequest.cs" />
@@ -327,6 +329,7 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="OAuthWrap\Messages\UserAgent\UserAgentSuccessResponse.cs" />
<Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordCaptchaResponse.cs" />
<Compile Include="OAuthWrap\Messages\UsernameAndPassword\UserNamePasswordVerificationResponse.cs" />
+ <Compile Include="OAuthWrap\WebAppAuthorizationServer.cs" />
<Compile Include="OAuthWrap\WrapUtilities.cs" />
<Compile Include="OAuth\ChannelElements\ICombinedOpenIdProviderTokenManager.cs" />
<Compile Include="OAuth\ChannelElements\IConsumerDescription.cs" />
diff --git a/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs.orig b/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs.orig
new file mode 100644
index 0000000..a17b379
--- /dev/null
+++ b/src/DotNetOpenAuth/Messaging/IDirectWebRequestHandler.cs.orig
@@ -0,0 +1,222 @@
+//-----------------------------------------------------------------------
+// <copyright file="IDirectWebRequestHandler.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Messaging {
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Net;
+ using DotNetOpenAuth.Messaging;
+
+ /// <summary>
+ /// A contract for <see cref="HttpWebRequest"/> handling.
+ /// </summary>
+ /// <remarks>
+ /// Implementations of this interface must be thread safe.
+ /// </remarks>
+ public interface IDirectWebRequestHandler {
+ /// <summary>
+ /// Determines whether this instance can support the specified options.
+ /// </summary>
+ /// <param name="options">The set of options that might be given in a subsequent web request.</param>
+ /// <returns>
+ /// <c>true</c> if this instance can support the specified options; otherwise, <c>false</c>.
+ /// </returns>
+ bool CanSupport(DirectWebRequestOptions options);
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>
+ /// The stream the caller should write out the entity data to.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
+ /// and any other appropriate properties <i>before</i> calling this method.
+ /// Callers <i>must</i> close and dispose of the request stream when they are done
+ /// writing to it to avoid taking up the connection too long and causing long waits on
+ /// subsequent requests.</para>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch.</para>
+ /// </remarks>
+ Stream GetRequestStream(HttpWebRequest request);
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <param name="options">The options to apply to this web request.</param>
+ /// <returns>
+ /// The stream the caller should write out the entity data to.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
+ /// and any other appropriate properties <i>before</i> calling this method.
+ /// Callers <i>must</i> close and dispose of the request stream when they are done
+ /// writing to it to avoid taking up the connection too long and causing long waits on
+ /// subsequent requests.</para>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch.</para>
+ /// </remarks>
+ Stream GetRequestStream(HttpWebRequest request, DirectWebRequestOptions options);
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>An instance of <see cref="IncomingWebResponse"/> describing the response.</returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
+ /// value, if set, should be Closed before throwing.</para>
+ /// </remarks>
+ IncomingWebResponse GetResponse(HttpWebRequest request);
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <param name="options">The options to apply to this web request.</param>
+ /// <returns>An instance of <see cref="IncomingWebResponse"/> describing the response.</returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
+ /// value, if set, should be Closed before throwing.</para>
+ /// </remarks>
+ IncomingWebResponse GetResponse(HttpWebRequest request, DirectWebRequestOptions options);
+ }
+<<<<<<< HEAD
+=======
+
+ /// <summary>
+ /// Code contract for the <see cref="IDirectWebRequestHandler"/> type.
+ /// </summary>
+ [ContractClassFor(typeof(IDirectWebRequestHandler))]
+ internal abstract class IDirectWebRequestHandlerContract : IDirectWebRequestHandler {
+ #region IDirectWebRequestHandler Members
+
+ /// <summary>
+ /// Determines whether this instance can support the specified options.
+ /// </summary>
+ /// <param name="options">The set of options that might be given in a subsequent web request.</param>
+ /// <returns>
+ /// <c>true</c> if this instance can support the specified options; otherwise, <c>false</c>.
+ /// </returns>
+ bool IDirectWebRequestHandler.CanSupport(DirectWebRequestOptions options) {
+ throw new System.NotImplementedException();
+ }
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <returns>
+ /// The stream the caller should write out the entity data to.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
+ /// and any other appropriate properties <i>before</i> calling this method.
+ /// Callers <i>must</i> close and dispose of the request stream when they are done
+ /// writing to it to avoid taking up the connection too long and causing long waits on
+ /// subsequent requests.</para>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch.</para>
+ /// </remarks>
+ Stream IDirectWebRequestHandler.GetRequestStream(HttpWebRequest request) {
+ Contract.Requires<ArgumentNullException>(request != null);
+ throw new System.NotImplementedException();
+ }
+
+ /// <summary>
+ /// Prepares an <see cref="HttpWebRequest"/> that contains an POST entity for sending the entity.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> that should contain the entity.</param>
+ /// <param name="options">The options to apply to this web request.</param>
+ /// <returns>
+ /// The stream the caller should write out the entity data to.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// <para>The caller should have set the <see cref="HttpWebRequest.ContentLength"/>
+ /// and any other appropriate properties <i>before</i> calling this method.
+ /// Callers <i>must</i> close and dispose of the request stream when they are done
+ /// writing to it to avoid taking up the connection too long and causing long waits on
+ /// subsequent requests.</para>
+ /// <para>Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch.</para>
+ /// </remarks>
+ Stream IDirectWebRequestHandler.GetRequestStream(HttpWebRequest request, DirectWebRequestOptions options) {
+ Contract.Requires<ArgumentNullException>(request != null);
+ Contract.Requires<NotSupportedException>(((IDirectWebRequestHandler)this).CanSupport(options), MessagingStrings.DirectWebRequestOptionsNotSupported);
+ ////ErrorUtilities.VerifySupported(((IDirectWebRequestHandler)this).CanSupport(options), string.Format(MessagingStrings.DirectWebRequestOptionsNotSupported, options, this.GetType().Name));
+ throw new System.NotImplementedException();
+ }
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <returns>
+ /// An instance of <see cref="IncomingWebResponse"/> describing the response.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
+ /// value, if set, should be Closed before throwing.
+ /// </remarks>
+ IncomingWebResponse IDirectWebRequestHandler.GetResponse(HttpWebRequest request) {
+ Contract.Requires<ArgumentNullException>(request != null);
+ Contract.Ensures(Contract.Result<IncomingWebResponse>() != null);
+ Contract.Ensures(Contract.Result<IncomingWebResponse>().ResponseStream != null);
+ throw new System.NotImplementedException();
+ }
+
+ /// <summary>
+ /// Processes an <see cref="HttpWebRequest"/> and converts the
+ /// <see cref="HttpWebResponse"/> to a <see cref="IncomingWebResponse"/> instance.
+ /// </summary>
+ /// <param name="request">The <see cref="HttpWebRequest"/> to handle.</param>
+ /// <param name="options">The options to apply to this web request.</param>
+ /// <returns>
+ /// An instance of <see cref="IncomingWebResponse"/> describing the response.
+ /// </returns>
+ /// <exception cref="ProtocolException">Thrown for any network error.</exception>
+ /// <remarks>
+ /// Implementations should catch <see cref="WebException"/> and wrap it in a
+ /// <see cref="ProtocolException"/> to abstract away the transport and provide
+ /// a single exception type for hosts to catch. The <see cref="WebException.Response"/>
+ /// value, if set, should be Closed before throwing.
+ /// </remarks>
+ IncomingWebResponse IDirectWebRequestHandler.GetResponse(HttpWebRequest request, DirectWebRequestOptions options) {
+ Contract.Requires<ArgumentNullException>(request != null);
+ Contract.Requires<NotSupportedException>(((IDirectWebRequestHandler)this).CanSupport(options), MessagingStrings.DirectWebRequestOptionsNotSupported);
+ Contract.Ensures(Contract.Result<IncomingWebResponse>() != null);
+ Contract.Ensures(Contract.Result<IncomingWebResponse>().ResponseStream != null);
+
+ ////ErrorUtilities.VerifySupported(((IDirectWebRequestHandler)this).CanSupport(options), string.Format(MessagingStrings.DirectWebRequestOptionsNotSupported, options, this.GetType().Name));
+ throw new System.NotImplementedException();
+ }
+
+ #endregion
+ }
+>>>>>>> 884bcec... Fixed typo in comments.
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
new file mode 100644
index 0000000..cfbd80f
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
@@ -0,0 +1,38 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthorizationServerBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+using System.Diagnostics.Contracts;
+using DotNetOpenAuth.OAuth.ChannelElements;
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+
+ public abstract class AuthorizationServerBase {
+ protected AuthorizationServerBase(IAuthorizationServer authorizationServer) {
+ Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer");
+ this.AuthorizationServer = authorizationServer;
+ }
+
+ public Channel Channel { get; set; }
+
+ public IAuthorizationServer AuthorizationServer { get; set; }
+
+ protected IConsumerDescription GetClient(string clientIdentifier) {
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(clientIdentifier));
+ Contract.Ensures(Contract.Result<IConsumerDescription>() != null);
+
+ try {
+ return this.AuthorizationServer.GetClient(clientIdentifier);
+ } catch (KeyNotFoundException ex) {
+ throw ErrorUtilities.Wrap(ex, DotNetOpenAuth.OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
+ }
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs b/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
new file mode 100644
index 0000000..ba328b1
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
@@ -0,0 +1,32 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAuthorizationServer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+using System.Diagnostics.Contracts;
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OAuth.ChannelElements;
+
+ [ContractClass(typeof(IAuthorizationServerContract))]
+ public interface IAuthorizationServer {
+ IConsumerDescription GetClient(string clientIdentifier);
+ }
+
+ [ContractClassFor(typeof(IAuthorizationServer))]
+ internal abstract class IAuthorizationServerContract : IAuthorizationServer {
+ private IAuthorizationServerContract() {
+ }
+
+ IConsumerDescription IAuthorizationServer.GetClient(string clientIdentifier) {
+ Contract.Ensures(Contract.Result<IConsumerDescription>() != null);
+ throw new NotImplementedException();
+ }
+ }
+
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
index 326beb6..d5836ff 100644
--- a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30128.0
+// Runtime Version:4.0.30426.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -86,5 +86,14 @@ namespace DotNetOpenAuth.OAuthWrap {
return ResourceManager.GetString("InvalidClientCredentials", resourceCulture);
}
}
+
+ /// <summary>
+ /// Looks up a localized string similar to No callback URI was available for this request..
+ /// </summary>
+ internal static string NoCallback {
+ get {
+ return ResourceManager.GetString("NoCallback", resourceCulture);
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
index d488810..2e70624 100644
--- a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
+++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
@@ -126,4 +126,7 @@
<data name="InvalidClientCredentials" xml:space="preserve">
<value>Failed to obtain access token due to invalid Client Identifier or Client Secret.</value>
</data>
+ <data name="NoCallback" xml:space="preserve">
+ <value>No callback URI was available for this request.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
new file mode 100644
index 0000000..91ce097
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
@@ -0,0 +1,106 @@
+//-----------------------------------------------------------------------
+// <copyright file="WebAppAuthorizationServer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuthWrap.Messages;
+
+ public class WebAppAuthorizationServer : AuthorizationServerBase {
+ public WebAppAuthorizationServer(IAuthorizationServer authorizationServer)
+ : base(authorizationServer) {
+ Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer");
+ }
+
+ /// <summary>
+ /// Reads in a client's request for the Authorization Server to obtain permission from
+ /// the user to authorize the Client's access of some protected resource(s).
+ /// </summary>
+ /// <returns>The incoming request, or null if no OAuth message was attached.</returns>
+ /// <exception cref="ProtocolException">Thrown if an unexpected OAuth message is attached to the incoming request.</exception>
+ /// <remarks>
+ /// Requires HttpContext.Current.
+ /// </remarks>
+ public WebAppRequest ReadAuthorizationRequest() {
+ return this.ReadAuthorizationRequest(this.Channel.GetRequestFromContext());
+ }
+
+ /// <summary>
+ /// Reads in a client's request for the Authorization Server to obtain permission from
+ /// the user to authorize the Client's access of some protected resource(s).
+ /// </summary>
+ /// <param name="request">The HTTP request to read from.</param>
+ /// <returns>The incoming request, or null if no OAuth message was attached.</returns>
+ /// <exception cref="ProtocolException">Thrown if an unexpected OAuth message is attached to the incoming request.</exception>
+ public WebAppRequest ReadAuthorizationRequest(HttpRequestInfo request) {
+ Contract.Requires<ArgumentNullException>(request != null);
+ WebAppRequest message;
+ this.Channel.TryReadFromRequest(request, out message);
+ return message;
+ }
+
+ public OutgoingWebResponse ApproveAuthorizationRequest(WebAppRequest authorizationRequest) {
+ Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
+ Contract.Ensures(Contract.Result<OutgoingWebResponse>() != null);
+
+ return ApproveAuthorizationRequest(authorizationRequest, this.GetCallback(authorizationRequest));
+ }
+
+ public OutgoingWebResponse ApproveAuthorizationRequest(WebAppRequest authorizationRequest, Uri callback) {
+ Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
+ Contract.Requires<ArgumentNullException>(callback != null, "callback");
+ Contract.Ensures(Contract.Result<OutgoingWebResponse>() != null);
+
+ var client = GetClient(authorizationRequest.ClientIdentifier);
+ var response = new WebAppSuccessResponse(callback, ((IMessage)authorizationRequest).Version) {
+ ClientState = authorizationRequest.ClientState,
+ VerificationCode = OAuth.ServiceProvider.CreateVerificationCode(client.VerificationCodeFormat, client.VerificationCodeLength),
+ };
+
+ return this.Channel.PrepareResponse(response);
+ }
+
+ public OutgoingWebResponse RejectAuthorizationRequest(WebAppRequest authorizationRequest) {
+ Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
+ Contract.Ensures(Contract.Result<OutgoingWebResponse>() != null);
+
+ return this.RejectAuthorizationRequest(authorizationRequest, GetCallback(authorizationRequest));
+ }
+
+ public OutgoingWebResponse RejectAuthorizationRequest(WebAppRequest authorizationRequest, Uri callback) {
+ Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
+ Contract.Requires<ArgumentNullException>(callback != null, "callback");
+ Contract.Ensures(Contract.Result<OutgoingWebResponse>() != null);
+
+ var response = new WebAppFailedResponse(callback, ((IMessage)authorizationRequest).Version) {
+ ClientState = authorizationRequest.ClientState,
+ };
+
+ return this.Channel.PrepareResponse(response);
+ }
+
+ protected Uri GetCallback(WebAppRequest authorizationRequest) {
+ Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
+ Contract.Ensures(Contract.Result<Uri>() != null);
+
+ // Prefer a request-specific callback to the pre-registered one (if any).
+ if (authorizationRequest.Callback != null) {
+ return authorizationRequest.Callback;
+ }
+
+ var client = this.AuthorizationServer.GetClient(authorizationRequest.ClientIdentifier);
+ if (client.Callback != null) {
+ return client.Callback;
+ }
+
+ throw ErrorUtilities.ThrowProtocol(OAuthWrapStrings.NoCallback);
+ }
+ }
+}