Настройка Windows Identity Foundation из кода

Я экспериментирую с «бесконфигурационным WIF», где я хочу принять токен SAML2, сгенерированный AppFabric STS Windows Azure.

Что я делаю, так это синтаксический анализ текущего запроса информации о токене, например:

        if (Request.Form.Get(WSFederationConstants.Parameters.Result) != null)
        {
            SignInResponseMessage message = 
                WSFederationMessage.CreateFromFormPost(System.Web.HttpContext.Current.Request) as SignInResponseMessage;

            var securityTokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();                    

            XmlTextReader xmlReader = new XmlTextReader(
                new StringReader(message.Result));

            SecurityToken token = securityTokenHandlers.ReadToken(xmlReader);

            if (token != null)
            {
                ClaimsIdentityCollection claims = securityTokenHandlers.ValidateToken(token);
                IPrincipal principal = new ClaimsPrincipal(claims);
            }
        }

В приведенном выше коде используется SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(); для проверки и обработки токена SAML. Однако: это не работает, потому что очевидно, что приложение не настроено правильно. Как мне программно указать следующую конфигурацию из XML в моей коллекции securityTokenHandlers?

  <microsoft.identityModel>
<service>
  <audienceUris>
    <add value="http://www.someapp.net/" />
  </audienceUris>
  <federatedAuthentication>
    <wsFederation passiveRedirectEnabled="true" issuer="https://rd-test.accesscontrol.appfabriclabs.com/v2/wsfederation" realm="http://www.thisapp.net" requireHttps="false" />
    <cookieHandler requireSsl="false" />
  </federatedAuthentication>
  <applicationService>
    <claimTypeRequired>
      <claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
      <claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
    </claimTypeRequired>
  </applicationService>
  <issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
    <trustedIssuers>
      <add thumbprint="XYZ123" name="https://somenamespace.accesscontrol.appfabriclabs.com/" />
    </trustedIssuers>
  </issuerNameRegistry>
</service>


person maartenba    schedule 06.02.2011    source источник


Ответы (3)


Я боролся с тем же и нашел рабочее решение в WIF 3.5/4.0. Поскольку ссылка maartenba кажется мертвой, я хотел опубликовать здесь свое решение.

Нашими требованиями были:

  • Конфигурация полностью в коде (поскольку мы отправляем файл web.config по умолчанию с приложением)
  • Максимально допустимая версия .Net 4.0 (поэтому я использую WIF 3.5/4.0)

Что я использовал, чтобы прийти к решению:

  • Информация о динамической конфигурации WIF предоставлена ​​Дэниелом Ву здесь.
  • Этот метод для регистрации модулей HTTP на время выполнения, объясненное Дэвидом Эббо. Я также попробовал более элегантный метод , объясненный Риком Стралом., но, к сожалению, мне это не помогло.

Изменить 2016/09/02: вместо добавления отдельного класса «стартового кода перед приложением», как в примере Дэвида Эббо, HTTP-модули, связанные с WIF, также могут быть зарегистрированы в статическом конструкторе класса «HttpApplication». Я адаптировал код к этому несколько более чистому решению.

Моему решению ничего не нужно в файле web.config. Основная часть кода находится в файле global.asax.cs. Конфигурация в этом примере жестко запрограммирована:

using System;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Web;

namespace TestADFS
{
  public class SessionAuthenticationModule : Microsoft.IdentityModel.Web.SessionAuthenticationModule
  {
    protected override void InitializePropertiesFromConfiguration(string serviceName)
    {
    }
  }
  public class WSFederationAuthenticationModule : Microsoft.IdentityModel.Web.WSFederationAuthenticationModule
  {
    protected override void InitializePropertiesFromConfiguration(string serviceName)
    {
      ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
      PassiveRedirectEnabled = true;
      RequireHttps = true;
      Issuer = "https://nl-joinadfstest.joinadfstest.local/adfs/ls/";
      Realm = "https://67px95j.decos.com/testadfs";
    }
  }

  public class Global : HttpApplication
  {
    static Global()
    {
      Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(SessionAuthenticationModule));
      Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(WSFederationAuthenticationModule));
    }

    protected void Application_Start(object sender, EventArgs e)
    {
      FederatedAuthentication.ServiceConfigurationCreated += FederatedAuthentication_ServiceConfigurationCreated;
    }

    internal void FederatedAuthentication_ServiceConfigurationCreated(object sender, Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs e)
    {
      X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
      store.Open(OpenFlags.ReadOnly);
      X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindByThumbprint, "245537E9BB2C086D3C880982FA86267FBD66B9A3", false);
      if (coll.Count > 0)
        e.ServiceConfiguration.ServiceCertificate = coll[0];
      store.Close();
      AudienceRestriction ar = new AudienceRestriction(AudienceUriMode.Always);
      ar.AllowedAudienceUris.Add(new Uri("https://67px95j.decos.com/testadfs"));
      e.ServiceConfiguration.AudienceRestriction = ar;
      ConfigurationBasedIssuerNameRegistry inr = new ConfigurationBasedIssuerNameRegistry();
      inr.AddTrustedIssuer("6C9B96D90257B65B6F181C2478D869473DC359EA", "http://NL-JOINADFSTEST.joinadfstest.local/adfs/services/trust");
      e.ServiceConfiguration.IssuerNameRegistry = inr;
      e.ServiceConfiguration.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
    }

    protected void Application_AuthenticateRequest(object sender, EventArgs e)
    {
      FederatedAuthentication.WSFederationAuthenticationModule.ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
    }
  }
}

использование

Мое приложение — asp.net WebForms, работает в классическом конвейерном режиме и поддерживает проверку подлинности с помощью форм, а также вход в ADFS. Из-за этого аутентификация обрабатывается в общем базовом классе, совместно используемом всеми страницами .aspx:

    protected override void OnInit(EventArgs e)
    {
      if (NeedsAuthentication && !User.Identity.IsAuthenticated)
      {
        SignInRequestMessage sirm = new SignInRequestMessage(
          new Uri("https://nl-joinadfstest.joinadfstest.local/adfs/ls/"),
          ApplicationRootUrl)
        {
          Context = ApplicationRootUrl,
          HomeRealm = ApplicationRootUrl
        };
        Response.Redirect(sirm.WriteQueryString());
      }
      base.OnInit(e);
    }

В этом коде ApplicationRootUrl — это путь к приложению, оканчивающийся на «/» («/» важен в классическом конвейерном режиме).

Поскольку стабильная реализация выхода из смешанного режима была не такой уж простой, я хочу показать код и для этого. Технически это работает, но у меня все еще есть проблема с повторным входом в IE после выхода из учетной записи ADFS:

      if (User.Identity.IsAuthenticated)
      {
        if (User.Identity.AuthenticationType == "Forms")
        {
          FormsAuthentication.SignOut();
          Session.Clear();
          Session.Abandon();
          ResetCookie(FormsAuthentication.FormsCookieName);
          ResetCookie("ASP.NET_SessionId");
          Response.Redirect(ApplicationRootUrl + "Default.aspx");
          HttpContext.Current.ApplicationInstance.CompleteRequest();
        }
        else
        {
          FederatedAuthentication.SessionAuthenticationModule.SignOut();
          FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
          Uri uri = new Uri(ApplicationRootUrl + "Default.aspx");
          WSFederationAuthenticationModule.FederatedSignOut(
            new Uri("https://nl-joinadfstest.joinadfstest.local/adfs/ls/"),
            uri); // 1st url is single logout service binding from adfs metadata
        }
      }

(ResetCookie — это вспомогательная функция, которая очищает файл cookie ответа и устанавливает срок его действия в прошлом)

person Berend Engelbrecht    schedule 01.09.2016
comment
Проблема с IE была связана с тем, что ADFS изначально настроена на попытку аутентификации WIA вместо проверки подлинности на основе форм ADFS конкретно для этого браузера. Эта командная строка PowerShell на сервере ADFS показывает браузеры, для которых это делается: Get-AdfsProperties | select -ExpandProperty WIASupportedUserAgents Чтобы отключить WIA для всех браузеров, измените настройку на использование только небраузерных клиентов: Set-AdfsProperties -WIASupportedUserAgents ("MSAuthHost/1.0/In-Domain","MSIPC","Windows Rights Management Client") Это устранило мою проблему. - person Berend Engelbrecht; 02.09.2016

Просто мысль, не знаю, работает ли это: нет ли способа получить фактический XML (который в вашем случае пуст) и изменить его во время выполнения с помощью классов в Microsoft.IdentityModel.Configuration?

Кроме того, некоторые вещи в XML, которые вы можете изменить во время отправки запроса на вход, в событие RedirectingToIdentityProvider путем изменения SignInRequestMessage

person MarnixKlooster ReinstateMonica    schedule 07.02.2011
comment
Не используя WsFederationAuthenticationModule, идея состоит в том, чтобы не трогать Web.config для регистрации модулей или конфигурации IdentityModel. Рассмотрю упомянутые вами изменения конфигурации времени выполнения, нашел некоторые другие тисы, касающиеся написания пользовательских IssuerTokenValidators и т. д. Если что-то получится, я опубликую это на SO в качестве ссылки. - person maartenba; 07.02.2011

К сведению: нашел решение и реализовал его в модуле, описанном (и связанном) здесь: http://blog.maartenballiauw.be/post/2011/02/14/Authenticate-Orchard-users-with-AppFabric-Access-Control-Service.aspx

person maartenba    schedule 17.02.2011