Skip to content
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

Fix #378: Authentication handlers #379

Open
wants to merge 26 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c4dc5c9
[Refactor] Basic authentication to make use AuthenticationHandler pat…
Jan 6, 2024
abc50e2
WIP - JWT
Jan 12, 2024
f89021d
[Update] dependencies Microsoft.AspNetCore.Authentication.JwtBearer a…
Jan 20, 2024
271d6e7
Rebase
antoineatstariongroup Jan 15, 2025
04c3a3f
Fix #378: Support Basic/Internal JWT and External JWT authentication
antoineatstariongroup Jan 20, 2025
ab1bea0
Fix typo and remove authentication requires for import action
antoineatstariongroup Jan 20, 2025
4f9d95e
Added enabled authentication schemes discovery route
antoineatstariongroup Jan 20, 2025
63c38f2
Remove potential SQL injection
antoineatstariongroup Jan 20, 2025
6f74238
SQL fix
antoineatstariongroup Jan 20, 2025
069cb86
fix typo in SQL command
antoineatstariongroup Jan 20, 2025
d2dd6d3
revert to string interpolation seams not supporting parameters
antoineatstariongroup Jan 20, 2025
5fe2521
Header update
antoineatstariongroup Jan 20, 2025
4501a81
Header update and header template in resharper
antoineatstariongroup Jan 21, 2025
8e48cc1
Undo exchangeFile changes, only kept sql query quotes
antoineatstariongroup Jan 21, 2025
215c1f6
Unit tests for Handler
antoineatstariongroup Jan 21, 2025
6cfd976
SonarQube fixes, Sam's comment. Missing username and logout implement
antoineatstariongroup Jan 21, 2025
4d94463
Fix build issue
antoineatstariongroup Jan 21, 2025
0b9f1bc
Coverage
antoineatstariongroup Jan 21, 2025
610c9d8
Internal and External auth cannot be enabled at the same time, redirect
antoineatstariongroup Jan 22, 2025
546dfe0
appsettings update
antoineatstariongroup Jan 22, 2025
15eabf4
UserName route logic implemented and added check empty header
antoineatstariongroup Jan 22, 2025
ddb940a
Replace AuthenticationException by AuthorizationException
antoineatstariongroup Jan 27, 2025
bb618e9
JWT response as JSON
antoineatstariongroup Jan 27, 2025
22535e4
username as json
antoineatstariongroup Jan 27, 2025
5615c07
Increasing waiting time
antoineatstariongroup Jan 28, 2025
ddf4892
moves to ubuntu-22.04
antoineatstariongroup Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/CodeQuality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
jobs:
build:
name: Build
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
run: dotnet-coverage collect --output CoverageResults/integration.test.report.coverage.xml --output-format cobertura --session-id integrationtestsession "dotnet run --project CometServer/CometServer.csproj -c Debug" &

- name: Wait for API to start
run: sleep 60 # Adjust as necessary to ensure the API is up
run: sleep 70 # Adjust as necessary to ensure the API is up

- name: Checkout Integration Test Suite
uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion CDP4Orm.Tests/UtilsTestFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// --------------------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UtilsTestFixture.cs" company="Starion Group S.A.">
// Copyright (c) 2015-2024 Starion Group S.A.
//
Expand Down
81 changes: 67 additions & 14 deletions CDP4Orm/Dao/Authentication/AuthenticationPersonDao.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AuthenticationPersonDao.cs" company="Starion Group S.A.">
// Copyright (c) 2015-2023 Starion Group S.A.
//
// Copyright (c) 2015-2025 Starion Group S.A.
//
// Author: Sam Gerené, Alex Vorobiev, Alexander van Delft, Nathanael Smiechowski, Antoine Théate
//
// This file is part of CDP4-COMET Webservices Community Edition.
// The CDP4-COMET Webservices Community Edition is the STARION implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET Webservices Community Edition is free software; you can redistribute it and/or
//
// This file is part of CDP4-COMET Webservices Community Edition.
// The CDP4-COMET Web Services Community Edition is the Starion implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET Web Services Community Edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// The CDP4-COMET Webservices Community Edition is distributed in the hope that it will be useful,
//
// The CDP4-COMET Web Services Community Edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// GNU Affero General Public License for more details.
//
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// </copyright>
Expand Down Expand Up @@ -100,6 +100,59 @@ public async Task<IEnumerable<AuthenticationPerson>> Read(NpgsqlTransaction tran
return result;
}

/// <summary>
/// Read the data from the database.
/// </summary>
/// <param name="transaction">
/// The current transaction to the database.
/// </param>
/// <param name="partition">
/// The database partition (schema) where the requested resource is stored.
/// </param>
/// <param name="userId">
/// User Iid to retrieve from the database.
/// </param>
/// <param name="instant">
/// The instant as a nullable <see cref="DateTime"/>
/// </param>
/// <returns>
/// List of instances of <see cref="AuthenticationPerson"/>.
/// </returns>
public async Task<IEnumerable<AuthenticationPerson>> Read(NpgsqlTransaction transaction, string partition, Guid userId, DateTime? instant = null)
{
var result = new List<AuthenticationPerson>();

await using var command = new NpgsqlCommand();

var sqlBuilder = new System.Text.StringBuilder();

sqlBuilder.Append(this.PersonDao.BuildReadQuery(partition, instant));

sqlBuilder.Append(" WHERE \"Iid\" = :userId");
command.Parameters.Add("userId", NpgsqlDbType.Uuid).Value = userId;

if (instant.HasValue && instant.Value != DateTime.MaxValue)
{
command.Parameters.Add("instant", NpgsqlDbType.Timestamp).Value = instant;
}

sqlBuilder.Append(';');

command.Connection = transaction.Connection;
command.Transaction = transaction;
command.CommandText = sqlBuilder.ToString();

await using var reader = await command.ExecuteReaderAsync();

while (await reader.ReadAsync())
{
var authenticationPerson = MapToDto(reader);
result.Add(authenticationPerson);
}

return result;
}

/// <summary>
/// The mapping from a database record to data transfer object.
/// </summary>
Expand All @@ -114,11 +167,11 @@ private static AuthenticationPerson MapToDto(NpgsqlDataReader reader)
var valueDict = (Dictionary<string, string>)reader["ValueTypeSet"];
var iid = Guid.Parse(reader["Iid"].ToString());
var revisionNumber = int.Parse(valueDict["RevisionNumber"]);

var dto = new AuthenticationPerson(iid, revisionNumber)
{
Role = reader["Role"] is DBNull ? null : Guid.Parse(reader["Role"].ToString()),
DefaultDomain = reader["DefaultDomain"] is DBNull? null : Guid.Parse(reader["DefaultDomain"].ToString()),
DefaultDomain = reader["DefaultDomain"] is DBNull ? null : Guid.Parse(reader["DefaultDomain"].ToString()),
Organization = reader["Organization"] is DBNull ? null : Guid.Parse(reader["Organization"].ToString())
};

Expand Down Expand Up @@ -147,7 +200,7 @@ private static AuthenticationPerson MapToDto(NpgsqlDataReader reader)
// map shortname to UserName
dto.UserName = tempShortName.UnEscape();
}

return dto;
}
}
Expand Down
46 changes: 33 additions & 13 deletions CDP4Orm/Dao/Authentication/IAuthenticationPersonDao.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="IAuthenticationPersonDao.cs" company="Starion Group S.A.">
// Copyright (c) 2015-2023 Starion Group S.A.
//
// Author: Sam Gerené, Alex Vorobiev, Alexander van Delft, Nathanael Smiechowski, Antoine Théate
//
// This file is part of CDP4-COMET Webservices Community Edition.
// The CDP4-COMET Webservices Community Edition is the STARION implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET Webservices Community Edition is free software; you can redistribute it and/or
// Copyright (c) 2015-2025 Starion Group S.A.
//
// Author: Sam Gerené, Alex Vorobiev, Alexander van Delft, Nathanael Smiechowski, Antoine Théate
//
// This file is part of CDP4-COMET Webservices Community Edition.
// The CDP4-COMET Web Services Community Edition is the Starion implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET Web Services Community Edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// The CDP4-COMET Webservices Community Edition is distributed in the hope that it will be useful,
//
// The CDP4-COMET Web Services Community Edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// GNU Affero General Public License for more details.
//
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// </copyright>
Expand Down Expand Up @@ -56,5 +56,25 @@ public interface IAuthenticationPersonDao
/// List of instances of <see cref="AuthenticationPerson"/>.
/// </returns>
Task<IEnumerable<AuthenticationPerson>> Read(NpgsqlTransaction transaction, string partition, string userName, DateTime? instant = null);

/// <summary>
/// Read the data from the database.
/// </summary>
/// <param name="transaction">
/// The current transaction to the database.
/// </param>
/// <param name="partition">
/// The database partition (schema) where the requested resource is stored.
/// </param>
/// <param name="userId">
/// User Iid to retrieve from the database.
/// </param>
/// <param name="instant">
/// The instant as a nullable <see cref="DateTime"/>
/// </param>
/// <returns>
/// List of instances of <see cref="AuthenticationPerson"/>.
/// </returns>
Task<IEnumerable<AuthenticationPerson>> Read(NpgsqlTransaction transaction, string partition, Guid userId, DateTime? instant = null);
}
}
}
2 changes: 1 addition & 1 deletion COMET-WebServices.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,6 @@
&#xD;
This file is part of CDP4-COMET Webservices Community Edition. &#xD;
The CDP4-COMET Web Services Community Edition is the Starion implementation of ECSS-E-TM-10-25 Annex A and Annex C.&#xD;
This is an auto-generated class. Any manual changes to this file will be overwritten!&#xD;
&#xD;
The CDP4-COMET Web Services Community Edition is free software; you can redistribute it and/or&#xD;
modify it under the terms of the GNU Affero General Public&#xD;
Expand Down Expand Up @@ -280,6 +279,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AnonymousAuthenticationHandlerTestFixture.cs" company="Starion Group S.A.">
// Copyright (c) 2015-2025 Starion Group S.A.
//
// Author: Sam Gerené, Alex Vorobiev, Alexander van Delft, Nathanael Smiechowski, Antoine Théate
//
// This file is part of CDP4-COMET Webservices Community Edition.
// The CDP4-COMET Web Services Community Edition is the Starion implementation of ECSS-E-TM-10-25 Annex A and Annex C.
//
// The CDP4-COMET Web Services Community Edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// The CDP4-COMET Web Services Community Edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace CometServer.Tests.Authentication.Anonymous
{
using System.Linq;
using System.Security.Claims;
using System.Text.Encodings.Web;
using System.Threading.Tasks;

using CometServer.Authentication.Anonymous;

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

using Moq;

using NUnit.Framework;

[TestFixture]
public class AnonymousAuthenticationHandlerTestFixture
{
public AnonymousAuthenticationHandler handler;
public Mock<IOptionsMonitor<AnonymousAuthenticationOptions>> optionsMonitor;
public Mock<ILoggerFactory> loggerFactory;
public Mock<UrlEncoder> encoder;
public Mock<ISystemClock> systemClock;

[SetUp]
public void Setup()
{
this.optionsMonitor = new Mock<IOptionsMonitor<AnonymousAuthenticationOptions>>();

this.optionsMonitor
.Setup(x => x.Get(It.IsAny<string>()))
.Returns(new AnonymousAuthenticationOptions());

this.loggerFactory = new Mock<ILoggerFactory>();
var logger = new Mock<ILogger<AnonymousAuthenticationHandler>>();
this.loggerFactory.Setup(x => x.CreateLogger(It.IsAny<string>())).Returns(logger.Object);

this.encoder = new Mock<UrlEncoder>();
this.systemClock = new Mock<ISystemClock>();
this.handler = new AnonymousAuthenticationHandler(this.optionsMonitor.Object, this.loggerFactory.Object, this.encoder.Object, this.systemClock.Object);
}

[Test]
public async Task VerifyHandleAnonymousAuthentication()
{
var context = new DefaultHttpContext();

await this.handler.InitializeAsync(new AuthenticationScheme(AnonymousAuthenticationDefaults.AuthenticationScheme, AnonymousAuthenticationDefaults.DisplayName,
typeof(AnonymousAuthenticationHandler)), context);

var result = await this.handler.AuthenticateAsync();

Assert.Multiple(() =>
{
Assert.That(result.Succeeded, Is.True);
Assert.That(result.Principal, Is.Not.Null);
Assert.That(result.Principal.Claims.Single(x => x.Type == ClaimTypes.Name).Value, Is.EqualTo("anonymous"));
});
}
}
}
Loading
Loading