Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.git
.github
.vs
bin
obj
data-protection-keys
*.user
*.suo
*.dbmdl
docker-compose*.yml
Dockerfile*
README.md
2 changes: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
Expand Down
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,11 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd

# Private deployment configuration and credentials
.env
.env.*
!.env.example
DEPLOYMENT_MANUAL.md
DEPLOYMENT_STEPS.md
100 changes: 32 additions & 68 deletions Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,21 @@
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using System.DirectoryServices.AccountManagement;
using Scribe.Services;
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.Blazor;
using Humanizer;
using System.Security;
using Scribe.Models;

namespace Scribe.Controllers
{
[AllowAnonymous]
public class AccountController : Controller
{
private readonly string domain = "zlt.co.zw";
private readonly string groupName = "Scribe Admins";
private readonly ILoggingService _loggingService;
private readonly IConfiguration _configuration;

public AccountController(ILoggingService loggingService)
public AccountController(ILoggingService loggingService, IConfiguration configuration)
{
_loggingService = loggingService;
_configuration = configuration;
}

[HttpGet]
Expand Down Expand Up @@ -49,32 +45,24 @@ public async Task<IActionResult> Login(string username, string password)
{
if (ValidateUser(username, password, out string validationMessage))
{
if (IsUserInGroup(username))
var claims = new List<Claim>
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Role, "Scribe Admins")
};

var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
TempData["Success"] = "Welcome " + username;
var details = "User " + username + " logged in.";
await _loggingService.LogActionAsync(details, username);

Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
Response.Headers["Pragma"] = "no-cache";
Response.Headers["Expires"] = "0";

return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", "You do not have permission to access this system.");
TempData["Failure"] = "You do not have permission to access this system.";
}
new Claim(ClaimTypes.Name, username),
new Claim(ClaimTypes.Role, "Scribe Admins")
};

var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
TempData["Success"] = "Welcome " + username;
var details = "User " + username + " logged in.";
await _loggingService.LogActionAsync(details, username);

Response.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate";
Response.Headers["Pragma"] = "no-cache";
Response.Headers["Expires"] = "0";

return RedirectToAction("Index", "Home");
}
else
{
Expand Down Expand Up @@ -117,45 +105,21 @@ public async Task<IActionResult> Logout()

private bool ValidateUser(string username, string password, out string validationMessage)
{
using (var context = new PrincipalContext(ContextType.Domain, domain))
{
if (context.ValidateCredentials(username, password))
{
validationMessage = string.Empty;
return true;
}
else
{
using (var user = UserPrincipal.FindByIdentity(context, username))
{
if (user != null && user.IsAccountLockedOut())
{
validationMessage = "Your account is locked. Please try again later.";
TempData["Failure"] = "Your account is locked. Please try again later.";
}
else
{
validationMessage = "Invalid username or password.";
TempData["Failure"] = "Invalid username or password.";
}
}
return false;
}
}
}
var configuredUsername = _configuration["DemoAuthentication:Username"];
var configuredPassword = _configuration["DemoAuthentication:Password"];

private bool IsUserInGroup(string username)
{
using (var context = new PrincipalContext(ContextType.Domain, domain))
using (var user = UserPrincipal.FindByIdentity(context, username))
using (var group = GroupPrincipal.FindByIdentity(context, groupName))
if (!string.IsNullOrWhiteSpace(configuredUsername) &&
!string.IsNullOrWhiteSpace(configuredPassword) &&
string.Equals(username?.Trim(), configuredUsername.Trim(), StringComparison.Ordinal) &&
string.Equals(password, configuredPassword, StringComparison.Ordinal))
{
if (user != null && group != null)
{
return group.GetMembers().Any(member => member.SamAccountName.Equals(username, StringComparison.OrdinalIgnoreCase));
}
validationMessage = string.Empty;
return true;
}

validationMessage = "Invalid username or password.";
TempData["Failure"] = validationMessage;
return false;
}
}
}
}
Loading