summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Arnott <andrewarnott@gmail.com>2012-12-02 15:57:23 -0800
committerAndrew Arnott <andrewarnott@gmail.com>2012-12-02 15:57:23 -0800
commitc7509b6d29ffe07098d0c2b81acbd1af34e1c076 (patch)
tree058db773e244038713f121b9381a962eca327ce3
parent67f3936edd8ed795f16e596f349a2f12712810e9 (diff)
parent84ef4b74365fe78156792cf17bb945a9ace4e03f (diff)
downloadDotNetOpenAuth-c7509b6d29ffe07098d0c2b81acbd1af34e1c076.zip
DotNetOpenAuth-c7509b6d29ffe07098d0c2b81acbd1af34e1c076.tar.gz
DotNetOpenAuth-c7509b6d29ffe07098d0c2b81acbd1af34e1c076.tar.bz2
Merge branch 'v4.1'
Conflicts: src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs src/version.txt
-rw-r--r--samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj4
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs46
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs79
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs2
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs2
-rw-r--r--src/DotNetOpenAuth.AspNet/Clients/OAuth2/MicrosoftClient.cs4
-rw-r--r--src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj3
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs4
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx7
-rw-r--r--src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs20
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.Designer.cs11
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.resx7
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs14
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServerAccessToken.cs1
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs8
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs2
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs4
-rw-r--r--src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs12
-rw-r--r--src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AssociationDataBag.cs2
-rw-r--r--src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/SelectorButton.cs1
-rw-r--r--src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs5
-rw-r--r--src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj1
-rw-r--r--src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs11
-rw-r--r--src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs5
-rw-r--r--src/DotNetOpenAuth.Test/OAuth2/ResourceServerTests.cs110
26 files changed, 338 insertions, 38 deletions
diff --git a/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj b/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj
index 9f810bb..8c7fd08 100644
--- a/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj
+++ b/samples/OAuthAuthorizationServer/OAuthAuthorizationServer.csproj
@@ -63,6 +63,10 @@
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+ <Reference Include="System.Net.Http, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\..\lib\net-v4.0\System.Net.Http.dll</HintPath>
+ </Reference>
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs
index 2ec988b..efc382f 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/AuthenticationOnlyCookieOAuthTokenManager.cs
@@ -17,7 +17,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// Key used for token cookie
/// </summary>
- private const string TokenCookieKey = "OAuthTokenSecret";
+ protected const string TokenCookieKey = "OAuthTokenSecret";
/// <summary>
/// Primary request context.
@@ -41,7 +41,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// Gets the effective HttpContext object to use.
/// </summary>
- private HttpContextBase Context {
+ protected HttpContextBase Context {
get {
return this.primaryContext ?? new HttpContextWrapper(HttpContext.Current);
}
@@ -54,15 +54,13 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <returns>
/// The token's secret
/// </returns>
- public string GetTokenSecret(string token) {
+ public virtual string GetTokenSecret(string token) {
HttpCookie cookie = this.Context.Request.Cookies[TokenCookieKey];
if (cookie == null || string.IsNullOrEmpty(cookie.Values[token])) {
return null;
}
- byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(cookie.Values[token]);
- byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token);
- string secret = Encoding.UTF8.GetString(clearBytes);
+ string secret = DecodeAndUnprotectToken(token, cookie.Values[token]);
return secret;
}
@@ -72,7 +70,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <param name="requestToken">The request token.</param>
/// <param name="accessToken">The access token.</param>
/// <param name="accessTokenSecret">The access token secret.</param>
- public void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) {
+ public virtual void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) {
var cookie = new HttpCookie(TokenCookieKey) {
Value = string.Empty,
Expires = DateTime.UtcNow.AddDays(-5)
@@ -85,7 +83,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// </summary>
/// <param name="requestToken">The request token.</param>
/// <param name="requestTokenSecret">The request token secret.</param>
- public void StoreRequestToken(string requestToken, string requestTokenSecret) {
+ public virtual void StoreRequestToken(string requestToken, string requestTokenSecret) {
var cookie = new HttpCookie(TokenCookieKey) {
HttpOnly = true
};
@@ -94,10 +92,36 @@ namespace DotNetOpenAuth.AspNet.Clients {
cookie.Secure = true;
}
- byte[] cookieBytes = Encoding.UTF8.GetBytes(requestTokenSecret);
- var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + requestToken);
- cookie.Values[requestToken] = HttpServerUtility.UrlTokenEncode(secretBytes);
+ var encryptedToken = ProtectAndEncodeToken(requestToken, requestTokenSecret);
+ cookie.Values[requestToken] = encryptedToken;
+
this.Context.Response.Cookies.Set(cookie);
}
+
+ /// <summary>
+ /// Protect and url-encode the specified token secret.
+ /// </summary>
+ /// <param name="token">The token to be used as a key.</param>
+ /// <param name="tokenSecret">The token secret to be protected</param>
+ /// <returns>The encrypted and protected string.</returns>
+ protected static string ProtectAndEncodeToken(string token, string tokenSecret)
+ {
+ byte[] cookieBytes = Encoding.UTF8.GetBytes(tokenSecret);
+ var secretBytes = MachineKeyUtil.Protect(cookieBytes, TokenCookieKey, "Token:" + token);
+ return HttpServerUtility.UrlTokenEncode(secretBytes);
+ }
+
+ /// <summary>
+ /// Url-decode and unprotect the specified encrypted token string.
+ /// </summary>
+ /// <param name="token">The token to be used as a key.</param>
+ /// <param name="encryptedToken">The encrypted token to be decrypted</param>
+ /// <returns>The original token secret</returns>
+ protected static string DecodeAndUnprotectToken(string token, string encryptedToken)
+ {
+ byte[] cookieBytes = HttpServerUtility.UrlTokenDecode(encryptedToken);
+ byte[] clearBytes = MachineKeyUtil.Unprotect(cookieBytes, TokenCookieKey, "Token:" + token);
+ return Encoding.UTF8.GetString(clearBytes);
+ }
}
} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs
new file mode 100644
index 0000000..398ee85
--- /dev/null
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/CookieOAuthTokenManager.cs
@@ -0,0 +1,79 @@
+//-----------------------------------------------------------------------
+// <copyright file="CookieOAuthTokenManager.cs" company="Microsoft">
+// Copyright (c) Microsoft. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.AspNet.Clients {
+ using System.Web;
+ using System.Web.Security;
+
+ /// <summary>
+ /// Stores OAuth tokens in the current request's cookie.
+ /// </summary>
+ /// <remarks>
+ /// This class is different from the <see cref="AuthenticationOnlyCookieOAuthTokenManager"/> in that
+ /// it also stores the access token after the authentication has succeeded.
+ /// </remarks>
+ public class CookieOAuthTokenManager : AuthenticationOnlyCookieOAuthTokenManager {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CookieOAuthTokenManager"/> class.
+ /// </summary>
+ public CookieOAuthTokenManager() {
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CookieOAuthTokenManager"/> class.
+ /// </summary>
+ /// <param name="context">The current request context.</param>
+ public CookieOAuthTokenManager(HttpContextBase context)
+ : base(context) {
+ }
+
+ /// <summary>
+ /// Gets the token secret from the specified token.
+ /// </summary>
+ /// <param name="token">The token.</param>
+ /// <returns>
+ /// The token's secret
+ /// </returns>
+ public override string GetTokenSecret(string token) {
+ string secret = base.GetTokenSecret(token);
+ if (secret != null) {
+ return secret;
+ }
+
+ // The base class checks for cookies in the Request object.
+ // Here we check in the Response object as well because we
+ // may have set it earlier in the request life cycle.
+ HttpCookie cookie = this.Context.Response.Cookies[TokenCookieKey];
+ if (cookie == null || string.IsNullOrEmpty(cookie.Values[token])) {
+ return null;
+ }
+
+ secret = DecodeAndUnprotectToken(token, cookie.Values[token]);
+ return secret;
+ }
+
+ /// <summary>
+ /// Replaces the request token with access token.
+ /// </summary>
+ /// <param name="requestToken">The request token.</param>
+ /// <param name="accessToken">The access token.</param>
+ /// <param name="accessTokenSecret">The access token secret.</param>
+ public override void ReplaceRequestTokenWithAccessToken(string requestToken, string accessToken, string accessTokenSecret) {
+ var cookie = new HttpCookie(TokenCookieKey) {
+ HttpOnly = true
+ };
+
+ if (FormsAuthentication.RequireSSL) {
+ cookie.Secure = true;
+ }
+
+ var encryptedToken = ProtectAndEncodeToken(accessToken, accessTokenSecret);
+ cookie.Values[accessToken] = encryptedToken;
+
+ this.Context.Response.Cookies.Set(cookie);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs
index 7eda8e4..9af6804 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/DotNetOpenAuthWebConsumer.cs
@@ -77,7 +77,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// The callback.
/// </param>
public void RequestAuthentication(Uri callback) {
- var redirectParameters = new Dictionary<string, string> { { "force_login", "false" } };
+ var redirectParameters = new Dictionary<string, string>();
UserAuthorizationRequest request = this.webConsumer.PrepareRequestUserAuthorization(
callback, null, redirectParameters);
this.webConsumer.Channel.PrepareResponse(request).Send();
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs
index 26bc88d..3c157f3 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth/LinkedInClient.cs
@@ -60,7 +60,7 @@ namespace DotNetOpenAuth.AspNet.Clients {
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
Justification = "We can't dispose the object because we still need it through the app lifetime.")]
public LinkedInClient(string consumerKey, string consumerSecret)
- : this(consumerKey, consumerSecret, new AuthenticationOnlyCookieOAuthTokenManager()) { }
+ : this(consumerKey, consumerSecret, new CookieOAuthTokenManager()) { }
/// <summary>
/// Initializes a new instance of the <see cref="LinkedInClient"/> class.
diff --git a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/MicrosoftClient.cs b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/MicrosoftClient.cs
index 5ac5591..faea868 100644
--- a/src/DotNetOpenAuth.AspNet/Clients/OAuth2/MicrosoftClient.cs
+++ b/src/DotNetOpenAuth.AspNet/Clients/OAuth2/MicrosoftClient.cs
@@ -20,12 +20,12 @@ namespace DotNetOpenAuth.AspNet.Clients {
/// <summary>
/// The authorization endpoint.
/// </summary>
- private const string AuthorizationEndpoint = "https://oauth.live.com/authorize";
+ private const string AuthorizationEndpoint = "https://login.live.com/oauth20_authorize.srf";
/// <summary>
/// The token endpoint.
/// </summary>
- private const string TokenEndpoint = "https://oauth.live.com/token";
+ private const string TokenEndpoint = "https://login.live.com/oauth20_token.srf";
/// <summary>
/// The _app id.
diff --git a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
index 2f03ec7..405ac3c 100644
--- a/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
+++ b/src/DotNetOpenAuth.AspNet/DotNetOpenAuth.AspNet.csproj
@@ -28,7 +28,7 @@
<Import Project="$(ProjectRoot)tools\DotNetOpenAuth.props" />
<Import Project="$(ProjectRoot)tools\DotNetOpenAuth.Product.props" />
<PropertyGroup>
- <RootNamespace>DotNetOpenAuth.AspNet</RootNamespace>
+ <RootNamespace>DotNetOpenAuth.AspNet</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@@ -48,6 +48,7 @@
<Compile Include="Clients\OAuth\AuthenticationOnlyCookieOAuthTokenManager.cs">
<SubType>Code</SubType>
</Compile>
+ <Compile Include="Clients\OAuth\CookieOAuthTokenManager.cs" />
<Compile Include="Clients\OAuth\IOAuthTokenManager.cs" />
<Compile Include="Clients\OAuth\SimpleConsumerTokenManager.cs" />
<Compile Include="IAuthenticationClient.cs" />
diff --git a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs
index 377e6d8..e7ac254 100644
--- a/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/DataBagFormatterBase.cs
@@ -215,8 +215,8 @@ namespace DotNetOpenAuth.Messaging {
if (this.signed) {
using (var dataStream = new MemoryStream(data)) {
var dataReader = new BinaryReader(dataStream);
- signature = dataReader.ReadBuffer();
- data = dataReader.ReadBuffer();
+ signature = dataReader.ReadBuffer(1024);
+ data = dataReader.ReadBuffer(8 * 1024);
}
// Verify that the verification code was issued by message authorization server.
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs
index 2fe273f..4f89589 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.239
+// Runtime Version:4.0.30319.18010
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -106,6 +106,15 @@ namespace DotNetOpenAuth.Messaging {
}
/// <summary>
+ /// Looks up a localized string similar to Decoding failed due to data corruption..
+ /// </summary>
+ internal static string DataCorruptionDetected {
+ get {
+ return ResourceManager.GetString("DataCorruptionDetected", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to An instance of type {0} was expected, but received unexpected derived type {1}..
/// </summary>
internal static string DerivedTypeNotExpected {
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx
index fbdb63d..15ca046 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingStrings.resx
@@ -112,10 +112,10 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentPropertyMissing" xml:space="preserve">
<value>Argument's {0}.{1} property is required but is empty or null.</value>
@@ -333,4 +333,7 @@
<data name="UnexpectedBufferLength" xml:space="preserve">
<value>Unexpected buffer length.</value>
</data>
+ <data name="DataCorruptionDetected" xml:space="preserve">
+ <value>Decoding failed due to data corruption.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
index d6df26c..2e72c97 100644
--- a/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
+++ b/src/DotNetOpenAuth.Core/Messaging/MessagingUtilities.cs
@@ -171,9 +171,10 @@ namespace DotNetOpenAuth.Messaging {
/// <param name="outgoingResponse">The response to send to the user agent.</param>
/// <returns>The <see cref="HttpResponseMessage"/> instance to be returned by the Web API method.</returns>
public static HttpResponseMessage AsHttpResponseMessage(this OutgoingWebResponse outgoingResponse) {
- HttpResponseMessage response = new HttpResponseMessage(outgoingResponse.Status) {
- Content = new StreamContent(outgoingResponse.ResponseStream)
- };
+ HttpResponseMessage response = new HttpResponseMessage(outgoingResponse.Status);
+ if (outgoingResponse.ResponseStream != null) {
+ response.Content = new StreamContent(outgoingResponse.ResponseStream);
+ }
var responseHeaders = outgoingResponse.Headers;
foreach (var header in responseHeaders.AllKeys) {
@@ -876,7 +877,7 @@ namespace DotNetOpenAuth.Messaging {
using (var encryptedStream = new MemoryStream(buffer)) {
var encryptedStreamReader = new BinaryReader(encryptedStream);
- byte[] encryptedPrequel = encryptedStreamReader.ReadBytes(encryptedStreamReader.ReadInt32());
+ byte[] encryptedPrequel = encryptedStreamReader.ReadBuffer(4096);
byte[] prequel = crypto.Decrypt(encryptedPrequel, false);
using (var symmetricCrypto = new RijndaelManaged()) {
@@ -1068,7 +1069,7 @@ namespace DotNetOpenAuth.Messaging {
missingPaddingCharacters = 0;
break;
default:
- throw ErrorUtilities.ThrowInternal("No more than two padding characters should be present for base64.");
+ throw new ProtocolException(MessagingStrings.DataCorruptionDetected, new ArgumentException("No more than two padding characters should be present for base64."));
}
var builder = new StringBuilder(base64WebSafe, base64WebSafe.Length + missingPaddingCharacters);
builder.Replace('-', '+').Replace('_', '/');
@@ -1746,10 +1747,17 @@ namespace DotNetOpenAuth.Messaging {
/// Reads a buffer that is prefixed with its own length.
/// </summary>
/// <param name="reader">The binary reader positioned at the buffer length.</param>
+ /// <param name="maxBufferSize">
+ /// The maximum size of the buffer that should be permitted.
+ /// Although the stream will indicate the size of the buffer, this mitigates data corruption
+ /// or DoS attacks causing the web server to allocate too much memory for a small data packet.
+ /// </param>
/// <returns>The read buffer.</returns>
- internal static byte[] ReadBuffer(this BinaryReader reader) {
+ internal static byte[] ReadBuffer(this BinaryReader reader, int maxBufferSize) {
Requires.NotNull(reader, "reader");
+ Requires.InRange(maxBufferSize > 0 && maxBufferSize < 1024 * 1024, "maxBufferSize");
int length = reader.ReadInt32();
+ ErrorUtilities.VerifyProtocol(length <= maxBufferSize, MessagingStrings.DataCorruptionDetected);
byte[] buffer = new byte[length];
ErrorUtilities.VerifyProtocol(reader.Read(buffer, 0, length) == length, MessagingStrings.UnexpectedBufferLength);
return buffer;
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.Designer.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.Designer.cs
index 4b4f830..8941a94 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.Designer.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.17614
+// Runtime Version:4.0.30319.18010
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -70,6 +70,15 @@ namespace DotNetOpenAuth.OAuth2 {
}
/// <summary>
+ /// Looks up a localized string similar to The access token&apos;s private signing key must be set..
+ /// </summary>
+ internal static string AccessTokenSigningKeyMissing {
+ get {
+ return ResourceManager.GetString("AccessTokenSigningKeyMissing", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The callback URL ({0}) is not allowed for this client..
/// </summary>
internal static string ClientCallbackDisallowed {
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.resx b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.resx
index 29d841a..8aaa567 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.resx
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthServerStrings.resx
@@ -112,14 +112,17 @@
<value>2.0</value>
</resheader>
<resheader name="reader">
- <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
- <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AccessScopeExceedsGrantScope" xml:space="preserve">
<value>The requested access scope exceeds the grant scope.</value>
</data>
+ <data name="AccessTokenSigningKeyMissing" xml:space="preserve">
+ <value>The access token's private signing key must be set.</value>
+ </data>
<data name="ClientCallbackDisallowed" xml:space="preserve">
<value>The callback URL ({0}) is not allowed for this client.</value>
</data>
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs
index 7d829c5..050a4ab 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs
@@ -10,6 +10,9 @@ namespace DotNetOpenAuth.OAuth2 {
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.Linq;
+#if CLR4
+ using System.Net.Http;
+#endif
using System.Security.Cryptography;
using System.Text;
using System.Web;
@@ -129,6 +132,17 @@ namespace DotNetOpenAuth.OAuth2 {
this.Channel.Respond(response);
}
+#if CLR4
+ /// <summary>
+ /// Handles an incoming request to the authorization server's token endpoint.
+ /// </summary>
+ /// <param name="request">The HTTP request.</param>
+ /// <returns>The HTTP response to send to the client.</returns>
+ public OutgoingWebResponse HandleTokenRequest(HttpRequestMessage request) {
+ return this.HandleTokenRequest(new HttpRequestInfo(request));
+ }
+#endif
+
/// <summary>
/// Handles an incoming request to the authorization server's token endpoint.
/// </summary>
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServerAccessToken.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServerAccessToken.cs
index c577a0a..a127166 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServerAccessToken.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServerAccessToken.cs
@@ -45,6 +45,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
/// <returns>A non-empty string.</returns>
protected internal override string Serialize() {
+ ErrorUtilities.VerifyHost(this.AccessTokenSigningKey != null, AuthServerStrings.AccessTokenSigningKeyMissing);
var formatter = CreateFormatter(this.AccessTokenSigningKey, this.ResourceServerEncryptionKey);
return formatter.Serialize(this);
}
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs
index 655d38f..6f0bbc4 100644
--- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/ClientCredentialHttpBasicReader.cs
@@ -7,6 +7,7 @@
namespace DotNetOpenAuth.OAuth2.ChannelElements {
using System;
using System.Collections.Generic;
+ using System.Globalization;
using System.Linq;
using System.Text;
using System.Web;
@@ -21,10 +22,15 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
/// Gets this module's contribution to an HTTP 401 WWW-Authenticate header so the client knows what kind of authentication this module supports.
/// </summary>
public override string AuthenticateHeader {
- get { return "Basic"; }
+ get { return string.Format(CultureInfo.InvariantCulture, "Basic realm=\"{0}\"", this.Realm); }
}
/// <summary>
+ /// Gets or sets the realm that is included in an HTTP WWW-Authenticate header included in a 401 Unauthorized response.
+ /// </summary>
+ public string Realm { get; set; }
+
+ /// <summary>
/// Attempts to extract client identification/authentication information from a message.
/// </summary>
/// <param name="authorizationServerHost">The authorization server host.</param>
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
index 822ce6d..d4ea171 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
@@ -126,7 +126,7 @@ namespace DotNetOpenAuth.OAuth2 {
Requires.NotNull(requestHeaders, "requestHeaders");
Requires.NotNull(authorization, "authorization");
Requires.True(!string.IsNullOrEmpty(authorization.AccessToken), "authorization");
- ErrorUtilities.VerifyProtocol(!authorization.AccessTokenExpirationUtc.HasValue || authorization.AccessTokenExpirationUtc < DateTime.UtcNow || authorization.RefreshToken != null, ClientStrings.AuthorizationExpired);
+ ErrorUtilities.VerifyProtocol(!authorization.AccessTokenExpirationUtc.HasValue || authorization.AccessTokenExpirationUtc >= DateTime.UtcNow || authorization.RefreshToken != null, ClientStrings.AuthorizationExpired);
if (authorization.AccessTokenExpirationUtc.HasValue && authorization.AccessTokenExpirationUtc.Value < DateTime.UtcNow) {
ErrorUtilities.VerifyProtocol(authorization.RefreshToken != null, ClientStrings.AccessTokenRefreshFailed);
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
index cc4e45f..0677f5a 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientCredentialApplicator.cs
@@ -135,7 +135,9 @@ namespace DotNetOpenAuth.OAuth2 {
clientIdentifier);
}
- request.Credentials = this.credential ?? new NetworkCredential(clientIdentifier, this.clientSecret);
+ // HttpWebRequest ignores the Credentials property until the remote server returns a 401 Unauthorized.
+ // So we also set the HTTP Authorization request header directly.
+ OAuthUtilities.ApplyHttpBasicAuth(request.Headers, clientIdentifier, this.clientSecret);
}
}
}
diff --git a/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs b/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs
index a03bdab..62436ec 100644
--- a/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs
+++ b/src/DotNetOpenAuth.OAuth2.ResourceServer/OAuth2/StandardAccessTokenAnalyzer.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.OAuth2 {
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
+ using System.IO;
using System.Security.Cryptography;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.ChannelElements;
@@ -23,8 +24,7 @@ namespace DotNetOpenAuth.OAuth2 {
/// <param name="resourceServerPrivateEncryptionKey">The crypto service provider with the resource server private encryption key.</param>
public StandardAccessTokenAnalyzer(RSACryptoServiceProvider authorizationServerPublicSigningKey, RSACryptoServiceProvider resourceServerPrivateEncryptionKey) {
Requires.NotNull(authorizationServerPublicSigningKey, "authorizationServerPublicSigningKey");
- Requires.NotNull(resourceServerPrivateEncryptionKey, "resourceServerPrivateEncryptionKey");
- Requires.True(!resourceServerPrivateEncryptionKey.PublicOnly, "resourceServerPrivateEncryptionKey");
+ Requires.True(resourceServerPrivateEncryptionKey == null || !resourceServerPrivateEncryptionKey.PublicOnly, "resourceServerPrivateEncryptionKey");
this.AuthorizationServerPublicSigningKey = authorizationServerPublicSigningKey;
this.ResourceServerPrivateEncryptionKey = resourceServerPrivateEncryptionKey;
}
@@ -49,9 +49,15 @@ namespace DotNetOpenAuth.OAuth2 {
/// <returns>The deserialized, validated token.</returns>
/// <exception cref="ProtocolException">Thrown if the access token is expired, invalid, or from an untrusted authorization server.</exception>
public virtual AccessToken DeserializeAccessToken(IDirectedProtocolMessage message, string accessToken) {
+ ErrorUtilities.VerifyProtocol(!string.IsNullOrEmpty(accessToken), ResourceServerStrings.MissingAccessToken);
var accessTokenFormatter = AccessToken.CreateFormatter(this.AuthorizationServerPublicSigningKey, this.ResourceServerPrivateEncryptionKey);
var token = new AccessToken();
- accessTokenFormatter.Deserialize(token, accessToken, message, Protocol.access_token);
+ try {
+ accessTokenFormatter.Deserialize(token, accessToken, message, Protocol.access_token);
+ } catch (IOException ex) {
+ throw new ProtocolException(ResourceServerStrings.InvalidAccessToken, ex);
+ }
+
return token;
}
}
diff --git a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AssociationDataBag.cs b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AssociationDataBag.cs
index ee48670..f619b76 100644
--- a/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AssociationDataBag.cs
+++ b/src/DotNetOpenAuth.OpenId.Provider/OpenId/Provider/AssociationDataBag.cs
@@ -72,7 +72,7 @@ namespace DotNetOpenAuth.OpenId.Provider {
public void Deserialize(Stream stream) {
var reader = new BinaryReader(stream);
this.IsPrivateAssociation = reader.ReadBoolean();
- this.Secret = reader.ReadBuffer();
+ this.Secret = reader.ReadBuffer(256);
this.ExpiresUtc = TimestampEncoder.Epoch + TimeSpan.FromSeconds(reader.ReadInt32());
}
diff --git a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/SelectorButton.cs b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/SelectorButton.cs
index b4d0aa0..670189c 100644
--- a/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/SelectorButton.cs
+++ b/src/DotNetOpenAuth.OpenId.RelyingParty.UI/OpenId/RelyingParty/SelectorButton.cs
@@ -13,6 +13,7 @@ namespace DotNetOpenAuth.OpenId.RelyingParty {
/// A button that would appear in the <see cref="OpenIdSelector"/> control via its <see cref="OpenIdSelector.Buttons"/> collection.
/// </summary>
[ContractClass(typeof(SelectorButtonContract))]
+ [Serializable]
public abstract class SelectorButton {
/// <summary>
/// Initializes a new instance of the <see cref="SelectorButton"/> class.
diff --git a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs
index fa7768b..912a322 100644
--- a/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs
+++ b/src/DotNetOpenAuth.OpenId/OpenId/ChannelElements/ReturnToSignatureBindingElement.cs
@@ -195,6 +195,11 @@ namespace DotNetOpenAuth.OpenId.ChannelElements {
try {
if (cryptoKey == null) {
cryptoKey = this.cryptoKeyStore.GetKey(SecretUri.AbsoluteUri, returnToParameters[ReturnToSignatureHandleParameterName]);
+ ErrorUtilities.VerifyProtocol(
+ cryptoKey != null,
+ MessagingStrings.MissingDecryptionKeyForHandle,
+ SecretUri.AbsoluteUri,
+ returnToParameters[ReturnToSignatureHandleParameterName]);
}
using (var signer = HmacAlgorithms.Create(HmacAlgorithms.HmacSha256, cryptoKey.Key)) {
diff --git a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
index b58aa17..189a569 100644
--- a/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
+++ b/src/DotNetOpenAuth.Test/DotNetOpenAuth.Test.csproj
@@ -249,6 +249,7 @@
<Compile Include="Mocks\TestMessageFactory.cs" />
<Compile Include="OAuth2\AuthorizationServerTests.cs" />
<Compile Include="OAuth2\MessageFactoryTests.cs" />
+ <Compile Include="OAuth2\ResourceServerTests.cs" />
<Compile Include="OAuth2\UserAgentClientAuthorizeTests.cs" />
<Compile Include="OAuth2\OAuth2Coordinator.cs" />
<Compile Include="OAuth2\OAuth2TestBase.cs" />
diff --git a/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs b/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs
index 0610018..cf0f9ca 100644
--- a/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs
+++ b/src/DotNetOpenAuth.Test/Messaging/MessagingUtilitiesTests.cs
@@ -91,6 +91,17 @@ namespace DotNetOpenAuth.Test.Messaging {
}
[Test]
+ public void AsHttpResponseMessageNoContent() {
+ var outgoingResponse = new OutgoingWebResponse();
+ outgoingResponse.Headers.Add("X-SOME-HEADER", "value");
+
+ var httpResponseMessage = outgoingResponse.AsHttpResponseMessage();
+ Assert.That(httpResponseMessage, Is.Not.Null);
+ Assert.That(httpResponseMessage.Headers.GetValues("X-SOME-HEADER").ToList(), Is.EqualTo(new[] { "value" }));
+ Assert.That(httpResponseMessage.Content, Is.Null);
+ }
+
+ [Test]
public void ToDictionary() {
NameValueCollection nvc = new NameValueCollection();
nvc["a"] = "b";
diff --git a/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs b/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs
index b8b930c..395b18c 100644
--- a/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs
+++ b/src/DotNetOpenAuth.Test/OAuth2/OAuth2TestBase.cs
@@ -8,6 +8,7 @@ namespace DotNetOpenAuth.Test.OAuth2 {
using System;
using System.Collections.Generic;
using System.Linq;
+ using System.Security.Cryptography;
using System.Text;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.Messaging.Bindings;
@@ -29,6 +30,8 @@ namespace DotNetOpenAuth.Test.OAuth2 {
protected static readonly Uri ClientCallback = new Uri("http://client/callback");
+ protected static readonly RSACryptoServiceProvider AsymmetricKey = new RSACryptoServiceProvider(512);
+
protected static readonly AuthorizationServerDescription AuthorizationServerDescription = new AuthorizationServerDescription {
AuthorizationEndpoint = new Uri("https://authserver/authorize"),
TokenEndpoint = new Uri("https://authserver/token"),
@@ -56,7 +59,7 @@ namespace DotNetOpenAuth.Test.OAuth2 {
authHostMock
.Setup(m => m.CheckAuthorizeResourceOwnerCredentialGrant(ResourceOwnerUsername, ResourceOwnerPassword, It.IsAny<IAccessTokenRequest>()))
.Returns<string, string, IAccessTokenRequest>((p1, p2, p3) => new AutomatedUserAuthorizationCheckResponse(p3, true, ResourceOwnerUsername));
- authHostMock.Setup(m => m.CreateAccessToken(It.IsAny<IAccessTokenRequest>())).Returns(new AccessTokenResult(new AuthorizationServerAccessToken()));
+ authHostMock.Setup(m => m.CreateAccessToken(It.IsAny<IAccessTokenRequest>())).Returns(new AccessTokenResult(new AuthorizationServerAccessToken() { AccessTokenSigningKey = AsymmetricKey }));
return authHostMock;
}
}
diff --git a/src/DotNetOpenAuth.Test/OAuth2/ResourceServerTests.cs b/src/DotNetOpenAuth.Test/OAuth2/ResourceServerTests.cs
new file mode 100644
index 0000000..80a8392
--- /dev/null
+++ b/src/DotNetOpenAuth.Test/OAuth2/ResourceServerTests.cs
@@ -0,0 +1,110 @@
+//-----------------------------------------------------------------------
+// <copyright file="ResourceServerTests.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.Test.OAuth2 {
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.Specialized;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+ using DotNetOpenAuth.OAuth2.Messages;
+ using Moq;
+ using NUnit.Framework;
+
+ [TestFixture]
+ public class ResourceServerTests : OAuth2TestBase {
+ [Test]
+ public void GetAccessTokenWithMissingAccessToken() {
+ var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(AsymmetricKey, null));
+
+ var requestHeaders = new NameValueCollection {
+ { "Authorization", "Bearer " },
+ };
+ var request = new HttpRequestInfo("GET", new Uri("http://localhost/resource"), headers: requestHeaders);
+ Assert.That(() => resourceServer.GetAccessToken(request), Throws.InstanceOf<ProtocolException>());
+ }
+
+ [Test]
+ public void GetPrincipalWithMissingAccessToken() {
+ var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(AsymmetricKey, null));
+
+ var requestHeaders = new NameValueCollection {
+ { "Authorization", "Bearer " },
+ };
+ var request = new HttpRequestInfo("GET", new Uri("http://localhost/resource"), headers: requestHeaders);
+ Assert.That(() => resourceServer.GetPrincipal(request), Throws.InstanceOf<ProtocolException>());
+ }
+
+ [Test]
+ public void GetAccessTokenWithTotallyFakeToken() {
+ var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(AsymmetricKey, null));
+
+ var requestHeaders = new NameValueCollection {
+ { "Authorization", "Bearer foobar" },
+ };
+ var request = new HttpRequestInfo("GET", new Uri("http://localhost/resource"), headers: requestHeaders);
+ Assert.That(() => resourceServer.GetAccessToken(request), Throws.InstanceOf<ProtocolException>());
+ }
+
+ [Test]
+ public void GetAccessTokenWithCorruptedToken() {
+ var accessToken = this.ObtainValidAccessToken();
+
+ var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(AsymmetricKey, null));
+
+ var requestHeaders = new NameValueCollection {
+ { "Authorization", "Bearer " + accessToken.Substring(0, accessToken.Length - 1) + "zzz" },
+ };
+ var request = new HttpRequestInfo("GET", new Uri("http://localhost/resource"), headers: requestHeaders);
+ Assert.That(() => resourceServer.GetAccessToken(request), Throws.InstanceOf<ProtocolException>());
+ }
+
+ [Test]
+ public void GetAccessTokenWithValidToken() {
+ var accessToken = this.ObtainValidAccessToken();
+
+ var resourceServer = new ResourceServer(new StandardAccessTokenAnalyzer(AsymmetricKey, null));
+
+ var requestHeaders = new NameValueCollection {
+ { "Authorization", "Bearer " + accessToken },
+ };
+ var request = new HttpRequestInfo("GET", new Uri("http://localhost/resource"), headers: requestHeaders);
+ var resourceServerDecodedToken = resourceServer.GetAccessToken(request);
+ Assert.That(resourceServerDecodedToken, Is.Not.Null);
+ }
+
+ private string ObtainValidAccessToken() {
+ string accessToken = null;
+ var authServer = CreateAuthorizationServerMock();
+ authServer.Setup(
+ a => a.IsAuthorizationValid(It.Is<IAuthorizationDescription>(d => d.User == null && d.ClientIdentifier == ClientId && MessagingUtilities.AreEquivalent(d.Scope, TestScopes))))
+ .Returns(true);
+ authServer.Setup(
+ a => a.CheckAuthorizeClientCredentialsGrant(It.Is<IAccessTokenRequest>(d => d.ClientIdentifier == ClientId && MessagingUtilities.AreEquivalent(d.Scope, TestScopes))))
+ .Returns<IAccessTokenRequest>(req => new AutomatedAuthorizationCheckResponse(req, true));
+ var coordinator = new OAuth2Coordinator<WebServerClient>(
+ AuthorizationServerDescription,
+ authServer.Object,
+ new WebServerClient(AuthorizationServerDescription),
+ client => {
+ var authState = client.GetClientAccessToken(TestScopes);
+ Assert.That(authState.AccessToken, Is.Not.Null.And.Not.Empty);
+ Assert.That(authState.RefreshToken, Is.Null);
+ accessToken = authState.AccessToken;
+ },
+ server => {
+ server.HandleTokenRequest().Respond();
+ });
+ coordinator.Run();
+
+ return accessToken;
+ }
+ }
+}