summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/DotNetOpenAuth/DotNetOpenAuth.csproj5
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/AccessToken.cs36
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthorizationDataBag.cs35
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/DataBag.cs (renamed from src/DotNetOpenAuth/OAuthWrap/ChannelElements/SignedDataBag.cs)20
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/IAuthorizationDescription.cs38
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs1
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshAccessTokenBindingElement.cs4
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshToken.cs14
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs12
-rw-r--r--src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs3
10 files changed, 149 insertions, 19 deletions
diff --git a/src/DotNetOpenAuth/DotNetOpenAuth.csproj b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
index 56fba07..5131b7e 100644
--- a/src/DotNetOpenAuth/DotNetOpenAuth.csproj
+++ b/src/DotNetOpenAuth/DotNetOpenAuth.csproj
@@ -309,13 +309,16 @@ 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\AccessToken.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\AuthorizationDataBag.cs" />
<Compile Include="OAuthWrap\ChannelElements\AuthServerBindingElementBase.cs" />
<Compile Include="OAuthWrap\ChannelElements\IAccessTokenRequest.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\IAuthorizationDescription.cs" />
<Compile Include="OAuthWrap\ChannelElements\OAuthWrapResourceServerChannel.cs" />
<Compile Include="Messaging\StandardMessageFactoryChannel.cs" />
<Compile Include="OAuthWrap\ChannelElements\RefreshAccessTokenBindingElement.cs" />
<Compile Include="OAuthWrap\ChannelElements\RefreshToken.cs" />
- <Compile Include="OAuthWrap\ChannelElements\SignedDataBag.cs" />
+ <Compile Include="OAuthWrap\ChannelElements\DataBag.cs" />
<Compile Include="OAuthWrap\ChannelElements\TimestampEncoder.cs" />
<Compile Include="OAuthWrap\ChannelElements\VerificationCode.cs" />
<Compile Include="OAuthWrap\ChannelElements\WebAppVerificationCodeBindingElement.cs" />
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AccessToken.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AccessToken.cs
new file mode 100644
index 0000000..e770f09
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AccessToken.cs
@@ -0,0 +1,36 @@
+//-----------------------------------------------------------------------
+// <copyright file="AccessToken.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.Messaging;
+
+ internal class AccessToken : AuthorizationDataBag {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AccessToken"/> class.
+ /// </summary>
+ /// <param name="channel">The channel.</param>
+ internal AccessToken(OAuthWrapAuthorizationServerChannel channel, TimeSpan lifetime)
+ : base(channel, true, true, true, lifetime) {
+ Contract.Requires<ArgumentNullException>(channel != null, "channel");
+ }
+
+ internal static AccessToken Decode(OAuthWrapAuthorizationServerChannel channel, string value, TimeSpan lifetime, IProtocolMessage containingMessage) {
+ Contract.Requires<ArgumentNullException>(channel != null, "channel");
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(value));
+ Contract.Requires<ArgumentNullException>(containingMessage != null, "containingMessage");
+ Contract.Ensures(Contract.Result<AccessToken>() != null);
+
+ var self = new AccessToken(channel, lifetime);
+ self.Decode(value, containingMessage);
+ return self;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthorizationDataBag.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthorizationDataBag.cs
new file mode 100644
index 0000000..6bd3041
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/AuthorizationDataBag.cs
@@ -0,0 +1,35 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthorizationDataBag.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.Messaging;
+ using DotNetOpenAuth.Messaging.Bindings;
+
+ internal abstract class AuthorizationDataBag : DataBag, IAuthorizationDescription {
+ protected AuthorizationDataBag(OAuthWrapAuthorizationServerChannel channel, bool signed = false, bool encrypted = false, bool compressed = false, TimeSpan? maximumAge = null, INonceStore decodeOnceOnly = null)
+ : base(channel, signed, encrypted, compressed, maximumAge, decodeOnceOnly) {
+ Contract.Requires<ArgumentNullException>(channel != null, "channel");
+ }
+
+ [MessagePart]
+ public string ClientIdentifier { get; set; }
+
+ public DateTime UtcIssued {
+ get { return this.UtcCreationDate; }
+ }
+
+ [MessagePart]
+ public string User { get; set; }
+
+ [MessagePart]
+ public string Scope { get; set; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/SignedDataBag.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/DataBag.cs
index 4b5a296..0b0bd3a 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/SignedDataBag.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/DataBag.cs
@@ -55,12 +55,12 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
internal string Nonce { get; set; }
[MessagePart("timestamp", IsRequired = true, Encoder = typeof(TimestampEncoder))]
- internal DateTime CreationDateUtc { get; set; }
+ internal DateTime UtcCreationDate { get; set; }
internal virtual string Encode() {
Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));
- this.CreationDateUtc = DateTime.UtcNow;
+ this.UtcCreationDate = DateTime.UtcNow;
if (decodeOnceOnly != null) {
this.Nonce = Convert.ToBase64String(MessagingUtilities.GetNonCryptoRandomData(NonceLength));
@@ -71,7 +71,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
}
var fields = this.Channel.MessageDescriptions.GetAccessor(this);
- string value = MessagingUtilities.CreateQueryString(fields);
+ string value = Uri.EscapeDataString(this.BagTypeName) + "&" + MessagingUtilities.CreateQueryString(fields);
byte[] encoded = Encoding.UTF8.GetBytes(value);
@@ -104,6 +104,10 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
// Deserialize into this newly created instance.
var fields = this.Channel.MessageDescriptions.GetAccessor(this);
+ string[] halves = value.Split(new char[] { '&' }, 2);
+ ErrorUtilities.VerifyProtocol(string.Equals(halves[0], Uri.EscapeDataString(this.BagTypeName), StringComparison.Ordinal), "Unexpected type of message while decoding.");
+ value = halves[1];
+
var nvc = HttpUtility.ParseQueryString(value);
foreach (string key in nvc) {
fields[key] = nvc[key];
@@ -116,7 +120,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
if (maximumAge.HasValue) {
// Has this verification code expired?
- DateTime expirationDate = this.CreationDateUtc + this.maximumAge.Value;
+ DateTime expirationDate = this.UtcCreationDate + this.maximumAge.Value;
if (expirationDate < DateTime.UtcNow) {
throw new ExpiredMessageException(expirationDate, containingMessage);
}
@@ -126,13 +130,17 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
if (decodeOnceOnly != null) {
ErrorUtilities.VerifyInternal(this.maximumAge.HasValue, "Oops! How can we validate a nonce without a maximum message age?");
string context = "{" + GetType().FullName + "}";
- if (!this.decodeOnceOnly.StoreNonce(context, this.Nonce, this.CreationDateUtc)) {
- Logger.OpenId.ErrorFormat("Replayed nonce detected ({0} {1}). Rejecting message.", this.Nonce, this.CreationDateUtc);
+ if (!this.decodeOnceOnly.StoreNonce(context, this.Nonce, this.UtcCreationDate)) {
+ Logger.OpenId.ErrorFormat("Replayed nonce detected ({0} {1}). Rejecting message.", this.Nonce, this.UtcCreationDate);
throw new ReplayedMessageException(containingMessage);
}
}
}
+ private string BagTypeName {
+ get { return this.GetType().Name; }
+ }
+
/// <summary>
/// Calculates the signature for the data in this verification code.
/// </summary>
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/IAuthorizationDescription.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/IAuthorizationDescription.cs
new file mode 100644
index 0000000..d7735b9
--- /dev/null
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/IAuthorizationDescription.cs
@@ -0,0 +1,38 @@
+//-----------------------------------------------------------------------
+// <copyright file="IAuthorizationDescription.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;
+
+ /// <summary>
+ /// Describes a delegated authorization between a resource server, a client, and a user.
+ /// </summary>
+ public interface IAuthorizationDescription {
+ /// <summary>
+ /// Gets the identifier of the client authorized to access protected data.
+ /// </summary>
+ string ClientIdentifier { get; }
+
+ /// <summary>
+ /// Gets the date this authorization was established or the token was issued.
+ /// </summary>
+ /// <value>A date/time expressed in UTC.</value>
+ DateTime UtcIssued { get; }
+
+ /// <summary>
+ /// Gets the name on the account whose data on the resource server is accessible using this authorization.
+ /// </summary>
+ string User { get; }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ string Scope { get; }
+ }
+}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
index 562b818..0148b7a 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/OAuthWrapAuthorizationServerChannel.cs
@@ -71,6 +71,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
var response = new AccessTokenSuccessResponse(request) {
Scope = request.Scope,
+ Lifetime = TimeSpan.FromDays(1), // reasonable default for access token lifetime
// TODO: code here to initialize the response
AccessToken = "TODO",
RefreshToken = "TODO",
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshAccessTokenBindingElement.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshAccessTokenBindingElement.cs
index 299353e..24aa1af 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshAccessTokenBindingElement.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshAccessTokenBindingElement.cs
@@ -31,11 +31,11 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
var request = message as RefreshAccessTokenRequest;
if (request != null) {
// Decode and validate the refresh token
- //request.RefreshToken
+ var refreshToken = RefreshToken.Decode(this.OAuthChannel, request.RefreshToken, message);
// Fill in the authorized access scope from the refresh token and fill in the property
// on the message so that others can read it later.
- //request.Scope =
+ request.Scope = refreshToken.Scope;
return MessageProtections.None;
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshToken.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshToken.cs
index 55a4416..c523127 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshToken.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/RefreshToken.cs
@@ -10,8 +10,9 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
+ using DotNetOpenAuth.Messaging;
- internal class RefreshToken : DataBag {
+ internal class RefreshToken : AuthorizationDataBag {
/// <summary>
/// Initializes a new instance of the <see cref="RefreshToken"/> class.
/// </summary>
@@ -20,5 +21,16 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
: base(channel, true, true, true) {
Contract.Requires<ArgumentNullException>(channel != null, "channel");
}
+
+ internal static RefreshToken Decode(OAuthWrapAuthorizationServerChannel channel, string value, IProtocolMessage containingMessage) {
+ Contract.Requires<ArgumentNullException>(channel != null, "channel");
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(value));
+ Contract.Requires<ArgumentNullException>(containingMessage != null, "containingMessage");
+ Contract.Ensures(Contract.Result<RefreshToken>() != null);
+
+ var self = new RefreshToken(channel);
+ self.Decode(value, containingMessage);
+ return self;
+ }
}
}
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
index faedf8b..4e5e449 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/VerificationCode.cs
@@ -10,7 +10,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
- internal class VerificationCode : DataBag {
+ internal class VerificationCode : AuthorizationDataBag {
/// <summary>
/// Initializes a new instance of the <see cref="VerificationCode"/> class.
/// </summary>
@@ -18,11 +18,13 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
/// <param name="callback">The callback.</param>
/// <param name="scope">The scope.</param>
/// <param name="username">The username.</param>
- internal VerificationCode(OAuthWrapAuthorizationServerChannel channel, Uri callback, string scope, string username)
+ internal VerificationCode(OAuthWrapAuthorizationServerChannel channel, string clientIdentifier, Uri callback, string scope, string username)
: this(channel) {
+ Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(clientIdentifier));
Contract.Requires<ArgumentNullException>(channel != null, "channel");
Contract.Requires<ArgumentNullException>(callback != null, "callback");
+ this.ClientIdentifier = clientIdentifier;
this.CallbackHash = this.CalculateCallbackHash(callback);
this.Scope = scope;
this.User = username;
@@ -38,12 +40,6 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
Contract.Requires<ArgumentException>(channel.AuthorizationServer != null);
}
- [MessagePart]
- internal string Scope { get; set; }
-
- [MessagePart]
- internal string User { get; set; }
-
[MessagePart("cb")]
private string CallbackHash { get; set; }
diff --git a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
index 285cf0f..faf896a 100644
--- a/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
+++ b/src/DotNetOpenAuth/OAuthWrap/ChannelElements/WebAppVerificationCodeBindingElement.cs
@@ -53,7 +53,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
var directResponse = (IDirectResponseProtocolMessage)response;
var request = (WebAppRequest)directResponse.OriginatingRequest;
- var code = new VerificationCode(this.OAuthChannel, request.Callback, request.Scope, response.AuthorizingUsername);
+ var code = new VerificationCode(this.OAuthChannel, request.ClientIdentifier, request.Callback, request.Scope, response.AuthorizingUsername);
response.VerificationCode = code.Encode();
return MessageProtections.None;
@@ -86,6 +86,7 @@ namespace DotNetOpenAuth.OAuthWrap.ChannelElements {
ErrorUtilities.VerifyProtocol(string.Equals(client.Secret, request.ClientSecret, StringComparison.Ordinal), Protocol.incorrect_client_credentials);
var verificationCode = VerificationCode.Decode(this.OAuthChannel, request.VerificationCode, message);
+ ErrorUtilities.VerifyProtocol(string.Equals(verificationCode.ClientIdentifier, request.ClientIdentifier, StringComparison.Ordinal), Protocol.bad_verification_code);
verificationCode.VerifyCallback(request.Callback);
request.Scope = verificationCode.Scope;