summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.Client
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.Client')
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/Configuration/OAuth2ClientSection.cs25
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs37
2 files changed, 51 insertions, 11 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.Client/Configuration/OAuth2ClientSection.cs b/src/DotNetOpenAuth.OAuth2.Client/Configuration/OAuth2ClientSection.cs
index 1ee5aa5..3bb6ffc 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/Configuration/OAuth2ClientSection.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/Configuration/OAuth2ClientSection.cs
@@ -5,6 +5,7 @@
//-----------------------------------------------------------------------
namespace DotNetOpenAuth.Configuration {
+ using System;
using System.Configuration;
using System.Diagnostics.Contracts;
@@ -18,6 +19,11 @@ namespace DotNetOpenAuth.Configuration {
private const string SectionName = OAuth2SectionGroup.SectionName + "/client";
/// <summary>
+ /// The name of the @maxAuthorizationTime attribute.
+ /// </summary>
+ private const string MaxAuthorizationTimePropertyName = "maxAuthorizationTime";
+
+ /// <summary>
/// Initializes a new instance of the <see cref="OAuth2ClientSection"/> class.
/// </summary>
internal OAuth2ClientSection() {
@@ -32,5 +38,24 @@ namespace DotNetOpenAuth.Configuration {
return (OAuth2ClientSection)ConfigurationManager.GetSection(SectionName) ?? new OAuth2ClientSection();
}
}
+
+ /// <summary>
+ /// Gets or sets the maximum time a user can take to complete authentication.
+ /// </summary>
+ [ConfigurationProperty(MaxAuthorizationTimePropertyName, DefaultValue = "0:15")] // 15 minutes
+ [PositiveTimeSpanValidator]
+ internal TimeSpan MaxAuthorizationTime {
+ get {
+ Contract.Ensures(Contract.Result<TimeSpan>() > TimeSpan.Zero);
+ TimeSpan result = (TimeSpan)this[MaxAuthorizationTimePropertyName];
+ Contract.Assume(result > TimeSpan.Zero); // our PositiveTimeSpanValidator should take care of this
+ return result;
+ }
+
+ set {
+ Requires.InRange(value > TimeSpan.Zero, "value");
+ this[MaxAuthorizationTimePropertyName] = value;
+ }
+ }
}
}
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
index 939d1df..4fc8687 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/WebServerClient.cs
@@ -8,10 +8,14 @@ namespace DotNetOpenAuth.OAuth2 {
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
+ using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
+ using System.Web.Security;
+
+ using DotNetOpenAuth.Configuration;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth2.Messages;
@@ -20,6 +24,11 @@ namespace DotNetOpenAuth.OAuth2 {
/// </summary>
public class WebServerClient : ClientBase {
/// <summary>
+ /// The cookie name for XSRF mitigation during authorization code grant flows.
+ /// </summary>
+ private const string XsrfCookieName = "DotNetOpenAuth.WebServerClient.XSRF-Session";
+
+ /// <summary>
/// Initializes a new instance of the <see cref="WebServerClient"/> class.
/// </summary>
/// <param name="authorizationServer">The authorization server.</param>
@@ -100,16 +109,25 @@ namespace DotNetOpenAuth.OAuth2 {
// Mitigate XSRF attacks by including a state value that would be unpredictable between users, but
// verifiable for the same user/session.
// If the host is implementing the authorization tracker though, they're handling this protection themselves.
+ HttpCookie cookie = null;
if (this.AuthorizationTracker == null) {
var context = this.Channel.GetHttpContext();
- if (context.Session != null) {
- request.ClientState = context.Session.SessionID;
- } else {
- Logger.OAuth.WarnFormat("No request context discovered, so no client state parameter could be set to mitigate XSRF attacks.");
- }
+
+ string xsrfKey = (new Random()).Next().ToString(CultureInfo.InvariantCulture);
+ cookie = new HttpCookie(XsrfCookieName, xsrfKey) {
+ HttpOnly = true,
+ Secure = FormsAuthentication.RequireSSL,
+ Expires = DateTime.Now.Add(OAuth2ClientSection.Configuration.MaxAuthorizationTime),
+ };
+ request.ClientState = xsrfKey;
+ }
+
+ var response = this.Channel.PrepareResponse(request);
+ if (cookie != null) {
+ response.Cookies.Add(cookie);
}
- return this.Channel.PrepareResponse(request);
+ return response;
}
/// <summary>
@@ -134,12 +152,9 @@ namespace DotNetOpenAuth.OAuth2 {
ErrorUtilities.VerifyProtocol(authorizationState != null, ClientStrings.AuthorizationResponseUnexpectedMismatch);
} else {
var context = this.Channel.GetHttpContext();
- if (context.Session != null) {
- ErrorUtilities.VerifyProtocol(string.Equals(response.ClientState, context.Session.SessionID, StringComparison.Ordinal), ClientStrings.AuthorizationResponseUnexpectedMismatch);
- } else {
- Logger.OAuth.WarnFormat("No request context discovered, so no client state parameter could be checked to mitigate XSRF attacks.");
- }
+ HttpCookie cookie = request.Cookies[XsrfCookieName];
+ ErrorUtilities.VerifyProtocol(cookie != null && string.Equals(response.ClientState, cookie.Value, StringComparison.Ordinal), ClientStrings.AuthorizationResponseUnexpectedMismatch);
authorizationState = new AuthorizationState { Callback = callback };
}
var success = response as EndUserAuthorizationSuccessAuthCodeResponse;