summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs54
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AccessRequestBindingElement.cs11
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IAuthorizationDescription.cs6
-rw-r--r--src/DotNetOpenAuth.OAuth2/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs44
-rw-r--r--src/DotNetOpenAuth.Test/OAuth2/WebServerClientAuthorizeTests.cs25
5 files changed, 120 insertions, 20 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
index b8cfbe3..ed9f1d4 100644
--- a/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
+++ b/src/DotNetOpenAuth.OAuth2.Client/OAuth2/ClientBase.cs
@@ -167,27 +167,22 @@ namespace DotNetOpenAuth.OAuth2 {
Requires.NotNullOrEmpty(userName, "userName");
Requires.NotNull(password, "password");
- var authorizationState = new AuthorizationState(scopes);
-
var request = new AccessTokenResourceOwnerPasswordCredentialsRequest(this.AuthorizationServer.TokenEndpoint, this.AuthorizationServer.Version) {
- ClientIdentifier = this.ClientIdentifier,
- ClientSecret = this.ClientSecret,
UserName = userName,
Password = password,
};
- var response = this.Channel.Request(request);
- var success = response as AccessTokenSuccessResponse;
- var failure = response as AccessTokenFailedResponse;
- ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany);
- if (success != null) {
- UpdateAuthorizationWithResponse(authorizationState, success);
- } else { // failure
- Logger.OAuth.Info("Resource Owner credentials rejected by the Authorization Server.");
- authorizationState.Delete();
- }
+ return this.RequestAccessToken(request, scopes);
+ }
- return authorizationState;
+ /// <summary>
+ /// Obtains an access token for accessing client-controlled resources on the resource server.
+ /// </summary>
+ /// <param name="scopes">The desired scopes.</param>
+ /// <returns>The result of the authorization request.</returns>
+ public IAuthorizationState ObtainClientAccessToken(IEnumerable<string> scopes = null) {
+ var request = new AccessTokenClientCredentialsRequest(this.AuthorizationServer.TokenEndpoint, this.AuthorizationServer.Version);
+ return this.RequestAccessToken(request, scopes);
}
/// <summary>
@@ -287,5 +282,34 @@ namespace DotNetOpenAuth.OAuth2 {
double proportionLifetimeRemaining = 1 - (elapsedLifetime.TotalSeconds / totalLifetime.TotalSeconds);
return proportionLifetimeRemaining;
}
+
+ /// <summary>
+ /// Requests an access token using a partially .initialized request message.
+ /// </summary>
+ /// <param name="request">The request message.</param>
+ /// <param name="scopes">The scopes requested by the client.</param>
+ /// <returns>The result of the request.</returns>
+ private IAuthorizationState RequestAccessToken(ScopedAccessTokenRequest request, IEnumerable<string> scopes = null) {
+ Requires.NotNull(request, "request");
+
+ var authorizationState = new AuthorizationState(scopes);
+
+ request.ClientIdentifier = this.ClientIdentifier;
+ request.ClientSecret = this.ClientSecret;
+ request.Scope.UnionWith(authorizationState.Scope);
+
+ var response = this.Channel.Request(request);
+ var success = response as AccessTokenSuccessResponse;
+ var failure = response as AccessTokenFailedResponse;
+ ErrorUtilities.VerifyProtocol(success != null || failure != null, MessagingStrings.UnexpectedMessageReceivedOfMany);
+ if (success != null) {
+ UpdateAuthorizationWithResponse(authorizationState, success);
+ } else { // failure
+ Logger.OAuth.Info("Credentials rejected by the Authorization Server.");
+ authorizationState.Delete();
+ }
+
+ return authorizationState;
+ }
}
}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AccessRequestBindingElement.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AccessRequestBindingElement.cs
index b0cef58..67a69fd 100644
--- a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AccessRequestBindingElement.cs
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/AccessRequestBindingElement.cs
@@ -115,6 +115,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
var authCodeCarrier = message as IAuthorizationCodeCarryingRequest;
var refreshTokenCarrier = message as IRefreshTokenCarryingRequest;
var resourceOwnerPasswordCarrier = message as AccessTokenResourceOwnerPasswordCredentialsRequest;
+ var clientCredentialOnly = message as AccessTokenClientCredentialsRequest;
if (authCodeCarrier != null) {
var authorizationCodeFormatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer);
var authorizationCode = authorizationCodeFormatter.Deserialize(message, authCodeCarrier.Code);
@@ -125,10 +126,13 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
refreshTokenCarrier.AuthorizationDescription = refreshToken;
} else if (resourceOwnerPasswordCarrier != null) {
try {
- if (this.AuthorizationServer.IsResourceOwnerCredentialValid(resourceOwnerPasswordCarrier.UserName, resourceOwnerPasswordCarrier.Password)) {
+ if (this.AuthorizationServer.IsResourceOwnerCredentialValid(resourceOwnerPasswordCarrier.UserName,
+ resourceOwnerPasswordCarrier.Password)) {
resourceOwnerPasswordCarrier.CredentialsValidated = true;
} else {
- Logger.OAuth.WarnFormat("Resource owner password credential for user \"{0}\" rejected by authorization server host.", resourceOwnerPasswordCarrier.UserName);
+ Logger.OAuth.WarnFormat(
+ "Resource owner password credential for user \"{0}\" rejected by authorization server host.",
+ resourceOwnerPasswordCarrier.UserName);
// TODO: fix this to report the appropriate error code for a bad credential.
throw new ProtocolException();
@@ -140,6 +144,9 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
// TODO: fix this to return the appropriate error code for not supporting resource owner password credentials
throw new ProtocolException();
}
+ } else if (clientCredentialOnly != null) {
+ // this method will throw later if the credentials are false.
+ clientCredentialOnly.CredentialsValidated = true;
} else {
throw ErrorUtilities.ThrowInternal("Unexpected message type: " + tokenRequest.GetType());
}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IAuthorizationDescription.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IAuthorizationDescription.cs
index 150a6a9..9c4219c 100644
--- a/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IAuthorizationDescription.cs
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/ChannelElements/IAuthorizationDescription.cs
@@ -68,11 +68,13 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements {
}
/// <summary>
- /// Gets the name on the account whose data on the resource server is accessible using this authorization.
+ /// Gets the name on the account whose data on the resource server is accessible using this authorization, if applicable.
/// </summary>
+ /// <value>A username, or <c>null</c> if the authorization is to access the client's own data (not a distinct resource owner's data).</value>
string IAuthorizationDescription.User {
get {
- Contract.Ensures(!string.IsNullOrEmpty(Contract.Result<string>()));
+ // Null and non-empty are allowed, but not empty.
+ Contract.Ensures(Contract.Result<string>() != String.Empty);
throw new NotImplementedException();
}
}
diff --git a/src/DotNetOpenAuth.OAuth2/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs b/src/DotNetOpenAuth.OAuth2/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs
index 266dbce..48419eb 100644
--- a/src/DotNetOpenAuth.OAuth2/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs
+++ b/src/DotNetOpenAuth.OAuth2/OAuth2/Messages/AccessTokenClientCredentialsRequest.cs
@@ -19,7 +19,7 @@ namespace DotNetOpenAuth.OAuth2.Messages {
/// <remarks>
/// This is somewhat analogous to 2-legged OAuth.
/// </remarks>
- internal class AccessTokenClientCredentialsRequest : ScopedAccessTokenRequest {
+ internal class AccessTokenClientCredentialsRequest : ScopedAccessTokenRequest, IAuthorizationCarryingRequest, IAuthorizationDescription {
/// <summary>
/// Initializes a new instance of the <see cref="AccessTokenClientCredentialsRequest"/> class.
/// </summary>
@@ -30,6 +30,43 @@ namespace DotNetOpenAuth.OAuth2.Messages {
this.HttpMethods = HttpDeliveryMethods.PostRequest;
}
+ #region IAuthorizationCarryingRequest members
+
+ /// <summary>
+ /// Gets the authorization that the code or token describes.
+ /// </summary>
+ IAuthorizationDescription IAuthorizationCarryingRequest.AuthorizationDescription {
+ get { return this.CredentialsValidated ? this : null; }
+ }
+
+ #endregion
+
+ #region IAuthorizationDescription Members
+
+ /// <summary>
+ /// Gets the date this authorization was established or the token was issued.
+ /// </summary>
+ /// <value>A date/time expressed in UTC.</value>
+ DateTime IAuthorizationDescription.UtcIssued {
+ get { return DateTime.UtcNow; }
+ }
+
+ /// <summary>
+ /// Gets the name on the account whose data on the resource server is accessible using this authorization.
+ /// </summary>
+ string IAuthorizationDescription.User {
+ get { return null; }
+ }
+
+ /// <summary>
+ /// Gets the scope of operations the client is allowed to invoke.
+ /// </summary>
+ HashSet<string> IAuthorizationDescription.Scope {
+ get { return this.Scope; }
+ }
+
+ #endregion
+
/// <summary>
/// Gets the type of the grant.
/// </summary>
@@ -37,5 +74,10 @@ namespace DotNetOpenAuth.OAuth2.Messages {
internal override GrantType GrantType {
get { return Messages.GrantType.ClientCredentials; }
}
+
+ /// <summary>
+ /// Gets or sets a value indicating whether the resource owner's credentials have been validated at the authorization server.
+ /// </summary>
+ internal bool CredentialsValidated { get; set; }
}
}
diff --git a/src/DotNetOpenAuth.Test/OAuth2/WebServerClientAuthorizeTests.cs b/src/DotNetOpenAuth.Test/OAuth2/WebServerClientAuthorizeTests.cs
index 1615f97..a284840 100644
--- a/src/DotNetOpenAuth.Test/OAuth2/WebServerClientAuthorizeTests.cs
+++ b/src/DotNetOpenAuth.Test/OAuth2/WebServerClientAuthorizeTests.cs
@@ -10,7 +10,9 @@ namespace DotNetOpenAuth.Test.OAuth2 {
using System.Linq;
using System.Text;
using DotNetOpenAuth.OAuth2;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
using DotNetOpenAuth.OAuth2.Messages;
+ using Moq;
using NUnit.Framework;
[TestFixture]
@@ -60,5 +62,28 @@ namespace DotNetOpenAuth.Test.OAuth2 {
});
coordinator.Run();
}
+
+ [TestCase]
+ public void ClientCredentialGrant() {
+ var authServer = CreateAuthorizationServerMock();
+ authServer.Setup(
+ a => a.IsAuthorizationValid(It.Is<IAuthorizationDescription>(d => d.User == null && d.ClientIdentifier == ClientId)))
+ .Returns(true);
+ var coordinator = new OAuth2Coordinator<WebServerClient>(
+ AuthorizationServerDescription,
+ authServer.Object,
+ new WebServerClient(AuthorizationServerDescription),
+ client => {
+ var authState = client.ObtainClientAccessToken();
+ Assert.IsNotNullOrEmpty(authState.AccessToken);
+ Assert.IsNull(authState.RefreshToken);
+ },
+ server => {
+ var request = server.ReadAccessTokenRequest();
+ var response = server.PrepareAccessTokenResponse(request);
+ server.Channel.Respond(response);
+ });
+ coordinator.Run();
+ }
}
}