Browse Source

Update the sponsors section

pull/1599/head
OpenIddict Bot 3 years ago
parent
commit
9a51962099
  1. 52
      sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/HomeController.cs
  2. 7
      sandbox/OpenIddict.Sandbox.AspNet.Client/Startup.cs
  3. 19
      sandbox/OpenIddict.Sandbox.AspNet.Client/Views/Home/Index.cshtml
  4. 54
      sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/HomeController.cs
  5. 7
      sandbox/OpenIddict.Sandbox.AspNetCore.Client/Startup.cs
  6. 13
      sandbox/OpenIddict.Sandbox.AspNetCore.Client/Views/Home/Index.cshtml
  7. 41
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs
  8. 3
      src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

52
sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/HomeController.cs

@ -1,10 +1,14 @@
using System.Net.Http; using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web; using System.Web;
using System.Web.Mvc; using System.Web.Mvc;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies; using Microsoft.Owin.Security.Cookies;
using OpenIddict.Client;
using static OpenIddict.Client.Owin.OpenIddictClientOwinConstants; using static OpenIddict.Client.Owin.OpenIddictClientOwinConstants;
namespace OpenIddict.Sandbox.AspNet.Client.Controllers namespace OpenIddict.Sandbox.AspNet.Client.Controllers
@ -12,14 +16,20 @@ namespace OpenIddict.Sandbox.AspNet.Client.Controllers
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpClientFactory _httpClientFactory;
private readonly OpenIddictClientService _service;
public HomeController(IHttpClientFactory httpClientFactory) public HomeController(
=> _httpClientFactory = httpClientFactory; IHttpClientFactory httpClientFactory,
OpenIddictClientService service)
{
_httpClientFactory = httpClientFactory;
_service = service;
}
[HttpGet, Route("~/")] [HttpGet, Route("~/")]
public ActionResult Index() => View(); public ActionResult Index() => View();
[Authorize, HttpPost, Route("~/")] [Authorize, HttpPost, Route("~/message")]
[ValidateAntiForgeryToken] [ValidateAntiForgeryToken]
public async Task<ActionResult> Index(CancellationToken cancellationToken) public async Task<ActionResult> Index(CancellationToken cancellationToken)
{ {
@ -38,5 +48,39 @@ namespace OpenIddict.Sandbox.AspNet.Client.Controllers
return View(model: await response.Content.ReadAsStringAsync()); return View(model: await response.Content.ReadAsStringAsync());
} }
[Authorize, HttpPost, Route("~/refresh-token")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> RefreshToken(CancellationToken cancellationToken)
{
var context = HttpContext.GetOwinContext();
var result = await context.Authentication.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationType);
if (!result.Properties.Dictionary.TryGetValue(Tokens.RefreshToken, out string token))
{
return new HttpStatusCodeResult(400);
}
var (response, principal) = await _service.AuthenticateWithRefreshTokenAsync(
issuer: new Uri(result.Identity.Claims.Select(claim => claim.Issuer).First(), UriKind.Absolute),
token: token,
cancellationToken: cancellationToken);
var properties = new AuthenticationProperties(result.Properties.Dictionary)
{
RedirectUri = null
};
properties.Dictionary[Tokens.BackchannelAccessToken] = response.AccessToken;
if (!string.IsNullOrEmpty(response.RefreshToken))
{
properties.Dictionary[Tokens.RefreshToken] = response.RefreshToken;
}
context.Authentication.SignIn(properties, result.Identity);
return View("Index", model: response.AccessToken);
}
} }
} }

7
sandbox/OpenIddict.Sandbox.AspNet.Client/Startup.cs

@ -82,8 +82,10 @@ namespace OpenIddict.Sandbox.AspNet.Client
options.SetPostLogoutRedirectionEndpointUris( options.SetPostLogoutRedirectionEndpointUris(
"/callback/logout/local"); "/callback/logout/local");
// Note: this sample uses the code flow, but you can enable the other flows if necessary. // Note: this sample uses the authorization code and refresh token
options.AllowAuthorizationCodeFlow(); // flows, but you can enable the other flows if necessary.
options.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
// Register the signing and encryption credentials used to protect // Register the signing and encryption credentials used to protect
// sensitive data like the state tokens produced by OpenIddict. // sensitive data like the state tokens produced by OpenIddict.
@ -128,6 +130,7 @@ namespace OpenIddict.Sandbox.AspNet.Client
options.SetClientId("1016114395689-kgtgq2p6dj27d7v6e2kjkoj54dgrrckh.apps.googleusercontent.com") options.SetClientId("1016114395689-kgtgq2p6dj27d7v6e2kjkoj54dgrrckh.apps.googleusercontent.com")
.SetClientSecret("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") .SetClientSecret("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")
.SetRedirectUri("https://localhost:44378/callback/login/google") .SetRedirectUri("https://localhost:44378/callback/login/google")
.SetAccessType("offline")
.AddScopes(Scopes.Profile); .AddScopes(Scopes.Profile);
}) })
.UseTwitter(options => .UseTwitter(options =>

19
sandbox/OpenIddict.Sandbox.AspNet.Client/Views/Home/Index.cshtml

@ -1,4 +1,8 @@
@using System.Security.Claims @using System.Security.Claims
@using Microsoft.Owin
@using Microsoft.Owin.Security
@using Microsoft.Owin.Security.Cookies
@using OpenIddict.Client.Owin
@model string @model string
<div class="jumbotron"> <div class="jumbotron">
@ -15,19 +19,30 @@
if (!string.IsNullOrEmpty(Model)) if (!string.IsNullOrEmpty(Model))
{ {
<h3>Message received from the resource controller: @Model</h3> <h3>Payload returned by the controller: @Model</h3>
} }
if (User is ClaimsPrincipal principal && if (User is ClaimsPrincipal principal &&
principal.FindFirst(ClaimTypes.NameIdentifier)?.Issuer is "https://localhost:44349/") principal.FindFirst(ClaimTypes.NameIdentifier)?.Issuer is "https://localhost:44349/")
{ {
<form action="/" method="post"> <form action="/message" method="post">
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
<button class="btn btn-lg btn-warning" type="submit">Query the resource controller</button> <button class="btn btn-lg btn-warning" type="submit">Query the resource controller</button>
</form> </form>
} }
if (Context.GetOwinContext() is IOwinContext context &&
context.Authentication.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationType).Result is AuthenticateResult result &&
result.Properties.Dictionary.ContainsKey(OpenIddictClientOwinConstants.Tokens.RefreshToken))
{
<form action="/refresh-token" method="post">
@Html.AntiForgeryToken()
<button class="btn btn-lg btn-warning" type="submit">Refresh the access token</button>
</form>
}
<form action="/logout" method="post"> <form action="/logout" method="post">
@Html.AntiForgeryToken() @Html.AntiForgeryToken()

54
sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/HomeController.cs

@ -3,25 +3,31 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using OpenIddict.Client.AspNetCore; using OpenIddict.Client;
using static OpenIddict.Client.AspNetCore.OpenIddictClientAspNetCoreConstants;
namespace OpenIddict.Sandbox.AspNetCore.Client.Controllers; namespace OpenIddict.Sandbox.AspNetCore.Client.Controllers;
public class HomeController : Controller public class HomeController : Controller
{ {
private readonly IHttpClientFactory _httpClientFactory; private readonly IHttpClientFactory _httpClientFactory;
private readonly OpenIddictClientService _service;
public HomeController(IHttpClientFactory httpClientFactory) public HomeController(
=> _httpClientFactory = httpClientFactory; IHttpClientFactory httpClientFactory,
OpenIddictClientService service)
{
_httpClientFactory = httpClientFactory;
_service = service;
}
[HttpGet("~/")] [HttpGet("~/")]
public ActionResult Index() => View(); public ActionResult Index() => View();
[Authorize, HttpPost("~/"), ValidateAntiForgeryToken] [Authorize, HttpPost("~/message"), ValidateAntiForgeryToken]
public async Task<ActionResult> Index(CancellationToken cancellationToken) public async Task<ActionResult> GetMessage(CancellationToken cancellationToken)
{ {
var token = await HttpContext.GetTokenAsync(CookieAuthenticationDefaults.AuthenticationScheme, var token = await HttpContext.GetTokenAsync(CookieAuthenticationDefaults.AuthenticationScheme, Tokens.BackchannelAccessToken);
OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken);
using var client = _httpClientFactory.CreateClient(); using var client = _httpClientFactory.CreateClient();
@ -31,6 +37,38 @@ public class HomeController : Controller
using var response = await client.SendAsync(request, cancellationToken); using var response = await client.SendAsync(request, cancellationToken);
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
return View(model: await response.Content.ReadAsStringAsync(cancellationToken)); return View("Index", model: await response.Content.ReadAsStringAsync(cancellationToken));
}
[Authorize, HttpPost("~/refresh-token"), ValidateAntiForgeryToken]
public async Task<ActionResult> RefreshToken(CancellationToken cancellationToken)
{
var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
var token = result?.Properties.GetTokenValue(Tokens.RefreshToken);
if (string.IsNullOrEmpty(token))
{
return BadRequest();
}
var (response, principal) = await _service.AuthenticateWithRefreshTokenAsync(
issuer: new Uri(result.Principal.Claims.Select(claim => claim.Issuer).First(), UriKind.Absolute),
token: token,
cancellationToken: cancellationToken);
var properties = new AuthenticationProperties(result.Properties.Items)
{
RedirectUri = null
};
properties.UpdateTokenValue(Tokens.BackchannelAccessToken, response.AccessToken);
if (!string.IsNullOrEmpty(response.RefreshToken))
{
properties.UpdateTokenValue(Tokens.RefreshToken, response.RefreshToken);
}
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, result.Principal, properties);
return View("Index", model: response.AccessToken);
} }
} }

7
sandbox/OpenIddict.Sandbox.AspNetCore.Client/Startup.cs

@ -91,8 +91,10 @@ public class Startup
options.SetPostLogoutRedirectionEndpointUris( options.SetPostLogoutRedirectionEndpointUris(
"/callback/logout/local"); "/callback/logout/local");
// Note: this sample uses the code flow, but you can enable the other flows if necessary. // Note: this sample uses the authorization code and refresh token
options.AllowAuthorizationCodeFlow(); // flows, but you can enable the other flows if necessary.
options.AllowAuthorizationCodeFlow()
.AllowRefreshTokenFlow();
// Register the signing and encryption credentials used to protect // Register the signing and encryption credentials used to protect
// sensitive data like the state tokens produced by OpenIddict. // sensitive data like the state tokens produced by OpenIddict.
@ -138,6 +140,7 @@ public class Startup
options.SetClientId("1016114395689-kgtgq2p6dj27d7v6e2kjkoj54dgrrckh.apps.googleusercontent.com") options.SetClientId("1016114395689-kgtgq2p6dj27d7v6e2kjkoj54dgrrckh.apps.googleusercontent.com")
.SetClientSecret("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") .SetClientSecret("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")
.SetRedirectUri("https://localhost:44381/callback/login/google") .SetRedirectUri("https://localhost:44381/callback/login/google")
.SetAccessType("offline")
.AddScopes(Scopes.Profile); .AddScopes(Scopes.Profile);
}) })
.UseReddit(options => .UseReddit(options =>

13
sandbox/OpenIddict.Sandbox.AspNetCore.Client/Views/Home/Index.cshtml

@ -1,4 +1,6 @@
@using System.Security.Claims @using System.Security.Claims
@using Microsoft.AspNetCore.Authentication;
@using OpenIddict.Client.AspNetCore;
@model string @model string
<div class="jumbotron"> <div class="jumbotron">
@ -15,16 +17,23 @@
if (!string.IsNullOrEmpty(Model)) if (!string.IsNullOrEmpty(Model))
{ {
<h3>Message received from the resource controller: @Model</h3> <h3>Payload returned by the controller: @Model</h3>
} }
if (User.FindFirst(ClaimTypes.NameIdentifier)?.Issuer is "https://localhost:44395/") if (User.FindFirst(ClaimTypes.NameIdentifier)?.Issuer is "https://localhost:44395/")
{ {
<form asp-action="Index" asp-controller="Home" method="post"> <form asp-action="GetMessage" asp-controller="Home" method="post">
<button class="btn btn-lg btn-warning" type="submit">Query the resource controller</button> <button class="btn btn-lg btn-warning" type="submit">Query the resource controller</button>
</form> </form>
} }
if (!string.IsNullOrEmpty(await Context.GetTokenAsync(OpenIddictClientAspNetCoreConstants.Tokens.RefreshToken)))
{
<form asp-action="RefreshToken" asp-controller="Home" method="post">
<button class="btn btn-lg btn-warning" type="submit">Refresh the access token</button>
</form>
}
<form asp-action="Logout" asp-controller="Authentication" method="post"> <form asp-action="Logout" asp-controller="Authentication" method="post">
<button class="btn btn-lg btn-danger" type="submit">Sign out</button> <button class="btn btn-lg btn-danger" type="submit">Sign out</button>
</form> </form>

41
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs

@ -32,7 +32,8 @@ public static partial class OpenIddictClientWebIntegrationHandlers
*/ */
OverrideResponseMode.Descriptor, OverrideResponseMode.Descriptor,
FormatNonStandardScopeParameter.Descriptor, FormatNonStandardScopeParameter.Descriptor,
IncludeStateParameterInRedirectUri.Descriptor) IncludeStateParameterInRedirectUri.Descriptor,
AttachAdditionalChallengeParameters.Descriptor)
.AddRange(Discovery.DefaultHandlers) .AddRange(Discovery.DefaultHandlers)
.AddRange(Exchange.DefaultHandlers) .AddRange(Exchange.DefaultHandlers)
.AddRange(Protection.DefaultHandlers) .AddRange(Protection.DefaultHandlers)
@ -509,4 +510,42 @@ public static partial class OpenIddictClientWebIntegrationHandlers
return default; return default;
} }
} }
/// <summary>
/// Contains the logic responsible for attaching additional parameters
/// to the authorization request for the providers that require it.
/// </summary>
public sealed class AttachAdditionalChallengeParameters : IOpenIddictClientHandler<ProcessChallengeContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
.AddFilter<RequireInteractiveGrantType>()
.UseSingletonHandler<AttachAdditionalChallengeParameters>()
.SetOrder(AttachChallengeParameters.Descriptor.Order + 500)
.SetType(OpenIddictClientHandlerType.BuiltIn)
.Build();
/// <inheritdoc/>
public ValueTask HandleAsync(ProcessChallengeContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
// By default, Google doesn't return a refresh token but allows sending an "access_type"
// parameter to retrieve one (but it is only returned during the first authorization dance).
if (context.Registration.ProviderName is Providers.Google)
{
var options = context.Registration.GetGoogleOptions();
context.Request["access_type"] = options.AccessType;
}
return default;
}
}
} }

3
src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml

@ -39,6 +39,9 @@
<Provider Name="Google" Documentation="https://developers.google.com/identity/protocols/oauth2/openid-connect"> <Provider Name="Google" Documentation="https://developers.google.com/identity/protocols/oauth2/openid-connect">
<Environment Issuer="https://accounts.google.com/" /> <Environment Issuer="https://accounts.google.com/" />
<Setting PropertyName="AccessType" ParameterName="type" Type="String" Required="false"
Description="The value used as the 'access_type' parameter (can be set to 'offline' to retrieve a refresh token)" />
</Provider> </Provider>
<Provider Name="Keycloak" Documentation="https://www.keycloak.org/getting-started/getting-started-docker"> <Provider Name="Keycloak" Documentation="https://www.keycloak.org/getting-started/getting-started-docker">

Loading…
Cancel
Save