Kode
Koden som vises er bare et utvalg av eksempel koden i GitHub.
ITfoxtec Identity Saml2-pakken integreres i en ASP.NET Core MVC Relying Party (RP)-applikasjon ved konfigurasjon i Startup og ved å legge til en Auth Controller med følgende metoder. Bindingen som vises kan endres etter behov avhengig av kravene.
Det er videre mulig å sette noen valgfrie parametere på Saml2AuthnRequest og Saml2LogoutRequest. På Saml2AuthnRequest støttes for eksempel ForceAuthn, som vil tvinge brukeren til å skrive inn innloggingsopplysninger selv om en SSO kontekst allerede eksisterer på Security Token Service (STS) / Identity Provider (IdP).
Legg til konfigurasjon i ConfigureServices metoden i Startup
Konfigurasjon med IdP metadata.
services.BindConfig<Saml2Configuration>(Configuration, "Saml2", (serviceProvider, saml2Configuration) =>
{
saml2Configuration.SigningCertificate = CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(
Configuration["Saml2:SigningCertificateFile"]), Configuration["Saml2:SigningCertificatePassword"]);
saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);
var httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
var entityDescriptor = new EntityDescriptor();
entityDescriptor.ReadIdPSsoDescriptorFromUrlAsync(httpClientFactory, new Uri(Configuration["Saml2:IdPMetadata"])).GetAwaiter().GetResult();
if (entityDescriptor.IdPSsoDescriptor != null)
{
saml2Configuration.AllowedIssuer = entityDescriptor.EntityId;
saml2Configuration.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.First().Location;
saml2Configuration.SingleLogoutDestination = entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.First().Location;
saml2Configuration.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
}
else
{
throw new Exception("IdPSsoDescriptor not loaded from metadata.");
}
return saml2Configuration;
});
services.AddSaml2();
services.AddHttpClient();
Konfigurasjon uten metadata.
services.BindConfig<Saml2Configuration>(Configuration, "Saml2", (serviceProvider, saml2Configuration) =>
{
saml2Configuration.SigningCertificate = CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(
Configuration["Saml2:SigningCertificateFile"]), Configuration["Saml2:SigningCertificatePassword"]);
saml2Configuration.AllowedAudienceUris.Add(saml2Configuration.Issuer);
saml2Configuration.SignatureValidationCertificates.Add(CertificateUtil.Load(AppEnvironment.MapToPhysicalFilePath(
Configuration["Saml2:SignatureValidationCertificateFile"])));
return saml2Configuration;
});
services.AddSaml2();
Login metode i Auth Controller
[Route("Login")]
public IActionResult Login(string returnUrl = null)
{
var binding = new Saml2RedirectBinding();
binding.SetRelayStateQuery(new Dictionary<string, string>
{ { relayStateReturnUrl, returnUrl ?? Url.Content("~/") } });
return binding.Bind(new Saml2AuthnRequest(config)).ToActionResult();
}
AssertionConsumerService metode i Auth Controller
Etter vellykket eller mislykket login mottar ACS metoden svaret.
[Route("AssertionConsumerService")]
public async Task<IActionResult> AssertionConsumerService()
{
var httpRequest = Request.ToGenericHttpRequest(validate: true);
var saml2AuthnResponse = new Saml2AuthnResponse(config);
httpRequest.Binding.ReadSamlResponse(httpRequest, saml2AuthnResponse);
if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
{
throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
}
httpRequest.Binding.Unbind(httpRequest, saml2AuthnResponse);
await saml2AuthnResponse.CreateSessionAsync(HttpContext,
claimsTransform: (claimsPrincipal) => Task.FromResult(ClaimsTransform.Transform(claimsPrincipal)));
var relayStateQuery = httpRequest.Binding.GetRelayStateQuery();
var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrl) ? relayStateQuery[relayStateReturnUrl] : Url.Content("~/");
return Redirect(returnUrl);
}
Logout metode i Auth Controller
[HttpPost("Logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
if (!User.Identity.IsAuthenticated)
{
return Redirect(Url.Content("~/"));
}
var binding = new Saml2PostBinding();
var saml2LogoutRequest = await new Saml2LogoutRequest(config, User).DeleteSession(HttpContext);
return binding.Bind(saml2LogoutRequest).ToActionResult();
}
LoggedOut metode i Auth Controller
Etter vellykket eller mislykket logout mottar LoggedOut metoden svaret.
[Route("LoggedOut")]
public IActionResult LoggedOut()
{
var httpRequest = Request.ToGenericHttpRequest(validate: true);
httpRequest.Binding.Unbind(httpRequest, new Saml2LogoutResponse(config));
return Redirect(Url.Content("~/"));
}
SingleLogout metode i Auth Controller
Mottar en Single Logout forespørsel og sender et svar.
[Route("SingleLogout")]
public async Task<IActionResult> SingleLogout()
{
Saml2StatusCodes status;
var httpRequest = Request.ToGenericHttpRequest(validate: true);
var logoutRequest = new Saml2LogoutRequest(config, User);
try
{
httpRequest.Binding.Unbind(httpRequest, logoutRequest);
status = Saml2StatusCodes.Success;
await logoutRequest.DeleteSession(HttpContext);
}
catch (Exception exc)
{
// log exception
Debug.WriteLine("SingleLogout error: " + exc.ToString());
status = Saml2StatusCodes.RequestDenied;
}
var responseBinding = new Saml2PostBinding();
responseBinding.RelayState = httpRequest.Binding.RelayState;
var saml2LogoutResponse = new Saml2LogoutResponse(config)
{
InResponseToAsString = logoutRequest.IdAsString,
Status = status,
};
return responseBinding.Bind(saml2LogoutResponse).ToActionResult();
}