基于Geneva框架的STS实现--RP端
- WSFederationHttpBinding 支持 WS-Federation 协议的绑定。
- WCF契约
- Client端
- RP端(WCF)
- 最终结果
WS-Federation 规范定义了一个模型和消息集合,用于在不同信任领域间代理信任并联合身份和身份验证信息。协议被BEA、IBM、Microsoft、RSA Security 和 VeriSign厂商支持。
WS-Federation 依赖另外一组协议:WS-Trust, WS-Policy,WS-Authorization。
1 namespace RP.Contracts
2 {
3 [ServiceContract]
4 public interface ITest
5 {
6 [OperationContract]
7 string Say(string message);
8 }
9 }
10
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
使用Federation绑定的WCF可以自动解密客户端传递的安全令牌,为请求线程创建安全主体IPrincipal,并将所有相关声明附加到AuthorizationContext的声明集合ClaimSet中。所以我们只需要遍历 AuthorizationContext中的实例集合ClaimSet,以获得基于声明的安全性。
先来看简单的页面文件和服务类:
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
将IP-STS端和RP端的WCF服务布置好,运行Client端,就可以看到结果。