Skip to content

Commit

Permalink
Add documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
jjrdk committed May 31, 2021
1 parent 9aaa5d4 commit e92ea28
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 23 deletions.
25 changes: 25 additions & 0 deletions src/simpleauth.client/DeviceTokenRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace SimpleAuth.Client
{
using System.Collections.Generic;

/// <summary>
/// Defines the device token request.
/// </summary>
public record DeviceTokenRequest : TokenRequest
{
/// <summary>
/// Initializes a new instance of the <see cref="DeviceTokenRequest"/> record.
/// </summary>
/// <param name="form">The request form.</param>
/// <param name="interval">The polling interval.</param>
public DeviceTokenRequest(Dictionary<string, string> form, int interval) : base(form)
{
Interval = interval;
}

/// <summary>
/// Gets the polling interval.
/// </summary>
public int Interval { get; }
}
}
8 changes: 8 additions & 0 deletions src/simpleauth.client/PkceBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,18 @@ namespace SimpleAuth.Client
using System.Text;
using SimpleAuth.Shared.Models;

/// <summary>
/// Defines the PKCE builder.
/// </summary>
public static class PkceBuilder
{
private static readonly Random Random = new();

/// <summary>
/// Builds a PKCE challenge.
/// </summary>
/// <param name="method">The challenge method.</param>
/// <returns>A <see cref="Pkce"/> instance.</returns>
public static Pkce BuildPkce(this string method)
{
var codeVerifier = GetCodeVerifier();
Expand Down
4 changes: 4 additions & 0 deletions src/simpleauth.client/TokenCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ public static TokenCredentials FromClientSecret(string clientAssertion, string c
return new TokenCredentials(dict);
}

/// <summary>
/// Creates the credentials as a device.
/// </summary>
/// <returns></returns>
public static TokenCredentials AsDevice()
{
return new(new Dictionary<string, string>());
Expand Down
37 changes: 19 additions & 18 deletions src/simpleauth.client/TokenRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public record TokenRequest : IEnumerable<KeyValuePair<string?, string?>>
{
private readonly Dictionary<string, string> _form;

/// <summary>
/// Initializes a new instance of the <see cref="TokenRequest"/> record.
/// </summary>
/// <param name="form"></param>
protected internal TokenRequest(Dictionary<string, string> form)
{
_form = form;
Expand Down Expand Up @@ -212,18 +216,13 @@ public static TokenRequest FromPassword(string userName, string password, string
return FromPassword(userName, password, scopes, new[] { amrValue });
}

/// <inheritdoc />
public IEnumerator<KeyValuePair<string?, string?>> GetEnumerator()
{
return _form.GetEnumerator();
}

/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

/// <summary>
/// Creates a request from the device code.
/// </summary>
/// <param name="clientId">The client id.</param>
/// <param name="deviceCode">The device code.</param>
/// <param name="interval">The polling interval.</param>
/// <returns>A <see cref="TokenRequest"/> instance.</returns>
public static TokenRequest FromDeviceCode(string clientId, string deviceCode, int interval)
{
var dictionary = new Dictionary<string, string>
Expand All @@ -234,15 +233,17 @@ public static TokenRequest FromDeviceCode(string clientId, string deviceCode, in
};
return new DeviceTokenRequest(dictionary, interval);
}
}

public record DeviceTokenRequest : TokenRequest
{
public DeviceTokenRequest(Dictionary<string, string> form, int interval) : base(form)
/// <inheritdoc />
public IEnumerator<KeyValuePair<string?, string?>> GetEnumerator()
{
Interval = interval;
return _form.GetEnumerator();
}

public int Interval { get; }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
34 changes: 34 additions & 0 deletions src/simpleauth.shared/Repositories/IDeviceAuthorizationStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,50 @@
using SimpleAuth.Shared.Requests;
using SimpleAuth.Shared.Responses;

/// <summary>
/// Defines the device authorization store interface.
/// </summary>
public interface IDeviceAuthorizationStore
{
/// <summary>
/// Gets the <see cref="DeviceAuthorizationResponse"/> for the user code.
/// </summary>
/// <param name="userCode">The user code.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns>A <see cref="DeviceAuthorizationResponse"/> as an async operation.</returns>
public Task<Option<DeviceAuthorizationResponse>> Get(string userCode, CancellationToken cancellationToken = default);

/// <summary>
/// Gets the <see cref="DeviceAuthorizationData"/> for the device code.
/// </summary>
/// <param name="clientId">The client id.</param>
/// <param name="deviceCode">The device code.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns>A <see cref="DeviceAuthorizationData"/> as an async operation.</returns>
public Task<Option<DeviceAuthorizationData>> Get(string clientId, string deviceCode, CancellationToken cancellationToken = default);

/// <summary>
/// Approves the authorization request.
/// </summary>
/// <param name="userCode">The user code.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns>An <see cref="Option"/> as an async operation.</returns>
public Task<Option> Approve(string userCode, CancellationToken cancellationToken = default);

/// <summary>
/// Saves the passed <see cref="DeviceAuthorizationData"/>.
/// </summary>
/// <param name="request">The <see cref="DeviceAuthorizationData"/> to save.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns>An <see cref="Option"/> as an async operation.</returns>
Task<Option> Save(DeviceAuthorizationData request, CancellationToken cancellationToken = default);

/// <summary>
/// Removes the passed <see cref="DeviceAuthorizationData"/>.
/// </summary>
/// <param name="authRequest">The <see cref="DeviceAuthorizationData"/> to save.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns>An <see cref="Option"/> as an async operation.</returns>
Task<Option> Remove(DeviceAuthorizationData authRequest, CancellationToken cancellationToken);
}
}
10 changes: 10 additions & 0 deletions src/simpleauth.shared/Requests/DeviceAuthorizationRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,20 @@ public DeviceAuthorizationRequest(string clientId, params string[] scopes)
Scopes = scopes;
}

/// <summary>
/// Gets the client id.
/// </summary>
public string ClientId { get; }

/// <summary>
/// Gets the scopes.
/// </summary>
public string[] Scopes { get; }

/// <summary>
/// Returns the request as a form.
/// </summary>
/// <returns>The form fields.</returns>
public IEnumerable<KeyValuePair<string?, string?>> ToForm()
{
yield return new KeyValuePair<string?, string?>("client_id", ClientId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
{
using System.Runtime.Serialization;

/// <summary>
/// Defines the device authorization response.
/// </summary>
[DataContract]
public record DeviceAuthorizationResponse
{
Expand Down
18 changes: 18 additions & 0 deletions src/simpleauth/Api/Device/DeviceAuthorizationActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
using SimpleAuth.Shared.Requests;
using SimpleAuth.Shared.Responses;

/// <summary>
/// Defines the device authorization.
/// </summary>
public class DeviceAuthorizationActions
{
private readonly RuntimeSettings _settings;
Expand All @@ -22,6 +25,13 @@ public class DeviceAuthorizationActions
private static readonly char[] Characters = "ABCDEFGHIJKMOPRSTVXYZ123456789".ToCharArray();
private static readonly Random Rnd = new(DateTime.UtcNow.Millisecond);

/// <summary>
/// Initializes a new instance of the <see cref="DeviceAuthorizationActions"/> class.
/// </summary>
/// <param name="settings">The runtime settings.</param>
/// <param name="store">The device authorization store.</param>
/// <param name="clientStore">The client store.</param>
/// <param name="logger">The logger.</param>
public DeviceAuthorizationActions(RuntimeSettings settings, IDeviceAuthorizationStore store, IClientStore clientStore, ILogger logger)
{
_settings = settings;
Expand All @@ -30,6 +40,14 @@ public DeviceAuthorizationActions(RuntimeSettings settings, IDeviceAuthorization
_logger = logger;
}

/// <summary>
/// Starts the device authorization request.
/// </summary>
/// <param name="clientId">The client id of the requesting application.</param>
/// <param name="authority">The token authority.</param>
/// <param name="scopes">The requested scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns></returns>
public async Task<Option<DeviceAuthorizationData>> StartDeviceAuthorizationRequest(string clientId, Uri authority, string[] scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(clientId)
Expand Down
32 changes: 28 additions & 4 deletions src/simpleauth/Controllers/DeviceAuthorizationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,23 @@
using SimpleAuth.Shared.Repositories;
using SimpleAuth.Shared.Requests;

/// <summary>
/// Defines the device authorization controller.
/// </summary>
[Route(CoreConstants.EndPoints.DeviceAuthorization)]
[ThrottleFilter]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public class DeviceAuthorizationController : ControllerBase
{
private readonly DeviceAuthorizationActions _actions;

/// <summary>
/// Initializes a new instance of the <see cref="DeviceAuthorizationController"/> class.
/// </summary>
/// <param name="settings">The runtime settings.</param>
/// <param name="deviceAuthorizationStore">The device authorization store.</param>
/// <param name="clientStore">The client store.</param>
/// <param name="logger">The logger.</param>
public DeviceAuthorizationController(
RuntimeSettings settings,
IClientStore clientStore,
Expand All @@ -29,14 +39,25 @@ public DeviceAuthorizationController(
_actions = new DeviceAuthorizationActions(settings, deviceAuthorizationStore, clientStore, logger);
}

/// <summary>
/// Requests the authorization.
/// </summary>
/// <param name="request">The token request.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns></returns>
[HttpPost]
public async Task<IActionResult> RequestAuthorization([FromForm] TokenRequest request, CancellationToken cancellationToken)
public async Task<IActionResult> RequestAuthorization(
[FromForm] TokenRequest request,
CancellationToken cancellationToken)
{
if (string.IsNullOrWhiteSpace(request.client_id))
{
return BadRequest();
}
var scopeArray = string.IsNullOrWhiteSpace(request.scope) ? Array.Empty<string>() : request.scope.Split(' ', StringSplitOptions.TrimEntries).ToArray();

var scopeArray = string.IsNullOrWhiteSpace(request.scope)
? Array.Empty<string>()
: request.scope.Split(' ', StringSplitOptions.TrimEntries).ToArray();
var response = await _actions.StartDeviceAuthorizationRequest(
request.client_id,
Request.GetAbsoluteUri(),
Expand All @@ -47,9 +68,12 @@ public async Task<IActionResult> RequestAuthorization([FromForm] TokenRequest re
return response switch
{
Option<DeviceAuthorizationData>.Result r => Ok(r.Item.Response),
Option<DeviceAuthorizationData>.Error e => new ObjectResult(e.Details) { StatusCode = (int)e.Details.Status },
Option<DeviceAuthorizationData>.Error e => new ObjectResult(e.Details)
{
StatusCode = (int) e.Details.Status
},
_ => throw new ArgumentOutOfRangeException()
};
}
}
}
}
19 changes: 19 additions & 0 deletions src/simpleauth/Controllers/DeviceController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
using SimpleAuth.Shared.Repositories;
using SimpleAuth.ViewModels;

/// <summary>
/// Defines the device controller.
/// </summary>
[Authorize]
[Route(CoreConstants.EndPoints.Device)]
[ThrottleFilter]
Expand All @@ -19,18 +22,34 @@ public class DeviceController : ControllerBase
private readonly IDeviceAuthorizationStore _deviceAuthorizationStore;
private readonly ILogger<DeviceController> _logger;

/// <summary>
/// Initializes a new instance of the <see cref="DeviceController"/> class.
/// </summary>
/// <param name="deviceAuthorizationStore">The device authorization store.</param>
/// <param name="logger">The logger.</param>
public DeviceController(IDeviceAuthorizationStore deviceAuthorizationStore, ILogger<DeviceController> logger)
{
_deviceAuthorizationStore = deviceAuthorizationStore;
_logger = logger;
}

/// <summary>
/// Gets the authorization form.
/// </summary>
/// <param name="code">The optional user code.</param>
/// <returns>The authorization form.</returns>
[HttpGet]
public async Task<IActionResult> Get([FromQuery] string code)
{
return Ok(new DeviceAuthorizationViewModel { Code = code });
}

/// <summary>
/// Approves the authorization request.
/// </summary>
/// <param name="code">The user code.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the async operation.</param>
/// <returns>The authorized form.</returns>
[HttpPost]
public async Task<IActionResult> Approve([FromForm] string code, CancellationToken cancellationToken)
{
Expand Down
2 changes: 1 addition & 1 deletion src/simpleauth/Controllers/TokenController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
using System.Linq;
using System.Net;
using System.Net.Http.Headers;
using System.Runtime.Serialization;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -50,6 +49,7 @@ public class TokenController : ControllerBase
/// <param name="ticketStore">The ticket store.</param>
/// <param name="jwksStore"></param>
/// <param name="resourceSetRepository">The resource set repository.</param>
/// <param name="deviceAuthorizationStore">The device authorization store.</param>
/// <param name="eventPublisher">The event publisher.</param>
/// <param name="logger">The logger.</param>
public TokenController(
Expand Down
3 changes: 3 additions & 0 deletions src/simpleauth/RuntimeSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ public RuntimeSettings(
/// </summary>
public TimeSpan DevicePollingInterval { get; }

/// <summary>
/// Gets the device authorization request lifetime.
/// </summary>
public TimeSpan DeviceAuthorizationLifetime { get; }
}
}

0 comments on commit e92ea28

Please sign in to comment.