summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2010-05-31 08:00:50 -0700
committerAndrew Arnott <andrewarnott@gmail.com>2010-05-31 08:00:50 -0700
commitad60330d66985c4892b7e0b7ddb424be9ca867c8 (patch)
tree5efdb30c9b14e1928828b76c8a66822779a17198 /src
parent52a77983f11cfbb948a574585ba8069dcbcbd89b (diff)
downloadDotNetOpenAuth-ad60330d66985c4892b7e0b7ddb424be9ca867c8.zip
DotNetOpenAuth-ad60330d66985c4892b7e0b7ddb424be9ca867c8.tar.gz
DotNetOpenAuth-ad60330d66985c4892b7e0b7ddb424be9ca867c8.tar.bz2
More work toward a working authorization server.
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj2
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth/Messaging/MessagingStrings.resx5
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs31
-rw-r--r--src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs16
-rw-r--r--src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs3
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs12
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs84
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs75
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs1
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs21
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs34
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs6
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs4
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs7
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs9
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx3
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs6
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs12
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs15
20 files changed, 300 insertions, 57 deletions
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index d282777..bdfb911 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -308,12 +308,14 @@ http://opensource.org/licenses/ms-pl.html
<Compile Include="Messaging\StandardMessageFactory.cs" />
<Compile Include="OAuthWrap\AuthorizationServerBase.cs" />
<Compile Include="OAuthWrap\AuthorizationState.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\AuthServerBindingElementBase.cs" />
<Compile Include="OAuthWrap\ChannelElements\IAccessTokenRequest.cs" />
<Compile Include="OAuthWrap\ChannelElements\OAuthWrapResourceServerChannel.cs" />
<Compile Include="Messaging\StandardMessageFactoryChannel.cs" />
<Compile Include="OAuthWrap\ChannelElements\TimestampEncoder.cs" />
<Compile Include="OAuthWrap\ChannelElements\VerificationCode.cs" />
<Compile Include="OAuthWrap\ChannelElements\WebAppVerificationCodeBindingElement.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\AuthServerWebServerFlowBindingElement.cs" />
<Compile Include="OAuthWrap\IAccessTokenAnalyzer.cs" />
<Compile Include="OAuthWrap\IAuthorizationServer.cs" />
<Compile Include="OAuthWrap\IAuthorizationState.cs" />
diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
index 1be62f5..21fd53a 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.1
+// Runtime Version:4.0.30426.0
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -349,6 +349,15 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Looks up a localized string similar to The following message parts had constant value requirements that were unsatisfied: {0}.
+ /// </summary>
+ internal static string RequiredMessagePartConstantIncorrect {
+ get {
+ return ResourceManager.GetString("RequiredMessagePartConstantIncorrect", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The following required non-empty parameters were empty in the {0} message: {1}.
/// </summary>
internal static string RequiredNonEmptyParameterWasEmpty {
diff --git a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
index cb80442..3a265f1 100644
--- a/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
+++ b/src/DotNetOpenAuth/Messaging/MessagingStrings.resx
@@ -306,4 +306,7 @@
<data name="StandardMessageFactoryUnsupportedMessageType" xml:space="preserve">
<value>This message factory does not support message type(s): {0}</value>
</data>
-</root>
+ <data name="RequiredMessagePartConstantIncorrect" xml:space="preserve">
+ <value>The following message parts had constant value requirements that were unsatisfied: {0}</value>
+ </data>
+</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
index 17b5304..808d5b8 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessageDescription.cs
@@ -93,6 +93,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
try {
this.CheckRequiredMessagePartsArePresent(parts.Keys, true);
this.CheckRequiredProtocolMessagePartsAreNotEmpty(parts, true);
+ this.CheckMessagePartsConstantValues(parts, true);
} catch (ProtocolException) {
Logger.Messaging.ErrorFormat(
"Error while performing basic validation of {0} with these message parts:{1}{2}",
@@ -112,7 +113,8 @@ namespace DotNetOpenAuth.Messaging.Reflection {
Contract.Requires<ArgumentNullException>(parts != null);
return this.CheckRequiredMessagePartsArePresent(parts.Keys, false) &&
- this.CheckRequiredProtocolMessagePartsAreNotEmpty(parts, false);
+ this.CheckRequiredProtocolMessagePartsAreNotEmpty(parts, false) &&
+ this.CheckMessagePartsConstantValues(parts, false);
}
/// <summary>
@@ -185,6 +187,33 @@ namespace DotNetOpenAuth.Messaging.Reflection {
return true;
}
+ private bool CheckMessagePartsConstantValues(IDictionary<string, string> partValues, bool throwOnFailure)
+ {
+ Contract.Requires<ArgumentNullException>(partValues != null);
+
+ var badConstantValues = (from part in this.Mapping.Values
+ where part.IsConstantValueAvailableStatically
+ where partValues.ContainsKey(part.Name)
+ where !string.Equals(partValues[part.Name], part.StaticConstantValue, StringComparison.Ordinal)
+ select part.Name).ToArray();
+ if (badConstantValues.Length > 0) {
+ if (throwOnFailure) {
+ ErrorUtilities.ThrowProtocol(
+ MessagingStrings.RequiredMessagePartConstantIncorrect,
+ this.MessageType.FullName,
+ string.Join(", ", badConstantValues));
+ } else {
+ Logger.Messaging.DebugFormat(
+ MessagingStrings.RequiredMessagePartConstantIncorrect,
+ this.MessageType.FullName,
+ badConstantValues.ToStringDeferred());
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/// <summary>
/// Reflects over some <see cref="IMessage"/>-implementing type
/// and prepares to serialize/deserialize instances of that type.
diff --git a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
index 4590c44..a9ec171 100644
--- a/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
+++ b/src/DotNetOpenAuth/Messaging/Reflection/MessagePart.cs
@@ -159,6 +159,7 @@ namespace DotNetOpenAuth.Messaging.Reflection {
(this.field.Attributes & FieldAttributes.InitOnly) == FieldAttributes.InitOnly ||
(this.field.Attributes & constAttributes) == constAttributes)) {
this.IsConstantValue = true;
+ this.IsConstantValueAvailableStatically = this.field.IsStatic;
} else if (this.property != null && !this.property.CanWrite) {
this.IsConstantValue = true;
}
@@ -194,6 +195,21 @@ namespace DotNetOpenAuth.Messaging.Reflection {
internal bool IsConstantValue { get; set; }
/// <summary>
+ /// Gets or sets a value indicating whether this part is defined as a constant field and can be read without a message instance.
+ /// </summary>
+ internal bool IsConstantValueAvailableStatically { get; set; }
+
+ /// <summary>
+ /// Gets the static constant value for this message part without a message instance.
+ /// </summary>
+ internal string StaticConstantValue {
+ get {
+ Contract.Requires<InvalidOperationException>(this.IsConstantValueAvailableStatically);
+ return this.ToString(this.field.GetValue(null));
+ }
+ }
+
+ /// <summary>
/// Sets the member of a given message to some given value.
/// Used in deserialization.
/// </summary>
diff --git a/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs b/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs
index abf3359..2eacf93 100644
--- a/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs
+++ b/src/DotNetOpenAuth/Messaging/StandardMessageFactory.cs
@@ -144,7 +144,8 @@ namespace DotNetOpenAuth.Messaging {
var matches = this.requestMessageTypes.Keys
.Where(message => message.CheckMessagePartsPassBasicValidation(fields))
- .OrderByDescending(message => message.Mapping.Count)
+ .OrderByDescending(message => CountInCommon(message.Mapping.Keys, fields.Keys))
+ .ThenByDescending(message => message.Mapping.Count)
.CacheGeneratedResults();
var match = matches.FirstOrDefault();
if (match != null) {
diff --git a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
index 1875bd1..f6f2041 100644
--- a/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/AuthorizationServerBase.cs
@@ -18,6 +18,7 @@ namespace DotNetOpenAuth.OAuthWrap {
protected AuthorizationServerBase(IAuthorizationServer authorizationServer) {
Contract.Requires<ArgumentNullException>(authorizationServer != null, "authorizationServer");
this.AuthorizationServer = authorizationServer;
+ this.Channel = new OAuthWrapAuthorizationServerChannel(authorizationServer);
}
public Channel Channel { get; set; }
@@ -27,16 +28,5 @@ namespace DotNetOpenAuth.OAuthWrap {
}
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, OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
- }
- }
}
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs
new file mode 100644
index 0000000..c84d37d
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerBindingElementBase.cs
@@ -0,0 +1,84 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthServerBindingElementBase.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using Messaging;
+
+ internal abstract class AuthServerBindingElementBase : IChannelBindingElement {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthServerBindingElementBase"/> class.
+ /// </summary>
+ protected AuthServerBindingElementBase()
+ {
+ }
+
+ /// <summary>
+ /// Gets or sets the channel that this binding element belongs to.
+ /// </summary>
+ /// <remarks>
+ /// This property is set by the channel when it is first constructed.
+ /// </remarks>
+ public Channel Channel { get; set; }
+
+ protected OAuthWrapAuthorizationServerChannel OAuthChannel {
+ get { return (OAuthWrapAuthorizationServerChannel)this.Channel; }
+ }
+
+ /// <summary>
+ /// Gets the authorization server hosting this channel.
+ /// </summary>
+ /// <value>The authorization server.</value>
+ protected IAuthorizationServer AuthorizationServer {
+ get { return this.OAuthChannel.AuthorizationServer; }
+ }
+
+ /// <summary>
+ /// Gets the protection commonly offered (if any) by this binding element.
+ /// </summary>
+ /// <value></value>
+ /// <remarks>
+ /// This value is used to assist in sorting binding elements in the channel stack.
+ /// </remarks>
+ public abstract MessageProtections Protection { get; }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public abstract MessageProtections? ProcessOutgoingMessage(IProtocolMessage message);
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the binding element rules indicate that this message is invalid and should
+ /// NOT be processed.
+ /// </exception>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public abstract MessageProtections? ProcessIncomingMessage(IProtocolMessage message);
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs
new file mode 100644
index 0000000..2f7b49e
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthServerWebServerFlowBindingElement.cs
@@ -0,0 +1,75 @@
+//-----------------------------------------------------------------------
+// <copyright file="WebServerFlowBindingElement.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Text;
+ using DotNetOpenAuth.OAuthWrap.Messages;
+ using Messaging;
+
+ internal class AuthServerWebServerFlowBindingElement : AuthServerBindingElementBase {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthServerWebServerFlowBindingElement"/> class.
+ /// </summary>
+ internal AuthServerWebServerFlowBindingElement() {
+ }
+
+ /// <summary>
+ /// Gets the protection commonly offered (if any) by this binding element.
+ /// </summary>
+ /// <remarks>
+ /// This value is used to assist in sorting binding elements in the channel stack.
+ /// </remarks>
+ public override MessageProtections Protection {
+ get { return MessageProtections.None; }
+ }
+
+ /// <summary>
+ /// Prepares a message for sending based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The message to prepare for sending.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
+ return null;
+ }
+
+ /// <summary>
+ /// Performs any transformation on an incoming message that may be necessary and/or
+ /// validates an incoming message based on the rules of this channel binding element.
+ /// </summary>
+ /// <param name="message">The incoming message to process.</param>
+ /// <returns>
+ /// The protections (if any) that this binding element applied to the message.
+ /// Null if this binding element did not even apply to this binding element.
+ /// </returns>
+ /// <exception cref="ProtocolException">
+ /// Thrown when the binding element rules indicate that this message is invalid and should
+ /// NOT be processed.
+ /// </exception>
+ /// <remarks>
+ /// Implementations that provide message protection must honor the
+ /// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
+ /// </remarks>
+ public override MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
+ var authorizationRequest = message as WebAppRequest;
+ if (authorizationRequest != null) {
+ var client = this.AuthorizationServer.GetClientOrThrow(authorizationRequest.ClientIdentifier);
+ ErrorUtilities.VerifyProtocol(client.Callback == null || client.Callback == authorizationRequest.Callback, OAuthWrapStrings.CallbackMismatch, client.Callback, authorizationRequest.Callback);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
index aae511d..f286e4d 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
@@ -161,6 +161,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
var bindingElements = new List<IChannelBindingElement>();
if (authorizationServer != null) {
+ bindingElements.Add(new AuthServerWebServerFlowBindingElement());
bindingElements.Add(new WebAppVerificationCodeBindingElement());
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
index 3a46517..e99a685 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
@@ -20,13 +20,14 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// </summary>
/// <param name="channel">The channel.</param>
/// <param name="callback">The callback.</param>
- internal VerificationCode(OAuthWrapAuthorizationServerChannel channel, Uri callback, string scope)
+ internal VerificationCode(OAuthWrapAuthorizationServerChannel channel, Uri callback, string scope, string username)
: this(channel) {
Contract.Requires<ArgumentNullException>(channel != null, "channel");
Contract.Requires<ArgumentNullException>(callback != null, "callback");
this.CallbackHash = this.CalculateCallbackHash(callback);
this.Scope = scope;
+ this.User = username;
this.CreationDateUtc = DateTime.UtcNow;
this.Nonce = Convert.ToBase64String(MessagingUtilities.GetNonCryptoRandomData(NonceLength));
}
@@ -50,10 +51,13 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
[MessagePart("cb")]
private string CallbackHash { get; set; }
- [MessagePart("scope")]
+ [MessagePart]
internal string Scope { get; set; }
- [MessagePart("nonce")]
+ [MessagePart]
+ internal string User { get; set; }
+
+ [MessagePart]
internal string Nonce { get; set; }
[MessagePart("timestamp", Encoder = typeof(TimestampEncoder))]
@@ -67,6 +71,12 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// before it passes through the channel binding elements.
/// </summary>
void IMessageWithEvents.OnSending() {
+ // Encrypt the authorizing username so as to not expose unintended private user data
+ // to the client or any eavesdropping third party.
+ if (this.User != null) {
+ // TODO: code here
+ }
+
this.Signature = CalculateSignature();
}
@@ -77,6 +87,11 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
void IMessageWithEvents.OnReceiving() {
// Verify that the verification code was issued by this authorization server.
ErrorUtilities.VerifyProtocol(string.Equals(this.Signature, this.CalculateSignature(), StringComparison.Ordinal), Protocol.bad_verification_code);
+
+ // Decrypt the authorizing username.
+ if (this.User != null) {
+ // TODO: code here
+ }
}
internal static VerificationCode Decode(OAuthWrapAuthorizationServerChannel channel, string value) {
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
index f85cf98..31639f3 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
@@ -17,7 +17,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// A binding element for OAuth 2.0 authorization servers that create/verify
/// issued verification codes as part of obtaining access/refresh tokens.
/// </summary>
- internal class WebAppVerificationCodeBindingElement : IChannelBindingElement {
+ internal class WebAppVerificationCodeBindingElement : AuthServerBindingElementBase {
private const string VerificationCodeContext = "{VerificationCode}";
/// <summary>
@@ -27,28 +27,16 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
}
/// <summary>
- /// Gets or sets the channel that this binding element belongs to.
- /// </summary>
- /// <remarks>
- /// This property is set by the channel when it is first constructed.
- /// </remarks>
- public Channel Channel { get; set; }
-
- /// <summary>
/// Gets the protection commonly offered (if any) by this binding element.
/// </summary>
/// <value>Always <c>MessageProtections.None</c></value>
/// <remarks>
/// This value is used to assist in sorting binding elements in the channel stack.
/// </remarks>
- public MessageProtections Protection {
+ public override MessageProtections Protection {
get { return MessageProtections.None; }
}
- protected OAuthWrapAuthorizationServerChannel OAuthChannel {
- get { return (OAuthWrapAuthorizationServerChannel)this.Channel; }
- }
-
/// <summary>
/// Gets the maximum message age from the standard expiration binding element.
/// </summary>
@@ -57,14 +45,6 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
}
/// <summary>
- /// Gets the authorization server hosting this channel.
- /// </summary>
- /// <value>The authorization server.</value>
- private IAuthorizationServer AuthorizationServer {
- get { return this.OAuthChannel.AuthorizationServer; }
- }
-
- /// <summary>
/// Prepares a message for sending based on the rules of this channel binding element.
/// </summary>
/// <param name="message">The message to prepare for sending.</param>
@@ -76,13 +56,13 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// Implementations that provide message protection must honor the
/// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
/// </remarks>
- public MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
+ public override MessageProtections? ProcessOutgoingMessage(IProtocolMessage message) {
var response = message as WebAppSuccessResponse;
if (response != null) {
- var directResponse = response as IDirectResponseProtocolMessage;
- var request = directResponse.OriginatingRequest as WebAppRequest;
+ var directResponse = (IDirectResponseProtocolMessage)response;
+ var request = (WebAppRequest)directResponse.OriginatingRequest;
- var code = new VerificationCode(this.OAuthChannel, request.Callback, request.Scope);
+ var code = new VerificationCode(this.OAuthChannel, request.Callback, request.Scope, response.AuthorizingUsername);
response.VerificationCode = code.Encode();
return MessageProtections.None;
@@ -108,7 +88,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// Implementations that provide message protection must honor the
/// <see cref="MessagePartAttribute.RequiredProtection"/> properties where applicable.
/// </remarks>
- public MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
+ public override MessageProtections? ProcessIncomingMessage(IProtocolMessage message) {
var request = message as WebAppAccessTokenRequest;
if (request != null) {
var client = this.AuthorizationServer.GetClient(request.ClientIdentifier);
diff --git a/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs b/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
index c92ecc7..fccf067 100644
--- a/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/IAuthorizationServer.cs
@@ -16,6 +16,12 @@ namespace DotNetOpenAuth.OAuthWrap {
[ContractClass(typeof(IAuthorizationServerContract))]
public interface IAuthorizationServer {
+ /// <summary>
+ /// Gets the client with a given identifier.
+ /// </summary>
+ /// <param name="clientIdentifier">The client identifier.</param>
+ /// <returns>The client registration. Never null.</returns>
+ /// <exception cref="ArgumentException">Thrown when no client with the given identifier is registered with this authorization server.</exception>
IConsumerDescription GetClient(string clientIdentifier);
byte[] Secret { get; }
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
index 9986d19..738846b 100644
--- a/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/MessageBase.cs
@@ -49,11 +49,13 @@ namespace DotNetOpenAuth.OAuthWrap.Messages {
/// Initializes a new instance of the <see cref="MessageBase"/> class.
/// </summary>
/// <param name="request">The originating request.</param>
- protected MessageBase(IDirectedProtocolMessage request) {
+ /// <param name="recipient">The recipient of the directed message. Null if not applicable.</param>
+ protected MessageBase(IDirectedProtocolMessage request, Uri recipient = null) {
Contract.Requires<ArgumentNullException>(request != null);
this.originatingRequest = request;
this.messageTransport = MessageTransport.Direct;
this.version = request.Version;
+ this.Recipient = recipient;
}
/// <summary>
diff --git a/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs
index e93acca..2cfb017 100644
--- a/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/Messages/WebServer/WebAppSuccessResponse.cs
@@ -32,7 +32,7 @@ namespace DotNetOpenAuth.OAuthWrap.Messages {
/// <param name="clientCallback">The client callback.</param>
/// <param name="request">The request.</param>
internal WebAppSuccessResponse(Uri clientCallback, WebAppRequest request)
- : this(clientCallback, ((IMessage)request).Version) {
+ : base(request, clientCallback) {
Contract.Requires<ArgumentNullException>(clientCallback != null, "clientCallback");
Contract.Requires<ArgumentNullException>(request != null, "request");
((IMessageWithClientState)this).ClientState = ((IMessageWithClientState)request).ClientState;
@@ -57,5 +57,10 @@ namespace DotNetOpenAuth.OAuthWrap.Messages {
/// </value>
[MessagePart(Protocol.code, IsRequired = true, AllowEmpty = true)]
internal string VerificationCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets the authorizing user's account name.
+ /// </summary>
+ internal string AuthorizingUsername { get; set; }
}
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
index d5836ff..35417e1 100644
--- a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.Designer.cs
@@ -61,6 +61,15 @@ namespace DotNetOpenAuth.OAuthWrap {
}
/// <summary>
+ /// Looks up a localized string similar to Client&apos;s pre-registered callback URL ({0}) does not match the one found in the authorization request ({1})..
+ /// </summary>
+ internal static string CallbackMismatch {
+ get {
+ return ResourceManager.GetString("CallbackMismatch", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Failed to obtain access token. Authorization Server reports reason: {0}.
/// </summary>
internal static string CannotObtainAccessTokenWithReason {
diff --git a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
index 2e70624..ae2cc6c 100644
--- a/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
+++ b/src/DotNetOpenAuth/OAuthWrap/OAuthWrapStrings.resx
@@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="CallbackMismatch" xml:space="preserve">
+ <value>Client's pre-registered callback URL ({0}) does not match the one found in the authorization request ({1}).</value>
+ </data>
<data name="CannotObtainAccessTokenWithReason" xml:space="preserve">
<value>Failed to obtain access token. Authorization Server reports reason: {0}</value>
</data>
diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
index b403f91..837d571 100644
--- a/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/WebAppAuthorizationServer.cs
@@ -40,10 +40,11 @@ namespace DotNetOpenAuth.OAuthWrap {
return message;
}
- public void ApproveAuthorizationRequest(WebAppRequest authorizationRequest, Uri callback = null) {
+ public void ApproveAuthorizationRequest(WebAppRequest authorizationRequest, string username, Uri callback = null) {
Contract.Requires<ArgumentNullException>(authorizationRequest != null, "authorizationRequest");
var response = this.PrepareApproveAuthorizationRequest(authorizationRequest, callback);
+ response.AuthorizingUsername = username;
this.Channel.Send(response);
}
@@ -59,7 +60,6 @@ namespace DotNetOpenAuth.OAuthWrap {
return this.TryPrepareAccessTokenResponse(this.Channel.GetRequestFromContext(), out response);
}
-
public bool TryPrepareAccessTokenResponse(HttpRequestInfo httpRequestInfo, out IDirectResponseProtocolMessage response)
{
Contract.Requires<ArgumentNullException>(httpRequestInfo != null, "httpRequestInfo");
@@ -95,7 +95,7 @@ namespace DotNetOpenAuth.OAuthWrap {
callback = this.GetCallback(authorizationRequest);
}
- var client = GetClient(authorizationRequest.ClientIdentifier);
+ var client = this.AuthorizationServer.GetClientOrThrow(authorizationRequest.ClientIdentifier);
var response = new WebAppSuccessResponse(callback, authorizationRequest);
return response;
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs
index 4ac1430..0e26994 100644
--- a/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/WebAppClient.cs
@@ -64,16 +64,14 @@ namespace DotNetOpenAuth.OAuthWrap {
return request;
}
- public IAuthorizationState ProcessUserAuthorization() {
- Contract.Requires<InvalidOperationException>(HttpContext.Current != null && HttpContext.Current.Request != null, MessagingStrings.HttpContextRequired);
- return this.ProcessUserAuthorization(this.Channel.GetRequestFromContext());
- }
-
- public IAuthorizationState ProcessUserAuthorization(HttpRequestInfo request) {
- Contract.Requires<ArgumentNullException>(request != null);
+ public IAuthorizationState ProcessUserAuthorization(HttpRequestInfo request = null) {
Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientIdentifier));
Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(this.ClientSecret));
+ if (request == null) {
+ request = this.Channel.GetRequestFromContext();
+ }
+
IMessageWithClientState response;
if (this.Channel.TryReadFromRequest<IMessageWithClientState>(request, out response)) {
Uri callback = MessagingUtilities.StripMessagePartsFromQueryString(request.UrlBeforeRewriting, this.Channel.MessageDescriptions.Get(response));
diff --git a/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs b/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs
index 7e04f3f..86a9c5d 100644
--- a/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/WrapUtilities.cs
@@ -4,6 +4,8 @@
// </copyright>
//-----------------------------------------------------------------------
+using DotNetOpenAuth.Messaging;
+
namespace DotNetOpenAuth.OAuthWrap {
using System;
using System.Collections.Generic;
@@ -30,5 +32,18 @@ namespace DotNetOpenAuth.OAuthWrap {
Protocol.HttpAuthorizationHeaderFormat,
accessToken);
}
+
+ internal static DotNetOpenAuth.OAuth.ChannelElements.IConsumerDescription GetClientOrThrow(this IAuthorizationServer authorizationServer, string clientIdentifier) {
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(clientIdentifier));
+ Contract.Ensures(Contract.Result<DotNetOpenAuth.OAuth.ChannelElements.IConsumerDescription>() != null);
+
+ try {
+ return authorizationServer.GetClient(clientIdentifier);
+ } catch (KeyNotFoundException ex) {
+ throw ErrorUtilities.Wrap(ex, OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
+ } catch (ArgumentException ex) {
+ throw ErrorUtilities.Wrap(ex, OAuth.OAuthStrings.ConsumerOrTokenSecretNotFound);
+ }
+ }
}
}