I am trying to create an ASP.NET Core 6 MVC app and want to implement CAS, but cannot find directions. I got the nuget package for GSS.Authentication.CAS
and they do not have instructions or explanations of what to do. I got the program.cs
file part then I do not know how to set up the controller.
program.cs
file:
#pragma warning disable SA1200 // Using directives should be placed correctly
using System.Security.Claims;
using GSS.Authentication.CAS.AspNetCore;
using GSS.Authentication.CAS.Validation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.Extensions;
#pragma warning restore SA1200 // Using directives should be placed correctly
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddAuthorization(options =>
{
// Globally Require Authenticated Users
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Events = new CookieAuthenticationEvents
{
OnSigningOut = context =>
{
// Single Sign-Out
var casUrl = new Uri(builder.Configuration["Authentication:CAS:ServerUrlBase"]);
var links = context.HttpContext.RequestServices.GetRequiredService<LinkGenerator>();
var serviceUrl = links.GetUriByPage(context.HttpContext, "/Index");
var redirectUri = UriHelper.BuildAbsolute(
casUrl.Scheme,
new HostString(casUrl.Host, casUrl.Port),
casUrl.LocalPath,
"/logout",
QueryString.Create("service", serviceUrl!));
var logoutRedirectContext = new RedirectContext<CookieAuthenticationOptions>(
context.HttpContext,
context.Scheme,
context.Options,
context.Properties,
redirectUri);
context.Response.StatusCode = 204; // Prevent RedirectToReturnUrl
context.Options.Events.RedirectToLogout(logoutRedirectContext);
return Task.CompletedTask;
},
};
})
.AddCAS(options =>
{
options.CasServerUrlBase = builder.Configuration["Authentication:CAS:ServerUrlBase"];
var protocolVersion = builder.Configuration.GetValue("Authentication:CAS:ProtocolVersion", 2); // change protocol to match your system
if (protocolVersion != 3)
{
options.ServiceTicketValidator = protocolVersion switch
{
1 => new Cas10ServiceTicketValidator(options),
2 => new Cas20ServiceTicketValidator(options),
_ => null
};
}
options.Events = new CasEvents
{
OnCreatingTicket = context =>
{
if (context.Identity == null)
{
return Task.CompletedTask;
}
// Map claims from assertion
var assertion = context.Assertion;
context.Identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, assertion.PrincipalName));
context.Identity.AddClaim(new Claim(ClaimTypes.Name, assertion.PrincipalName)); //This line allows you to access primary login info as User.identity.Name in cs code
if (assertion.Attributes.TryGetValue("display_name", out var displayName))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Name, displayName));
}
if (assertion.Attributes.TryGetValue("email", out var email))
{
context.Identity.AddClaim(new Claim(ClaimTypes.Email, email));
}
return Task.CompletedTask;
},
OnRemoteFailure = context =>
{
var failure = context.Failure;
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<CasEvents>>();
if (!string.IsNullOrWhiteSpace(failure?.Message))
{
logger.LogError(failure, "{Exception}", failure.Message);
}
context.Response.Redirect("/Account/ExternalLoginFailure");
context.HandleResponse();
return Task.CompletedTask;
},
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCookiePolicy();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
So I think I was on the right track with the posted program.cs.
The next step is to create a controller AccountController.cs
namespace {YourAppName}.Controllers {
using System;
using System.Diagnostics;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OneRecordIssue6.Models;
[AllowAnonymous]
public class AccountController : Controller
{
IConfiguration configuration;
public AccountController(IConfiguration configuration)
{
this.configuration = configuration;
}
public IActionResult Login()
{
string isDev = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
if (isDev == "Development")
{
// if in developement, allow me to use any user choosen for testing. This shows me how different rules apply
var simulatedUser = this.configuration.GetSection("Settings:simulatedUser").Value.ToString();
var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, simulatedUser) }, CookieAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
var authProperties = new AuthenticationProperties { ExpiresUtc = DateTimeOffset.UtcNow.AddSeconds(5), IsPersistent = false, RedirectUri = "/" };
this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, authProperties);
return this.RedirectToAction("Index", "Home");
}
else
{
return this.Challenge(new AuthenticationProperties { RedirectUri = "/" }, "CAS");
}
}
public IActionResult ExternalLoginFailureModel()
{
this.Response.StatusCode = 500;
return this.RedirectToAction("Error", "Home");
}
} }
Then make sure in a any controller that needs to to be authorized just add the
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
then any page or controller that needs to be authenticated add
[Authorize]
(include the square brackets) and this will enforce the auth