21 Commits

Author SHA1 Message Date
806b5242b0 Merge pull request 'Add the code to retrieve the idToken instead of accessToken in google authentication' (#7) from feature/use-id-token into development
Reviewed-on: #7
Reviewed-by: efrain_marin <efrain.marin@agilewebs.com>
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
2025-08-28 17:39:55 +00:00
Oscar Morales
24f5711e1c Add the code to retrieve the idToken instead of accessToken in google authentication 2025-08-27 23:23:04 -06:00
e3d75fbfa8 Fix duplicated property 2025-08-26 14:18:33 -06:00
9872c1b88b Merge pull request 'Add tenant property to user' (#6) from feature/add-tenant-to-user into development
Reviewed-on: #6
Reviewed-by: OscarMmtz <oscar.morales@agilewebs.com>
2025-08-26 20:18:04 +00:00
fe4c0696e8 Merge branch 'development' into feature/add-tenant-to-user 2025-08-26 14:16:33 -06:00
3b752f182f fix 2025-08-26 14:11:09 -06:00
4a2ed52a2f fix 2025-08-26 14:10:48 -06:00
5277896bdc Add tenant identifier in user property 2025-08-26 14:10:29 -06:00
9a02f0e4d6 Fixed google settings 2025-08-22 21:04:25 -06:00
4cd89c6a83 Fix id property in user claims 2025-08-08 23:51:23 -06:00
0bd46f2594 Remove GUID property from user 2025-08-08 23:49:44 -06:00
7bbb8ebfe5 Add tenant property to user 2025-08-08 23:05:27 -06:00
035da054d6 Fix Change status route 2025-08-07 13:16:37 -06:00
a025bd87c1 fix id route 2025-07-31 19:56:56 -06:00
ff404ec105 Add collection attribute name 2025-07-31 19:43:46 -06:00
8d1e218eb9 Added catalog and tenant adapter 2025-07-31 18:45:08 -06:00
db10d185da Remove unnecessary properties from user adapter 2025-07-25 23:53:00 -06:00
cbeeebd5a6 Revise authentication logic 2025-07-25 23:44:07 -06:00
0f7567ec67 Merge pull request 'Add google and jwt authentication and authorization' (#5) from feature/add-google-and-jwt-auth into development
Reviewed-on: #5
Reviewed-by: Sergio Matías <sergio.matias@agilewebs.com>
Reviewed-by: efrain_marin <efrain.marin@agilewebs.com>
2025-07-18 00:59:23 +00:00
Oscar Morales
aeab9548b8 Add google and jwt authentication and authorization 2025-07-15 13:52:09 -06:00
3eb6bfc60f Merge pull request #4 from SergioMatias94/feature/fix-adapters
Remove _id from adapters
2025-06-17 15:11:07 -06:00
49 changed files with 700 additions and 183 deletions

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
namespace Core.Thalos.BuildingBlocks.Common.Constants
{
/// <summary>
/// Constants for policy.
/// </summary>
public class Policies
{
/// <summary>
/// Defines the access policy for reading mobile-related data.
/// This policy grants read-only permissions for retrieving mobile device information,
/// user mobile settings, or related data as per the application's authorization scope.
/// </summary>
public const string Read = "Read";
/// <summary>
/// Defines the access policy for writing mobile-related data.
/// This policy grants permissions to modify, update, or store mobile device information,
/// user mobile settings, or related data as per the application's authorization scope.
/// </summary>
public const string Write = "Write";
}
}

View File

@@ -0,0 +1,15 @@
namespace Core.Thalos.BuildingBlocks.Common.Constants
{
public class Roles
{
/// <summary>
/// The role for Guest.
/// </summary>
public const string Guest = "684909c4826cd093b4f61c11";
/// <summary>
/// The role for Admin.
/// </summary>
public const string Admin = "68407642ec46a0e6fe1e8ec9";
}
}

View File

@@ -1,11 +1,6 @@
using System; using System.Text.Json;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
public class BaseAdapterResponse public class BaseAdapterResponse
{ {

View File

@@ -0,0 +1,32 @@
using Core.Blueprint.Mongo;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace Core.Thalos.BuildingBlocks.Adapters
{
[CollectionAttributeName("Catalogs")]
public class CatalogAdapter : Document
{
[BsonElement("name")]
public string Name { get; set; } = null!;
[BsonElement("key")]
public string? Key { get; set; } = null!;
[BsonElement("description")]
public string? Description { get; set; }
public IEnumerable<CatalogValue>? Values { get; set; }
}
public class CatalogValue
{
[BsonId]
[BsonElement("_id")]
[BsonRepresentation(BsonType.ObjectId)]
public string _Id { get; set; } = null!;
[BsonElement("value")]
public string Value { get; set; } = null!;
}
}

View File

@@ -5,12 +5,11 @@
// *********************************************************************** // ***********************************************************************
using Core.Blueprint.Mongo; using Core.Blueprint.Mongo;
using Core.Thalos.Adapters.Common.Enums;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Adapter for representing a module. /// Adapter for representing a module.

View File

@@ -5,12 +5,11 @@
// *********************************************************************** // ***********************************************************************
using Core.Blueprint.Mongo; using Core.Blueprint.Mongo;
using Core.Thalos.Adapters.Common.Constants;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Adapter for representing a permission. /// Adapter for representing a permission.

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
namespace Core.Thalos.Adapters.Handlers.Adapters namespace Core.Thalos.BuildingBlocks
{ {
public class PermissionsAuthorizationAdapter : IAuthorizationRequirement public class PermissionsAuthorizationAdapter : IAuthorizationRequirement
{ {

View File

@@ -5,12 +5,11 @@
// *********************************************************************** // ***********************************************************************
using Core.Blueprint.Mongo; using Core.Blueprint.Mongo;
using Core.Thalos.Adapters.Common.Enums;
using MongoDB.Bson; using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Adapter representing a role. /// Adapter representing a role.

View File

@@ -0,0 +1,53 @@
using Core.Blueprint.Mongo;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace Core.Thalos.BuildingBlocks
{
[CollectionAttributeName("Tenants")]
public class TenantAdapter : Document
{
[BsonElement("name")]
public string Name { get; set; } = null!;
[BsonElement("taxIdentifier")]
public string TaxIdentifier { get; set; } = null!;
[BsonElement("addressLine1")]
public string AddressLine1 { get; set; } = null!;
[BsonElement("addressLine2")]
[BsonIgnoreIfNull]
public string? AddressLine2 { get; set; }
[BsonElement("city")]
public string City { get; set; } = null!;
[BsonElement("state")]
public string State { get; set; } = null!;
[BsonElement("country")]
public string Country { get; set; } = null!;
[BsonElement("postalCode")]
public string PostalCode { get; set; } = null!;
[BsonElement("contactEmail")]
public string ContactEmail { get; set; } = null!;
[BsonElement("contactPhone")]
public string ContactPhone { get; set; } = null!;
[BsonElement("website")]
[BsonIgnoreIfNull]
public string? Website { get; set; }
[BsonElement("connectionString")]
[BsonIgnoreIfNull]
public string? ConnectionString { get; set; }
[BsonElement("isolated")]
public bool Isolated { get; set; }
}
}

View File

@@ -4,13 +4,14 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
public class TokenAdapter public class TokenAdapter
{ {
public UserAdapter? User { get; set; } public UserAdapter? User { get; set; }
public RoleAdapter? Role { get; set; } public RoleAdapter? Role { get; set; }
public TenantAdapter? Tenant { get; set; }
public IEnumerable<PermissionAdapter>? Permissions { get; set; } public IEnumerable<PermissionAdapter>? Permissions { get; set; }
public IEnumerable<ModuleAdapter> Modules { get; set; } = null!; public IEnumerable<ModuleAdapter> Modules { get; set; } = null!;

View File

@@ -8,7 +8,7 @@ using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Adapter representing a user. /// Adapter representing a user.
@@ -16,14 +16,6 @@ namespace Core.Thalos.Adapters
[CollectionAttributeName("Users")] [CollectionAttributeName("Users")]
public class UserAdapter : Document public class UserAdapter : Document
{ {
/// <summary>
/// Gets or sets the guid of the user.
/// </summary>
[BsonElement("guid")]
[BsonRepresentation(BsonType.String)]
[JsonPropertyName("guid")]
public string? Guid { get; set; }
/// <summary> /// <summary>
/// Gets or sets the email address of the user. /// Gets or sets the email address of the user.
/// </summary> /// </summary>
@@ -64,6 +56,14 @@ namespace Core.Thalos.Adapters
[JsonPropertyName("displayName")] [JsonPropertyName("displayName")]
public string? DisplayName { get; set; } public string? DisplayName { get; set; }
/// <summary>
/// Gets or sets the Tenand ID of the user.
/// </summary>
[BsonElement("tenantId")]
[BsonRepresentation(BsonType.ObjectId)]
[JsonPropertyName("tenantId")]
public string TenantId { get; set; } = null!;
/// <summary> /// <summary>
/// Gets or sets the role ID of the user. /// Gets or sets the role ID of the user.
/// </summary> /// </summary>
@@ -72,28 +72,6 @@ namespace Core.Thalos.Adapters
[JsonPropertyName("roleId")] [JsonPropertyName("roleId")]
public string RoleId { get; set; } = null!; public string RoleId { get; set; } = null!;
/// <summary>
/// Gets or sets the array of companies associated with the user.
/// </summary>
[BsonElement("companies")]
[JsonPropertyName("companies")]
public string[] Companies { get; set; } = null!;
/// <summary>
/// Gets or sets the array of projects associated with the user.
/// </summary>
[BsonElement("projects")]
[JsonPropertyName("projects")]
public string[]? Projects { get; set; }
/// <summary>
/// Gets or sets the boolean of the consent form accepted by the user.
/// </summary>
[BsonElement("consentFormAccepted")]
[JsonPropertyName("consentFormAccepted")]
[BsonIgnoreIfNull]
public bool ConsentFormAccepted { get; set; }
/// <summary> /// <summary>
/// Gets or sets the timestamp of the last login of the user. /// Gets or sets the timestamp of the last login of the user.
/// </summary> /// </summary>

View File

@@ -6,7 +6,7 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Adapter representing a user. /// Adapter representing a user.

View File

@@ -1,4 +1,4 @@
namespace Core.Thalos.Adapters namespace Core.Thalos.BuildingBlocks
{ {
public class Permission public class Permission
{ {

View File

@@ -2,7 +2,7 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.Filters;
namespace Core.Thalos.Adapters.Attributes namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Custom authorization attribute that checks if the user has any of the required permissions. /// Custom authorization attribute that checks if the user has any of the required permissions.

View File

@@ -0,0 +1,37 @@
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Microsoft.Extensions.Configuration;
namespace Core.Thalos.BuildingBlocks
{
public class GoogleAuthorization(
IGoogleAuthHelper googleHelper, IConfiguration config, GoogleAuthSettings googlesettings) : IGoogleAuthorization
{
private string RedirectUrl = googlesettings.RedirectUri ?? string.Empty;
public async Task<UserCredential> ExchangeCodeForToken(string code)
{
var flow = new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = googleHelper.GetClientSecrets(),
Scopes = googleHelper.GetScopes()
});
var token = await flow.ExchangeCodeForTokenAsync(
"user", code, RedirectUrl, CancellationToken.None);
return new UserCredential(flow, "user", token);
}
public string GetAuthorizationUrl() =>
new GoogleAuthorizationCodeFlow(
new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = googleHelper.GetClientSecrets(),
Scopes = googleHelper.GetScopes(),
Prompt = "consent"
}).CreateAuthorizationCodeRequest(RedirectUrl).Build().ToString();
}
}

View File

@@ -0,0 +1,10 @@
using Google.Apis.Auth.OAuth2;
namespace Core.Thalos.BuildingBlocks
{
public interface IGoogleAuthorization
{
string GetAuthorizationUrl();
Task<UserCredential> ExchangeCodeForToken(string code);
}
}

View File

@@ -6,7 +6,7 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Specifies different access level for a permission. /// Specifies different access level for a permission.

View File

@@ -3,7 +3,7 @@
// AgileWebs // AgileWebs
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants for Azure Active Directory. /// Constants for Azure Active Directory.

View File

@@ -3,7 +3,7 @@
// AgileWebs // AgileWebs
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants for claims used in JWT tokens. /// Constants for claims used in JWT tokens.
@@ -23,10 +23,20 @@ namespace Core.Thalos.Adapters.Common.Constants
/// <summary> /// <summary>
/// Claim name for user's ID. /// Claim name for user's ID.
/// </summary> /// </summary>
public const string Id = "id"; public const string Id = "_id";
/// <summary> /// <summary>
/// Claim name for user's role ID. /// Claim name for user's tenant name.
/// </summary>
public const string Tenant = "tenant";
/// <summary>
/// Claim name for user's tenant identifier.
/// </summary>
public const string TenantId = "tenantId";
/// <summary>
/// Claim name for user's role name.
/// </summary> /// </summary>
public const string Role = "role"; public const string Role = "role";

View File

@@ -1,4 +1,4 @@
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
public static class CollectionNames public static class CollectionNames
{ {

View File

@@ -4,7 +4,7 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants of the environment variables for this service. /// Constants of the environment variables for this service.

View File

@@ -3,7 +3,7 @@
// AgileWebs // AgileWebs
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants for Key Vault configuration. /// Constants for Key Vault configuration.

View File

@@ -6,7 +6,7 @@
using System.Globalization; using System.Globalization;
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants for the mime types. /// Constants for the mime types.

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
namespace Core.Thalos.BuildingBlocks
{
/// <summary>
/// Constants for policy.
/// </summary>
public class Policies
{
/// <summary>
/// Defines the access policy for reading mobile-related data.
/// This policy grants read-only permissions for retrieving mobile device information,
/// user mobile settings, or related data as per the application's authorization scope.
/// </summary>
public const string Read = "Read";
/// <summary>
/// Defines the access policy for writing mobile-related data.
/// This policy grants permissions to modify, update, or store mobile device information,
/// user mobile settings, or related data as per the application's authorization scope.
/// </summary>
public const string Write = "Write";
}
}

View File

@@ -0,0 +1,15 @@
namespace Core.Thalos.BuildingBlocks
{
public class Roles
{
/// <summary>
/// The role for Guest.
/// </summary>
public const string Guest = "684909c4826cd093b4f61c11";
/// <summary>
/// The role for Admin.
/// </summary>
public const string Admin = "68407642ec46a0e6fe1e8ec9";
}
}

View File

@@ -4,7 +4,7 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants of the routes of this service. /// Constants of the routes of this service.
@@ -24,7 +24,7 @@ namespace Core.Thalos.Adapters.Common.Constants
/// <summary> /// <summary>
/// The identifier route. /// The identifier route.
/// </summary> /// </summary>
public const string Id = "{id}"; public const string Id = "{_id}";
/// <summary> /// <summary>
/// The Authentication route. /// The Authentication route.
@@ -74,7 +74,7 @@ namespace Core.Thalos.Adapters.Common.Constants
/// <summary> /// <summary>
/// The ChangeStatus route. /// The ChangeStatus route.
/// </summary> /// </summary>
public const string ChangeStatus = "{id}/{newStatus}/ChangeStatus"; public const string ChangeStatus = "{_id}/{newStatus}/ChangeStatus";
/// <summary> /// <summary>
/// The AddCompany route. /// The AddCompany route.

View File

@@ -1,4 +1,4 @@
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants for schemes. /// Constants for schemes.
@@ -14,5 +14,10 @@
/// The azure scheme. /// The azure scheme.
/// </summary> /// </summary>
public const string AzureScheme = "AzureScheme"; public const string AzureScheme = "AzureScheme";
/// <summary>
/// The google scheme.
/// </summary>
public const string GoogleScheme = "GoogleScheme";
} }
} }

View File

@@ -3,7 +3,7 @@
// AgileWebs // AgileWebs
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Common.Constants namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Constants for secrets in azure key vault. /// Constants for secrets in azure key vault.
@@ -23,12 +23,12 @@ namespace Core.Thalos.Adapters.Common.Constants
/// <summary> /// <summary>
/// The Issuer parameter for JWT settings. /// The Issuer parameter for JWT settings.
/// </summary> /// </summary>
public const string Issuer = "Issuer"; public const string Issuer = "JWTIssuer";
/// <summary> /// <summary>
/// The Audience parameter for JWT settings. /// The Audience parameter for JWT settings.
/// </summary> /// </summary>
public const string Audience = "Audience"; public const string Audience = "JWTAudience";
/// <summary> /// <summary>
/// The TokenExpirationInMinutes parameter for JWT settings. /// The TokenExpirationInMinutes parameter for JWT settings.
@@ -55,5 +55,8 @@ namespace Core.Thalos.Adapters.Common.Constants
public const string ThalosAppScope = "Swagger:Scope"; public const string ThalosAppScope = "Swagger:Scope";
public const string PrivateKey = "JwtTokenPrivateKey"; public const string PrivateKey = "JwtTokenPrivateKey";
public const string PublicKey = "JwtTokenPublicKey"; public const string PublicKey = "JwtTokenPublicKey";
public const string GoogleClientId = "GoogleClientId";
public const string GoogleClientSecret = "GoogleClientSecret";
public const string GoogleRedirectUri = "GoogleRedirectUri";
} }
} }

View File

@@ -6,7 +6,7 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters.Common.Enums namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Defines the applications associated with the role. /// Defines the applications associated with the role.

View File

@@ -6,7 +6,7 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Core.Thalos.Adapters.Common.Enums namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Defines the status of an entity. /// Defines the status of an entity.

View File

@@ -0,0 +1,11 @@
using Google.Apis.Auth.OAuth2;
namespace Core.Thalos.BuildingBlocks
{
public interface IGoogleAuthHelper
{
string[] GetScopes();
string ScopeToString();
ClientSecrets GetClientSecrets();
}
}

View File

@@ -4,7 +4,7 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.Adapters.Contracts namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Interface for token provider. /// Interface for token provider.

View File

@@ -7,7 +7,7 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace Core.Thalos.Adapters.Contracts namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Interface for authenticacion service. /// Interface for authenticacion service.

View File

@@ -8,15 +8,20 @@
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<VersionPrefix>1.0.2</VersionPrefix> <VersionPrefix>1.0.5</VersionPrefix>
<VersionSuffix>$(Date:yyyyMMddHHmm)</VersionSuffix> <VersionSuffix>$(Date:yyyyMMddHHmm)</VersionSuffix>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" /> <PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="Core.Blueprint.KeyVault" Version="1.0.3" />
<PackageReference Include="Core.Blueprint.Mongo" Version="1.0.0" /> <PackageReference Include="Core.Blueprint.Mongo" Version="1.0.0" />
<PackageReference Include="Google.Apis.Auth" Version="1.70.0" />
<PackageReference Include="Google.Apis.Oauth2.v2" Version="1.68.0.1869" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.18" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="8.2.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.AzureAppConfiguration" Version="8.2.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.7" />
<PackageReference Include="Microsoft.Identity.Web" Version="3.9.1" /> <PackageReference Include="Microsoft.Identity.Web" Version="3.9.1" />
<PackageReference Include="Microsoft.Identity.Web.MicrosoftGraph" Version="3.9.1" /> <PackageReference Include="Microsoft.Identity.Web.MicrosoftGraph" Version="3.9.1" />
<PackageReference Include="MongoDB.Bson" Version="3.4.0" /> <PackageReference Include="MongoDB.Bson" Version="3.4.0" />
@@ -30,4 +35,8 @@
<PackageReference Include="System.Text.Json" Version="9.0.5" /> <PackageReference Include="System.Text.Json" Version="9.0.5" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Handlers\Adapters\" />
</ItemGroup>
</Project> </Project>

View File

@@ -4,11 +4,7 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
using Core.Thalos.Adapters.Common.Constants; using Microsoft.AspNetCore.Authentication;
using Core.Thalos.Adapters.Contracts;
using Core.Thalos.Adapters.Handlers;
using Core.Thalos.Adapters.Options;
using Core.Thalos.Adapters.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@@ -17,7 +13,7 @@ using Microsoft.Identity.Web;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography; using System.Security.Cryptography;
namespace Core.Thalos.Adapters.Extensions namespace Core.Thalos.BuildingBlocks.Configuration
{ {
/// <summary> /// <summary>
/// Extension methods for configuring authentication with various Azure AD setups. /// Extension methods for configuring authentication with various Azure AD setups.
@@ -33,36 +29,38 @@ namespace Core.Thalos.Adapters.Extensions
{ {
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty; var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
var azureAdInMemorySettings = new Dictionary<string, string?> var identityProviders = new IdentityProviders();
{ configuration.GetSection("IdentityProviders").Bind(identityProviders);
{ "AzureAdB2C:Instance", authSettings.AzureADInstance ?? string.Empty },
{ "AzureAdB2C:TenantId", authSettings.AzureADTenantId ?? string.Empty },
{ "AzureAdB2C:ClientId", authSettings.AzureADClientId ?? string.Empty },
{ "AzureAdB2C:ClientSecret", authSettings.AzureADClientSecret ?? string.Empty }
};
var configurationBuilder = new ConfigurationBuilder() AddCustomAuthentication(services, authSettings.Token);
.AddConfiguration(configuration)
.AddInMemoryCollection(azureAdInMemorySettings);
var combinedConfiguration = configurationBuilder.Build(); if (identityProviders.Azure)
AddAzureAuthentication(authSettings, configuration, services);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) if (identityProviders.Google)
.AddMicrosoftIdentityWebApi(combinedConfiguration.GetSection("AzureAdB2C"), Schemes.AzureScheme) AddGoogleAuthentication(services, authSettings.Google);
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
services.AddAuthorization();
services.AddTransient<IAuthorizationHandler, PermissionsAuthorizationHandler>();
services.AddTransient<ITokenService, TokenService>();
}
public static void AddCustomAuthentication(IServiceCollection services, TokenAuthSettings tokenAuthSettings)
{
var rsa = RSA.Create(); var rsa = RSA.Create();
rsa.ImportFromPem(authSettings.PrivateKey?.ToCharArray()); rsa.ImportFromPem(tokenAuthSettings.PrivateKey?.ToCharArray());
var rsaPrivateKey = new RsaSecurityKey(rsa); var rsaPrivateKey = new RsaSecurityKey(rsa);
var rsaPublic = RSA.Create(); var rsaPublic = RSA.Create();
rsaPublic.ImportFromPem(authSettings.PublicKey?.ToCharArray()); rsaPublic.ImportFromPem(tokenAuthSettings.PublicKey?.ToCharArray());
var rsaPublicKey = new RsaSecurityKey(rsaPublic); var rsaPublicKey = new RsaSecurityKey(rsaPublic);
var jwtAppSettingOptions = configuration.GetSection("B2C:JwtIssuerOptions");
var jwtIssuerOptions = jwtAppSettingOptions.Get<JwtIssuerOptions>(); var jwtIssuerOptions = new JwtIssuerOptions
{
Audience = tokenAuthSettings.Audience,
Issuer = tokenAuthSettings.Issuer,
};
if (string.IsNullOrEmpty(jwtIssuerOptions?.Issuer) || string.IsNullOrEmpty(jwtIssuerOptions.Audience)) if (string.IsNullOrEmpty(jwtIssuerOptions?.Issuer) || string.IsNullOrEmpty(jwtIssuerOptions.Audience))
throw new InvalidOperationException("JwtIssuerOptions are not configured correctly."); throw new InvalidOperationException("JwtIssuerOptions are not configured correctly.");
@@ -88,10 +86,52 @@ namespace Core.Thalos.Adapters.Extensions
options.Audience = jwtIssuerOptions?.Audience; options.Audience = jwtIssuerOptions?.Audience;
options.SigningCredentials = new SigningCredentials(rsaPrivateKey, SecurityAlgorithms.RsaSha256); options.SigningCredentials = new SigningCredentials(rsaPrivateKey, SecurityAlgorithms.RsaSha256);
}); });
}
services.AddSingleton(jwtAppSettingOptions); public static void AddAzureAuthentication(AuthSettings authSettings, IConfiguration configuration, IServiceCollection services)
services.AddTransient<IAuthorizationHandler, PermissionsAuthorizationHandler>(); {
services.AddTransient<ITokenService, TokenService>(); var azureAdInMemorySettings = new Dictionary<string, string?>
{
{ "AzureAdB2C:Instance", authSettings.Azure.Instance ?? string.Empty },
{ "AzureAdB2C:TenantId", authSettings.Azure.TenantId ?? string.Empty },
{ "AzureAdB2C:ClientId", authSettings.Azure.ClientId ?? string.Empty },
{ "AzureAdB2C:ClientSecret", authSettings.Azure.ClientSecret ?? string.Empty }
};
var configurationBuilder = new ConfigurationBuilder()
.AddConfiguration(configuration)
.AddInMemoryCollection(azureAdInMemorySettings);
var combinedConfiguration = configurationBuilder.Build();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(combinedConfiguration.GetSection("AzureAdB2C"), Schemes.AzureScheme)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(configuration.GetSection("MicrosoftGraph"))
.AddInMemoryTokenCaches();
}
public static void AddGoogleAuthentication(IServiceCollection services, GoogleAuthSettings googleAuthSettings)
{
services.AddSingleton<GoogleAuthSettings>(googleAuthSettings);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = Schemes.GoogleScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddScheme<AuthenticationSchemeOptions,
GoogleAccessTokenAuthenticationHandler>(Schemes.GoogleScheme, null)
.AddGoogle(options =>
{
options.ClientId = googleAuthSettings.ClientId!;
options.ClientSecret = googleAuthSettings.ClientSecret!;
//options.SaveTokens = true;
options.CallbackPath = $"/{googleAuthSettings.RedirectUri}";
});
services.AddScoped<IGoogleAuthHelper, GoogleAuthHelper>();
services.AddScoped<IGoogleAuthorization, GoogleAuthorization>();
} }
} }
} }

View File

@@ -5,18 +5,17 @@
// *********************************************************************** // ***********************************************************************
using Asp.Versioning.ApiExplorer; using Asp.Versioning.ApiExplorer;
using Core.Thalos.Adapters.Common.Constants;
using Core.Thalos.Adapters.Extensions;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen; using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI; using Swashbuckle.AspNetCore.SwaggerUI;
namespace Core.Thalos.Adapters.Extensions namespace Core.Thalos.BuildingBlocks.Configuration
{ {
/// <summary> /// <summary>
/// Extension methods for configuring Swagger documentation and UI. /// Extension methods for configuring Swagger documentation and UI.
@@ -40,71 +39,121 @@ namespace Core.Thalos.Adapters.Extensions
/// </summary> /// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
/// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger and OAuth2 configuration settings.</param> /// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger and OAuth2 configuration settings.</param>
public static void AddSwaggerGen(this IServiceCollection services, IConfiguration configuration, string DocumentationFile, AuthSettings authSettings) public static void AddSwaggerGen(
this IServiceCollection services,
IConfiguration configuration,
string documentationFile,
AuthSettings authSettings)
{ {
var identityProviders = new IdentityProviders();
configuration.GetSection("IdentityProviders").Bind(identityProviders);
services.AddSwaggerGen(c => services.AddSwaggerGen(c =>
{
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{ {
c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme Description = "JWT Authorization header using the Bearer scheme",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.Http,
Scheme = "bearer",
BearerFormat = "JWT"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{ {
Description = "OAuth2.0 Authorization Code flow", Type = ReferenceType.SecurityScheme,
Name = "oauth2.0", Id = "Bearer"
}
},
Array.Empty<string>()
}
});
if (identityProviders.Azure)
{
const string azureScheme = "oauth2-Azure";
c.AddSecurityDefinition(azureScheme, new OpenApiSecurityScheme
{
Description = "Azure OAuth2 Authorization Code flow",
Type = SecuritySchemeType.OAuth2, Type = SecuritySchemeType.OAuth2,
Flows = new OpenApiOAuthFlows Flows = new OpenApiOAuthFlows
{ {
AuthorizationCode = new OpenApiOAuthFlow AuthorizationCode = new OpenApiOAuthFlow
{ {
AuthorizationUrl = new Uri(authSettings.ThalosAppAuthorizationUrl ?? string.Empty), AuthorizationUrl = new Uri(authSettings.Azure?.ThalosAppAuthorizationUrl ??
TokenUrl = new Uri(authSettings.ThalosAppTokenUrl ?? string.Empty), "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"),
TokenUrl = new Uri(authSettings.Azure?.ThalosAppTokenUrl ??
"https://login.microsoftonline.com/common/oauth2/v2.0/token"),
Scopes = new Dictionary<string, string> Scopes = new Dictionary<string, string>
{ {
{ authSettings.ThalosAppScope ?? string.Empty, "Access API as User" } { authSettings.Azure?.ThalosAppScope ?? "access_as_user", "Access API as User" }
} }
} }
} }
}); });
c.AddSecurityRequirement(new OpenApiSecurityRequirement c.AddSecurityRequirement(new OpenApiSecurityRequirement
{ {
{ [new OpenApiSecurityScheme
new OpenApiSecurityScheme
{ {
Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = azureScheme }
}, }] = new[] { authSettings.Azure?.ThalosAppScope ?? "access_as_user" }
new[] { authSettings.ThalosAppScope }
}
}); });
}
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme if (identityProviders.Google)
{
const string googleScheme = "oauth2-Google";
c.AddSecurityDefinition(googleScheme, new OpenApiSecurityScheme
{ {
Description = "JWT Authorization header using the Bearer scheme", Type = SecuritySchemeType.OAuth2,
Name = "Authorization",
In = ParameterLocation.Header, Extensions = new Dictionary<string, IOpenApiExtension>
Type = SecuritySchemeType.Http, {
Scheme = "bearer", ["x-tokenName"] = new OpenApiString("id_token")
BearerFormat = "JWT" },
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri("https://accounts.google.com/o/oauth2/v2/auth"),
TokenUrl = new Uri("https://oauth2.googleapis.com/token"),
Scopes = new Dictionary<string, string>
{
{ "openid", "OpenID Connect" },
{ "email", "Access email" },
{ "profile", "Access profile" }
}
}
}
}); });
c.AddSecurityRequirement(new OpenApiSecurityRequirement c.AddSecurityRequirement(new OpenApiSecurityRequirement
{ {
{ [new OpenApiSecurityScheme
new OpenApiSecurityScheme
{ {
Reference = new OpenApiReference Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = googleScheme }
{ }] = new[] { "openid", "email", "profile" }
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
Array.Empty<string>()
}
}); });
}
var filePath = Path.Combine(AppContext.BaseDirectory, DocumentationFile); // ✅ XML Comments
c.IncludeXmlComments(filePath); var filePath = Path.Combine(AppContext.BaseDirectory, documentationFile);
c.SchemaFilter<EnumSchemaFilter>(); c.IncludeXmlComments(filePath);
}); c.SchemaFilter<EnumSchemaFilter>();
});
} }
/// <summary> /// <summary>
/// Configures Swagger and Swagger UI for the application. /// Configures Swagger and Swagger UI for the application.
/// </summary> /// </summary>
@@ -129,15 +178,36 @@ namespace Core.Thalos.Adapters.Extensions
/// </summary> /// </summary>
/// <param name="app">The <see cref="WebApplication"/> instance.</param> /// <param name="app">The <see cref="WebApplication"/> instance.</param>
/// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger UI and OAuth2 configuration settings.</param> /// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger UI and OAuth2 configuration settings.</param>
public static void UseSwaggerUI(this WebApplication app, IConfiguration configuration, AuthSettings authSettings) public static void UseSwaggerUI(
this WebApplication app,
IConfiguration configuration,
AuthSettings authSettings)
{ {
app.UseSwaggerUI(options => var identityProviders = new IdentityProviders();
configuration.GetSection("IdentityProviders").Bind(identityProviders);
app.UseSwagger();
if (identityProviders.Google)
{ {
options.SwaggerEndpoint("/swagger/v1/swagger.json", "Custom Auth API with Azure AD v1"); app.UseSwaggerUI(options =>
options.OAuthClientId(authSettings.ThalosAppClientId); {
options.OAuthUsePkce(); options.OAuthUsePkce();
options.OAuthScopeSeparator(" "); options.OAuthScopeSeparator(" ");
}); options.OAuthClientId(authSettings.Google?.ClientId);
options.OAuthClientSecret(authSettings.Google?.ClientSecret);
});
}
if (identityProviders.Azure)
{
app.UseSwaggerUI(options =>
{
options.OAuthUsePkce();
options.OAuthScopeSeparator(" ");
options.OAuthClientId(authSettings.Azure?.ThalosAppClientId);
});
}
} }
/// <summary> /// <summary>

View File

@@ -4,15 +4,15 @@ using OpenTelemetry.Metrics;
using OpenTelemetry.Resources; using OpenTelemetry.Resources;
using OpenTelemetry.Trace; using OpenTelemetry.Trace;
namespace Core.Thalos.Adapters.Extensions namespace Core.Thalos.BuildingBlocks.Configuration
{ {
public static class TelemetryExtensions public static class TelemetryExtensions
{ {
public static void AddTelemetry(this IServiceCollection services) public static void AddTelemetry(this IServiceCollection services, string apiName)
{ {
// Add OpenTelemetry Tracing // Add OpenTelemetry Tracing
services.AddOpenTelemetry() services.AddOpenTelemetry()
.ConfigureResource(resource => resource.AddService("lsa.dashboard.bff.api")) .ConfigureResource(resource => resource.AddService($"{apiName}"))
.WithTracing(tracing => tracing.AddAspNetCoreInstrumentation().AddConsoleExporter()) .WithTracing(tracing => tracing.AddAspNetCoreInstrumentation().AddConsoleExporter())
.WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation().AddConsoleExporter()). .WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation().AddConsoleExporter()).
WithLogging(logs => logs.AddConsoleExporter()); WithLogging(logs => logs.AddConsoleExporter());

View File

@@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Core.Thalos.Adapters.Extensions namespace Core.Thalos.BuildingBlocks.Extensions
{ {
public sealed class TrackingMechanismExtension : DelegatingHandler public sealed class TrackingMechanismExtension : DelegatingHandler
{ {

View File

@@ -4,9 +4,8 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
using Core.Thalos.Adapters.Contracts;
namespace Core.Thalos.Adapters.Handlers namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Class to inject the token in all requests. /// Class to inject the token in all requests.

View File

@@ -0,0 +1,65 @@
using Google.Apis.Auth;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Security.Claims;
using System.Text.Encodings.Web;
namespace Core.Thalos.BuildingBlocks
{
public class GoogleAccessTokenAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
IConfiguration config,
GoogleAuthSettings googleSettings
) : AuthenticationHandler<AuthenticationSchemeOptions>(options, logger, encoder)
{
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization header");
var authHeader = Request.Headers.Authorization.ToString();
if (!authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
return AuthenticateResult.Fail("Invalid Authorization header");
var idToken = authHeader["Bearer ".Length..].Trim();
GoogleJsonWebSignature.Payload payload;
try
{
payload = await GoogleJsonWebSignature.ValidateAsync(
idToken,
new GoogleJsonWebSignature.ValidationSettings
{
Audience = new[] { googleSettings.ClientId! }
});
}
catch (InvalidJwtException)
{
return AuthenticateResult.Fail("Invalid Google token");
}
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, payload.Subject),
new Claim(ClaimTypes.Email, payload.Email),
new Claim(ClaimTypes.Name, payload.Name ?? "")
};
var identity = new ClaimsIdentity(claims, Schemes.GoogleScheme);
var principal = new ClaimsPrincipal(identity);
var userEmail = principal.FindFirst(ClaimTypes.Email)?.Value;
if (string.IsNullOrEmpty(userEmail) ||
!userEmail.EndsWith("@agilewebs.com", StringComparison.OrdinalIgnoreCase))
return AuthenticateResult.Fail("Unauthorized Access");
var ticket = new AuthenticationTicket(principal, Schemes.GoogleScheme);
return AuthenticateResult.Success(ticket);
}
}
}

View File

@@ -1,7 +1,6 @@
using Core.Thalos.Adapters.Handlers.Adapters; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization;
namespace Core.Thalos.Adapters.Handlers namespace Core.Thalos.BuildingBlocks
{ {
public class PermissionsAuthorizationHandler : AuthorizationHandler<PermissionsAuthorizationAdapter> public class PermissionsAuthorizationHandler : AuthorizationHandler<PermissionsAuthorizationAdapter>
{ {

View File

@@ -1,11 +1,12 @@
using Azure.Identity; using Azure.Identity;
using Core.Thalos.Adapters.Common.Constants; using Core.Blueprint.KeyVault;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureAppConfiguration; using Microsoft.Extensions.Configuration.AzureAppConfiguration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Core.Thalos.Adapters.Helpers namespace Core.Thalos.BuildingBlocks
{ {
public static class AuthHelper public static class AuthHelper
{ {
@@ -15,9 +16,16 @@ namespace Core.Thalos.Adapters.Helpers
}).CreateLogger("AuthHelper"); }).CreateLogger("AuthHelper");
public static AuthSettings GetAuthSettings(WebApplicationBuilder builder, string appConfigLabel) public static async Task<AuthSettings> GetAuthSettings(this IServiceCollection services, WebApplicationBuilder builder, string appConfigLabel)
{ {
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty; var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
var authSettings = new AuthSettings();
var identityProviders = new IdentityProviders();
builder.Configuration.GetSection("IdentityProviders").Bind(identityProviders);
using var serviceProvider = services.BuildServiceProvider();
var keyVaultProvider = serviceProvider.GetRequiredService<IKeyVaultProvider>();
if (environment != "Local") if (environment != "Local")
{ {
@@ -39,19 +47,82 @@ namespace Core.Thalos.Adapters.Helpers
}); });
} }
return new AuthSettings if (identityProviders.Google)
authSettings.Google = await GetGoogleSettings(keyVaultProvider, builder);
if (identityProviders.Azure)
authSettings.Azure = GetAzureSettings(builder);
authSettings.Token = await GetTokenSettings(keyVaultProvider, builder);
return authSettings;
}
private async static ValueTask<TokenAuthSettings> GetTokenSettings(IKeyVaultProvider keyVaultProvider, WebApplicationBuilder builder)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
var tokenSettings = new TokenAuthSettings();
if (environment == "Local")
{ {
AzureADInstance = builder.Configuration.GetSection(Secrets.AzureADInstance).Value, tokenSettings.PublicKey = (await keyVaultProvider.GetSecretAsync(Secrets.PublicKey, new CancellationToken { })).Secret.Value;
AzureADTenantId = builder.Configuration.GetSection(Secrets.AzureADTenantId).Value, tokenSettings.PrivateKey = (await keyVaultProvider.GetSecretAsync(Secrets.PrivateKey, new CancellationToken { })).Secret.Value;
AzureADClientId = builder.Configuration.GetSection(Secrets.AzureADClientId).Value, tokenSettings.Issuer = (await keyVaultProvider.GetSecretAsync(Secrets.Issuer, new CancellationToken { })).Secret.Value;
AzureADClientSecret = builder.Configuration.GetSection(Secrets.AzureADClientSecret).Value, tokenSettings.Audience = (await keyVaultProvider.GetSecretAsync(Secrets.Audience, new CancellationToken { })).Secret.Value;
}
else
{
tokenSettings.PrivateKey = builder.Configuration.GetSection(Secrets.PrivateKey).Value;
tokenSettings.PublicKey = builder.Configuration.GetSection(Secrets.PublicKey).Value;
tokenSettings.Issuer = builder.Configuration.GetSection(Secrets.Issuer).Value;
tokenSettings.Audience = builder.Configuration.GetSection(Secrets.Audience).Value;
}
if (string.IsNullOrEmpty(tokenSettings.PrivateKey) || string.IsNullOrEmpty(tokenSettings.PublicKey))
{
logger.LogError("Settings for token creation are missing or incorrectly formatted.");
throw new InvalidOperationException("Invalid public or private key.");
}
return tokenSettings;
}
private static AzureAuthSettings GetAzureSettings(WebApplicationBuilder builder)
{
return new AzureAuthSettings
{
Instance = builder.Configuration.GetSection(Secrets.AzureADInstance).Value,
TenantId = builder.Configuration.GetSection(Secrets.AzureADTenantId).Value,
ClientId = builder.Configuration.GetSection(Secrets.AzureADClientId).Value,
ClientSecret = builder.Configuration.GetSection(Secrets.AzureADClientSecret).Value,
ThalosAppAuthorizationUrl = builder.Configuration.GetSection(Secrets.ThalosAppAuthorizationUrl).Value, ThalosAppAuthorizationUrl = builder.Configuration.GetSection(Secrets.ThalosAppAuthorizationUrl).Value,
ThalosAppTokenUrl = builder.Configuration.GetSection(Secrets.ThalosAppTokenUrl).Value, ThalosAppTokenUrl = builder.Configuration.GetSection(Secrets.ThalosAppTokenUrl).Value,
ThalosAppClientId = builder.Configuration.GetSection(Secrets.ThalosAppClientId).Value, ThalosAppClientId = builder.Configuration.GetSection(Secrets.ThalosAppClientId).Value,
ThalosAppScope = builder.Configuration.GetSection(Secrets.ThalosAppScope).Value, ThalosAppScope = builder.Configuration.GetSection(Secrets.ThalosAppScope).Value,
PrivateKey = builder.Configuration.GetSection(Secrets.PrivateKey).Value,
PublicKey = builder.Configuration.GetSection(Secrets.PublicKey).Value,
}; };
} }
private static async ValueTask<GoogleAuthSettings> GetGoogleSettings(IKeyVaultProvider keyVaultProvider, WebApplicationBuilder builder)
{
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var googleSettings = new GoogleAuthSettings();
if (environment == "Local")
{
googleSettings.ClientId = (await keyVaultProvider.GetSecretAsync(Secrets.GoogleClientId, new CancellationToken { })).Secret.Value; ;
googleSettings.ClientSecret = (await keyVaultProvider.GetSecretAsync(Secrets.GoogleClientSecret, new CancellationToken { })).Secret.Value;
googleSettings.RedirectUri = (await keyVaultProvider.GetSecretAsync(Secrets.GoogleRedirectUri, new CancellationToken { })).Secret.Value;
}
else
{
googleSettings.ClientId = builder.Configuration.GetSection(Secrets.GoogleClientId).Value;
googleSettings.ClientSecret = builder.Configuration.GetSection(Secrets.GoogleClientSecret).Value;
googleSettings.RedirectUri = builder.Configuration.GetSection(Secrets.GoogleRedirectUri).Value;
}
return googleSettings;
}
} }
} }

View File

@@ -0,0 +1,31 @@
using Google.Apis.Auth.OAuth2;
using Google.Apis.Oauth2.v2;
using Microsoft.Extensions.Configuration;
namespace Core.Thalos.BuildingBlocks
{
public class GoogleAuthHelper(IConfiguration config, GoogleAuthSettings googleSettings) : IGoogleAuthHelper
{
public ClientSecrets GetClientSecrets()
{
string clientId = googleSettings.ClientId ?? string.Empty;
string clientSecret = googleSettings.ClientSecret ?? string.Empty;
return new() { ClientId = clientId, ClientSecret = clientSecret };
}
public string[] GetScopes()
{
var scopes = new[]
{
Oauth2Service.Scope.Openid,
Oauth2Service.Scope.UserinfoEmail,
Oauth2Service.Scope.UserinfoProfile
};
return scopes;
}
public string ScopeToString() => string.Join(", ", GetScopes());
}
}

View File

@@ -10,7 +10,7 @@ using Org.BouncyCastle.Security;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
namespace Core.Thalos.Adapters.Helpers namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Handles all methods related to RSA encryption"/>. /// Handles all methods related to RSA encryption"/>.

View File

@@ -1,6 +1,6 @@
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
namespace Core.Thalos.Adapters.Options namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// JWT token Issuer options (used for JWT Factory) /// JWT token Issuer options (used for JWT Factory)

View File

@@ -3,9 +3,6 @@
// AgileWebs // AgileWebs
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
using Core.Thalos.Adapters.Common.Constants;
using Core.Thalos.Adapters.Contracts;
using Core.Thalos.Adapters.Options;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@@ -16,7 +13,7 @@ using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;
using System.Text.Json; using System.Text.Json;
namespace Core.Thalos.Adapters.Services namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Service responsible for manage authenticacion. /// Service responsible for manage authenticacion.
@@ -90,8 +87,10 @@ namespace Core.Thalos.Adapters.Services
{ {
new Claim(Claims.Name, adapter?.User?.DisplayName ?? string.Empty), new Claim(Claims.Name, adapter?.User?.DisplayName ?? string.Empty),
new Claim(Claims.GUID, adapter?.User?.Guid ?? string.Empty), new Claim(Claims.Id, adapter?.User?.Id ?? string.Empty),
new Claim(Claims.Email, adapter?.User?.Email ?? string.Empty), new Claim(Claims.Email, adapter?.User?.Email ?? string.Empty),
new Claim(Claims.Tenant, adapter?.Tenant?.Name ?? string.Empty),
new Claim(Claims.Tenant, adapter?.Tenant?.Id ?? string.Empty),
new Claim(Claims.Role, adapter?.Role?.Name ?? string.Empty), new Claim(Claims.Role, adapter?.Role?.Name ?? string.Empty),
new Claim(Claims.RoleId, adapter?.Role?.Id ?? string.Empty), new Claim(Claims.RoleId, adapter?.Role?.Id ?? string.Empty),
new Claim(Claims.Applications, JsonSerializer.Serialize(adapter?.Role?.Applications), JsonClaimValueTypes.JsonArray), new Claim(Claims.Applications, JsonSerializer.Serialize(adapter?.Role?.Applications), JsonClaimValueTypes.JsonArray),

View File

@@ -4,22 +4,39 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
namespace Core.Thalos.BuildingBlocks;
public class AuthSettings public class AuthSettings
{ {
// Azure AD Settings public AzureAuthSettings? Azure { get; set; }
public string? AzureADInstance { get; set; } public TokenAuthSettings Token { get; set; } = null!;
public string? AzureADTenantId { get; set; } public GoogleAuthSettings? Google { get; set; }
public string? AzureADClientId { get; set; } }
public string? AzureADClientSecret { get; set; }
//Thalos App Settings public class AzureAuthSettings
{
public string? Instance { get; set; }
public string? TenantId { get; set; }
public string? ClientId { get; set; }
public string? ClientSecret { get; set; }
public string? ThalosAppAuthorizationUrl { get; set; } public string? ThalosAppAuthorizationUrl { get; set; }
public string? ThalosAppTokenUrl { get; set; } public string? ThalosAppTokenUrl { get; set; }
public string? ThalosAppClientId { get; set; } public string? ThalosAppClientId { get; set; }
public string? ThalosAppScope { get; set; } public string? ThalosAppScope { get; set; }
}
// Token Keys
public string? PrivateKey { get; set; } public class GoogleAuthSettings
public string? PublicKey { get; set; } {
public string? ClientId { get; set; }
public string? ClientSecret { get; set; }
public string? RedirectUri { get; set; }
}
public class TokenAuthSettings
{
public string? PrivateKey { get; set; }
public string? PublicKey { get; set; }
public string? Audience { get; set; }
public string? Issuer { get; set; }
} }

View File

@@ -0,0 +1,8 @@
namespace Core.Thalos.BuildingBlocks
{
public class IdentityProviders
{
public bool Google { get; set; }
public bool Azure { get; set; }
}
}

View File

@@ -4,10 +4,9 @@
// </copyright> // </copyright>
// *********************************************************************** // ***********************************************************************
using Core.Thalos.Adapters.Contracts;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Core.Thalos.Adapters.TokenProvider namespace Core.Thalos.BuildingBlocks
{ {
/// <summary> /// <summary>
/// Class to return the access token to controllers. /// Class to return the access token to controllers.