Я использовал библиотеку SAML2 itfoxte c для реализации SP в моем приложении ASP. NET MVC. Я тестирую, используя samltest.id в качестве IdP. Инициированный IdP рабочий процесс работает отлично, но рабочий процесс, инициированный SP, всегда возвращает ошибку 400 из samltest.id. Я попытался просмотреть журнал samltest.id, чтобы увидеть, не была ли там записана ошибка для моего запроса, но я не могу найти там ничего.
Это действие, которое обрабатывает URL, который будет делать его пользователь. go при запуске SSO:
public ActionResult SSOLogin() {
LogManager logger = new LogManager("SSOLogin");
string hostname = this.GetHostname();
SchoolSettings settings = this.GetClientSettings();
if (settings.UseSAMLSSO) {
Saml2Configuration samlConfig = null;
try {
samlConfig = SamlConfigLoader.GetSaml2Config(HttpContext, settings, this.IsSandbox());
} catch (Exception e) {
logger.exception($"loading Saml2Configuration for {hostname}", e);
}
if (samlConfig != null) {
try {
var binding = new Saml2RedirectBinding();
binding.SetRelayStateQuery(new Dictionary<string, string> { { "Home/Index", Url.Content("~/") } });
return binding.Bind(new Saml2AuthnRequest(samlConfig) {
}).ToActionResult();
} catch (Exception e) {
logger.error($"Exception redirecting to IdP. {e.GetType().ToString()}: {e.Message}\n{e.StackTrace}");
ViewBag.ssoerror = $"Error redirecting to IdP for {hostname}";
}
} else {
logger.critical($"Could not load SAML2 configuration for {hostname}");
ViewBag.ssoerror = $"Could not load SAML2 configuration for {hostname}";
}
} else {
ViewBag.ssoerror = "SSO is not configured for this client. Please contact Support";
}
return Redirect("/Home/SSOError");
}
Метод, который загружает клиентские метаданные c, выглядит следующим образом:
public static Saml2Configuration GetSaml2Config(HttpContextBase context, SchoolSettings forSchool, bool forSandbox) {
LogManager log = new LogManager("getSaml2Config");
Saml2Configuration config = new Saml2Configuration();
if (!forSandbox) {
config.Issuer = _saml2Issuer;
} else {
config.Issuer = _saml2IssuerSandbox;
}
config.SignatureAlgorithm = _saml2SignatureAlgo;
config.CertificateValidationMode = X509CertificateValidationMode.None;
config.RevocationMode = (X509RevocationMode)Enum.Parse(typeof(X509RevocationMode), ConfigurationManager.AppSettings["Saml2:RevocationMode"]);
config.AllowedAudienceUris.Add(config.Issuer);
var entityDescriptor = new EntityDescriptor();
if (forSchool.SAMLMetadataLocationIsUrl) {
try {
entityDescriptor.ReadIdPSsoDescriptorFromUrl(new Uri(forSchool.SAMLMetadataLocation));
} catch (Exception e) {
log.error($"Exception caught loading metadata from school {forSchool.Hostname} at URL {forSchool.SAMLMetadataLocation}\n Exception {e.GetType().ToString()}: {e.Message}\n{e.StackTrace}");
entityDescriptor.IdPSsoDescriptor = null;
}
} else {
var schoolMetadataPath = context.Server.MapPath("~/App_Data/SAMLMetadata/" + forSchool.SAMLMetadataLocation);
log.info($"Loading metadata for school {forSchool.Hostname} from file {schoolMetadataPath}");
try {
entityDescriptor.ReadIdPSsoDescriptorFromFile(schoolMetadataPath);
} catch (IOException ioe) {
log.error($"IOException caught loading metadata for school {forSchool.Hostname} from file {schoolMetadataPath}: {ioe.Message}\n{ioe.StackTrace}");
entityDescriptor.IdPSsoDescriptor = null;
} catch (Exception e) {
log.error($"Exception caught loading metadata for school {forSchool.Hostname} from file {schoolMetadataPath}\n Exception {e.GetType().ToString()}: {e.Message}\n{e.StackTrace}");
entityDescriptor.IdPSsoDescriptor = null;
}
}
if (entityDescriptor.IdPSsoDescriptor != null) {
if (entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.Count() > 0) {
config.SingleSignOnDestination = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.First().Location;
} else {
log.error($"WARNING: metadata for {forSchool.Hostname} does not have any SingleSignOnServices that could be parsed.");
}
if (entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.Count() > 0) {
config.SingleLogoutDestination = entityDescriptor.IdPSsoDescriptor.SingleLogoutServices.First().Location;
} else {
log.error($"WARNING: metadata for {forSchool.Hostname} does not have any SingleLogoutServices that could be parsed.");
}
if (entityDescriptor.IdPSsoDescriptor.SigningCertificates.Count() > 0) {
config.SignatureValidationCertificates.AddRange(entityDescriptor.IdPSsoDescriptor.SigningCertificates);
} else {
log.error($"WARNING: metadata for {forSchool.Hostname} does not have any SigningCertificates that could be parsed.");
}
} else {
throw new Exception("IdPSsoDescriptor not loaded from metadata.");
}
return config;
}
Если это поможет прояснить ситуацию Я могу добавить код для действия AssertionConsumerService, который отлично работает в сценарии, инициированном IdP.