ADFS SSO SAML Windows集成身份验证不起作用

时间:2015-08-17 14:40:59

标签: c# asp.net single-sign-on adfs windows-integrated-auth

我们现在正在开展的项目是使用SAML令牌通过ADFS进行单点登录 此项目应遵循的基本规则如下:
    1.代理使用他/她的凭据登录Windows     2.代理登录Web应用程序(依赖方)
    3. Web应用程序应重定向到ADFS中的STS(Active Directory是身份提供程序),并使用代理在其Windows身份验证(无缝身份验证)中使用的凭据登录。
    4.因此,STS登录页面不应出现,用户应进行身份验证     5.之后,应收到索赔和安全令牌,以便我们授权代理

实际结果:
    1.重定向是第一次完成,需要再次进行身份验证(IE身份验证页面和Firefox \ Chrome身份验证页面) enter image description here
enter image description here

  1. 可以对所有类型的域用户进行身份验证,而不仅仅是经过Windows身份验证的用户。
  2. 首次登录sts登录页面后,不再需要进行身份验证。但是,我们不希望第二次身份验证。仅在Windows登录时(仅适用于IE)。
  3. 已配置的环境:
        1.同一台机器上的域控制器+ ADFS服务器3.0(Win2k12R2)
        2. Web应用程序机器(Win2k12 + IIS8.5)
        3.机器在同一个域

    ADFS配置:

    enter image description here
    enter image description here
    enter image description here

    依赖方配置:

    enter image description here enter image description here
    enter image description here

    IE配置:
    enter image description here
    enter image description here
    enter image description here

    Web App配置:
    身份验证:

    enter image description here ASP.Net项目:
    Web配置文件:

    <?xml version="1.0" encoding="utf-8"?>
    <!--
      For more information on how to configure your ASP.NET application, please visit
      http://go.microsoft.com/fwlink/?LinkId=169433
      -->
    <configuration>
      <configSections>
        <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
        <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
        <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
      </configSections>
      <connectionStrings>
        <add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=aspnet-TestApp-20150730141753;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnet-TestApp-20150730141753.mdf" />
      </connectionStrings>
      <location path="FederationMetadata">
        <system.web>
          <authorization>
            <allow users="*" />
          </authorization>
        </system.web>
      </location>
      <system.web>
        <authorization>
          <deny users="?" />
        </authorization>
        <authentication mode="None" />
        <compilation debug="true" targetFramework="4.5" />
        <httpRuntime targetFramework="4.5" />
        <pages>
          <namespaces>
            <add namespace="System.Web.Optimization" />
          </namespaces>
        <controls><add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" /></controls></pages>
        <!--<authentication mode="Forms">
          <forms loginUrl="~/Account/Login" timeout="2880" defaultUrl="~/" />
        </authentication>-->
        <profile defaultProvider="DefaultProfileProvider">
          <providers>
            <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
          </providers>
        </profile>
        <membership defaultProvider="DefaultMembershipProvider">
          <providers>
            <add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
          </providers>
        </membership>
        <roleManager defaultProvider="DefaultRoleProvider">
          <providers>
            <add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" />
          </providers>
        </roleManager>
        <!--
                If you are deploying to a cloud environment that has multiple web server instances,
                you should change session state mode from "InProc" to "Custom". In addition,
                change the connection string named "DefaultConnection" to connect to an instance
                of SQL Server (including SQL Azure and SQL  Compact) instead of to SQL Server Express.
          -->
        <sessionState mode="InProc" customProvider="DefaultSessionProvider">
          <providers>
            <add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
          </providers>
        </sessionState>
    
      </system.web>
      <system.webServer>
        <modules>
          <!--<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />-->
          <add name="FixedWSFederationAuthenticationModule" type="TestApp.FixedWSFederationAuthenticationModule, TestApp" preCondition="managedHandler" />
          <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
        </modules>
      </system.webServer>
      <system.identityModel>
        <identityConfiguration saveBootstrapContext="true">
          <!-- The identity configuration. No name means default configuration which is always used for passive federation scenarios. see federationConfiguration element -->
          <audienceUris>
            <add value="https://ccsp12.pj12.loc/testapp" />
          </audienceUris>
          <issuerNameRegistry type="System.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
            <trustedIssuers>
              <add thumbprint="91992FCF8B03FF9BD98A259FE93B92620E9DD89A" name="http://sts.pj12.loc/adfs/services/trust" />
            </trustedIssuers>
          </issuerNameRegistry>
          <certificateValidation certificateValidationMode="None" />
        </identityConfiguration>
      </system.identityModel>
      <system.identityModel.services>
        <federationConfiguration> <!-- Configures the WSFederationAuthenticationModule (WSFAM) and the SessionAuthenticationModule (SAM) when using federated authentication through the WS-Federation protocol -->
          <cookieHandler requireSsl="false" />
          <!-- passiveRedirectEnabled true means that a relaying party (test app) instead of having its own login page, it will redirect to the sts issuer for authentication and the sts will reply to the relaying party -->
          <!-- Due to WSFederationAuthenticationModule bug, the relaying party address must be with '/' at the end -->
          <wsFederation passiveRedirectEnabled="true" issuer="https://sts.pj12.loc/adfs/ls/" realm="https://ccsp12.pj12.loc/testapp/" reply="https://ccsp12.pj12.loc/testapp/" requireHttps="true" />
        </federationConfiguration>
      </system.identityModel.services>
      <!--<runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
          <dependentAssembly>
            <assemblyIdentity name="DotNetOpenAuth.Core" publicKeyToken="2780ccd10d57b246" />
            <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.1.0.0" />
          </dependentAssembly>
          <dependentAssembly>
            <assemblyIdentity name="DotNetOpenAuth.AspNet" publicKeyToken="2780ccd10d57b246" />
            <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.1.0.0" />
          </dependentAssembly>
        </assemblyBinding>
      </runtime>-->
      <entityFramework>
        <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
      </entityFramework>
    </configuration>
    

    C#代码:

    namespace TestApp
    {
        public partial class _Default : Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                // local variables
                string claimsTypes = string.Empty;
                string claimsValues = string.Empty;
                string claimsValueTypes = string.Empty;
                string claimsSubjectNames = string.Empty;
                string claimsIssuers = string.Empty;
                // initialize claims and identity
                ClaimsPrincipal claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
                ClaimsIdentity claimsIdentity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
                BootstrapContext bootstrapContext =
                ClaimsPrincipal.Current.Identities.First().BootstrapContext
                                                        as BootstrapContext;
    
                if (claimsPrincipal != null)
                {
                    signedIn.Text = "You are signed in.";
    
                    foreach (Claim claim in claimsPrincipal.Claims)
                    {
                        claimsTypes = string.Concat(claimsTypes, "; ", claim.Type);
                        claimsValues = string.Concat(claimsValues, "; ", claim.Value);
                        claimsValueTypes = string.Concat(claimsValueTypes, "; ", claim.ValueType);
                        claimsSubjectNames = string.Concat(claimsSubjectNames, "; ", claim.Subject.Name);
                        claimsIssuers = string.Concat(claimsIssuers, "; ", claim.Issuer);
                    }
    
                    //claims principals
                    claimType.Text = claimsTypes;
                    claimValue.Text = claimsValues;
                    claimValueType.Text = claimsValueTypes;
                    claimSubjectName.Text = claimsSubjectNames;
                    claimIssuer.Text = claimsIssuers;
    
                    // ClaimsIdentity
                    isUserAuthenticated.Text = claimsIdentity.IsAuthenticated.ToString();
                    authenticationType.Text = claimsIdentity.AuthenticationType;
                    claimName.Text = claimsIdentity.Name;
    
                    // Token
                    // known bug : http://stackoverflow.com/questions/13514553/wif-4-5-bootstrapcontext-security-token-null
                    SecurityToken token = null;
                    if (bootstrapContext.SecurityToken != null)
                    {
                        token = bootstrapContext.SecurityToken;
                    }
                    else if (!bootstrapContext.Token.Equals(string.Empty))
                    {
                        var handlers = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;
                        token = handlers.ReadToken(new XmlTextReader(new StringReader(bootstrapContext.Token)));
                    }
    
                    SamlSecurityToken sst = token as SamlSecurityToken;
                    tokenId.Text = sst.Id;
                    tokenAssertionId.Text = sst.Assertion.AssertionId;
                    tokenIssuer.Text = sst.Assertion.Issuer;
    
                }
                else
                {
                    signedIn.Text = "You are not signed in.";
                }
            }
        }  
    

    任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:11)

最后我能够实现无缝的Windows集成SSO!

我找到了一些名为“WIASupportedUserAgents”的ADFS属性。这意味着:支持WIA(Windows集成身份验证)的浏览器 在PowerShell中运行以下命令:

Set-ADFSProperties -WIASupportedUserAgents @("MSIE 6.0", "MSIE 7.0", "MSIE 8.0", "MSIE 9.0", "MSIE 10.0", "MSIE 11.0", "Trident/7.0", "MSIPC", "Windows Rights Management Client", "Mozilla/5.0")  

重新启动ADFS服务。

为所有浏览器支持设置此属性后,无缝Windows身份验证SSO开始工作! 我现在没有获取凭据窗口,并且经过身份验证的Windows用户通过ADFS自动进行身份验证。

像魅力一样工作。

感谢所有人,尤其是Wiktor Zychla,他非常愿意提供帮助!