diff options
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.AuthorizationServer')
8 files changed, 182 insertions, 37 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj index 34d59ee..73c563b 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj @@ -27,6 +27,8 @@ <DependentUpon>AuthServerStrings.resx</DependentUpon> </Compile> <Compile Include="OAuth2\AuthServerUtilities.cs" /> + <Compile Include="OAuth2\AutomatedAuthorizationCheckResponse.cs" /> + <Compile Include="OAuth2\AutomatedUserAuthorizationCheckResponse.cs" /> <Compile Include="OAuth2\ChannelElements\AggregatingClientCredentialReader.cs" /> <Compile Include="OAuth2\ChannelElements\ClientCredentialHttpBasicReader.cs" /> <Compile Include="OAuth2\ChannelElements\ClientCredentialMessagePartReader.cs" /> @@ -42,6 +44,7 @@ <Compile Include="OAuth2\IAuthorizationServerHost.cs" /> <Compile Include="OAuth2\Messages\AccessTokenAuthorizationCodeRequestAS.cs" /> <Compile Include="OAuth2\Messages\AccessTokenRefreshRequestAS.cs" /> + <Compile Include="OAuth2\Messages\AccessTokenResult.cs" /> <Compile Include="OAuth2\Messages\EndUserAuthorizationSuccessAuthCodeResponseAS.cs" /> <Compile Include="OAuth2\Messages\IAuthorizationCodeCarryingRequest.cs" /> <Compile Include="OAuth2\Messages\IRefreshTokenCarryingRequest.cs" /> diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs index 1e404e7..050a4ab 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs @@ -265,6 +265,25 @@ namespace DotNetOpenAuth.OAuth2 { } /// <summary> + /// Decodes a refresh token into its authorization details. + /// </summary> + /// <param name="refreshToken">The encoded refresh token as it would appear to the client.</param> + /// <returns>A description of the authorization represented by the refresh token.</returns> + /// <exception cref="ProtocolException">Thrown if the refresh token is not valid due to expiration, corruption or not being authentic.</exception> + /// <remarks> + /// This can be useful if the authorization server supports the client revoking its own access (on uninstall, for example). + /// Outside the scope of the OAuth 2 spec, the client may contact the authorization server host requesting that its refresh + /// token be revoked. The authorization server would need to decode the refresh token so it knows which authorization in + /// the database to delete. + /// </remarks> + public IAuthorizationDescription DecodeRefreshToken(string refreshToken) { + var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServerServices.CryptoKeyStore); + var token = new RefreshToken(); + refreshTokenFormatter.Deserialize(token, refreshToken); + return token; + } + + /// <summary> /// Gets the redirect URL to use for a particular authorization request. /// </summary> /// <param name="authorizationRequest">The authorization request.</param> diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AutomatedAuthorizationCheckResponse.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AutomatedAuthorizationCheckResponse.cs new file mode 100644 index 0000000..0179d05 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AutomatedAuthorizationCheckResponse.cs @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------- +// <copyright file="AutomatedAuthorizationCheckResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using DotNetOpenAuth.OAuth2.Messages; + + /// <summary> + /// Describes the result of an automated authorization check, such as for client credential or resource owner password grants. + /// </summary> + public class AutomatedAuthorizationCheckResponse { + /// <summary> + /// Initializes a new instance of the <see cref="AutomatedAuthorizationCheckResponse" /> class. + /// </summary> + /// <param name="accessRequest">The access token request.</param> + /// <param name="approved">A value indicating whether the authorization should be approved.</param> + public AutomatedAuthorizationCheckResponse(IAccessTokenRequest accessRequest, bool approved) { + Requires.NotNull(accessRequest, "accessRequest"); + + this.IsApproved = approved; + this.ApprovedScope = new HashSet<string>(accessRequest.Scope); + } + + /// <summary> + /// Gets a value indicating whether the authorization should be approved. + /// </summary> + public bool IsApproved { get; private set; } + + /// <summary> + /// Gets the scope to be granted. + /// </summary> + public HashSet<string> ApprovedScope { get; private set; } + } +} diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AutomatedUserAuthorizationCheckResponse.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AutomatedUserAuthorizationCheckResponse.cs new file mode 100644 index 0000000..b62807c --- /dev/null +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AutomatedUserAuthorizationCheckResponse.cs @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------- +// <copyright file="AutomatedUserAuthorizationCheckResponse.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using DotNetOpenAuth.OAuth2.Messages; + + /// <summary> + /// Describes the result of an automated authorization check for resource owner grants. + /// </summary> + public class AutomatedUserAuthorizationCheckResponse : AutomatedAuthorizationCheckResponse { + /// <summary> + /// Initializes a new instance of the <see cref="AutomatedUserAuthorizationCheckResponse" /> class. + /// </summary> + /// <param name="accessRequest">The access token request.</param> + /// <param name="approved">A value indicating whether the authorization should be approved.</param> + /// <param name="canonicalUserName"> + /// Canonical username of the authorizing user (resource owner), as the resource server would recognize it. + /// Ignored if <paramref name="approved"/> is false. + /// </param> + public AutomatedUserAuthorizationCheckResponse(IAccessTokenRequest accessRequest, bool approved, string canonicalUserName) + : base(accessRequest, approved) { + if (approved) { + Requires.NotNullOrEmpty(canonicalUserName, "canonicalUserName"); + } + + this.CanonicalUserName = canonicalUserName; + } + + /// <summary> + /// Gets the canonical username of the authorizing user (resource owner). + /// </summary> + public string CanonicalUserName { get; private set; } + } +} diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs index 27b71db..3eac5a6 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/MessageValidationBindingElement.cs @@ -120,11 +120,13 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { // Check that any resource owner password credential is correct. if (resourceOwnerPasswordCarrier != null) { try { - string canonicalUserName; - if (this.AuthorizationServer.TryAuthorizeResourceOwnerCredentialGrant(resourceOwnerPasswordCarrier.UserName, resourceOwnerPasswordCarrier.Password, resourceOwnerPasswordCarrier, out canonicalUserName)) { - ErrorUtilities.VerifyHost(!string.IsNullOrEmpty(canonicalUserName), "TryAuthorizeResourceOwnerCredentialGrant did not initialize out parameter."); + var authorizeResult = + this.AuthorizationServer.CheckAuthorizeResourceOwnerCredentialGrant( + resourceOwnerPasswordCarrier.UserName, resourceOwnerPasswordCarrier.Password, resourceOwnerPasswordCarrier); + if (authorizeResult.IsApproved) { resourceOwnerPasswordCarrier.CredentialsValidated = true; - resourceOwnerPasswordCarrier.UserName = canonicalUserName; + resourceOwnerPasswordCarrier.UserName = authorizeResult.CanonicalUserName; + resourceOwnerPasswordCarrier.Scope.ResetContents(authorizeResult.ApprovedScope); } else { Logger.OAuth.ErrorFormat( "Resource owner password credential for user \"{0}\" rejected by authorization server host.", @@ -140,12 +142,15 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { applied = true; } else if (clientCredentialOnly != null) { try { - if (!this.AuthorizationServer.TryAuthorizeClientCredentialsGrant(clientCredentialOnly)) { + var authorizeResult = this.AuthorizationServer.CheckAuthorizeClientCredentialsGrant(clientCredentialOnly); + if (!authorizeResult.IsApproved) { Logger.OAuth.ErrorFormat( "Client credentials grant access request for client \"{0}\" rejected by authorization server host.", clientCredentialOnly.ClientIdentifier); throw new TokenEndpointProtocolException(accessTokenRequest, Protocol.AccessTokenRequestErrorCodes.UnauthorizedClient); } + + clientCredentialOnly.Scope.ResetContents(authorizeResult.ApprovedScope); } catch (NotSupportedException) { throw new TokenEndpointProtocolException(accessTokenRequest, Protocol.AccessTokenRequestErrorCodes.UnsupportedGrantType); } catch (NotImplementedException) { diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs index 494a10b..5a1dbae 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/ChannelElements/TokenCodeSerializationBindingElement.cs @@ -103,7 +103,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { if (authCodeCarrier != null) { var authorizationCodeFormatter = AuthorizationCode.CreateFormatter(this.AuthorizationServer); var authorizationCode = new AuthorizationCode(); - authorizationCodeFormatter.Deserialize(authorizationCode, message, authCodeCarrier.Code, Protocol.code); + authorizationCodeFormatter.Deserialize(authorizationCode, authCodeCarrier.Code, message, Protocol.code); authCodeCarrier.AuthorizationDescription = authorizationCode; } @@ -111,7 +111,7 @@ namespace DotNetOpenAuth.OAuth2.ChannelElements { if (refreshTokenCarrier != null) { var refreshTokenFormatter = RefreshToken.CreateFormatter(this.AuthorizationServer.CryptoKeyStore); var refreshToken = new RefreshToken(); - refreshTokenFormatter.Deserialize(refreshToken, message, refreshTokenCarrier.RefreshToken, Protocol.refresh_token); + refreshTokenFormatter.Deserialize(refreshToken, refreshTokenCarrier.RefreshToken, message, Protocol.refresh_token); refreshTokenCarrier.AuthorizationDescription = refreshToken; } diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/IAuthorizationServerHost.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/IAuthorizationServerHost.cs index b75cb29..b9b5725 100644 --- a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/IAuthorizationServerHost.cs +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/IAuthorizationServerHost.cs @@ -91,17 +91,11 @@ namespace DotNetOpenAuth.OAuth2 { /// The access request the credentials came with. /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request. /// </param> - /// <param name="canonicalUserName"> - /// Receives the canonical username (normalized for the resource server) of the user, for valid credentials; - /// Or <c>null</c> if the return value is false. - /// </param> - /// <returns> - /// <c>true</c> if the given credentials are valid and the authorization granted; otherwise, <c>false</c>. - /// </returns> + /// <returns>A value that describes the result of the authorization check.</returns> /// <exception cref="NotSupportedException"> /// May be thrown if the authorization server does not support the resource owner password credential grant type. /// </exception> - bool TryAuthorizeResourceOwnerCredentialGrant(string userName, string password, IAccessTokenRequest accessRequest, out string canonicalUserName); + AutomatedUserAuthorizationCheckResponse CheckAuthorizeResourceOwnerCredentialGrant(string userName, string password, IAccessTokenRequest accessRequest); /// <summary> /// Determines whether an access token request given a client credential grant should be authorized @@ -112,17 +106,15 @@ namespace DotNetOpenAuth.OAuth2 { /// The access request the credentials came with. /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request. /// </param> - /// <returns> - /// <c>true</c> if the given credentials are valid and the authorization granted; otherwise, <c>false</c>. - /// </returns> + /// <returns>A value that describes the result of the authorization check.</returns> /// <exception cref="NotSupportedException"> /// May be thrown if the authorization server does not support the client credential grant type. /// </exception> - bool TryAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest); + AutomatedAuthorizationCheckResponse CheckAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest); } /// <summary> - /// Code Contract for the <see cref="IAuthorizationServerHost"/> interface. + /// Code Contract for the <see cref="IAuthorizationServerHost" /> interface. /// </summary> [ContractClassFor(typeof(IAuthorizationServerHost))] internal abstract class IAuthorizationServerHostContract : IAuthorizationServerHost { @@ -203,40 +195,34 @@ namespace DotNetOpenAuth.OAuth2 { /// The access request the credentials came with. /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request. /// </param> - /// <param name="canonicalUserName"> - /// Receives the canonical username (normalized for the resource server) of the user, for valid credentials; - /// Or <c>null</c> if the return value is false. - /// </param> /// <returns> - /// <c>true</c> if the given credentials are valid and the authorization granted; otherwise, <c>false</c>. + /// A value that describes the result of the authorization check. /// </returns> /// <exception cref="NotSupportedException"> /// May be thrown if the authorization server does not support the resource owner password credential grant type. /// </exception> - bool IAuthorizationServerHost.TryAuthorizeResourceOwnerCredentialGrant(string userName, string password, IAccessTokenRequest accessRequest, out string canonicalUserName) { + AutomatedUserAuthorizationCheckResponse IAuthorizationServerHost.CheckAuthorizeResourceOwnerCredentialGrant(string userName, string password, IAccessTokenRequest accessRequest) { Contract.Requires(!string.IsNullOrEmpty(userName)); Contract.Requires(password != null); Contract.Requires(accessRequest != null); - Contract.Ensures(!Contract.Result<bool>() || !string.IsNullOrEmpty(Contract.ValueAtReturn<string>(out canonicalUserName))); + Contract.Ensures(Contract.Result<AutomatedUserAuthorizationCheckResponse>() != null); throw new NotImplementedException(); } /// <summary> /// Determines whether an access token request given a client credential grant should be authorized - /// and if so records an authorization entry such that subsequent calls to <see cref="IAuthorizationServerHost.IsAuthorizationValid"/> would + /// and if so records an authorization entry such that subsequent calls to <see cref="IAuthorizationServerHost.IsAuthorizationValid" /> would /// return <c>true</c>. /// </summary> - /// <param name="accessRequest"> - /// The access request the credentials came with. - /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request. - /// </param> + /// <param name="accessRequest">The access request the credentials came with. + /// This may be useful if the authorization server wishes to apply some policy based on the client that is making the request.</param> /// <returns> - /// <c>true</c> if the given credentials are valid and the authorization granted; otherwise, <c>false</c>. + /// A value that describes the result of the authorization check. /// </returns> - /// <exception cref="NotSupportedException"> - /// May be thrown if the authorization server does not support the client credential grant type. - /// </exception> - bool IAuthorizationServerHost.TryAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest) { + /// <exception cref="NotSupportedException">May be thrown if the authorization server does not support the client credential grant type.</exception> + AutomatedAuthorizationCheckResponse IAuthorizationServerHost.CheckAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest) { + Contract.Requires(accessRequest != null); + Contract.Ensures(Contract.Result<AutomatedAuthorizationCheckResponse>() != null); throw new NotImplementedException(); } diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/Messages/AccessTokenResult.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/Messages/AccessTokenResult.cs new file mode 100644 index 0000000..4297165 --- /dev/null +++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/Messages/AccessTokenResult.cs @@ -0,0 +1,50 @@ +//----------------------------------------------------------------------- +// <copyright file="AccessTokenResult.cs" company="Andrew Arnott"> +// Copyright (c) Andrew Arnott. All rights reserved. +// </copyright> +//----------------------------------------------------------------------- + +namespace DotNetOpenAuth.OAuth2 { + using System; + using System.Collections.Generic; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + + /// <summary> + /// Describes the parameters to be fed into creating a response to an access token request. + /// </summary> + public class AccessTokenResult : IAccessTokenResult { + /// <summary> + /// Initializes a new instance of the <see cref="AccessTokenResult"/> class. + /// </summary> + /// <param name="accessToken">The access token to include in this result.</param> + public AccessTokenResult(AuthorizationServerAccessToken accessToken) { + Requires.NotNull(accessToken, "accessToken"); + this.AllowRefreshToken = true; + this.AccessToken = accessToken; + } + + /// <summary> + /// Gets or sets a value indicating whether to provide the client with a refresh token, when applicable. + /// </summary> + /// <value>The default value is <c>true</c>.</value> + /// <remarks>> + /// The refresh token will never be provided when this value is false. + /// The refresh token <em>may</em> be provided when this value is true. + /// </remarks> + public bool AllowRefreshToken { get; set; } + + /// <summary> + /// Gets the access token. + /// </summary> + public AuthorizationServerAccessToken AccessToken { get; private set; } + + /// <summary> + /// Gets the access token. + /// </summary> + AccessToken IAccessTokenResult.AccessToken { + get { return this.AccessToken; } + } + } +} |