Azure Active Directory和WCF身份验证

3
我有一个WCF服务,需要使用Azure Active Directory进行安全保护。我已经阅读了所有相关的问题,并在social.msdn上进行了研究,但仍无法使我的示例工作。我希望身份验证以以下方式工作。
1.用户从客户端调用WCF服务时不显示任何弹出窗口。 2.用户通过用户名/密码并从Azure ADFS接收身份验证令牌。 3.然后,在应用程序中(现在先假设为控制台应用程序),我们通过CreateChannelWithIssuedToken方法打开通道,并使用从AAD获取的令牌进行所有后续调用。
我正在做什么以及我的问题是什么。 我现在正在使用VS 2012和Identity和Access工具生成适当的配置文件用于WCF服务。因此,我的服务具有以下地址:http://localhost:1785/Service1.svc
然后我登录Azure门户并创建一个名为http://localhost:1785/Service1.svc的新Web应用程序,登录URL http://localhost:1785/Service1.svc和应用程序ID URL http://localhost:1785/Service1.svc。
然后我检查应用程序的端点并复制联合元数据,其格式如下: https://login.windows.net/{some guid}/federationmetadata/2007-06/federationmetadata.xml
使用Identity和Access工具,我向服务项目添加了WAAD身份提供程序,我的web.config文件如下:
<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
  </configSections>
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    <add key="ida:FederationMetadataLocation" value="https://login.windows.net/34bb8966-5537-4b1b-85ed-f501a06c1225/federationmetadata/2007-06/federationmetadata.xml" />
    <add key="ida:ProviderSelection" value="productionSTS" />
  </appSettings>
  <location path="FederationMetadata">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceCredentials useIdentityConfiguration="true">
            <!--Certificate added by Identity and Access Tool for Visual Studio.-->
            <serviceCertificate findValue="CN=localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add scheme="http" binding="ws2007FederationHttpBinding" />
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
    <bindings>
      <ws2007FederationHttpBinding>
        <binding name="">
          <security mode="Message">
            <message>
              <issuerMetadata address="https://login.windows.net/adfs/services/trust/mex" />
            </message>
          </security>
        </binding>
      </ws2007FederationHttpBinding>
    </bindings>
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true" />
  </system.webServer>
  <system.identityModel>
    <identityConfiguration>
      <audienceUris>
        <add value="http://localhost:1785/Service1.svc" />
      </audienceUris>
      <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
        <authority name="https://sts.windows.net/34bb8966-5537-4b1b-85ed-f501a06c1225/">
          <keys>
            <add thumbprint="92B88C3DD981BF1EBCB244FCFA63C007706C79E0" />
            <add thumbprint="3270BF5597004DF339A4E62224731B6BD82810A6" />
          </keys>
          <validIssuers>
            <add name="https://sts.windows.net/34bb8966-5537-4b1b-85ed-f501a06c1225/" />
          </validIssuers>
        </authority>
      </issuerNameRegistry>
      <!--certificationValidationMode set to "None" by the the Identity and Access Tool for Visual Studio. For development purposes.-->
      <certificateValidation certificateValidationMode="None" />
    </identityConfiguration>
  </system.identityModel>
</configuration>

然后我创建了控制台应用程序,并向服务项目添加了服务引用。

添加引用后,配置文件如下所示

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
            <ws2007FederationHttpBinding>
                <binding name="WS2007FederationHttpBinding_IService1">
                    <security>
                        <message>
                            <!--<issuer address="http://schemas.microsoft.com/2005/12/ServiceModel/Addressing/Anonymous" />-->
                          <issuer address="https://login.windows.net/34bb8966-5537-4b1b-85ed-f501a06c1225/wsfed" binding="ws2007HttpBinding"/>
                          <issuerMetadata address="https://login.windows.net/adfs/services/trust/mex" />
                            <tokenRequestParameters>
                                <trust:SecondaryParameters xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
                                    <trust:KeyType xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</trust:KeyType>
                                    <trust:KeySize xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">256</trust:KeySize>
                                    <trust:KeyWrapAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p</trust:KeyWrapAlgorithm>
                                    <trust:EncryptWith xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptWith>
                                    <trust:SignWith xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2000/09/xmldsig#hmac-sha1</trust:SignWith>
                                    <trust:CanonicalizationAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/10/xml-exc-c14n#</trust:CanonicalizationAlgorithm>
                                    <trust:EncryptionAlgorithm xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">http://www.w3.org/2001/04/xmlenc#aes256-cbc</trust:EncryptionAlgorithm>
                                </trust:SecondaryParameters>
                            </tokenRequestParameters>
                        </message>
                    </security>
                </binding>
            </ws2007FederationHttpBinding>
            <ws2007HttpBinding>
                <binding name="">
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="InheritedFromHost" />
                        <message establishSecurityContext="false" />
                    </security>
                </binding>
            </ws2007HttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:1785/Service1.svc" binding="ws2007FederationHttpBinding"
                bindingConfiguration="WS2007FederationHttpBinding_IService1"
                contract="SomeService.IService1" name="WS2007FederationHttpBinding_IService1">
                <identity>
                    <certificate encodedValue="AwAAAAEAAAAUAAAACLf4gntwdBYHCTmyInF5gU9oXNYgAAAAAQAAANUBAAAwggHRMIIBOqADAgECAhAT1EWwzeLBk0ez5Bg+JKyVMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xMjExMTUxNTMyMDdaFw0xNzExMTUwMDAwMDBaMBQxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtgkwd4GLTIwRtoHFjoSCBqrEcFgYMPh7f8aSWSYTrBGtaS9c2zOAuhxnaIAo1ELe3JLWUJmHq35IEu34gTwN9RfSna9Gis45TKrINY5nlAmKu0XpuI3ncf4WQRPbPx7hS6A0BHytXqQ3+FA1BSRr13iNUaaAkqwcCLWHXqno188CAwEAAaMkMCIwCwYDVR0PBAQDAgSwMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4GBACKXEQpUUVm1g3BfpqRSn9hIYpuLojPX2wfySbIAan4jK5oo0dC5QUkbRjyEtqe6Io+POL3gbtoVzJOXnUDvYDUXRaR6dUmHJ5A4JLChUJZLHis0resLKO5yXrf4JqJSwEsL4Et5xiIRPoEvdPWWBhkDwuMvDGtQrzpp6ZYEt2sh" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

我试图启动控制台应用程序,但是出现了必须指定有效问题的错误。

我认为,在Azure AD配置页面的终结点中可以找到有效的问题,并将WS-Federation单一登录终结点复制为发布者。

以下是控制台程序代码。

var client = new SomeService.Service1Client();
            client.ClientCredentials.UserName.UserName = "<valid user name>";
            client.ClientCredentials.UserName.Password = "<password>";
            client.GetData(10);

当我调用服务时,在Fiddler中看到请求被发送到WS-Fed终点,但响应终点会向我发送带有错误的HTML页面。
AADSTS20012:当我们尝试处理WS-Federation消息时发生错误。该消息无效。
请问您能否建议我在哪里出错了以及如何实现我在问题开头描述的场景?
谢谢。

这个回答解决了你的问题吗?WCF Rest基于令牌的身份验证 - Abhishek Anand
4个回答

4
可以使用用户名和密码从Azure AD获取令牌,详见http://www.cloudidentity.com/blog/2014/07/08/using-adal-net-to-authenticate-users-via-usernamepassword/。请注意,正如Brent所指出的,这是通过OAuth2而不是WS-Trust来完成的。您不能使用类似于createchannelwithissuedtoken或类似的WCF机制。总的来说,Azure AD和我们所有现代库都不与WCF集成,而是专注于Web API。WCF集成在技术上是可能的,但它需要非常深入的WCF可扩展性知识。如果您有重构服务以使用Web API的机会,您会发现一切都会变得更容易。HTH V.

感谢Vittorio的澄清。@Oleg,是的,我们正在讨论软件,所以一切皆有可能,您可以拼凑出一个解决方案,但它将有多个部分,因为AAD没有WsTrust端点。Vittorio的建议将带领您找到一个更易于维护的解决方案。 - Brent Schmaltz

2
如果有人遇到这个问题并需要连接到WCF Web服务(它们是否被认为是传统的?),那么可以使用此源代码将令牌封装到SecurityToken中。同时,Dominick Baier也写了一篇博客文章介绍了相关内容。请注意保留HTML标签,但不要添加解释。

1

我理解你的意思是,你希望你的WCF服务使用由Azure Active Directory发行的令牌作为身份:Thread.CurrentPrincipal?WsFederation绑定使用wstrust而AAD不使用。看起来你正在使用一个智能客户端,而不是浏览器?是这样吗?

AAD通过wsfederation和openidconnect两种被动协议提供身份令牌。AAD使用OAuth提供AccessTokens。

然而,这两种方式都需要用户同意/凭据页面。没有办法传递凭据并获取令牌。


Brent,谢谢。 但我还有一个问题。 如果我理解正确的话,那么ADFS(指本地AD)可以使用在WCF ClientCredentials中传递的uid/pwd为我提供令牌。 由于Azure AD公开了AD联合端点,我认为它也能做到同样的事情。 是这样吗? 您能否指向一下声明AAD无法通过凭据返回令牌,用户必须通过AAD网页登录的页面? - Oleg
2
WsFederation和WsTrust的行为不同。使用WsTrust,您将凭据发送到RequestSecurityToken结构中。使用WsFederation,终结点会要求凭据。这是主动和被动之间的区别。请查看WsTrust和WsFederation规范。 - Brent Schmaltz

0

我在这里回答了一个类似的问题 -

如何使用自定义消息检查器和调用程序在WCF服务中实现基于AAD令牌的身份验证

我实现这个的方式是使用WCF可扩展性。我编写了自定义的消息检查器自定义调用程序来完成此操作。消息检查器从授权标头中提取令牌并验证它,而自定义调用程序则在令牌无效时停止合同的调用。

请参考上面链接中的答案以获取完整的实现细节。除了消息检查器自定义调用程序之外,还需要添加几个类,并对web.config进行一些更改,以便将所有内容集成在一起。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接