dependabot[bot] on nuget
Bump Newtonsoft.Json in /legacy… (compare)
AndersAbel on develop
Update LICENSE (compare)
AndersAbel on develop
Update LICENSE (compare)
AuthenticationProperties
object. Is this the "correct" way to handle a single authentiation scheme with multiple identity providers?
var props = new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(Callback)),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", scheme },
{ "idp", idp }
}
};
SelectIdentityProvider
and GetIdentityProvider
notifications. Anyone can guide me in the right direction would be appreciated. Thank you.
builder.AddSaml2(
saml2Options =>
{
saml2Options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
saml2Options.SPOptions.EntityId = new EntityId(config.Saml2.ServiceProviderEntityId);
saml2Options.SPOptions.ServiceCertificates.Add(certificate);
saml2Options.Notifications.SelectIdentityProvider =
(id, data) => GetProvider(identityProviderStore, id, data, saml2Options, logger);
saml2Options.Notifications.GetIdentityProvider =
(id, data, options) => GetProvider(identityProviderStore, id, data, options, logger);
saml2Options.Notifications.AcsCommandResultCreated =
(commandResult, response) =>
{
if (commandResult.Principal.Identity is ClaimsIdentity identity)
identity.AddClaim(new Claim("in_response_to", response.InResponseTo.Value));
};
});
GetProvider
method looks something like this...
private IdentityProvider GetProvider(IEegIdentityProviderStore identityProviderStore, EntityId id, IDictionary<string,string> data, IOptions options, ILogger logger)
{
Saml2IdentityProvider provider = identityProviderStore.GetSamlProviderByEntityId(id.Id);
if (provider == null)
return null;
idp =
new IdentityProvider(new EntityId(provider.EntityId), options.SPOptions)
{
MetadataLocation = provider.Debug
? provider.DebugMetadataLocation
: provider.MetadataLocation
};
logger.Verbose("Adding Identity Provider: {IdpName}", provider.DisplayName);
if (provider.Debug)
logger.Warning(
"Provider {Provider} is in debug mode, using metadata URL: {MetadataUrl}",
provider.DisplayName,
provider.DebugMetadataLocation);
options.IdentityProviders.Add(idp);
return idp;
}
options.IdentityProviders
collection multiple times. That would also be a problem.
@mlindegarde and @AndersAbel thank you for your input. There are a couple methods there that I don't have a great understanding how they work, in either way here's what I've done adjusting your code to mine. FYI: this project is a legacy Asp.Net Web App (non-MVC).
in my Global.asax
void Application_BeginRequest(object sender, EventArgs e) {
Saml2Config.Initialize();
}
In the Sam2Config
file:
public class Saml2Config {
private static bool _alreadyInitialized;
private static readonly object Lock = new object();
private static NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
public static void Initialize() {
if (_alreadyInitialized) {
return;
}
lock (Lock) {
if (_alreadyInitialized) {
return;
}
spOptions = Options.FromConfiguration.SPOptions;
// Get list of IdentityProviders
var saml2IdentityProvidersRepository = new Saml2IdentityProvidersRepository();
var saml2IdentityProviders = saml2IdentityProvidersRepository.FindByServiceProviderEntityId(spOptions.EntityId.Id, x => x.Saml2BindingType).OrderBy(x => x.OrderPreference);
Options.FromConfiguration.Notifications.SelectIdentityProvider = (id, data) => GetProvider(saml2IdentityProviders, id, data, Options.FromConfiguration, _logger);
Options.FromConfiguration.Notifications.GetIdentityProvider = (id, data, options) => GetProvider(saml2IdentityProviders, id, data, options, _logger);
saml2IdentityProvidersRepository.Dispose();
_alreadyInitialized = true;
}
}
private static IdentityProvider GetProvider(IQueryable<Saml2IdentityProvider> identityProviderStore, EntityId id, IDictionary<string, string> data, IOptions options, ILogger logger) {
var identityProvider = identityProviderStore.FirstOrDefault(x => x.IsActive && x.IdentityProviderEntityId.Equals(id.Id));
if (identityProvider == null) {
return null;
}
var idpEntityId = new EntityId(identityProvider.IdentityProviderEntityId);
var bindingType = EnumHelper.NumToEnum<Sustainsys.Saml2.WebSso.Saml2BindingType>(identityProvider.Saml2BindingType.Value);
var idp = new IdentityProvider(idpEntityId, options.SPOptions) {
MetadataLocation = identityProvider.MetadataLocation,
LoadMetadata = identityProvider.LoadMetadata,
AllowUnsolicitedAuthnResponse = identityProvider.AllowUnsolicitedAuthnResponse,
Binding = bindingType,
};
options.IdentityProviders.Add(idp);
return idp;
}
/External/Challenge?scheme=${scheme}&idp=${entityId}&returnUrl=${returnUrl}
. Your exact route is probably different than mine, but somewhere you should have a route that starts the SAML2 process.
idp
parameter in the query string is where the entity id value comes from.
idp
value is in the AuthenticationProperties.Items
collection:new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(Callback)),
Items =
{
{ "returnUrl", returnUrl },
{ "scheme", scheme },
{ "idp", idp }
}
}
idp
value in the Items
collection you should get that value in your GetProvider
method. You can then use that value to look up the data in the database.
[16:05:57 Debug] Sustainsys.Saml2.AspNetCore2.Saml2Handler
Expanded Saml2Url
AssertionConsumerServiceUrl: https://localhost:5001/Saml2/Acs
SignInUrl: https://localhost:5001/Saml2/SignIn
LogoutUrl: https://localhost:5001/Saml2/Logout
ApplicationUrl: https://localhost:5001/
AssertionConsumerServiceUrl
is properly using https
.
AssertionConsumerServiceUrl
is http://auth.my-company/Saml2/Acs
. It's using http
instead of https
. I'm not sure why that is.
Hi @AndersAbel , I am using HTTPModules with Asp.Net 4.6 framework, I have implemented everything but getting the below Error after redirecting from ADFS on Saml2/ACS page.
Server Error in '/' Application.
The Saml2Response must have status success to extract claims.
Saml2 Status Code: Responder
Saml2 Status Message:
Saml2 Second Level Status:
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: Sustainsys.Saml2.Exceptions.UnsuccessfulSamlOperationException: The Saml2Response must have status success to extract claims.
Saml2 Status Code: Responder
Saml2 Status Message:
Saml2 Second Level Status:
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Its been months and not able to find out solution.
Any gentleman can give their suggestion as well, please!