Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Multifactor.Radius.Adapter.v2.Application.Cache;

public interface IAuthenticatedClientCache
{
void SetCache(string? callingStationId, string userName, string clientName, TimeSpan lifetime);
bool TryHitCache(string? callingStationId, string userName, string clientName, TimeSpan lifetime);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace Multifactor.Radius.Adapter.v2.Services.Cache;
namespace Multifactor.Radius.Adapter.v2.Application.Cache;

public interface ICacheService
{
//TODO разделить на несколько
void Set<T>(string key, T value, DateTimeOffset expirationDate);
void Set<T>(string key, T value);
bool TryGetValue<T>(string key, out T? value);
void Remove(string key);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Multifactor.Radius.Adapter.v2.Core
namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models
{
public class ApplicationVariables
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Multifactor.Radius.Adapter.v2.Core.Auth
namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models.Enum
{
[Flags]
public enum AuthenticationSource
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это не конфиг, а Core

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace Multifactor.Radius.Adapter.v2.Core.Auth.PreAuthMode
namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models.Enum
{
[Flags]
public enum PreAuthMode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это не конфиг, а Core. Если бы тут был DTO для чтения из конфига - тогда ладно

{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
//Please see licence at
//https://github.com/MultifactorLab/multifactor-radius-adapter/blob/main/LICENSE.md

namespace Multifactor.Radius.Adapter.v2.Core.MultifactorApi.PrivacyMode;
namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models.Enum;

/// <summary>
/// User information disclosure mode
/// </summary>
[Flags]
public enum PrivacyMode
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Net;
using Multifactor.Radius.Adapter.v2.Application.Configuration.Models.Enum;
using NetTools;

namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models;

public interface IClientConfiguration
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Почему некоторые сеттеры используются, а остальные - нет? Зачем в интерфейсе допускать сеттер? Нашел только один вызов - в тесте. Вывод: сеттер надо убрать

public string Name { get; set; }

public string MultifactorNasIdentifier { get; set; }
public string MultifactorSharedSecret { get; set; }
public IReadOnlyList<string> SignUpGroups { get; set; }
public bool BypassSecondFactorWhenApiUnreachable { get; set; }
public AuthenticationSource FirstFactorAuthenticationSource { get; set; }
public IPEndPoint AdapterClientEndpoint { get; set; }

public IPAddress? RadiusClientIp { get; set; }
public string RadiusClientNasIdentifier { get; set; }
public string RadiusSharedSecret { get; set; }
public IPEndPoint[] NpsServerEndpoints { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Раз уж это интерфейс, все свойства должн быть немутабельными. Массив мутабелен. Лучше заменить на IReadOnlyList, например

public TimeSpan NpsServerTimeout { get; set; }

public (PrivacyMode PrivacyMode, string[] PrivacyFields) Privacy { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Неудачная сигнатура, лучше сделать record. Кроме того, массив можно мутировать снаружи


public PreAuthMode? PreAuthenticationMethod { get; set; }
public TimeSpan AuthenticationCacheLifetime { get; set; }
public (int min, int max)? InvalidCredentialDelay { get; set; }
public string? CallingStationIdAttribute { get; set; } //TODO not used
public IReadOnlyList<IPAddressRange> IpWhiteList { get; set; }

public IReadOnlyList<ILdapServerConfiguration>? LdapServers { get; set; }
public IReadOnlyDictionary<string, IRadiusReplyAttribute[]>? ReplyAttributes { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Multifactor.Core.Ldap.Name;

namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models;

public interface ILdapServerConfiguration
{
public string ConnectionString { get; init; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А тут вообще иниты... зачем?

public string Username { get; init; }
public string Password { get; init; }
public int BindTimeoutSeconds{ get; init; }
public IReadOnlyList<DistinguishedName> AccessGroups { get; init; }
public IReadOnlyList<DistinguishedName> SecondFaGroups { get; init; }
public IReadOnlyList<DistinguishedName> SecondFaBypassGroups { get; init; }
public bool LoadNestedGroups { get; init; }
public IReadOnlyList<DistinguishedName> NestedGroupsBaseDns { get; init; }
public IReadOnlyList<DistinguishedName> AuthenticationCacheGroups { get; init; }
public IReadOnlyList<string> PhoneAttributes { get; init; }
public string IdentityAttribute { get; init; }
public bool RequiresUpn { get; init; }
public bool TrustedDomainsEnabled { get; init; }
public bool AlternativeSuffixesEnabled { get; init; }
public IReadOnlyList<string> IncludedDomains { get; init; }//TODO not used
public IReadOnlyList<string> ExcludedDomains { get; init; }//TODO not used
public IReadOnlyList<string> IncludedSuffixes { get; init; }
public IReadOnlyList<string> ExcludedSuffixes { get; init; }
public IReadOnlyList<string> BypassSecondFactorWhenApiUnreachableGroups { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models;

public interface IRadiusReplyAttribute
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

опять сеттеры

public string Name { get; set; }
public object Value { get; set; }
public IReadOnlyList<string> UserGroupCondition { get; set; }
public IReadOnlyList<string> UserNameCondition { get; set; }
public bool Sufficient { get; set; }
public bool IsMemberOf => Name?.ToLower() == "memberof";
public bool FromLdap => !string.IsNullOrWhiteSpace(Name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Net;

namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models;

public interface IRootConfiguration
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

зачем тут везде сеттеры? Это же интерфейс. Иначе зачем интерфейс?


IReadOnlyList<Uri> MultifactorApiUrls { get; set; }
string? MultifactorApiProxy { get; set; }
TimeSpan MultifactorApiTimeout { get; set; }
IPEndPoint? AdapterServerEndpoint { get; set; }
string LoggingLevel { get; set; }
string? LoggingFormat { get; set; }
bool SyslogUseTls { get; set; }
string? SyslogServer { get; set; }
string? SyslogFormat { get; set; }
string? SyslogFacility { get; set; }
string SyslogAppName { get; set; }
string? SyslogFramer { get; set; }
string? SyslogOutputTemplate { get; set; }

string? ConsoleLogOutputTemplate { get; set; }
string? FileLogOutputTemplate { get; set; }
int LogFileMaxSizeBytes { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Net;

namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models;

public class ServiceConfiguration
{
public required IRootConfiguration RootConfiguration { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

зачем set? init + required

public required IReadOnlyList<IClientConfiguration> ClientsConfigurations { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set не нужен

public IClientConfiguration? GetClientConfiguration(string nasIdentifier) => ClientsConfigurations.FirstOrDefault(config => config.RadiusClientNasIdentifier == nasIdentifier);
public IClientConfiguration? GetClientConfiguration(IPAddress ip)
{
if (SingleClientMode)
{
return ClientsConfigurations.FirstOrDefault();
}

return ClientsConfigurations.FirstOrDefault(config =>
config.RadiusClientIp != null && config.RadiusClientIp.Equals(ip));

}
public bool SingleClientMode { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Аналогично. Получился мутабельный снаружи объект и хрупкий код

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Multifactor.Radius.Adapter.v2.Application.Configuration.Models;
using Multifactor.Radius.Adapter.v2.Application.Features.Multifactor;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline.AccessChallenge;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline.FirstFactor;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline.FirstFactor.BindNameFormat;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline.Interfaces;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline.Steps;
using Multifactor.Radius.Adapter.v2.Application.Features.Radius.Services;

namespace Multifactor.Radius.Adapter.v2.Application.Extensions;

public static class ApplicationExtensions
{
public static void AddApplicationVariables(this IServiceCollection services)
{
var appVars = new ApplicationVariables
{
AppPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory),
AppVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString(),
StartedAt = DateTime.Now
};
services.AddSingleton(appVars);
}

private static void AddLdapBindNameFormation(IServiceCollection services)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Предлагаю эти вещи раскидать по модулям, чтобы сделать честными фичами и избавиться от DI hell

{
services.AddSingleton<ILdapBindNameFormatterProvider, LdapBindNameFormatterProvider>();
services.AddTransient<ILdapBindNameFormatter, ActiveDirectoryFormatter>();
services.AddTransient<ILdapBindNameFormatter, FreeIpaFormatter>();
services.AddTransient<ILdapBindNameFormatter, MultiDirectoryFormatter>();
services.AddTransient<ILdapBindNameFormatter, OpenLdapFormatter>();
services.AddTransient<ILdapBindNameFormatter, SambaFormatter>();
}

public static void AddFirstFactor(this IServiceCollection services)
{
services.AddSingleton<IFirstFactorProcessorProvider, FirstFactorProcessorProvider>();
services.AddTransient<IFirstFactorProcessor, LdapFirstFactorProcessor>();
services.AddTransient<IFirstFactorProcessor, RadiusFirstFactorProcessor>();
services.AddTransient<IFirstFactorProcessor, NoneFirstFactorProcessor>();
}

public static void AddChallenge(this IServiceCollection services)
{
services.AddTransient<IChallengeProcessor, SecondFactorChallengeProcessor>();
services.AddTransient<IChallengeProcessor, ChangePasswordChallengeProcessor>();
services.AddSingleton<IChallengeProcessorProvider, ChallengeProcessorProvider>();
}

public static void AddPipelines(this IServiceCollection services)
{
services.AddSingleton<IPipelineProvider, RadiusPipelineProvider>();
services.AddSingleton<IRadiusPipelineFactory, RadiusPipelineFactory>();
}

public static void AddPipelineSteps(this IServiceCollection services)
{
services.AddTransient<StatusServerFilteringStep>();
services.AddTransient<AccessRequestFilteringStep>();
services.AddTransient<LdapSchemaLoadingStep>();
services.AddTransient<ProfileLoadingStep>();
services.AddTransient<AccessGroupsCheckingStep>();
services.AddTransient<AccessChallengeStep>();
services.AddTransient<FirstFactorStep>();
services.AddTransient<SecondFactorStep>();
services.AddTransient<PreAuthCheckStep>();
services.AddTransient<PreAuthPostCheck>();
services.AddTransient<UserGroupLoadingStep>();
services.AddTransient<UserNameValidationStep>();
services.AddTransient<IpWhiteListStep>();
}

public static void AddAppServices(this IServiceCollection services)
{
services.AddTransient<MultifactorApiService>();
services.AddTransient<IRadiusPacketProcessor, RadiusPacketProcessor>();
AddLdapBindNameFormation(services);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Multifactor.Core.Ldap.Name;
using Multifactor.Core.Ldap.Schema;

namespace Multifactor.Radius.Adapter.v2.Application.Features.Ldap.Models;

public class ChangeUserPasswordRequest
{
public LdapConnectionData ConnectionData { get; set; }
public ILdapSchema LdapSchema { get; set; }
public DistinguishedName DistinguishedName { get; set; }
public string NewPassword { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Multifactor.Core.Ldap.Attributes;
using Multifactor.Core.Ldap.Name;
using Multifactor.Core.Ldap.Schema;
using Multifactor.Radius.Adapter.v2.Application.Features.Pipeline.Models;

namespace Multifactor.Radius.Adapter.v2.Application.Features.Ldap.Models;

public class FindUserRequest
{
public LdapConnectionData ConnectionData { get; set; }
public UserIdentity UserIdentity { get; set; }
public DistinguishedName SearchBase { get; set; }
public ILdapSchema LdapSchema { get; set; }
public LdapAttributeName[]? AttributeNames { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
using Multifactor.Core.Ldap.Attributes;
using Multifactor.Core.Ldap.Name;

namespace Multifactor.Radius.Adapter.v2.Core.Ldap;
namespace Multifactor.Radius.Adapter.v2.Application.Features.Ldap.Models;

public interface ILdapProfile
{
DistinguishedName Dn { get; }
string? Upn { get; }
string? Phone { get; }
string? Email { get; }
string? DisplayName { get; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Multifactor.Radius.Adapter.v2.Application.Features.Ldap.Models;

public class LdapConnectionData
{
public string ConnectionString { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public int BindTimeoutInSeconds { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
using Multifactor.Core.Ldap.Attributes;
using Multifactor.Core.Ldap.Entry;
using Multifactor.Core.Ldap.LangFeatures;
using Multifactor.Core.Ldap.Name;
using Multifactor.Core.Ldap.Schema;

namespace Multifactor.Radius.Adapter.v2.Core.Ldap;
namespace Multifactor.Radius.Adapter.v2.Application.Features.Ldap.Models;

public class LdapProfile : ILdapProfile
{
private readonly LdapEntry _ldapEntry;

public LdapProfile(LdapEntry ldapEntry, ILdapSchema? schema = null)
{
Throw.IfNull(ldapEntry, nameof(ldapEntry));
ArgumentNullException.ThrowIfNull(ldapEntry, nameof(ldapEntry));
_ldapEntry = ldapEntry;

MemberOf = _ldapEntry.Attributes["memberOf"]?.GetNotEmptyValues().Select(n => new DistinguishedName(n, schema)).ToList() ?? [];
Expand All @@ -26,9 +25,9 @@ public LdapProfile(LdapEntry ldapEntry, ILdapSchema? schema = null)

public DistinguishedName Dn { get; }
public string? Upn { get; }
public string? Phone { get; }
public string? Email { get; }
public string? DisplayName { get; }
public string? Phone { get; set; }
public string? Email { get; set; }
public string? DisplayName { get; set; }
public IReadOnlyCollection<DistinguishedName> MemberOf { get; }
public IReadOnlyCollection<LdapAttribute> Attributes { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Multifactor.Core.Ldap.Name;
using Multifactor.Core.Ldap.Schema;

namespace Multifactor.Radius.Adapter.v2.Application.Features.Ldap.Models;

public class LoadUserGroupRequest
{
public LdapConnectionData ConnectionData { get; set; }
public ILdapSchema LdapSchema { get; set; }
public DistinguishedName UserDN { get; set; }
public DistinguishedName? SearchBase { get; set; }
public int Limit { get; set; } = int.MaxValue;
}
Loading