Browse Source

Add a new OpenIddictApplicationManager.UpdateAsync overload accepting a client secret and rework the validation logic

pull/378/head
Kévin Chalet 9 years ago
parent
commit
347b75cb4d
  1. 96
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  2. 2
      src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs
  3. 8
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs

96
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -47,34 +47,16 @@ namespace OpenIddict.Core
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the unique identifier associated with the application.
/// </returns>
public virtual async Task<TApplication> CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
public virtual Task<TApplication> CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
if (!string.IsNullOrEmpty(await Store.GetHashedSecretAsync(application, cancellationToken)))
{
throw new ArgumentException("The client secret hash cannot be directly set on the application entity. " +
"To create a confidential application, use the CreateAsync() overload accepting a secret parameter.");
}
// If no client type was specified, assume it's a public application.
if (string.IsNullOrEmpty(await Store.GetClientTypeAsync(application, cancellationToken)))
{
await Store.SetClientTypeAsync(application, OpenIddictConstants.ClientTypes.Public, cancellationToken);
}
await ValidateAsync(application, cancellationToken);
return await Store.CreateAsync(application, cancellationToken);
return CreateAsync(application, /* secret: */ null, cancellationToken);
}
/// <summary>
/// Creates a new confidential application, using the specified client secret.
/// Creates a new application.
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="secret">The client secret associated with the application, if applicable.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
@ -82,7 +64,7 @@ namespace OpenIddict.Core
/// </returns>
public virtual async Task<TApplication> CreateAsync(
[NotNull] TApplication application,
[NotNull] string secret, CancellationToken cancellationToken)
[CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
{
@ -94,16 +76,32 @@ namespace OpenIddict.Core
throw new ArgumentException("The client secret hash cannot be directly set on the application entity.");
}
// If no client type was specified, assume it's a public application if no secret was provided.
var type = await Store.GetClientTypeAsync(application, cancellationToken);
if (!string.IsNullOrEmpty(type) &&
!string.Equals(type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase))
if (string.IsNullOrEmpty(type))
{
await Store.SetClientTypeAsync(application, string.IsNullOrEmpty(secret) ?
OpenIddictConstants.ClientTypes.Public :
OpenIddictConstants.ClientTypes.Confidential, cancellationToken);
}
if (string.IsNullOrEmpty(secret))
{
throw new InvalidOperationException("The client type must be set to 'confidential' when creating an application with a client secret." +
"To create a public application, use the CreateAsync() overload that doesn't take a secret parameter.");
// If the client is a confidential application, throw an
// exception as the client secret is required in this case.
if (string.Equals(type, OpenIddictConstants.ClientTypes.Confidential, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("A client secret must be provided when creating a confidential application.");
}
await Store.SetHashedSecretAsync(application, null, cancellationToken);
}
else
{
await Store.SetHashedSecretAsync(application, Crypto.HashPassword(secret), cancellationToken);
}
await Store.SetClientTypeAsync(application, OpenIddictConstants.ClientTypes.Confidential, cancellationToken);
await Store.SetHashedSecretAsync(application, Crypto.HashPassword(secret), cancellationToken);
await ValidateAsync(application, cancellationToken);
return await Store.CreateAsync(application, cancellationToken);
@ -347,7 +345,7 @@ namespace OpenIddict.Core
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task SetClientSecretAsync([NotNull] TApplication application, [NotNull] string secret, CancellationToken cancellationToken)
public virtual async Task SetClientSecretAsync([NotNull] TApplication application, [CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
{
@ -356,10 +354,14 @@ namespace OpenIddict.Core
if (string.IsNullOrEmpty(secret))
{
throw new ArgumentException("The client secret cannot be null or empty.", nameof(secret));
await Store.SetHashedSecretAsync(application, null, cancellationToken);
}
else
{
await Store.SetHashedSecretAsync(application, Crypto.HashPassword(secret), cancellationToken);
}
await Store.SetHashedSecretAsync(application, Crypto.HashPassword(secret), cancellationToken);
await UpdateAsync(application, cancellationToken);
}
@ -382,6 +384,36 @@ namespace OpenIddict.Core
await Store.UpdateAsync(application, cancellationToken);
}
/// <summary>
/// Updates an existing application.
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="secret">The client secret associated with the application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual async Task UpdateAsync([NotNull] TApplication application,
[CanBeNull] string secret, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
if (string.IsNullOrEmpty(secret))
{
await Store.SetHashedSecretAsync(application, null, cancellationToken);
}
else
{
await Store.SetHashedSecretAsync(application, Crypto.HashPassword(secret), cancellationToken);
}
await UpdateAsync(application, cancellationToken);
}
/// <summary>
/// Validates the application to ensure it's in a consistent state.
/// </summary>

2
src/OpenIddict.Core/Stores/IOpenIddictApplicationStore.cs

@ -178,7 +178,7 @@ namespace OpenIddict.Core
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task SetHashedSecretAsync([NotNull] TApplication application, [NotNull] string hash, CancellationToken cancellationToken);
Task SetHashedSecretAsync([NotNull] TApplication application, [CanBeNull] string hash, CancellationToken cancellationToken);
/// <summary>
/// Updates an existing application.

8
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictApplicationStore.cs

@ -368,18 +368,14 @@ namespace OpenIddict.EntityFrameworkCore
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public virtual Task SetHashedSecretAsync([NotNull] TApplication application, [NotNull] string hash, CancellationToken cancellationToken)
public virtual Task SetHashedSecretAsync([NotNull] TApplication application,
[CanBeNull] string hash, CancellationToken cancellationToken)
{
if (application == null)
{
throw new ArgumentNullException(nameof(application));
}
if (string.IsNullOrEmpty(hash))
{
throw new ArgumentException("The client secret hash cannot be null or empty.", nameof(hash));
}
application.ClientSecret = hash;
return Task.FromResult(0);

Loading…
Cancel
Save