Umamaheswaran Umamaheswaran - 2 months ago 41
C# Question

No Idp with entity id "http://stubidp.kentor.se/Metadata" found error in Kentor Auth Services

We have a requirement to enable SAML SSO login to my application. My application is a Angular JS + Asp.Net Web API solution. My application already uses Owin Bearer Authentication as the Authorization model.

To Enable Saml SSO Im experimenting with Kentor Auth Services. But I'm facing an issue when the Idp calls my webapi. The kentor service throws The given key was not present in the dictionary. error. Im using http://stubidp.kentor.se/ to test the implementation. Below is my Saml configuration from the start up class

public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
ConfigureOAuth(app);

var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);

AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configuration.MessageHandlers.Add(new CachingHandler(GlobalConfiguration.Configuration));
}
public void ConfigureOAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
var oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/Auth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new JobPulseAuthorizationServerProvider()
};
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager, DefaultAuthenticationTypes.ExternalCookie))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

// Token Generation
//app.UseOAuthAuthorizationServer(oAuthServerOptions);
//app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseKentorAuthServicesAuthentication(CreateAuthServicesOptions());
}

private static KentorAuthServicesAuthenticationOptions CreateAuthServicesOptions()
{
var spOptions = GetServiceProviderOptions();
var authServicesOptions = new KentorAuthServicesAuthenticationOptions(false)
{
SPOptions = spOptions
};

var idp = new IdentityProvider(new EntityId("~/App_Data/KentorIDPMetadata.xml"), spOptions)
{
AllowUnsolicitedAuthnResponse = true,
Binding = Saml2BindingType.HttpRedirect,
SingleSignOnServiceUrl = new Uri("http://stubidp.kentor.se/")
};

idp.SigningKeys.AddConfiguredKey(
new X509Certificate2(fileName: HostingEnvironment.MapPath(
"~/App_Data/Kentor.AuthServices.StubIdp.cer")));

authServicesOptions.IdentityProviders.Add(idp);

return authServicesOptions;
}

private static SPOptions GetServiceProviderOptions()
{
var cultureInfo = CultureInfo.GetCultureInfo("en-US");
var organization = new Organization
{
Names = { new LocalizedName("Kentor", cultureInfo) },
DisplayNames = { new LocalizedName("Kentor IT AB", cultureInfo) },
Urls = { new LocalizedUri(new Uri("http://www.kentor.se"), cultureInfo) }
};
var spOptions = new SPOptions
{
EntityId = new EntityId("http://localhost:53390/AuthServices/acs"),
ReturnUrl = new Uri("http://localhost:53390/Account/ExternalLoginCallback"),
Organization = organization
};
spOptions.Contacts.Add(new ContactPerson
{
Type = ContactType.Technical,
EmailAddresses = { "authservices@example.com" }
});

spOptions.Contacts.Add(new ContactPerson
{
Type = ContactType.Support,
EmailAddresses = { "support@example.com" }
});
var attributeConsumingService = new AttributeConsumingService("AuthServices")
{
IsDefault = true,
RequestedAttributes =
{
new RequestedAttribute("urn:someName")
{
FriendlyName = "Some Name",
IsRequired = true,
NameFormat = RequestedAttribute.AttributeNameFormatUri
},
new RequestedAttribute("Minimal")
}
};
spOptions.AttributeConsumingServices.Add(attributeConsumingService);

spOptions.ServiceCertificates.Add(new X509Certificate2(
AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "/App_Data/Kentor.AuthServices.Tests.pfx"));

return spOptions;
}

}


Stack Trace of the error

[KeyNotFoundException: The given key was not present in the dictionary.]
System.Collections.Generic.Dictionary`2.get_Item(TKey key) +11759657
Kentor.AuthServices.Configuration.IdentityProviderDictionary.get_Item(EntityId entityId) +155

[KeyNotFoundException: No Idp with entity id "http://stubidp.kentor.se/Metadata" found.]
Kentor.AuthServices.Configuration.IdentityProviderDictionary.get_Item(EntityId entityId) +291
Kentor.AuthServices.Saml2P.Saml2Response.CheckIfUnsolicitedIsAllowed(IOptions options) +108
Kentor.AuthServices.Saml2P.Saml2Response.Validate(IOptions options) +37
Kentor.AuthServices.Saml2P.<CreateClaims>d__53.MoveNext() +170
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) +381


Can you please let me know why Kentor was no able to fetch the metadata?

Answer

You're confusing the entity id with the path of the metadata. The metadata is exposed at the address that is the entity id, but if you put the metadata locally you need to separate them.

var idp = new IdentityProvider(new EntityId("http://stubidp.kentor.se/Metadata"), spOptions)
{
  MetadataLocation = ""~/App_Data/KentorIDPMetadata.xml"
  AllowUnsolicitedAuthnResponse = true,
  // No need to add these if metadata is read.
  // Binding = Saml2BindingType.HttpRedirect,
  // SingleSignOnServiceUrl = new Uri("http://stubidp.kentor.se/")
};

Another even more simple way is to load the metadata directly from the idp:

var idp = new IdentityProvider(new EntityId("http://stubidp.kentor.se/Metadata"), spOptions)
{
  LoadMetadata = true,
  AllowUnsolicitedAuthnResponse = true,
};