Skip to content

[Blazor] API cleanups for the authentication Package #19601

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
3 commits merged into from
Mar 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ enum AuthenticationResultStatus {
Redirect = "redirect",
Success = "success",
Failure = "failure",
OperationCompleted = "operation-completed"
OperationCompleted = "operationCompleted"
}

interface AuthenticationResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export enum AuthenticationResultStatus {
Redirect = 'redirect',
Success = 'success',
Failure = 'failure',
OperationCompleted = 'operation-completed'
OperationCompleted = 'operationCompleted'
};

export interface AuthenticationResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class RemoteAuthenticationResult<TState> where TState : class
/// <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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,17 @@ public class OidcProviderOptions
/// </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; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ private async Task ProcessLogOut(string returnUrl)
await NavigateToReturnUrl(uri);
break;
default:
throw new InvalidOperationException($"Invalid authentication result status '{result.Status ?? "(null)"}'.");
throw new InvalidOperationException($"Invalid authentication result status.");
}
}
else
Expand Down Expand Up @@ -332,7 +332,7 @@ private async Task ProcessLogOutCallback()
await NavigateToReturnUrl(uri);
break;
default:
throw new InvalidOperationException($"Invalid authentication result status '{result.Status ?? "(null)"}'.");
throw new InvalidOperationException($"Invalid authentication result status.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class AccessTokenResult
/// <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;
Expand All @@ -28,7 +28,7 @@ public AccessTokenResult(string status, AccessToken token, string redirectUrl)
/// <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"/>.
Expand All @@ -42,7 +42,7 @@ public AccessTokenResult(string status, AccessToken token, string redirectUrl)
/// <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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ public virtual async Task<RemoteAuthenticationResult<TRemoteAuthenticationState>
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());
Expand All @@ -84,7 +85,8 @@ public virtual async Task<RemoteAuthenticationResult<TRemoteAuthenticationState>
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());
Expand All @@ -98,7 +100,8 @@ public virtual async Task<RemoteAuthenticationResult<TRemoteAuthenticationState>
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());
Expand All @@ -112,7 +115,8 @@ public virtual async Task<RemoteAuthenticationResult<TRemoteAuthenticationState>
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());
Expand All @@ -127,13 +131,18 @@ public virtual async ValueTask<AccessTokenResult> RequestAccessToken()
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 />
Expand All @@ -147,13 +156,18 @@ public virtual async ValueTask<AccessTokenResult> RequestAccessToken(AccessToken
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)
Expand Down Expand Up @@ -242,4 +256,32 @@ internal struct InternalAccessTokenResult
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;
}
}
}
Loading