Azure Active Directory和WCF身份验证

时间:2014-11-14 12:27:03

标签: wcf azure adfs2.0 azure-active-directory

我有WCF服务,我需要使用Azure Active Directory保护它。 我已经在这里和social.msdn上阅读了所有相关问题,但仍然无法让我的样本正常工作。 我希望身份验证以下列方式工作。

  1. 当用户从客户端调用WCF服务时,不会显示任何弹出窗口。
  2. 用户传递用户名/密码并从Azure ADFS接收身份验证令牌
  3. 然后在应用程序中(现在让它成为控制台应用程序)我们通过Create CreateChannelWithIssuedToken方法打开频道,所有后续调用都是使用我们从AAD获得的令牌。
  4. 我在做什么以及我的问题是什么。 我现在使用VS 2012和身份和访问工具为WCF服务生成正确的配置文件。 所以我的服务有以下地址。 http://localhost:1785/Service1.svc

    我转到azure portal并创建名为http://localhost:1785/Service1.svc的新Web应用程序,在网址http://localhost:1785/Service1.svc和app id url http://localhost:1785/Service1.svc

    上签名

    然后我检查应用程序的端点并复制看起来像的联合元数据 https://login.windows.net/{some guid}/federationmetadata/2007-06/federationmetadata.xml

    使用Identity and Access工具我将WAAD Identity提供程序添加到Service项目中。 我的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>
    

    然后我创建了控制台应用程序并添加了服务项目的服务引用。 添加引用后,config看起来像

    <?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 Single登录端点复制为发布者。

    控制台程序代码如下。

    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消息时发生错误。消息无效。

    您能否建议我在哪里出错?如何实施我在问题开头描述的情景? 感谢。

4 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:2)

如果有人遇到这种情况并且必须连接到WCF Web服务(它们被认为是遗留的吗?)那么this source code是将令牌包装成SecurityToken的一种方式。

Dominick Baier也提到了a blog

答案 2 :(得分:1)

我是否正确理解您希望WCF服务使用Azure Active Directory颁发的令牌作为标识:Thread.CurrentPrincipal? WsFederation绑定说的是wstrust而AAD没有。看起来您使用的是智能客户端,而不是浏览器?这是对的吗?

AAD使用以下方式提供身份令牌:wsfederation和openidconnect两种被动协议。 AAD确实使用OAuth提供AccessTokens。

但是,这两者都有用户同意/凭证页面。无法通过凭据获取令牌。

答案 3 :(得分:0)

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

How I implemented AAD Token based Authentication in WCF Service using custom Message Inspector and Invoker

我实现的方式是使用 WCF 可扩展性。我编写了自定义 Message InspectorCustom Invoker 来执行此操作。消息检查器从授权标头中提取令牌并对其进行验证,如果令牌无效,自定义调用程序将停止调用合约。

请参阅链接中的上述答案以了解完整的实施细节。除了 Message InspectorCustom Invoker 之外,还有一些类需要添加,并且需要在 web.config 中进行一些更改以集成所有内容。