Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ac27de6
commit 7046bd7
Showing
23 changed files
with
668 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Localization; | ||
using OrchardCore.Environment.Shell.Descriptor.Models; | ||
using OrchardCore.Modules; | ||
using OrchardCore.Navigation; | ||
|
||
namespace OrchardCore.Github | ||
{ | ||
[Feature(GithubConstants.Features.GithubAuthentication)] | ||
public class AdminMenuGithubLogin : INavigationProvider | ||
{ | ||
private readonly ShellDescriptor _shellDescriptor; | ||
|
||
public AdminMenuGithubLogin( | ||
IStringLocalizer<AdminMenuGithubLogin> localizer, | ||
ShellDescriptor shellDescriptor) | ||
{ | ||
T = localizer; | ||
_shellDescriptor = shellDescriptor; | ||
} | ||
|
||
public IStringLocalizer T { get; set; } | ||
|
||
public Task BuildNavigationAsync(string name, NavigationBuilder builder) | ||
{ | ||
if (String.Equals(name, "admin", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
builder.Add(T["Github"], "15", settings => settings | ||
.AddClass("github").Id("github") | ||
.Add(T["Github Authentication"], "10", client => client | ||
.Action("Index", "Admin", new { area = "OrchardCore.Settings", groupId = GithubConstants.Features.GithubAuthentication }) | ||
.Permission(Permissions.ManageGithubAuthentication) | ||
.LocalNav()) | ||
); | ||
} | ||
return Task.CompletedTask; | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/OrchardCore.Modules/OrchardCore.Github/Configuration/GithubDefaults.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace OrchardCore.Github.Configuration | ||
{ | ||
public class GithubDefaults | ||
{ | ||
public const string AuthenticationScheme = "Github"; | ||
public static readonly string DisplayName = "Github"; | ||
public static readonly string AuthorizationEndpoint = "https://github.com/login/oauth/authorize"; | ||
public static readonly string TokenEndpoint = "https://github.com/login/oauth/access_token"; | ||
public static readonly string UserInformationEndpoint = "https://api.github.com/user"; | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
src/OrchardCore.Modules/OrchardCore.Github/Configuration/GithubHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
using System.Net.Http; | ||
using System.Net.Http.Headers; | ||
using System.Security.Claims; | ||
using System.Text.Encodings.Web; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Authentication.OAuth; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
|
||
namespace OrchardCore.Github.Configuration | ||
{ | ||
public class GithubHandler : OAuthHandler<GithubOptions> | ||
{ | ||
public GithubHandler(IOptionsMonitor<GithubOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) | ||
: base(options, logger, encoder, clock) | ||
{ } | ||
|
||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) | ||
{ | ||
var request = new HttpRequestMessage(HttpMethod.Get, Options.UserInformationEndpoint); | ||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.AccessToken); | ||
|
||
var response = await Backchannel.SendAsync(request, Context.RequestAborted); | ||
if (!response.IsSuccessStatusCode) | ||
{ | ||
throw new HttpRequestException($"An error occurred when retrieving Github user information ({response.StatusCode}). Please check if the authentication information is correct in the corresponding Github Application."); | ||
} | ||
|
||
var payload = JObject.Parse(await response.Content.ReadAsStringAsync()); | ||
|
||
var context = new OAuthCreatingTicketContext(new ClaimsPrincipal(identity), properties, Context, Scheme, Options, Backchannel, tokens, payload); | ||
context.RunClaimActions(); | ||
|
||
await Events.CreatingTicket(context); | ||
return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); | ||
} | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
src/OrchardCore.Modules/OrchardCore.Github/Configuration/GithubOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using System.Security.Claims; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.Authentication.OAuth; | ||
using Microsoft.AspNetCore.Http; | ||
|
||
namespace OrchardCore.Github.Configuration | ||
{ | ||
/// <summary> | ||
/// Configuration options for <see cref="MicrosoftAccountHandler"/>. | ||
/// </summary> | ||
public class GithubOptions : OAuthOptions | ||
{ | ||
/// <summary> | ||
/// Initializes a new <see cref="MicrosoftAccountOptions"/>. | ||
/// </summary> | ||
public GithubOptions() | ||
{ | ||
CallbackPath = new PathString("/signin-github"); | ||
AuthorizationEndpoint = GithubDefaults.AuthorizationEndpoint; | ||
TokenEndpoint = GithubDefaults.TokenEndpoint; | ||
UserInformationEndpoint = GithubDefaults.UserInformationEndpoint; | ||
|
||
|
||
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id"); | ||
ClaimActions.MapJsonKey("name", "login"); | ||
ClaimActions.MapJsonKey(ClaimTypes.Email, "email", ClaimValueTypes.Email); | ||
ClaimActions.MapJsonKey("url", "url"); | ||
} | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
src/OrchardCore.Modules/OrchardCore.Github/Configuration/GithubOptionsConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
using System; | ||
using System.ComponentModel.DataAnnotations; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Authentication; | ||
using Microsoft.AspNetCore.DataProtection; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.Extensions.Options; | ||
using OrchardCore.Modules; | ||
using OrchardCore.Github.Services; | ||
using OrchardCore.Github.Settings; | ||
|
||
namespace OrchardCore.Github.Configuration | ||
{ | ||
public class GithubOptionsConfiguration : | ||
IConfigureOptions<AuthenticationOptions>, | ||
IConfigureNamedOptions<GithubOptions> | ||
{ | ||
private readonly IGithubAuthenticationService _githubAuthenticationService; | ||
private readonly IDataProtectionProvider _dataProtectionProvider; | ||
private readonly ILogger<GithubOptionsConfiguration> _logger; | ||
|
||
public GithubOptionsConfiguration( | ||
IGithubAuthenticationService githubAuthenticationService, | ||
IDataProtectionProvider dataProtectionProvider, | ||
ILogger<GithubOptionsConfiguration> logger) | ||
{ | ||
_githubAuthenticationService = githubAuthenticationService; | ||
_dataProtectionProvider = dataProtectionProvider; | ||
_logger = logger; | ||
} | ||
|
||
public void Configure(AuthenticationOptions options) | ||
{ | ||
var settings = GetGithubAuthenticationSettingsAsync().GetAwaiter().GetResult(); | ||
if (settings == null) | ||
{ | ||
return; | ||
} | ||
|
||
if (_githubAuthenticationService.ValidateSettings(settings).Any()) | ||
return; | ||
|
||
// Register the OpenID Connect client handler in the authentication handlers collection. | ||
options.AddScheme(GithubDefaults.AuthenticationScheme, builder => | ||
{ | ||
builder.DisplayName = "Github"; | ||
builder.HandlerType = typeof(GithubHandler); | ||
}); | ||
} | ||
|
||
public void Configure(string name, GithubOptions options) | ||
{ | ||
// Ignore OpenID Connect client handler instances that don't correspond to the instance managed by the OpenID module. | ||
if (!string.Equals(name, GithubDefaults.AuthenticationScheme, StringComparison.Ordinal)) | ||
{ | ||
return; | ||
} | ||
|
||
var loginSettings = GetGithubAuthenticationSettingsAsync().GetAwaiter().GetResult(); | ||
|
||
options.ClientId = loginSettings?.ClientID ?? string.Empty; | ||
|
||
try | ||
{ | ||
options.ClientSecret = _dataProtectionProvider.CreateProtector(GithubConstants.Features.GithubAuthentication).Unprotect(loginSettings.ClientSecret); | ||
} | ||
catch | ||
{ | ||
_logger.LogError("The Microsoft Account secret key could not be decrypted. It may have been encrypted using a different key."); | ||
} | ||
|
||
if (loginSettings.CallbackPath.HasValue) | ||
{ | ||
options.CallbackPath = loginSettings.CallbackPath; | ||
} | ||
} | ||
|
||
public void Configure(GithubOptions options) => Debug.Fail("This infrastructure method shouldn't be called."); | ||
|
||
private async Task<GithubAuthenticationSettings> GetGithubAuthenticationSettingsAsync() | ||
{ | ||
var settings = await _githubAuthenticationService.GetSettingsAsync(); | ||
if ((_githubAuthenticationService.ValidateSettings(settings)).Any(result => result != ValidationResult.Success)) | ||
{ | ||
_logger.LogWarning("The Microsoft Account Authentication is not correctly configured."); | ||
|
||
return null; | ||
} | ||
return settings; | ||
} | ||
} | ||
} |
90 changes: 90 additions & 0 deletions
90
...chardCore.Modules/OrchardCore.Github/Drivers/GithubAuthenticationSettingsDisplayDriver.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.DataProtection; | ||
using Microsoft.AspNetCore.Http; | ||
using OrchardCore.DisplayManagement.Entities; | ||
using OrchardCore.DisplayManagement.Handlers; | ||
using OrchardCore.DisplayManagement.Views; | ||
using OrchardCore.Environment.Shell; | ||
using OrchardCore.Github.Settings; | ||
using OrchardCore.Github.ViewModels; | ||
using OrchardCore.Settings; | ||
|
||
namespace OrchardCore.Github.Drivers | ||
{ | ||
public class GithubAuthenticationSettingsDisplayDriver : SectionDisplayDriver<ISite, GithubAuthenticationSettings> | ||
{ | ||
private readonly IAuthorizationService _authorizationService; | ||
private readonly IDataProtectionProvider _dataProtectionProvider; | ||
private readonly IHttpContextAccessor _httpContextAccessor; | ||
private readonly IShellHost _shellHost; | ||
private readonly ShellSettings _shellSettings; | ||
|
||
public GithubAuthenticationSettingsDisplayDriver( | ||
IAuthorizationService authorizationService, | ||
IDataProtectionProvider dataProtectionProvider, | ||
IHttpContextAccessor httpContextAccessor, | ||
IShellHost shellHost, | ||
ShellSettings shellSettings) | ||
{ | ||
_authorizationService = authorizationService; | ||
_dataProtectionProvider = dataProtectionProvider; | ||
_httpContextAccessor = httpContextAccessor; | ||
_shellHost = shellHost; | ||
_shellSettings = shellSettings; | ||
} | ||
|
||
public override async Task<IDisplayResult> EditAsync(GithubAuthenticationSettings settings, BuildEditorContext context) | ||
{ | ||
var user = _httpContextAccessor.HttpContext?.User; | ||
if (user == null || !await _authorizationService.AuthorizeAsync(user, Permissions.ManageGithubAuthentication)) | ||
{ | ||
return null; | ||
} | ||
|
||
return Initialize<GithubAuthenticationSettingsViewModel>("GithubAuthenticationSettings_Edit", model => | ||
{ | ||
model.ClientID = settings.ClientID; | ||
if (!string.IsNullOrWhiteSpace(settings.ClientSecret)) | ||
{ | ||
var protector = _dataProtectionProvider.CreateProtector(GithubConstants.Features.GithubAuthentication); | ||
model.ClientSecret = protector.Unprotect(settings.ClientSecret); | ||
} | ||
else | ||
{ | ||
model.ClientSecret = string.Empty; | ||
} | ||
if (settings.CallbackPath.HasValue) | ||
{ | ||
model.CallbackUrl = settings.CallbackPath; | ||
} | ||
}).Location("Content:5").OnGroup(GithubConstants.Features.GithubAuthentication); | ||
} | ||
|
||
public override async Task<IDisplayResult> UpdateAsync(GithubAuthenticationSettings settings, BuildEditorContext context) | ||
{ | ||
if (context.GroupId == GithubConstants.Features.GithubAuthentication) | ||
{ | ||
var user = _httpContextAccessor.HttpContext?.User; | ||
if (user == null || !await _authorizationService.AuthorizeAsync(user, Permissions.ManageGithubAuthentication)) | ||
{ | ||
return null; | ||
} | ||
|
||
var model = new GithubAuthenticationSettingsViewModel(); | ||
await context.Updater.TryUpdateModelAsync(model, Prefix); | ||
|
||
if (context.Updater.ModelState.IsValid) | ||
{ | ||
var protector = _dataProtectionProvider.CreateProtector(GithubConstants.Features.GithubAuthentication); | ||
|
||
settings.ClientID = model.ClientID; | ||
settings.ClientSecret = protector.Protect(model.ClientSecret); | ||
settings.CallbackPath = model.CallbackUrl; | ||
await _shellHost.ReloadShellContextAsync(_shellSettings); | ||
} | ||
} | ||
return await EditAsync(settings, context); | ||
} | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/OrchardCore.Modules/OrchardCore.Github/GithubConstants.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
namespace OrchardCore.Github | ||
{ | ||
public static class GithubConstants | ||
{ | ||
public static class Features | ||
{ | ||
public const string GithubAuthentication = "OrchardCore.Github.Authentication"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
using OrchardCore.Modules.Manifest; | ||
using OrchardCore.Github; | ||
|
||
[assembly: Module( | ||
Name = "Github", | ||
Author = "The Orchard Team", | ||
Website = "https://orchardproject.net", | ||
Version = "2.0.0", | ||
Category = "Github" | ||
)] | ||
|
||
[assembly: Feature( | ||
Id = GithubConstants.Features.GithubAuthentication, | ||
Name = "Github Authentication", | ||
Category = "Github", | ||
Description = "Authenticates users with their Github Account." | ||
)] |
Oops, something went wrong.