Skip to content

Commit e164d11

Browse files
authored
Merge pull request #8 from fireflylearning/REA-3709/bwf-multitenancy
REA-3709: Add multi-tenancy support
2 parents 1f77636 + cb58872 commit e164d11

6 files changed

Lines changed: 87 additions & 39 deletions

File tree

src/SAML2/Bindings/BindingUtility.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ public class BindingUtility
1212
/// Validates the SAML20Federation configuration.
1313
/// </summary>
1414
/// <returns>True if validation passes, false otherwise</returns>
15-
public static bool ValidateConfiguration()
15+
public static void ValidateConfiguration(Saml2Section config)
1616
{
17-
var config = Saml2Config.GetConfig();
1817
if (config == null)
1918
{
2019
throw new ConfigurationErrorsException(ErrorMessages.ConfigMissingSaml2Element);
@@ -52,7 +51,7 @@ public static bool ValidateConfiguration()
5251
throw new ConfigurationErrorsException(ErrorMessages.ConfigMissingMetadataLocation);
5352
}
5453

55-
return true;
54+
config.MarkAsValidated();
5655
}
5756
}
5857
}

src/SAML2/Config/Saml2Config.cs

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,43 @@
1-
using System.Configuration;
1+
using System;
2+
using System.Web;
3+
using LazyCache;
4+
using Microsoft.Extensions.Caching.Memory;
25

36
namespace SAML2.Config
47
{
5-
/// <summary>
6-
/// Provides helper methods for getting the configuration.
7-
/// </summary>
88
public static class Saml2Config
99
{
10-
/// <summary>
11-
/// The configuration
12-
/// </summary>
13-
private static Saml2Section _config;
10+
private static IAppCache _cache;
11+
private static Saml2Section _defaultProvider;
1412

15-
public static void Init(ISaml2ConfigProvider configProvider)
13+
public static void Init(IAppCache cache, ISaml2ConfigProvider defaultProvider)
1614
{
17-
_config = configProvider.SAML2Config;
15+
_cache = cache;
16+
_defaultProvider = defaultProvider.SAML2Config;
1817
}
19-
public static void ReloadIdentityProvider(ISaml2ConfigProvider configProvider)
18+
19+
public static void AddTenant(string tenantIdentifier, ISaml2ConfigProvider configProvider)
2020
{
21-
_config = configProvider.SAML2Config;
22-
_config.IdentityProviders.Refresh();
21+
var samlConfig = _cache.GetOrAdd(
22+
tenantIdentifier,
23+
() => configProvider.SAML2Config,
24+
new MemoryCacheEntryOptions
25+
{
26+
AbsoluteExpiration = null
27+
});
28+
29+
samlConfig.IdentityProviders.Refresh();
2330
}
2431

25-
/// <summary>
26-
/// Gets the config.
27-
/// </summary>
28-
/// <returns>The <see cref="Saml2Section"/> config.</returns>
2932
public static Saml2Section GetConfig()
3033
{
31-
if (_config == null)
32-
{
33-
_config = ConfigurationManager.GetSection(Saml2Section.Name) as Saml2Section;
34-
35-
if (_config == null)
36-
{
37-
throw new ConfigurationErrorsException(string.Format("Configuration section \"{0}\" not found", typeof(Saml2Section).Name));
38-
}
39-
40-
_config.IdentityProviders.Refresh();
41-
}
34+
var host = HttpContext.Current.Request.Url.DnsSafeHost;
35+
return GetConfig(host);
36+
}
4237

43-
return _config;
38+
public static Saml2Section GetConfig(string tenantIdentifier)
39+
{
40+
return _cache.Get<Saml2Section>(tenantIdentifier) ?? _defaultProvider;
4441
}
4542
}
4643
}

src/SAML2/Config/Saml2Section.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,5 +144,16 @@ public override bool IsReadOnly()
144144
{
145145
return false;
146146
}
147+
148+
public bool IsValidated { get; private set; } = false;
149+
150+
/// <summary>
151+
/// Set the IsValidated flag to true.
152+
///
153+
/// Written like this to enforce the requirement that IsValidated can never be updated to 'false'
154+
/// Allowing this to be falsified compromises thread safety.
155+
/// </summary>
156+
public void MarkAsValidated() => IsValidated = true;
157+
147158
}
148159
}

src/SAML2/Protocol/Saml20AbstractEndpointHandler.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@ public abstract class Saml20AbstractEndpointHandler : AbstractEndpointHandler
5555
/// </summary>
5656
public const string IdpTempSessionKey = "TempIDPId";
5757

58-
/// <summary>
59-
/// Gets or sets a value indicating whether configuration has been validated
60-
/// </summary>
61-
public static bool Validated { get; set; }
62-
6358
/// <summary>
6459
/// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
6560
/// </summary>
@@ -216,12 +211,13 @@ internal static IdentityProviderEndpointElement DetermineEndpointConfiguration(B
216211
/// </summary>
217212
private void CheckConfiguration()
218213
{
219-
if (Validated)
214+
var config = Saml2Config.GetConfig();
215+
if (config.IsValidated)
220216
{
221217
return;
222218
}
223219

224-
Validated = BindingUtility.ValidateConfiguration();
220+
BindingUtility.ValidateConfiguration(config);
225221
}
226222
}
227223
}

src/SAML2/SAML2.csproj

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,45 @@
3636
<Prefer32Bit>false</Prefer32Bit>
3737
</PropertyGroup>
3838
<ItemGroup>
39+
<Reference Include="LazyCache, Version=2.4.0.174, Culture=neutral, processorArchitecture=MSIL">
40+
<HintPath>..\packages\LazyCache.2.4.0\lib\netstandard2.0\LazyCache.dll</HintPath>
41+
</Reference>
42+
<Reference Include="LazyCache.AspNetCore, Version=2.4.0.174, Culture=neutral, processorArchitecture=MSIL">
43+
<HintPath>..\packages\LazyCache.AspNetCore.2.4.0\lib\netstandard2.0\LazyCache.AspNetCore.dll</HintPath>
44+
</Reference>
45+
<Reference Include="Microsoft.Extensions.Caching.Abstractions, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
46+
<HintPath>..\packages\Microsoft.Extensions.Caching.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll</HintPath>
47+
</Reference>
48+
<Reference Include="Microsoft.Extensions.Caching.Memory, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
49+
<HintPath>..\packages\Microsoft.Extensions.Caching.Memory.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Memory.dll</HintPath>
50+
</Reference>
51+
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
52+
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
53+
</Reference>
54+
<Reference Include="Microsoft.Extensions.Options, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
55+
<HintPath>..\packages\Microsoft.Extensions.Options.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
56+
</Reference>
57+
<Reference Include="Microsoft.Extensions.Primitives, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
58+
<HintPath>..\packages\Microsoft.Extensions.Primitives.2.1.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
59+
</Reference>
3960
<Reference Include="System" />
61+
<Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
62+
<HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
63+
</Reference>
4064
<Reference Include="System.Configuration" />
4165
<Reference Include="System.Core" />
4266
<Reference Include="System.IdentityModel" />
4367
<Reference Include="System.IdentityModel.Selectors" />
68+
<Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
69+
<HintPath>..\packages\System.Memory.4.5.0\lib\netstandard2.0\System.Memory.dll</HintPath>
70+
</Reference>
71+
<Reference Include="System.Numerics" />
72+
<Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
73+
<HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
74+
</Reference>
75+
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
76+
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
77+
</Reference>
4478
<Reference Include="System.Runtime.Serialization" />
4579
<Reference Include="System.Security" />
4680
<Reference Include="System.ServiceModel" />

src/SAML2/packages.config

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3+
<package id="LazyCache" version="2.4.0" targetFramework="net462" />
4+
<package id="LazyCache.AspNetCore" version="2.4.0" targetFramework="net462" />
5+
<package id="Microsoft.Extensions.Caching.Abstractions" version="2.1.0" targetFramework="net462" />
6+
<package id="Microsoft.Extensions.Caching.Memory" version="2.1.0" targetFramework="net462" />
7+
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.1.0" targetFramework="net462" />
8+
<package id="Microsoft.Extensions.Options" version="2.1.0" targetFramework="net462" />
9+
<package id="Microsoft.Extensions.Primitives" version="2.1.0" targetFramework="net462" />
310
<package id="StyleCop.MSBuild" version="4.7.45.0" targetFramework="net35" developmentDependency="true" />
11+
<package id="System.Buffers" version="4.4.0" targetFramework="net462" />
12+
<package id="System.Memory" version="4.5.0" targetFramework="net462" />
13+
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net462" />
14+
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.0" targetFramework="net462" />
415
</packages>

0 commit comments

Comments
 (0)