using System.IdentityModel.Claims; using System.Text.Json; using AspNet.Security.OAuth.Keycloak; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.OAuth; using Umbraco.Cms.Core.Services; using Umbraco.KeycloakShowcase.Web.Configuration; namespace Umbraco.KeycloakShowcase.Web.Extensions; public static class KeycloakAuthenticationExtension { public static IUmbracoBuilder AddBackOfficeKeycloakAuthentication(this IUmbracoBuilder builder) { var configuration = new KeycloakConfiguration(builder.Config); builder.AddBackOfficeExternalLogins(logins => { logins.AddBackOfficeLogin( backOfficeAuthenticationBuilder => { var schemeName = backOfficeAuthenticationBuilder.SchemeForBackOffice(KeycloakMemberExternalLoginProviderOptions.SchemeName); ArgumentNullException.ThrowIfNull(schemeName); backOfficeAuthenticationBuilder.AddKeycloak( schemeName, options => { options.BaseAddress = new Uri(configuration.BaseAddress); options.ClientId = configuration.ClientId; options.ClientSecret = configuration.ClientSecret; options.AccessType = KeycloakAuthenticationAccessType.Confidential; options.Realm = configuration.Realm; options.Version = new Version(configuration.Version ?? string.Empty); options.CallbackPath = configuration.CallbackPath; options.AuthorizationEndpoint = "https://auth.pokash.pl/realms/pokash/protocol/openid-connect/auth"; options.TokenEndpoint = "https://auth.pokash.pl/realms/pokash/protocol/openid-connect/token"; options.UserInformationEndpoint = "https://auth.pokash.pl/realms/pokash/protocol/openid-connect/userinfo"; options.SaveTokens = true; options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); options.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub"); options.ClaimActions.MapJsonKey(ClaimTypes.Name, "preferred_username"); options.ClaimActions.MapJsonKey(ClaimTypes.Email, "email"); options.Events = new OAuthEvents { OnCreatingTicket = async ctx => { var request = new HttpRequestMessage(HttpMethod.Get, ctx.Options.UserInformationEndpoint); request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", ctx.AccessToken); var response = await ctx.Backchannel.SendAsync(request, ctx.HttpContext.RequestAborted); response.EnsureSuccessStatusCode(); using var responseStream = await response.Content.ReadAsStreamAsync(); using var jsonDocument = await JsonDocument.ParseAsync(responseStream); var user = jsonDocument.RootElement; ctx.RunClaimActions(user); var userService = ctx.HttpContext.RequestServices.GetRequiredService(); var email = ctx.Principal?.FindFirst(ClaimTypes.Email)?.Value; var username = ctx.Principal?.FindFirst(ClaimTypes.Name)?.Value; if (!string.IsNullOrEmpty(email) && !string.IsNullOrEmpty(username)) { var existingUser = userService.GetByEmail(email); if (existingUser == null) { var newUser = userService.CreateUserWithIdentity(username, email); newUser.IsApproved = true; userService.Save(newUser); } else { existingUser.IsApproved = true; userService.Save(existingUser); } } } }; }); }); }); return builder; } }