-
Notifications
You must be signed in to change notification settings - Fork 6
Refactoring Radius 2.0 #129
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
base: main
Are you sure you want to change the base?
Changes from all commits
d898a5c
467842f
a42e35b
b487323
689237d
3fa2cb7
3ec4959
f1401ca
10ad7dc
f25b325
25df330
0725629
668c7eb
b6f312e
e3281e1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| using System.Net; | ||
| using Multifactor.Radius.Adapter.v2.Application.Core.Models; | ||
| using Multifactor.Radius.Adapter.v2.Application.Core.Models.Enum; | ||
| using NetTools; | ||
|
|
||
| namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models; | ||
|
|
||
| public interface IClientConfiguration | ||
| { | ||
| public string Name { get; } | ||
|
|
||
| public string MultifactorNasIdentifier { get; } | ||
| public string MultifactorSharedSecret { get; } | ||
| public IReadOnlyList<string> SignUpGroups { get; } | ||
| public bool BypassSecondFactorWhenApiUnreachable { get; } | ||
| public AuthenticationSource FirstFactorAuthenticationSource { get; } | ||
| public IPEndPoint AdapterClientEndpoint { get; } | ||
|
|
||
| public IReadOnlyList<IPAddress?> RadiusClientIps { get; } | ||
| public string RadiusClientNasIdentifier { get; } | ||
| public string RadiusSharedSecret { get; } | ||
| public IReadOnlyList<IPEndPoint> NpsServerEndpoints { get; } | ||
| public TimeSpan NpsServerTimeout { get; } | ||
|
|
||
| public Privacy Privacy { get; } | ||
|
|
||
| public PreAuthMode? PreAuthenticationMethod { get; } | ||
| public TimeSpan AuthenticationCacheLifetime { get; } | ||
| public CredentialDelay? InvalidCredentialDelay { get; } | ||
| public string? CallingStationIdAttribute { get; } //TODO not used | ||
| public IReadOnlyList<IPAddressRange> IpWhiteList { get; } | ||
|
|
||
| public IReadOnlyList<ILdapServerConfiguration>? LdapServers { get; } | ||
| public IReadOnlyDictionary<string, IReadOnlyList<IRadiusReplyAttribute>>? ReplyAttributes { get; } | ||
| } | ||
|
|
||
| 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; } | ||
| public string Username { get; } | ||
| public string Password { get; } | ||
| public int BindTimeoutSeconds{ get; } | ||
| public IReadOnlyList<DistinguishedName> AccessGroups { get; } | ||
| public IReadOnlyList<DistinguishedName> SecondFaGroups { get; } | ||
| public IReadOnlyList<DistinguishedName> SecondFaBypassGroups { get; } | ||
| public bool LoadNestedGroups { get; } | ||
| public IReadOnlyList<DistinguishedName> NestedGroupsBaseDns { get; } | ||
| public IReadOnlyList<DistinguishedName> AuthenticationCacheGroups { get; } | ||
| public IReadOnlyList<string> PhoneAttributes { get; } | ||
| public string IdentityAttribute { get; } | ||
| public bool RequiresUpn { get; } | ||
| public bool TrustedDomainsEnabled { get; } | ||
| public bool AlternativeSuffixesEnabled { get; } | ||
| public IReadOnlyList<string> IncludedDomains { get; }//TODO not used | ||
| public IReadOnlyList<string> ExcludedDomains { get; }//TODO not used | ||
| public IReadOnlyList<string> IncludedSuffixes { get; } | ||
| public IReadOnlyList<string> ExcludedSuffixes { get; } | ||
| public IReadOnlyList<string> BypassSecondFactorWhenApiUnreachableGroups { get; } | ||
| } |
| 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 | ||
| { | ||
KotikovAlexander marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| public string Name { get; } | ||
| public object Value { get; } | ||
| public IReadOnlyList<string> UserGroupCondition { get; } | ||
| public IReadOnlyList<string> UserNameCondition { get; } | ||
| public bool Sufficient { get; } | ||
| 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,24 @@ | ||
| using System.Net; | ||
|
|
||
| namespace Multifactor.Radius.Adapter.v2.Application.Configuration.Models; | ||
|
|
||
| public interface IRootConfiguration | ||
| { | ||
KotikovAlexander marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| IReadOnlyList<Uri> MultifactorApiUrls { get; } | ||
| string? MultifactorApiProxy { get; } | ||
| TimeSpan MultifactorApiTimeout { get; } | ||
| IPEndPoint? AdapterServerEndpoint { get; } | ||
| string LoggingLevel { get; } | ||
| string? LoggingFormat { get; } | ||
| bool SyslogUseTls { get; } | ||
| string? SyslogServer { get; } | ||
| string? SyslogFormat { get; } | ||
| string? SyslogFacility { get; } | ||
| string SyslogAppName { get; } | ||
| string? SyslogFramer { get; } | ||
| string? SyslogOutputTemplate { get; } | ||
|
|
||
| string? ConsoleLogOutputTemplate { get; } | ||
| string? FileLogOutputTemplate { get; } | ||
| int LogFileMaxSizeBytes { get; } | ||
| } | ||
| 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; init; } | ||
| public required IReadOnlyList<IClientConfiguration> ClientsConfigurations { get; init; } | ||
| 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.RadiusClientIps != null && config.RadiusClientIps.Any() && config.RadiusClientIps.Contains(ip)); | ||
|
|
||
| } | ||
| public bool SingleClientMode { get; init; } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| namespace Multifactor.Radius.Adapter.v2.Application.Core.Models | ||
| { | ||
| public record CredentialDelay(int Min, int Max); | ||
| } |
| 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.Core.Models.Enum | ||
| { | ||
| [Flags] | ||
| public enum AuthenticationSource | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Это не конфиг, а Core |
||
|
|
||
| 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.Core.Models.Enum | ||
| { | ||
| [Flags] | ||
| public enum PreAuthMode | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Это не конфиг, а Core. Если бы тут был DTO для чтения из конфига - тогда ладно |
||
| { | ||
| /// <summary> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| using Multifactor.Radius.Adapter.v2.Application.Core.Models.Enum; | ||
|
|
||
| namespace Multifactor.Radius.Adapter.v2.Application.Core.Models | ||
| { | ||
| public record Privacy(PrivacyMode PrivacyMode, string[] PrivacyFields); | ||
| } |
| 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
|---|---|---|
| @@ -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 |
|---|---|---|
| @@ -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; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.