Release v1.0.0 #16
.editorconfig.envDbInitializer.csDependencyInjection.csnuget.config
.gitea/workflows
.gitignoreApiDto
ApiDto.csproj
Backend.slnDockerfileCommon
AuthRoles.csCacheType.csDatabaseType.csOAuthAction.csOAuthProvider.csPairPeriodTime.csPasswordPolicy.csTwoFactorAuthentication.cs
Requests
Responses
Endpoint
Backend.httpISaveSettings.cs
README.mdCommon
Attributes
BadRequestResponseAttribute.csCacheMaxAgeAttribute.csLocalhostAttribute.csMaintenanceModeIgnoreAttribute.csNotFoundResponseAttribute.csSwaggerDefaultAttribute.csTokenAuthenticationAttribute.cs
Exceptions
Interfaces
MapperDto
AvailableProvidersConverter.csPairPeriodTimeConverter.csPasswordPolicyConverter.csTwoFactorAuthenticationConverter.csUserConverter.cs
Services
Configuration
Core
BackgroundTasks
Middleware
CacheMaxAgeMiddleware.csCookieAuthorizationMiddleware.csCustomExceptionHandlerMiddleware.csJwtRevocationMiddleware.csMaintenanceModeMiddleware.cs
Startup
Model
SwaggerOptions
Validation
Controllers
BaseController.cs
Endpoint.csprojProgram.csConfiguration
V1
AuthController.csCampusController.csDisciplineController.csFacultyController.csGroupController.csImportController.csLectureHallController.csProfessorController.csScheduleController.csSecurityController.cs
WeatherForecastController.csSync
WeatherForecast.cswwwroot
css
swagger
Security
Common
CookieNames.cs
DependencyInjection.csDomain
Interfaces
Model
OAuth2
ViewModel
Properties
Security.csprojServices
SqlData
Application
Application.csprojDependencyInjection.cs
Common
Cqrs
Campus
Queries
Discipline
Queries
Faculty
Queries
Group
Queries
LectureHall
Queries
Professor
Queries
GetProfessorDetails
GetProfessorDetailsBySearch
GetProfessorList
Schedule
Interfaces
Domain
Domain.csproj
Schedule
Migrations
MysqlMigrations
Migrations
20240601023106_InitialMigration.Designer.cs20240601023106_InitialMigration.cs20241027034820_RemoveUnusedRef.Designer.cs20241027034820_RemoveUnusedRef.csUberDbContextModelSnapshot.cs
MysqlMigrations.csprojPsqlMigrations
Migrations
20240601021702_InitialMigration.Designer.cs20240601021702_InitialMigration.cs20241027032753_RemoveUnusedRef.Designer.cs20241027032753_RemoveUnusedRef.csUberDbContextModelSnapshot.cs
PsqlMigrations.csprojSqliteMigrations
Persistence
Common
BaseDbContext.csConfigurationResolver.csDatabaseProvider.csDbContextFactory.csModelBuilderExtensions.cs
Contexts
Schedule
EntityTypeConfigurations
Persistence.csprojUberDbContext.cs@@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Http;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Data.Sqlite;
|
using Microsoft.Data.Sqlite;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
using Mirea.Api.Dto.Common;
|
using Mirea.Api.Dto.Common;
|
||||||
using Mirea.Api.Dto.Requests;
|
using Mirea.Api.Dto.Requests;
|
||||||
using Mirea.Api.Dto.Requests.Configuration;
|
using Mirea.Api.Dto.Requests.Configuration;
|
||||||
@@ -18,6 +17,7 @@ using Mirea.Api.Endpoint.Common.Services;
|
|||||||
using Mirea.Api.Endpoint.Configuration.Model;
|
using Mirea.Api.Endpoint.Configuration.Model;
|
||||||
using Mirea.Api.Endpoint.Configuration.Model.GeneralSettings;
|
using Mirea.Api.Endpoint.Configuration.Model.GeneralSettings;
|
||||||
using Mirea.Api.Endpoint.Configuration.Validation.Validators;
|
using Mirea.Api.Endpoint.Configuration.Validation.Validators;
|
||||||
|
using Mirea.Api.Security.Common.Domain;
|
||||||
using Mirea.Api.Security.Common.Model;
|
using Mirea.Api.Security.Common.Model;
|
||||||
using Mirea.Api.Security.Services;
|
using Mirea.Api.Security.Services;
|
||||||
using MySqlConnector;
|
using MySqlConnector;
|
||||||
@@ -26,13 +26,17 @@ using Serilog;
|
|||||||
using StackExchange.Redis;
|
using StackExchange.Redis;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CookieOptions = Microsoft.AspNetCore.Http.CookieOptions;
|
using CookieOptions = Microsoft.AspNetCore.Http.CookieOptions;
|
||||||
|
using OAuthProvider = Mirea.Api.Security.Common.Domain.OAuthProvider;
|
||||||
using PasswordPolicy = Mirea.Api.Dto.Common.PasswordPolicy;
|
using PasswordPolicy = Mirea.Api.Dto.Common.PasswordPolicy;
|
||||||
|
|
||||||
namespace Mirea.Api.Endpoint.Controllers.Configuration;
|
namespace Mirea.Api.Endpoint.Controllers.Configuration;
|
||||||
@@ -45,7 +49,7 @@ public class SetupController(
|
|||||||
IMaintenanceModeNotConfigureService notConfigureService,
|
IMaintenanceModeNotConfigureService notConfigureService,
|
||||||
IMemoryCache cache,
|
IMemoryCache cache,
|
||||||
PasswordHashService passwordHashService,
|
PasswordHashService passwordHashService,
|
||||||
IOptionsSnapshot<Admin> user) : BaseController
|
OAuthService oAuthService) : BaseController
|
||||||
{
|
{
|
||||||
private const string CacheGeneralKey = "config_general";
|
private const string CacheGeneralKey = "config_general";
|
||||||
private const string CacheAdminKey = "config_admin";
|
private const string CacheAdminKey = "config_admin";
|
||||||
@@ -319,29 +323,54 @@ public class SetupController(
|
|||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("UpdateAdminConfiguration")]
|
[HttpGet("HandleToken")]
|
||||||
[TokenAuthentication]
|
[TokenAuthentication]
|
||||||
public ActionResult UpdateAdminConfiguration()
|
public async Task<ActionResult> HandleToken([FromQuery][MinLength(2)] string token)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(user.Value.Email))
|
var (user, error, isSuccess, provider) = await oAuthService.GetOAuthUser(new Security.Common.Model.CookieOptions
|
||||||
return Ok();
|
{
|
||||||
|
Domain = HttpContext.GetCurrentDomain(),
|
||||||
|
Path = UrlHelper.GetSubPathWithoutFirstApiName + "api"
|
||||||
|
}, HttpContext, token);
|
||||||
|
|
||||||
|
if (!isSuccess || user == null || provider == null)
|
||||||
|
throw new ControllerArgumentException(error ?? "Token processing error.");
|
||||||
|
|
||||||
if (!cache.TryGetValue<Admin>(CacheAdminKey, out var admin))
|
if (!cache.TryGetValue<Admin>(CacheAdminKey, out var admin))
|
||||||
{
|
{
|
||||||
admin = user.Value;
|
admin = new Admin()
|
||||||
|
{
|
||||||
|
Email = user.Email ?? string.Empty,
|
||||||
|
Username = user.Username ?? string.Empty,
|
||||||
|
PasswordHash = string.Empty,
|
||||||
|
Salt = string.Empty,
|
||||||
|
OAuthProviders = new Dictionary<OAuthProvider, OAuthUser>
|
||||||
|
{
|
||||||
|
{provider.Value, user}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
cache.Set(CacheAdminKey, admin);
|
cache.Set(CacheAdminKey, admin);
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
admin!.OAuthProviders = user.Value.OAuthProviders;
|
if (admin!.OAuthProviders != null && admin.OAuthProviders.ContainsKey(provider.Value))
|
||||||
|
return Conflict(new ProblemDetails
|
||||||
if (string.IsNullOrEmpty(admin.Email))
|
{
|
||||||
admin.Email = user.Value.Email;
|
Type = "https://tools.ietf.org/html/rfc9110#section-15.5.10",
|
||||||
|
Title = "Conflict",
|
||||||
if (string.IsNullOrEmpty(admin.Username))
|
Status = StatusCodes.Status409Conflict,
|
||||||
admin.Username = user.Value.Username;
|
Detail = "This OAuth provider is already associated with the account.",
|
||||||
|
Extensions = new Dictionary<string, object?>()
|
||||||
|
{
|
||||||
|
{ "traceId", Activity.Current?.Id ?? HttpContext.TraceIdentifier }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
admin.OAuthProviders ??= [];
|
||||||
|
admin.OAuthProviders.Add(provider.Value, user);
|
||||||
cache.Set(CacheAdminKey, admin);
|
cache.Set(CacheAdminKey, admin);
|
||||||
|
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -172,7 +172,6 @@ public class AuthController(IOptionsSnapshot<Admin> user, IOptionsSnapshot<Gener
|
|||||||
/// <param name="action">The action to be performed: Login or Bind.</param>
|
/// <param name="action">The action to be performed: Login or Bind.</param>
|
||||||
/// <returns>If <see cref="OAuthAction.Bind"/> return Ok. If <see cref="OAuthAction.Login"/> return <see cref="TwoFactorAuthentication"/></returns>
|
/// <returns>If <see cref="OAuthAction.Bind"/> return Ok. If <see cref="OAuthAction.Login"/> return <see cref="TwoFactorAuthentication"/></returns>
|
||||||
[HttpGet("HandleToken")]
|
[HttpGet("HandleToken")]
|
||||||
[MaintenanceModeIgnore]
|
|
||||||
[BadRequestResponse]
|
[BadRequestResponse]
|
||||||
public async Task<ActionResult> HandleToken([FromQuery][MinLength(2)] string token, [FromQuery] OAuthAction action)
|
public async Task<ActionResult> HandleToken([FromQuery][MinLength(2)] string token, [FromQuery] OAuthAction action)
|
||||||
{
|
{
|
||||||
|
@@ -332,7 +332,7 @@ public class OAuthService(ILogger<OAuthService> logger, Dictionary<OAuthProvider
|
|||||||
var requestInfo = new RequestContextInfo(context, cookieOptions);
|
var requestInfo = new RequestContextInfo(context, cookieOptions);
|
||||||
|
|
||||||
var result = await cache.GetAsync<OAuthUserExtension>(token, cancellation);
|
var result = await cache.GetAsync<OAuthUserExtension>(token, cancellation);
|
||||||
string tokenFailedKey = $"{requestInfo.Fingerprint}_oauth_token_failed";
|
var tokenFailedKey = $"{requestInfo.Fingerprint}_oauth_token_failed";
|
||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user