基于Geneva框架的STS实现--RP端

  1. WSFederationHttpBinding
  2.       支持 WS-Federation 协议的绑定。

          WS-Federation 规范定义了一个模型和消息集合,用于在不同信任领域间代理信任并联合身份和身份验证信息。协议被BEA、IBM、Microsoft、RSA Security 和 VeriSign厂商支持。

          WS-Federation 依赖另外一组协议:WS-Trust, WS-Policy,WS-Authorization。 

     

  3. WCF契约
  4. 1 namespace RP.Contracts
    2 {
    3 [ServiceContract]
    4 public interface ITest
    5 {
    6 [OperationContract]
    7 string Say(string message);
    8 }
    9 }
    10  

       

  5. Client端
  6.       WCF服务发布成Federation绑定,客户端就要以Federation绑定去访问。这与访问其他形式绑定的行为有所区别,因为在调用时需要向服务提供安全令牌。

          这里再次利用Geneva框架,写一个WCF调用类。

    TestClient类
    1 using Microsoft.IdentityModel.Protocols.WSTrust;
    2  using RP.Contracts;
    3  namespace STS.Client
    4 {
    5 public class TestClient : ITest
    6 {
    7 private SecurityToken Token;
    8
    9 public TestClient(SecurityToken token)
    10 {
    11 Token = token;
    12 }
    13
    14 public string Say(string message)
    15 {
    16 string result = "";
    17 using (ChannelFactory<ITest> channelFactory = new ChannelFactory<ITest>(STSConfiguration.ServiceName))
    18 {
    19 //配置文件里的终结点信息还是会被框架忽略,所以要显示指定。如果RP服务端证书与域名不一致,需要根据RP证书改写终结点标识。
    20 //channelFactory.Endpoint.Address = new EndpointAddress(new Uri(ServiceUrl), EndpointIdentity.CreateX509CertificateIdentity(Configuration.RPCertificate));
    21   channelFactory.Endpoint.Address = new EndpointAddress(new Uri(STSConfiguration.ServiceUrl));
    22 ChannelFactoryOperations.ConfigureChannelFactory(channelFactory);
    23 ITest testClient = channelFactory.CreateChannelWithIssuedToken(Token);
    24 using (testClient as IDisposable)
    25 {
    26 try
    27 {
    28 result = testClient.Say("hello");
    29 }
    30 catch (CommunicationException)
    31 {
    32 (testClient as ICommunicationObject).Abort();
    33 throw;
    34 }
    35 catch (TimeoutException)
    36 {
    37 (testClient as ICommunicationObject).Abort();
    38 throw;
    39 }
    40 }
    41 }
    42 return result;
    43 }
    44 }
    45 }
    46  

          客户端可以调用这个类去访问服务了。

    Client Main函数
    1 namespace STS.Client
    2 {
    3 class Program
    4 {
    5 static void Main(string[] args)
    6 {
    7 string username = Console.ReadLine();
    8 string password = Console.ReadLine();
    9
    10 SecurityToken token = TokenHelper.Issue(username, password);
    11 Console.WriteLine(token.ToString());
    12
    13 TestClient client = new TestClient(token);
    14 string result = client.Say("hello");
    15 Console.WriteLine(result);
    16
    17 Console.ReadLine();
    18 }
    19 }
    20 }

          客户端配置文件。需要注意的是,WCF服务地址还是要另外配置,因为Geneva框架会忽略终结点的地址信息:

    app.Config
    1 <system.serviceModel>
    2 <client>
    3 <endpoint name="TestService"
    4 address=""
    5 binding="ws2007FederationHttpBinding" bindingConfiguration="wsFederation"
    6 contract="RP.Contracts.ITest"
    7 behaviorConfiguration="RPCertificateBehavior">
    8 </endpoint>
    9 </client>
    10 <bindings>
    11 <ws2007FederationHttpBinding>
    12 <binding name="wsFederation">
    13 <security mode="Message">
    14 <message>
    15  <!—需要指定一个颁发者,这个节点不能为空-->
    16 <issuer address="http://sts-server/" binding="ws2007HttpBinding">
    17 </issuer>
    18 </message>
    19 </security>
    20 </binding>
    21 </ws2007FederationHttpBinding>
    22 </bindings>
    23 <behaviors>
    24 <endpointBehaviors>
    25 <behavior name="RPCertificateBehavior">
    26 <clientCredentials>
    27 <serviceCertificate>
    28 <!--指定服务默认证书,以及正式验证模式和吊销模式-->
    29 <defaultCertificate findValue="CN=rp-server" storeLocation="LocalMachine" storeName="TrustedPeople"/>
    30 <authentication certificateValidationMode="PeerOrChainTrust" revocationMode="NoCheck" />
    31 </serviceCertificate>
    32 </clientCredentials>
    33 </behavior>
    34 </endpointBehaviors>
    35 </behaviors>
    36 </system.serviceModel>
    37  
  7. RP端(WCF) 
  8.       使用Federation绑定的WCF可以自动解密客户端传递的安全令牌,为请求线程创建安全主体IPrincipal,并将所有相关声明附加到AuthorizationContext的声明集合ClaimSet中。所以我们只需要遍历 AuthorizationContext中的实例集合ClaimSet,以获得基于声明的安全性。

          先来看简单的页面文件和服务类:

    1 <%@ServiceHost language="c#" Debug="true" Service="RP.WCF.TestService" %>
    Service类
    1 namespace RP.WCF
    2 {
    3 public class TestService : FederatedBase, ITest
    4 {
    5 public string Say(string message)
    6 {
    7 return string.Format("Say {0}, {1} {2}", message, (this.FederatedUser.IsAdmin ? "(Admin)" : ""), this.FederatedUser.LoginName);
      8 }
    9 }
    10 }
    11

          服务的基类FederatedBase则用来保存从声明集合解析出来的信息:

    Service Base类
    1 namespace RP.WCF
    2 {
    3 public class FederatedBase
    4 {
    5 FederatedContextUser _FederatedUser;
    6 /// <summary>
    7 /// 当前用户信息
    8 /// </summary>
    9   public FederatedContextUser FederatedUser
    10 {
    11 get
    12 {
    13 if (_FederatedUser == null)
    14 _FederatedUser = FederatedContextUser.Current;
    15 return _FederatedUser;
    16 }
    17 }
    18 }
    19
    20 /// <summary>
    21 /// 当前WCF上下文的用户信息
    22 /// </summary>
    23 public class FederatedContextUser
    24 {
    25 /// <summary>
    26 /// 当前WCF上下文的用户信息
    27 /// </summary>
    28 public static FederatedContextUser Current
    29 {
    30 get
    31 {
    32 return new FederatedContextUser();
    33 }
    34 }
    35 private FederatedContextUser()
    36 {
    37 if (ServiceSecurityContext.Current != null && ServiceSecurityContext.Current.AuthorizationContext != null &&
    38 ServiceSecurityContext.Current.AuthorizationContext.ClaimSets != null)
    39 {
    40 foreach (ClaimSet claimset in ServiceSecurityContext.Current.AuthorizationContext.ClaimSets)
    41 {
    42 foreach (Claim claim in claimset)
    43 {
    44 if (claim.ClaimType.Equals(System.IdentityModel.Claims.ClaimTypes.Name))
    45 LoginName = claim.Resource.ToString();
    46
    47
    48 if (claim.ClaimType.Equals("http://sts-server/claims/isadmin"))
    49 IsAdmin = bool.Parse(claim.Resource.ToString());
    50
    51 //其他声明也可以转换成类的属性便于访问
    52
    53 }
    54 }
    55 }
    56 else
    57 {
    58 throw new FaultException("没有有效的用户信息");
    59 }
    60 }
    61
    62 /// <summary>
    63 /// 用户名
    64 /// </summary>
    65 public string LoginName { get; private set; }
    66 /// <summary>
    67 /// 是否管理员
    68 /// </summary>
    69 public bool IsAdmin { get; private set; }
    70
    71 //其他声明
    72 }
    73 }
    74

          服务配置文件:

    Web.Config
    1 <system.serviceModel>
    2 <bindings>
    3 <ws2007FederationHttpBinding>
    4 <binding name="federationBinding">
    5 <security mode="Message">
    6 <message/>
    7 </security>
    8 </binding>
    9 </ws2007FederationHttpBinding>
    10 </bindings>
    11 <behaviors>
    12 <serviceBehaviors>
    13 <behavior name="federationBehavior">
    14 <!—指定服务器证书-->
    15 <serviceCredentials>
    16 <serviceCertificate storeLocation="LocalMachine" storeName="My" findValue="CN=rp-server"/>
    17 </serviceCredentials>
    18 </behavior>
    19 </serviceBehaviors>
    20 </behaviors>
    21 <services>
    22 <service name="RP.WCF.TestService" behaviorConfiguration="federationBehavior">
    23 <endpoint address="federation" binding="ws2007FederationHttpBinding" contract=" RP.Contracts.ITest"
    24 bindingConfiguration="federationBinding">
    25 </endpoint>
    26 </service>
    27 </services>
    28 </system.serviceModel>
    29  
  9. 最终结果
  10.       将IP-STS端和RP端的WCF服务布置好,运行Client端,就可以看到结果。

posted @ 2010-11-24 09:31  reni  阅读(927)  评论(1编辑  收藏  举报