[Blazor] API cleanups for the authentication Package (#19601)

* Add missing OIDC provider options

* Convert string to enum

* Revert changes to JS files
This commit is contained in:
msftbot[bot] 2020-03-05 14:47:47 +00:00 committed by GitHub
parent e5cd390a8c
commit 28c44ce1c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 109 additions and 57 deletions

View File

@ -27,7 +27,7 @@ enum AuthenticationResultStatus {
Redirect = "redirect",
Success = "success",
Failure = "failure",
OperationCompleted = "operation-completed"
OperationCompleted = "operationCompleted"
}
interface AuthenticationResult {

View File

@ -43,7 +43,7 @@ export enum AuthenticationResultStatus {
Redirect = 'redirect',
Success = 'success',
Failure = 'failure',
OperationCompleted = 'operation-completed'
OperationCompleted = 'operationCompleted'
};
export interface AuthenticationResult {

View File

@ -12,7 +12,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// <summary>
/// Gets or sets the status of the authentication operation. The status can be one of <see cref="RemoteAuthenticationStatus"/>.
/// </summary>
public string Status { get; set; }
public RemoteAuthenticationStatus Status { get; set; }
/// <summary>
/// Gets or sets the error message of a failed authentication operation.

View File

@ -6,27 +6,27 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// <summary>
/// Represents the status of an authentication operation.
/// </summary>
public class RemoteAuthenticationStatus
public enum RemoteAuthenticationStatus
{
/// <summary>
/// The application is going to be redirected.
/// </summary>
public const string Redirect = "redirect";
Redirect,
/// <summary>
/// The authentication operation completed successfully.
/// </summary>
public const string Success = "success";
Success,
/// <summary>
/// There was an error performing the authentication operation.
/// </summary>
public const string Failure = "failure";
Failure,
/// <summary>
/// The operation in the current navigation context has completed. This signals that the application running on the
/// current browser context is about to be shut down and no other work is required.
/// </summary>
public const string OperationCompleted = "operation-completed";
OperationCompleted,
}
}

View File

@ -40,5 +40,17 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// </summary>
[JsonPropertyName("post_logout_redirect_uri")]
public string PostLogoutRedirectUri { get; set; }
/// <summary>
/// Gets or sets the response type to use on the authorization flow. The valid values are specified by the identity provider metadata.
/// </summary>
[JsonPropertyName("response_type")]
public string ResponseType { get; set; }
/// <summary>
/// Gets or sets the response mode to use in the authorization flow.
/// </summary>
[JsonPropertyName("response_mode")]
public string ResponseMode { get; set; }
}
}

View File

@ -300,7 +300,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
await NavigateToReturnUrl(uri);
break;
default:
throw new InvalidOperationException($"Invalid authentication result status '{result.Status ?? "(null)"}'.");
throw new InvalidOperationException($"Invalid authentication result status.");
}
}
else
@ -332,7 +332,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
await NavigateToReturnUrl(uri);
break;
default:
throw new InvalidOperationException($"Invalid authentication result status '{result.Status ?? "(null)"}'.");
throw new InvalidOperationException($"Invalid authentication result status.");
}
}

View File

@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// <param name="status">The status of the result.</param>
/// <param name="token">The <see cref="AccessToken"/> in case it was successful.</param>
/// <param name="redirectUrl">The redirect uri to go to for provisioning the token.</param>
public AccessTokenResult(string status, AccessToken token, string redirectUrl)
public AccessTokenResult(AccessTokenResultStatus status, AccessToken token, string redirectUrl)
{
Status = status;
_token = token;
@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// <summary>
/// Gets or sets the status of the current operation. See <see cref="AccessTokenResultStatus"/> for a list of statuses.
/// </summary>
public string Status { get; set; }
public AccessTokenResultStatus Status { get; set; }
/// <summary>
/// Gets or sets the URL to redirect to if <see cref="Status"/> is <see cref="AccessTokenResultStatus.RequiresRedirect"/>.
@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// <returns><c>true</c> when the token request is successful; <c>false</c> otherwise.</returns>
public bool TryGetToken(out AccessToken accessToken)
{
if (string.Equals(Status, AccessTokenResultStatus.Success, StringComparison.OrdinalIgnoreCase))
if (Status == AccessTokenResultStatus.Success)
{
accessToken = _token;
return true;

View File

@ -6,16 +6,16 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
/// <summary>
/// Represents the possible results from trying to acquire an access token.
/// </summary>
public class AccessTokenResultStatus
public enum AccessTokenResultStatus
{
/// <summary>
/// The token was successfully acquired.
/// </summary>
public const string Success = "success";
Success,
/// <summary>
/// A redirect is needed in order to provision the token.
/// </summary>
public const string RequiresRedirect = "requiesRedirect";
RequiresRedirect,
}
}

View File

@ -70,7 +70,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
RemoteAuthenticationContext<TRemoteAuthenticationState> context)
{
await EnsureAuthService();
var result = await _jsRuntime.InvokeAsync<RemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.signIn", context.State);
var internalResult = await _jsRuntime.InvokeAsync<InternalRemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.signIn", context.State);
var result = internalResult.Convert();
if (result.Status == RemoteAuthenticationStatus.Success)
{
UpdateUser(GetUser());
@ -84,7 +85,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
RemoteAuthenticationContext<TRemoteAuthenticationState> context)
{
await EnsureAuthService();
var result = await _jsRuntime.InvokeAsync<RemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.completeSignIn", context.Url);
var internalResult = await _jsRuntime.InvokeAsync<InternalRemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.completeSignIn", context.Url);
var result = internalResult.Convert();
if (result.Status == RemoteAuthenticationStatus.Success)
{
UpdateUser(GetUser());
@ -98,7 +100,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
RemoteAuthenticationContext<TRemoteAuthenticationState> context)
{
await EnsureAuthService();
var result = await _jsRuntime.InvokeAsync<RemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.signOut", context.State);
var internalResult = await _jsRuntime.InvokeAsync<InternalRemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.signOut", context.State);
var result = internalResult.Convert();
if (result.Status == RemoteAuthenticationStatus.Success)
{
UpdateUser(GetUser());
@ -112,7 +115,8 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
RemoteAuthenticationContext<TRemoteAuthenticationState> context)
{
await EnsureAuthService();
var result = await _jsRuntime.InvokeAsync<RemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.completeSignOut", context.Url);
var internalResult = await _jsRuntime.InvokeAsync<InternalRemoteAuthenticationResult<TRemoteAuthenticationState>>("AuthenticationService.completeSignOut", context.Url);
var result = internalResult.Convert();
if (result.Status == RemoteAuthenticationStatus.Success)
{
UpdateUser(GetUser());
@ -127,13 +131,18 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
await EnsureAuthService();
var result = await _jsRuntime.InvokeAsync<InternalAccessTokenResult>("AuthenticationService.getAccessToken");
if (string.Equals(result.Status, AccessTokenResultStatus.RequiresRedirect, StringComparison.OrdinalIgnoreCase))
if (!Enum.TryParse<AccessTokenResultStatus>(result.Status, ignoreCase: true, out var parsedStatus))
{
throw new InvalidOperationException($"Invalid access token result status '{result.Status ?? "(null)"}'");
}
if (parsedStatus == AccessTokenResultStatus.RequiresRedirect)
{
var redirectUrl = GetRedirectUrl(null);
result.RedirectUrl = redirectUrl.ToString();
}
return new AccessTokenResult(result.Status, result.Token, result.RedirectUrl);
return new AccessTokenResult(parsedStatus, result.Token, result.RedirectUrl);
}
/// <inheritdoc />
@ -147,13 +156,18 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
await EnsureAuthService();
var result = await _jsRuntime.InvokeAsync<InternalAccessTokenResult>("AuthenticationService.getAccessToken", options);
if (string.Equals(result.Status, AccessTokenResultStatus.RequiresRedirect, StringComparison.OrdinalIgnoreCase))
if (!Enum.TryParse<AccessTokenResultStatus>(result.Status, ignoreCase: true, out var parsedStatus))
{
throw new InvalidOperationException($"Invalid access token result status '{result.Status ?? "(null)"}'");
}
if (parsedStatus == AccessTokenResultStatus.RequiresRedirect)
{
var redirectUrl = GetRedirectUrl(options.ReturnUrl);
result.RedirectUrl = redirectUrl.ToString();
}
return new AccessTokenResult(result.Status, result.Token, result.RedirectUrl);
return new AccessTokenResult(parsedStatus, result.Token, result.RedirectUrl);
}
private Uri GetRedirectUrl(string customReturnUrl)
@ -242,4 +256,32 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
public AccessToken Token { get; set; }
public string RedirectUrl { get; set; }
}
// Internal for testing purposes
internal struct InternalRemoteAuthenticationResult<TRemoteAuthenticationState> where TRemoteAuthenticationState : RemoteAuthenticationState
{
public string Status { get; set; }
public string ErrorMessage { get; set; }
public TRemoteAuthenticationState State { get; set; }
public RemoteAuthenticationResult<TRemoteAuthenticationState> Convert()
{
var result = new RemoteAuthenticationResult<TRemoteAuthenticationState>();
result.ErrorMessage = ErrorMessage;
result.State = State;
if (Status != null && Enum.TryParse<RemoteAuthenticationStatus>(Status, ignoreCase: true, out var status))
{
result.Status = status;
}
else
{
throw new InvalidOperationException($"Can't convert status '${Status ?? "(null)"}'.");
}
return result;
}
}
}

View File

@ -27,10 +27,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.SignInResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.SignInResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
State = state,
Status = RemoteAuthenticationStatus.Success
Status = RemoteAuthenticationStatus.Success.ToString()
};
// Act
@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[InlineData(RemoteAuthenticationStatus.Redirect)]
[InlineData(RemoteAuthenticationStatus.Failure)]
[InlineData(RemoteAuthenticationStatus.OperationCompleted)]
public async Task RemoteAuthenticationService_SignIn_DoesNotUpdateUserOnOtherResult(string value)
public async Task RemoteAuthenticationService_SignIn_DoesNotUpdateUserOnOtherResult(RemoteAuthenticationStatus value)
{
// Arrange
var testJsRuntime = new TestJsRuntime();
@ -57,9 +57,9 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.SignInResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.SignInResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
Status = value
Status = value.ToString()
};
// Act
@ -83,10 +83,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.CompleteSignInResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.CompleteSignInResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
State = state,
Status = RemoteAuthenticationStatus.Success
Status = RemoteAuthenticationStatus.Success.ToString()
};
// Act
@ -102,7 +102,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[InlineData(RemoteAuthenticationStatus.Redirect)]
[InlineData(RemoteAuthenticationStatus.Failure)]
[InlineData(RemoteAuthenticationStatus.OperationCompleted)]
public async Task RemoteAuthenticationService_CompleteSignInAsync_DoesNotUpdateUserOnOtherResult(string value)
public async Task RemoteAuthenticationService_CompleteSignInAsync_DoesNotUpdateUserOnOtherResult(RemoteAuthenticationStatus value)
{
// Arrange
var testJsRuntime = new TestJsRuntime();
@ -113,9 +113,9 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.CompleteSignInResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.CompleteSignInResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
Status = value
Status = value.ToString().ToString()
};
// Act
@ -139,10 +139,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.SignOutResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.SignOutResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
State = state,
Status = RemoteAuthenticationStatus.Success
Status = RemoteAuthenticationStatus.Success.ToString()
};
// Act
@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[InlineData(RemoteAuthenticationStatus.Redirect)]
[InlineData(RemoteAuthenticationStatus.Failure)]
[InlineData(RemoteAuthenticationStatus.OperationCompleted)]
public async Task RemoteAuthenticationService_SignOut_DoesNotUpdateUserOnOtherResult(string value)
public async Task RemoteAuthenticationService_SignOut_DoesNotUpdateUserOnOtherResult(RemoteAuthenticationStatus value)
{
// Arrange
var testJsRuntime = new TestJsRuntime();
@ -169,9 +169,9 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.SignOutResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.SignOutResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
Status = value
Status = value.ToString()
};
// Act
@ -195,10 +195,10 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.CompleteSignOutResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.CompleteSignOutResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
State = state,
Status = RemoteAuthenticationStatus.Success
Status = RemoteAuthenticationStatus.Success.ToString()
};
// Act
@ -214,7 +214,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
[InlineData(RemoteAuthenticationStatus.Redirect)]
[InlineData(RemoteAuthenticationStatus.Failure)]
[InlineData(RemoteAuthenticationStatus.OperationCompleted)]
public async Task RemoteAuthenticationService_CompleteSignOutAsync_DoesNotUpdateUserOnOtherResult(string value)
public async Task RemoteAuthenticationService_CompleteSignOutAsync_DoesNotUpdateUserOnOtherResult(RemoteAuthenticationStatus value)
{
// Arrange
var testJsRuntime = new TestJsRuntime();
@ -225,9 +225,9 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
new TestNavigationManager());
var state = new RemoteAuthenticationState();
testJsRuntime.CompleteSignOutResult = new RemoteAuthenticationResult<RemoteAuthenticationState>
testJsRuntime.CompleteSignOutResult = new InternalRemoteAuthenticationResult<RemoteAuthenticationState>
{
Status = value
Status = value.ToString()
};
// Act
@ -253,7 +253,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
var state = new RemoteAuthenticationState();
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
{
Status = AccessTokenResultStatus.Success,
Status = "success",
Token = new AccessToken
{
Value = "1234",
@ -271,7 +271,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
testJsRuntime.PastInvocations.Select(i => i.identifier).ToArray());
Assert.True(result.TryGetToken(out var token));
Assert.Equal(result.Status, testJsRuntime.GetAccessTokenResult.Status);
Assert.Equal(result.Status, Enum.Parse<AccessTokenResultStatus>(testJsRuntime.GetAccessTokenResult.Status, ignoreCase: true));
Assert.Equal(result.RedirectUrl, testJsRuntime.GetAccessTokenResult.RedirectUrl);
Assert.Equal(token, testJsRuntime.GetAccessTokenResult.Token);
}
@ -290,7 +290,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
var state = new RemoteAuthenticationState();
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
{
Status = AccessTokenResultStatus.RequiresRedirect,
Status = "requiresRedirect",
};
var tokenOptions = new AccessTokenRequestOptions
@ -310,7 +310,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
Assert.False(result.TryGetToken(out var token));
Assert.Null(token);
Assert.Equal(result.Status, testJsRuntime.GetAccessTokenResult.Status);
Assert.Equal(result.Status, Enum.Parse<AccessTokenResultStatus>(testJsRuntime.GetAccessTokenResult.Status, ignoreCase: true));
Assert.Equal(expectedRedirectUrl, result.RedirectUrl);
Assert.Equal(tokenOptions, (AccessTokenRequestOptions)testJsRuntime.PastInvocations[^1].args[0]);
}
@ -329,7 +329,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
var state = new RemoteAuthenticationState();
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
{
Status = AccessTokenResultStatus.RequiresRedirect,
Status = "requiresRedirect",
};
var tokenOptions = new AccessTokenRequestOptions
@ -350,7 +350,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
Assert.False(result.TryGetToken(out var token));
Assert.Null(token);
Assert.Equal(result.Status, testJsRuntime.GetAccessTokenResult.Status);
Assert.Equal(result.Status, Enum.Parse<AccessTokenResultStatus>(testJsRuntime.GetAccessTokenResult.Status, ignoreCase: true));
Assert.Equal(expectedRedirectUrl, result.RedirectUrl);
Assert.Equal(tokenOptions, (AccessTokenRequestOptions)testJsRuntime.PastInvocations[^1].args[0]);
}
@ -435,7 +435,7 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
testJsRuntime.GetUserResult = JsonSerializer.Deserialize<IDictionary<string, object>>(serializedUser);
testJsRuntime.GetAccessTokenResult = new InternalAccessTokenResult
{
Status = AccessTokenResultStatus.Success,
Status = "success",
Token = new AccessToken
{
Value = "1234",
@ -499,15 +499,13 @@ namespace Microsoft.AspNetCore.Components.WebAssembly.Authentication
{
public IList<(string identifier, object[] args)> PastInvocations { get; set; } = new List<(string, object[])>();
public RemoteAuthenticationResult<RemoteAuthenticationState> SignInResult { get; set; }
public InternalRemoteAuthenticationResult<RemoteAuthenticationState> SignInResult { get; set; }
public RemoteAuthenticationResult<RemoteAuthenticationState> CompleteSignInResult { get; set; }
public InternalRemoteAuthenticationResult<RemoteAuthenticationState> CompleteSignInResult { get; set; }
public RemoteAuthenticationResult<RemoteAuthenticationState> SignOutResult { get; set; }
public InternalRemoteAuthenticationResult<RemoteAuthenticationState> SignOutResult { get; set; }
public RemoteAuthenticationResult<RemoteAuthenticationState> CompleteSignOutResult { get; set; }
public RemoteAuthenticationResult<RemoteAuthenticationState> InitResult { get; set; }
public InternalRemoteAuthenticationResult<RemoteAuthenticationState> CompleteSignOutResult { get; set; }
public InternalAccessTokenResult GetAccessTokenResult { get; set; }