Skip to content

Commit 5526a1f

Browse files
author
Xadmin
committed
Add OIDC/SSO authentication support
Implements OpenID Connect (OIDC) Single Sign-On authentication to address issue #512. Features: - OIDC authentication via ASP.NET Core middleware - Support for multiple IdPs (Entra ID, Okta, Auth0, etc.) - Automatic user provisioning with configurable group mappings - HttpOnly cookie-based session management - Rate limiting for provisioning attempts - Comprehensive environment variable configuration - Docker secrets support for sensitive values - Security headers (CSP, HSTS, X-Frame-Options, etc.) - Backward compatible with existing local authentication Security: - JWT signature validation via OIDC discovery - Cryptographically secure cookie secrets (32-byte) - SameSite=Lax cookie protection - No secrets in frontend bundles - Proper error handling without information leakage Documentation: - Added SSO configuration to DockerEnvironmentVariables.md - Includes examples for major IdP providers - Environment variable reference with _FILE variants Closes #512
1 parent 7f7ce26 commit 5526a1f

8 files changed

Lines changed: 5716 additions & 1572 deletions

File tree

DnsServerCore/Auth/User.cs

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,24 @@ class User : IComparable<User>
5252
AuthenticatorKeyUri _totpKeyUri;
5353
bool _totpEnabled;
5454
bool _disabled;
55+
bool _isSsoUser; // New field for SSO tracking
5556
int _sessionTimeoutSeconds = 30 * 60; //default 30 mins
5657

5758
DateTime _previousSessionLoggedOn;
5859
IPAddress _previousSessionRemoteAddress;
5960
DateTime _recentSessionLoggedOn;
6061
IPAddress _recentSessionRemoteAddress;
6162

62-
readonly ConcurrentDictionary<string, Group> _memberOfGroups;
63-
64-
#endregion
65-
66-
#region constructor
67-
68-
public User(string displayName, string username, string password, int iterations = DEFAULT_ITERATIONS)
63+
ConcurrentDictionary<string, Group> _memberOfGroups;
64+
public User(string displayName, string username, string password, int iterations)
6965
{
70-
Username = username;
7166
DisplayName = displayName;
72-
67+
Username = username;
7368
ChangePassword(password, iterations);
7469

70+
_memberOfGroups = new ConcurrentDictionary<string, Group>();
7571
_previousSessionRemoteAddress = IPAddress.Any;
7672
_recentSessionRemoteAddress = IPAddress.Any;
77-
78-
_memberOfGroups = new ConcurrentDictionary<string, Group>(1, 2);
7973
}
8074

8175
public User(BinaryReader bR, IReadOnlyDictionary<string, Group> groups)
@@ -85,6 +79,7 @@ public User(BinaryReader bR, IReadOnlyDictionary<string, Group> groups)
8579
{
8680
case 1:
8781
case 2:
82+
case 3: // Version 3 adds IsSsoUser
8883
_displayName = bR.ReadShortString();
8984
_username = bR.ReadShortString();
9085
_passwordHashType = (UserPasswordHashType)bR.ReadByte();
@@ -102,6 +97,12 @@ public User(BinaryReader bR, IReadOnlyDictionary<string, Group> groups)
10297
}
10398

10499
_disabled = bR.ReadBoolean();
100+
101+
if (version >= 3)
102+
{
103+
_isSsoUser = bR.ReadBoolean();
104+
}
105+
105106
_sessionTimeoutSeconds = bR.ReadInt32();
106107

107108
_previousSessionLoggedOn = bR.ReadDateTime();
@@ -259,13 +260,13 @@ public bool IsMemberOfGroup(Group group)
259260

260261
public void WriteTo(BinaryWriter bW)
261262
{
262-
bW.Write((byte)2);
263-
bW.WriteShortString(_displayName);
264-
bW.WriteShortString(_username);
263+
bW.Write((byte)3); // Bump version to 3
264+
bW.WriteShortString(_displayName ?? "");
265+
bW.WriteShortString(_username ?? "");
265266
bW.Write((byte)_passwordHashType);
266267
bW.Write(_iterations);
267-
bW.WriteBuffer(_salt);
268-
bW.WriteShortString(_passwordHash);
268+
bW.WriteBuffer(_salt ?? Array.Empty<byte>());
269+
bW.WriteShortString(_passwordHash ?? "");
269270

270271
if (_totpKeyUri is null)
271272
bW.Write("");
@@ -274,6 +275,7 @@ public void WriteTo(BinaryWriter bW)
274275

275276
bW.Write(_totpEnabled);
276277
bW.Write(_disabled);
278+
bW.Write(_isSsoUser); // Write IsSsoUser
277279
bW.Write(_sessionTimeoutSeconds);
278280

279281
bW.Write(_previousSessionLoggedOn);
@@ -284,7 +286,7 @@ public void WriteTo(BinaryWriter bW)
284286
bW.Write(Convert.ToByte(_memberOfGroups.Count));
285287

286288
foreach (KeyValuePair<string, Group> group in _memberOfGroups)
287-
bW.WriteShortString(group.Value.Name.ToLowerInvariant());
289+
bW.WriteShortString(group.Value.Name?.ToLowerInvariant() ?? "");
288290
}
289291

290292
public override bool Equals(object obj)
@@ -417,6 +419,12 @@ public IPAddress RecentSessionRemoteAddress
417419
public ICollection<Group> MemberOfGroups
418420
{ get { return _memberOfGroups.Values; } }
419421

422+
public bool IsSsoUser
423+
{
424+
get { return _isSsoUser; }
425+
set { _isSsoUser = value; }
426+
}
427+
420428
#endregion
421429
}
422430
}

DnsServerCore/DnsServerCore.csproj

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
44
<TargetFramework>net9.0</TargetFramework>
@@ -27,25 +27,26 @@
2727

2828
<ItemGroup>
2929
<Reference Include="TechnitiumLibrary">
30-
<HintPath>..\..\TechnitiumLibrary\bin\TechnitiumLibrary.dll</HintPath>
30+
<HintPath>..\TechnitiumLibrary\bin\TechnitiumLibrary.dll</HintPath>
3131
</Reference>
3232
<Reference Include="TechnitiumLibrary.ByteTree">
33-
<HintPath>..\..\TechnitiumLibrary\bin\TechnitiumLibrary.ByteTree.dll</HintPath>
33+
<HintPath>..\TechnitiumLibrary\bin\TechnitiumLibrary.ByteTree.dll</HintPath>
3434
</Reference>
3535
<Reference Include="TechnitiumLibrary.IO">
36-
<HintPath>..\..\TechnitiumLibrary\bin\TechnitiumLibrary.IO.dll</HintPath>
36+
<HintPath>..\TechnitiumLibrary\bin\TechnitiumLibrary.IO.dll</HintPath>
3737
</Reference>
3838
<Reference Include="TechnitiumLibrary.Net">
39-
<HintPath>..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll</HintPath>
39+
<HintPath>..\TechnitiumLibrary\bin\TechnitiumLibrary.Net.dll</HintPath>
4040
</Reference>
4141
<Reference Include="TechnitiumLibrary.Security.OTP">
42-
<HintPath>..\..\TechnitiumLibrary\bin\TechnitiumLibrary.Security.OTP.dll</HintPath>
42+
<HintPath>..\TechnitiumLibrary\bin\TechnitiumLibrary.Security.OTP.dll</HintPath>
4343
</Reference>
4444
</ItemGroup>
4545

4646
<ItemGroup>
4747
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.2" />
4848
<PackageReference Include="QRCoder" Version="1.7.0" />
49+
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0" />
4950
</ItemGroup>
5051

5152
<ItemGroup>
@@ -264,3 +265,4 @@
264265
</ItemGroup>
265266

266267
</Project>
268+

0 commit comments

Comments
 (0)