OIDC improvements

This commit is contained in:
Shaun Walker 2022-03-16 17:28:32 -04:00
parent 5901365e0e
commit 39dfc00693
5 changed files with 110 additions and 13 deletions

View File

@ -89,7 +89,11 @@ namespace Oqtane.Extensions
private static async Task OnTokenValidated(TokenValidatedContext context)
{
var email = context.Principal.Identity.Name;
var email = context.Principal.FindFirstValue(ClaimTypes.Email);
var providerKey = context.Principal.FindFirstValue(ClaimTypes.NameIdentifier);
var loginProvider = context.HttpContext.GetAlias().SiteSettings["OpenIdConnectOptions:Authority"];
var _logger = context.HttpContext.RequestServices.GetRequiredService<ILogManager>();
if (email != null)
{
var _identityUserManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>();
@ -107,6 +111,9 @@ namespace Oqtane.Extensions
var result = await _identityUserManager.CreateAsync(identityuser, DateTime.UtcNow.ToString("yyyy-MMM-dd-HH-mm-ss"));
if (result.Succeeded)
{
// add user login
await _identityUserManager.AddLoginAsync(identityuser, new UserLoginInfo(loginProvider, providerKey, ""));
user = new User();
user.SiteId = context.HttpContext.GetAlias().SiteId;
user.Username = email;
@ -157,13 +164,37 @@ namespace Oqtane.Extensions
}
else
{
email = identityuser.UserName;
var logins = await _identityUserManager.GetLoginsAsync(identityuser);
var login = logins.FirstOrDefault(item => item.LoginProvider == loginProvider);
if (login != null)
{
if (login.ProviderKey == providerKey)
{
user = _users.GetUser(identityuser.UserName);
}
else
{
// provider keys do not match
_logger.Log(LogLevel.Error, nameof(OqtaneSiteAuthenticationBuilderExtensions), Enums.LogFunction.Security, "OpenId Connect Server Provider Key Does Not Match For User {Email}", email);
}
}
else
{
// add user login
await _identityUserManager.AddLoginAsync(identityuser, new UserLoginInfo(loginProvider, providerKey, identityuser.UserName));
user = _users.GetUser(identityuser.UserName);
}
}
// add claims to principal
user = _users.GetUser(email);
if (user != null)
{
// update user
user.LastLoginOn = DateTime.UtcNow;
user.LastIPAddress = context.HttpContext.Connection.RemoteIpAddress.ToString();
_users.UpdateUser(user);
_logger.Log(LogLevel.Information, nameof(OqtaneSiteAuthenticationBuilderExtensions), Enums.LogFunction.Security, "User Login Successful {Username}", user.Username);
var principal = (ClaimsIdentity)context.Principal.Identity;
// remove the name claim if it exists in the principal
@ -181,8 +212,7 @@ namespace Oqtane.Extensions
}
else
{
var _logger = context.HttpContext.RequestServices.GetRequiredService<ILogManager>();
_logger.Log(LogLevel.Information, "OqtaneSiteAuthenticationBuilderExtensions", Enums.LogFunction.Security, "OpenId Connect Server Did Not Return An Email For User");
_logger.Log(LogLevel.Information, nameof(OqtaneSiteAuthenticationBuilderExtensions), Enums.LogFunction.Security, "OpenId Connect Server Did Not Return An Email Claim");
}
}

View File

@ -34,17 +34,17 @@ namespace Oqtane.Infrastructure
public void Log(LogLevel level, object @class, LogFunction function, string message, params object[] args)
{
Log(-1, level, @class.GetType().AssemblyQualifiedName, function, null, message, args);
Log(-1, level, @class, function, null, message, args);
}
public void Log(LogLevel level, object @class, LogFunction function, Exception exception, string message, params object[] args)
{
Log(-1, level, @class.GetType().AssemblyQualifiedName, function, exception, message, args);
Log(-1, level, @class, function, exception, message, args);
}
public void Log(int siteId, LogLevel level, object @class, LogFunction function, string message, params object[] args)
{
Log(siteId, level, @class.GetType().AssemblyQualifiedName, function, null, message, args);
Log(siteId, level, @class, function, null, message, args);
}
public void Log(int siteId, LogLevel level, object @class, LogFunction function, Exception exception, string message, params object[] args)
@ -80,8 +80,8 @@ namespace Oqtane.Infrastructure
}
}
Type type = Type.GetType(@class.ToString());
if (type != null)
Type type = @class.GetType();
if (type != null && type != typeof(string))
{
log.Category = type.AssemblyQualifiedName;
log.Feature = Utilities.GetTypeNameLastSegment(log.Category, 0);

View File

@ -0,0 +1,41 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Migrations.Operations;
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
using Oqtane.Databases.Interfaces;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Oqtane.Migrations.EntityBuilders
{
public class AspNetUserLoginsEntityBuilder : BaseEntityBuilder<AspNetUserLoginsEntityBuilder>
{
private const string _entityTableName = "AspNetUserLogins";
private readonly PrimaryKey<AspNetUserLoginsEntityBuilder> _primaryKey = new("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
private readonly ForeignKey<AspNetUserLoginsEntityBuilder> _foreignKey = new("FK_AspNetUserLogins_AspNetUsers_UserId", x => x.UserId, "AspNetUsers", "Id", ReferentialAction.Cascade);
public AspNetUserLoginsEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
{
EntityTableName = _entityTableName;
PrimaryKey = _primaryKey;
ForeignKeys.Add(_foreignKey);
}
protected override AspNetUserLoginsEntityBuilder BuildTable(ColumnsBuilder table)
{
LoginProvider = AddStringColumn(table, "LoginProvider", 450);
ProviderKey = AddStringColumn(table, "ProviderKey", 450);
ProviderDisplayName = AddMaxStringColumn(table, "ProviderDisplayName", true);
UserId = AddStringColumn(table, "UserId", 450);
return this;
}
public OperationBuilder<AddColumnOperation> LoginProvider { get; set; }
public OperationBuilder<AddColumnOperation> ProviderKey { get; set; }
public OperationBuilder<AddColumnOperation> ProviderDisplayName { get; set; }
public OperationBuilder<AddColumnOperation> UserId { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Oqtane.Databases.Interfaces;
using Oqtane.Migrations.EntityBuilders;
using Oqtane.Repository;
namespace Oqtane.Migrations.Tenant
{
[DbContext(typeof(TenantDBContext))]
[Migration("Tenant.03.01.00.03")]
public class AddAspNetUserLogins : MultiDatabaseMigration
{
public AddAspNetUserLogins(IDatabase database) : base(database)
{
}
protected override void Up(MigrationBuilder migrationBuilder)
{
var aspNetUserLoginsEntityBuilder = new AspNetUserLoginsEntityBuilder(migrationBuilder, ActiveDatabase);
aspNetUserLoginsEntityBuilder.Create();
}
protected override void Down(MigrationBuilder migrationBuilder)
{
var aspNetUserLoginsEntityBuilder = new AspNetUserLoginsEntityBuilder(migrationBuilder, ActiveDatabase);
aspNetUserLoginsEntityBuilder.Drop();
}
}
}

View File

@ -16,9 +16,6 @@ using Oqtane.Repository;
using Oqtane.Security;
using Oqtane.Shared;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using System.Threading.Tasks;
namespace Oqtane
{