To get it working with RazorPages, we need to add the following in Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
// Other statements...
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(x => x.LoginPath = "/login");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Other statements...
app.UseAuthentication();
app.UseAuthorization();
}
Then on the PageModel
for the page we'd like to authenticate, we add the [Authorize] attribute to the class.
Then in the LoginModel
PageModel:
public class LoginModel : PageModel
{
[BindProperty]
[DisplayName("Username:")]
[Required]
public string Username { get; set; }
[BindProperty]
[Required]
[DataType(DataType.Password)]
[DisplayName("Password:")]
public string Password { get; set; }
public string ReturnUrl { get; set; }
public void OnGet(string returnUrl = null)
{
ReturnUrl = returnUrl;
}
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
if (!ModelState.IsValid)
{
return Page();
}
// Check both LDAPs. User must authenticate against one
var isAuthenticated = IsAuthenticated(ConfigurationManager.AppSettings["MyFirstLDAPPath"]) || IsAuthenticated(ConfigurationManager.AppSettings["MySecondLDAPPath"]);
if (isAuthenticated)
{
// Must provide at least the Username claim or it will throw an InvalidOperationException
var identity = new ClaimsIdentity(new List<Claim>{ new Claim(ClaimTypes.Name, Username, ClaimValueTypes.String, "SomeUniqueValue") }, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal,
new AuthenticationProperties());
return LocalRedirect(returnUrl);
}
ViewData["Message"] = "Invalid credentials.";
ReturnUrl = returnUrl;
return Page();
}
// This is a reliable way to check the user's credentials.
// Note that this also considers users with a changed password,
// as some other techniques don't
private bool IsAuthenticated(string ldapPath)
{
try
{
var conn = new LdapConnection(ldapPath);
conn.Credential = new NetworkCredential(Username, Password);
conn.Bind();
return true;
}
catch (Exception)
{
return false;
}
}
}
Then in Login.cshtml
:
<form asp-route-returnurl="@returnUrl" method="post">
@Html.AntiForgeryToken()
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
@if (!string.IsNullOrEmpty(ViewData["Message"]?.ToString()))
{
<span class="text-danger">
@ViewData["Message"]
</span>
}
@Html.HiddenFor(x => x.ReturnUrl)
<h3 class="text-center text-info">Login</h3>
<div class="form-group">
<label asp-for="Username" class="text-info"></label>
<input asp-for="Username" class="form-control" autofocus/>
<span asp-validation-for="Username" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password" class="text-info"></label>
<input asp-for="Password" class="form-control"/>
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" name="submit" class="btn btn-info btn-md" value="submit">
</div>
</form>
Hope this helps others.