Skip to content
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

Added additional OpenId Introspection/Revocation endpoints and PKCE to the OpenID Settings and Application UI pages #11903

Merged
merged 36 commits into from
Jul 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ed03571
Added introspection permisson checkbox to application page
May 2, 2022
e4d8b5c
Added revocation permission checkbox to application page
May 2, 2022
c034198
Merge branch 'OrchardCMS:main' into main
mcalasa May 2, 2022
3a7b7a8
Merged changes after resolving conflict when fetching upstream
mcalasa May 23, 2022
662456d
Added back the introspection and revocation after fetching the upstre…
mcalasa May 24, 2022
d059da8
Merge branch 'OrchardCMS:main' into main
mcalasa May 24, 2022
36ce483
Merge branch 'main' of https://github.com/mcalasa/OrchardCore
mcalasa May 24, 2022
59c77d2
Merge branch 'OrchardCMS:main' into main
mcalasa May 30, 2022
1e690e2
Merge branch 'OrchardCMS:main' into main
mcalasa May 31, 2022
9926f98
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 5, 2022
3424679
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 6, 2022
5731ca7
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 9, 2022
404f2af
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 11, 2022
2e332c9
Added PKCE to the server settings
mcalasa Jun 12, 2022
2cf0f95
Merge branch 'main' of https://github.com/mcalasa/OrchardCore
mcalasa Jun 12, 2022
b3af2f5
Added PKCE to application settings
mcalasa Jun 12, 2022
3c62295
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 16, 2022
6193b65
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 18, 2022
b14c78f
Added PKCE to deployment and recipes. Also added note for the PKCE …
mcalasa Jun 21, 2022
429dd1e
Merge branch 'main' of https://github.com/mcalasa/OrchardCore
mcalasa Jun 21, 2022
1b975ae
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 22, 2022
66f977c
Merge branch 'OrchardCMS:main' into main
mcalasa Jun 25, 2022
adaab8a
Added RequireProofKeyForCodeExchange to fix failing test
mcalasa Jun 26, 2022
9a8818f
Merge branch 'main' of https://github.com/mcalasa/OrchardCore
mcalasa Jun 26, 2022
a65d7db
Update src/OrchardCore.Modules/OrchardCore.OpenId/Configuration/OpenI…
mcalasa Jul 4, 2022
9c6bdd9
Removed extra lines
mcalasa Jul 4, 2022
50623fa
Merge branch 'main' of https://github.com/mcalasa/OrchardCore
mcalasa Jul 4, 2022
e904523
Renamed 'RequirePkce' to 'RequireProofKeyForCodeExchange' for consist…
mcalasa Jul 4, 2022
fa9941f
Reversed the formatting and renamed Require Pkce to Require Proof Key…
mcalasa Jul 4, 2022
ff787a5
Merge branch 'OrchardCMS:main' into main
mcalasa Jul 5, 2022
8f7bbbb
Removed file
mcalasa Jul 5, 2022
0a1ef8e
Reverted file
mcalasa Jul 5, 2022
a58c711
Added a space after each if block
mcalasa Jul 5, 2022
1b30b45
Changed the text for clarification of its inteneded use
mcalasa Jul 5, 2022
de7324a
Removed unwanted whitespace
mcalasa Jul 8, 2022
8f075aa
Removed the unnecessary comma and update the code comment stating tha…
mcalasa Jul 8, 2022
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 @@ -79,19 +79,32 @@ public void Configure(OpenIddictServerOptions options)
{
options.AuthorizationEndpointUris.Add(new Uri(settings.AuthorizationEndpointPath.Value, UriKind.Relative));
}

if (settings.LogoutEndpointPath.HasValue)
{
options.LogoutEndpointUris.Add(new Uri(settings.LogoutEndpointPath.Value, UriKind.Relative));
}

if (settings.TokenEndpointPath.HasValue)
{
options.TokenEndpointUris.Add(new Uri(settings.TokenEndpointPath.Value, UriKind.Relative));
}

if (settings.UserinfoEndpointPath.HasValue)
{
options.UserinfoEndpointUris.Add(new Uri(settings.UserinfoEndpointPath.Value, UriKind.Relative));
}

if (settings.IntrospectionEndpointPath.HasValue)
mcalasa marked this conversation as resolved.
Show resolved Hide resolved
{
options.IntrospectionEndpointUris.Add(new Uri(settings.IntrospectionEndpointPath.Value, UriKind.Relative));
}

if (settings.RevocationEndpointPath.HasValue)
{
options.RevocationEndpointUris.Add(new Uri(settings.RevocationEndpointPath.Value, UriKind.Relative));
}

// For now, response types and response modes are not directly
// configurable and are inferred from the selected flows.
if (settings.AllowAuthorizationCodeFlow)
Expand All @@ -106,10 +119,12 @@ public void Configure(OpenIddictServerOptions options)

options.ResponseTypes.Add(ResponseTypes.Code);
}

if (settings.AllowClientCredentialsFlow)
{
options.GrantTypes.Add(GrantTypes.ClientCredentials);
}

if (settings.AllowHybridFlow)
{
options.CodeChallengeMethods.Add(CodeChallengeMethods.Sha256);
Expand All @@ -124,6 +139,7 @@ public void Configure(OpenIddictServerOptions options)
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.IdToken + ' ' + ResponseTypes.Token);
options.ResponseTypes.Add(ResponseTypes.Code + ' ' + ResponseTypes.Token);
}

if (settings.AllowImplicitFlow)
{
options.GrantTypes.Add(GrantTypes.Implicit);
Expand All @@ -135,17 +151,21 @@ public void Configure(OpenIddictServerOptions options)
options.ResponseTypes.Add(ResponseTypes.IdToken + ' ' + ResponseTypes.Token);
options.ResponseTypes.Add(ResponseTypes.Token);
}

if (settings.AllowPasswordFlow)
{
options.GrantTypes.Add(GrantTypes.Password);
}

if (settings.AllowRefreshTokenFlow)
{
options.GrantTypes.Add(GrantTypes.RefreshToken);

options.Scopes.Add(Scopes.OfflineAccess);
}

options.RequireProofKeyForCodeExchange = settings.RequireProofKeyForCodeExchange;

options.Scopes.Add(Scopes.Email);
options.Scopes.Add(Scopes.Phone);
options.Scopes.Add(Scopes.Profile);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,11 @@ public async Task<IActionResult> Create(CreateOpenIdApplicationViewModel model,
AllowClientCredentialsFlow = model.AllowClientCredentialsFlow,
AllowHybridFlow = model.AllowHybridFlow,
AllowImplicitFlow = model.AllowImplicitFlow,
AllowIntrospectionEndpoint = model.AllowIntrospectionEndpoint,
AllowLogoutEndpoint = model.AllowLogoutEndpoint,
AllowPasswordFlow = model.AllowPasswordFlow,
AllowRefreshTokenFlow = model.AllowRefreshTokenFlow,
AllowRevocationEndpoint = model.AllowRevocationEndpoint,
ClientId = model.ClientId,
ClientSecret = model.ClientSecret,
ConsentType = model.ConsentType,
Expand All @@ -174,7 +176,8 @@ public async Task<IActionResult> Create(CreateOpenIdApplicationViewModel model,
RedirectUris = model.RedirectUris,
Roles = model.RoleEntries.Where(x => x.Selected).Select(x => x.Name).ToArray(),
Scopes = model.ScopeEntries.Where(x => x.Selected).Select(x => x.Name).ToArray(),
Type = model.Type
Type = model.Type,
RequireProofKeyForCodeExchange = model.RequireProofKeyForCodeExchange
};

await _applicationManager.UpdateDescriptorFromSettings(settings);
Expand All @@ -201,6 +204,7 @@ public async Task<IActionResult> Edit(string id, string returnUrl = null)
}

ValueTask<bool> HasPermissionAsync(string permission) => _applicationManager.HasPermissionAsync(application, permission);
ValueTask<bool> HasRequirementAsync(string requirement) => _applicationManager.HasRequirementAsync(application, requirement);

var model = new EditOpenIdApplicationViewModel
{
Expand All @@ -226,13 +230,16 @@ await HasPermissionAsync(OpenIddictConstants.Permissions.ResponseTypes.Token)),
AllowPasswordFlow = await HasPermissionAsync(OpenIddictConstants.Permissions.GrantTypes.Password),
AllowRefreshTokenFlow = await HasPermissionAsync(OpenIddictConstants.Permissions.GrantTypes.RefreshToken),
AllowLogoutEndpoint = await HasPermissionAsync(OpenIddictConstants.Permissions.Endpoints.Logout),
AllowIntrospectionEndpoint = await HasPermissionAsync(OpenIddictConstants.Permissions.Endpoints.Introspection),
AllowRevocationEndpoint = await HasPermissionAsync(OpenIddictConstants.Permissions.Endpoints.Revocation),
ClientId = await _applicationManager.GetClientIdAsync(application),
ConsentType = await _applicationManager.GetConsentTypeAsync(application),
DisplayName = await _applicationManager.GetDisplayNameAsync(application),
Id = await _applicationManager.GetPhysicalIdAsync(application),
PostLogoutRedirectUris = string.Join(" ", await _applicationManager.GetPostLogoutRedirectUrisAsync(application)),
RedirectUris = string.Join(" ", await _applicationManager.GetRedirectUrisAsync(application)),
Type = await _applicationManager.GetClientTypeAsync(application)
Type = await _applicationManager.GetClientTypeAsync(application),
RequireProofKeyForCodeExchange = await HasRequirementAsync(OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange)
};

var roleService = HttpContext.RequestServices?.GetService<IRoleService>();
Expand Down Expand Up @@ -322,9 +329,11 @@ await _applicationManager.GetIdAsync(application), StringComparison.Ordinal))
AllowClientCredentialsFlow = model.AllowClientCredentialsFlow,
AllowHybridFlow = model.AllowHybridFlow,
AllowImplicitFlow = model.AllowImplicitFlow,
AllowIntrospectionEndpoint = model.AllowIntrospectionEndpoint,
AllowLogoutEndpoint = model.AllowLogoutEndpoint,
AllowPasswordFlow = model.AllowPasswordFlow,
AllowRefreshTokenFlow = model.AllowRefreshTokenFlow,
AllowRevocationEndpoint = model.AllowRevocationEndpoint,
ClientId = model.ClientId,
ClientSecret = model.ClientSecret,
ConsentType = model.ConsentType,
Expand All @@ -333,7 +342,8 @@ await _applicationManager.GetIdAsync(application), StringComparison.Ordinal))
RedirectUris = model.RedirectUris,
Roles = model.RoleEntries.Where(x => x.Selected).Select(x => x.Name).ToArray(),
Scopes = model.ScopeEntries.Where(x => x.Selected).Select(x => x.Name).ToArray(),
Type = model.Type
Type = model.Type,
RequireProofKeyForCodeExchange = model.RequireProofKeyForCodeExchange
};

await _applicationManager.UpdateDescriptorFromSettings(settings, application);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlan
EnableLogoutEndpoint = !string.IsNullOrWhiteSpace(settings.LogoutEndpointPath),
EnableTokenEndpoint = !string.IsNullOrWhiteSpace(settings.TokenEndpointPath),
EnableUserInfoEndpoint = !string.IsNullOrWhiteSpace(settings.UserinfoEndpointPath),
EnableIntrospectionEndpoint = !string.IsNullOrWhiteSpace(settings.IntrospectionEndpointPath),
EnableRevocationEndpoint = !string.IsNullOrWhiteSpace(settings.RevocationEndpointPath),

AllowAuthorizationCodeFlow = settings.AllowAuthorizationCodeFlow,
AllowClientCredentialsFlow = settings.AllowClientCredentialsFlow,
Expand All @@ -58,6 +60,7 @@ public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlan
DisableAccessTokenEncryption = settings.DisableAccessTokenEncryption,
DisableRollingRefreshTokens = settings.DisableRollingRefreshTokens,
UseReferenceAccessTokens = settings.UseReferenceAccessTokens,
RequireProofKeyForCodeExchange = settings.RequireProofKeyForCodeExchange,
};

// Use nameof(OpenIdServerSettings) as name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public override Task<IDisplayResult> EditAsync(OpenIdServerSettings settings, Bu
model.EnableLogoutEndpoint = settings.LogoutEndpointPath.HasValue;
model.EnableTokenEndpoint = settings.TokenEndpointPath.HasValue;
model.EnableUserInfoEndpoint = settings.UserinfoEndpointPath.HasValue;
model.EnableIntrospectionEndpoint = settings.IntrospectionEndpointPath.HasValue;
model.EnableRevocationEndpoint = settings.RevocationEndpointPath.HasValue;
model.AllowAuthorizationCodeFlow = settings.AllowAuthorizationCodeFlow;
model.AllowClientCredentialsFlow = settings.AllowClientCredentialsFlow;
Expand All @@ -46,6 +48,7 @@ public override Task<IDisplayResult> EditAsync(OpenIdServerSettings settings, Bu
model.DisableAccessTokenEncryption = settings.DisableAccessTokenEncryption;
model.DisableRollingRefreshTokens = settings.DisableRollingRefreshTokens;
model.UseReferenceAccessTokens = settings.UseReferenceAccessTokens;
model.RequireProofKeyForCodeExchange = settings.RequireProofKeyForCodeExchange;
foreach (var (certificate, location, name) in await _serverService.GetAvailableCertificatesAsync())
{
Expand Down Expand Up @@ -89,6 +92,10 @@ public override async Task<IDisplayResult> UpdateAsync(OpenIdServerSettings sett
new PathString("/connect/token") : PathString.Empty;
settings.UserinfoEndpointPath = model.EnableUserInfoEndpoint ?
new PathString("/connect/userinfo") : PathString.Empty;
settings.IntrospectionEndpointPath = model.EnableIntrospectionEndpoint ?
new PathString("/connect/introspect") : PathString.Empty;
settings.RevocationEndpointPath = model.EnableRevocationEndpoint ?
new PathString("/connect/revoke") : PathString.Empty;

settings.AllowAuthorizationCodeFlow = model.AllowAuthorizationCodeFlow;
settings.AllowClientCredentialsFlow = model.AllowClientCredentialsFlow;
Expand All @@ -100,6 +107,7 @@ public override async Task<IDisplayResult> UpdateAsync(OpenIdServerSettings sett
settings.DisableAccessTokenEncryption = model.DisableAccessTokenEncryption;
settings.DisableRollingRefreshTokens = model.DisableRollingRefreshTokens;
settings.UseReferenceAccessTokens = model.UseReferenceAccessTokens;
settings.RequireProofKeyForCodeExchange = model.RequireProofKeyForCodeExchange;

return await EditAsync(settings, context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ public class OpenIdApplicationSettings
public bool AllowHybridFlow { get; set; }
public bool AllowImplicitFlow { get; set; }
public bool AllowLogoutEndpoint { get; set; }
public bool AllowIntrospectionEndpoint { get; set; }
public bool AllowRevocationEndpoint { get; set; }
public bool RequireProofKeyForCodeExchange { get; set; }
}

internal static class OpenIdApplicationExtensions
Expand Down Expand Up @@ -158,6 +161,7 @@ public static async Task UpdateDescriptorFromSettings(this IOpenIdApplicationMan
descriptor.Permissions.Remove(OpenIddictConstants.Permissions.ResponseTypes.IdTokenToken);
descriptor.Permissions.Remove(OpenIddictConstants.Permissions.ResponseTypes.Token);
}

if (model.AllowHybridFlow)
{
descriptor.Permissions.Add(OpenIddictConstants.Permissions.ResponseTypes.CodeIdToken);
Expand All @@ -180,6 +184,33 @@ public static async Task UpdateDescriptorFromSettings(this IOpenIdApplicationMan
descriptor.Permissions.Remove(OpenIddictConstants.Permissions.ResponseTypes.CodeToken);
}

if (model.AllowIntrospectionEndpoint)
mcalasa marked this conversation as resolved.
Show resolved Hide resolved
{
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Introspection);
}
else
{
descriptor.Permissions.Remove(OpenIddictConstants.Permissions.Endpoints.Introspection);
}

if (model.AllowRevocationEndpoint)
{
descriptor.Permissions.Add(OpenIddictConstants.Permissions.Endpoints.Revocation);
}
else
{
descriptor.Permissions.Remove(OpenIddictConstants.Permissions.Endpoints.Revocation);
}

if (model.RequireProofKeyForCodeExchange)
{
descriptor.Requirements.Add(OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange);
}
else
{
descriptor.Requirements.Remove(OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange);
}

descriptor.Roles.Clear();

foreach (var role in model.Roles)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ public async Task ExecuteAsync(RecipeExecutionContext context)
AllowClientCredentialsFlow = model.AllowClientCredentialsFlow,
AllowHybridFlow = model.AllowHybridFlow,
AllowImplicitFlow = model.AllowImplicitFlow,
AllowIntrospectionEndpoint = model.AllowIntrospectionEndpoint,
AllowLogoutEndpoint = model.AllowLogoutEndpoint,
AllowPasswordFlow = model.AllowPasswordFlow,
AllowRefreshTokenFlow = model.AllowRefreshTokenFlow,
AllowRevocationEndpoint = model.AllowRevocationEndpoint,
ClientId = model.ClientId,
ClientSecret = model.ClientSecret,
ConsentType = model.ConsentType,
Expand All @@ -48,7 +50,8 @@ public async Task ExecuteAsync(RecipeExecutionContext context)
RedirectUris = model.RedirectUris,
Roles = model.RoleEntries.Select(x => x.Name).ToArray(),
Scopes = model.ScopeEntries.Select(x => x.Name).ToArray(),
Type = model.Type
Type = model.Type,
RequireProofKeyForCodeExchange = model.RequireProofKeyForCodeExchange,
};

await _applicationManager.UpdateDescriptorFromSettings(settings, app);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public class OpenIdApplicationStepModel
public bool AllowHybridFlow { get; set; }
public bool AllowImplicitFlow { get; set; }
public bool AllowLogoutEndpoint { get; set; }
public bool AllowIntrospectionEndpoint { get; set; }
public bool AllowRevocationEndpoint { get; set; }
public bool RequireProofKeyForCodeExchange { get; set; }

public class RoleEntry
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ public async Task ExecuteAsync(RecipeExecutionContext context)
new PathString("/connect/token") : PathString.Empty;
settings.UserinfoEndpointPath = model.EnableUserInfoEndpoint ?
new PathString("/connect/userinfo") : PathString.Empty;
settings.IntrospectionEndpointPath = model.EnableIntrospectionEndpoint ?
new PathString("/connect/introspect") : PathString.Empty;
settings.RevocationEndpointPath = model.EnableRevocationEndpoint ?
new PathString("/connect/revoke") : PathString.Empty;

settings.AllowAuthorizationCodeFlow = model.AllowAuthorizationCodeFlow;
settings.AllowClientCredentialsFlow = model.AllowClientCredentialsFlow;
Expand All @@ -58,6 +62,7 @@ public async Task ExecuteAsync(RecipeExecutionContext context)
settings.DisableAccessTokenEncryption = model.DisableAccessTokenEncryption;
settings.DisableRollingRefreshTokens = model.DisableRollingRefreshTokens;
settings.UseReferenceAccessTokens = model.UseReferenceAccessTokens;
settings.RequireProofKeyForCodeExchange = model.RequireProofKeyForCodeExchange;

await _serverService.UpdateSettingsAsync(settings);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ public class OpenIdServerSettingsStepModel
public bool EnableAuthorizationEndpoint { get; set; }
public bool EnableLogoutEndpoint { get; set; }
public bool EnableUserInfoEndpoint { get; set; }
public bool EnableIntrospectionEndpoint { get; set; }
public bool EnableRevocationEndpoint { get; set; }
public bool AllowPasswordFlow { get; set; }
public bool AllowClientCredentialsFlow { get; set; }
public bool AllowAuthorizationCodeFlow { get; set; }
public bool AllowRefreshTokenFlow { get; set; }
public bool AllowHybridFlow { get; set; }
public bool AllowImplicitFlow { get; set; }
public bool DisableRollingRefreshTokens { get; set; }
public bool RequireProofKeyForCodeExchange { get; set; }

public bool UseReferenceAccessTokens { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ private OpenIdServerSettings GetSettingsFromContainer(ISite container)
}

// If the OpenID server settings haven't been populated yet, the authorization,
// logout, token and userinfo endpoints are assumed to be enabled by default.
// logout, token, userinfo, introspection and revocation endpoints are assumed to be enabled by default.
// In this case, only the authorization code and refresh token flows are used.
return new OpenIdServerSettings
{
Expand All @@ -78,7 +78,9 @@ private OpenIdServerSettings GetSettingsFromContainer(ISite container)
AuthorizationEndpointPath = "/connect/authorize",
LogoutEndpointPath = "/connect/logout",
TokenEndpointPath = "/connect/token",
UserinfoEndpointPath = "/connect/userinfo"
UserinfoEndpointPath = "/connect/userinfo",
IntrospectionEndpointPath = "/connect/introspect",
RevocationEndpointPath = "/connect/revoke"
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public class OpenIdServerSettings

public PathString UserinfoEndpointPath { get; set; }

public PathString IntrospectionEndpointPath { get; set; }

public PathString RevocationEndpointPath { get; set; }

public bool AllowPasswordFlow { get; set; }
public bool AllowClientCredentialsFlow { get; set; }
public bool AllowAuthorizationCodeFlow { get; set; }
Expand All @@ -36,6 +40,8 @@ public class OpenIdServerSettings

public bool UseReferenceAccessTokens { get; set; }

public bool RequireProofKeyForCodeExchange { get; set; }

public enum TokenFormat
{
DataProtection = 0,
Expand Down
Loading