2 // ServiceCredentialsSecurityTokenManager.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2006 Novell, Inc. http://www.novell.com
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Net.Security;
30 using System.IdentityModel.Selectors;
31 using System.IdentityModel.Tokens;
32 using System.Security.Cryptography.X509Certificates;
33 using System.ServiceModel;
34 using System.ServiceModel.Channels;
35 using System.ServiceModel.Description;
36 using System.ServiceModel.Security.Tokens;
38 using ReqType = System.ServiceModel.Security.Tokens.ServiceModelSecurityTokenRequirement;
40 namespace System.ServiceModel.Security
42 public class ServiceCredentialsSecurityTokenManager : SecurityTokenManager, IEndpointIdentityProvider
44 ServiceCredentials credentials;
46 public ServiceCredentialsSecurityTokenManager (
47 ServiceCredentials credentials)
49 this.credentials = credentials;
52 public ServiceCredentials ServiceCredentials {
53 get { return credentials; }
57 public virtual EndpointIdentity GetIdentityOfSelf (
58 SecurityTokenRequirement requirement)
60 throw new NotImplementedException ();
64 public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator (
65 SecurityTokenRequirement requirement,
66 out SecurityTokenResolver outOfBandTokenResolver)
68 outOfBandTokenResolver = null;
69 if (requirement.TokenType == SecurityTokenTypes.UserName)
70 return CreateUserNameAuthenticator (requirement);
71 if (requirement.TokenType == SecurityTokenTypes.X509Certificate)
72 return CreateX509Authenticator (requirement);
73 if (requirement.TokenType == SecurityTokenTypes.Rsa)
74 return new RsaSecurityTokenAuthenticator ();
75 if (requirement.TokenType == ServiceModelSecurityTokenTypes.SecureConversation) {
76 SecurityBindingElement binding;
77 if (!requirement.TryGetProperty<SecurityBindingElement> (ReqType.SecurityBindingElementProperty, out binding))
78 throw new ArgumentException ("SecurityBindingElement is required in the security token requirement");
79 SecureConversationSecurityTokenParameters issuedParams;
80 if (!requirement.TryGetProperty<SecureConversationSecurityTokenParameters> (ReqType.IssuedSecurityTokenParametersProperty, out issuedParams))
81 throw new ArgumentException ("IssuedSecurityTokenParameters are required in the security token requirement");
82 BindingContext issuerBC;
83 if (!requirement.TryGetProperty<BindingContext> (ReqType.IssuerBindingContextProperty, out issuerBC))
84 throw new ArgumentException ("IssuerBindingContext is required in the security token requirement");
85 SecurityTokenVersion secVer;
86 if (!requirement.TryGetProperty<SecurityTokenVersion> (ReqType.MessageSecurityVersionProperty, out secVer))
87 throw new ArgumentException ("MessageSecurityVersion property (of type SecurityTokenVersion) is required in the security token requirement");
89 // FIXME: get parameters from somewhere
90 SecurityContextSecurityTokenResolver resolver =
91 new SecurityContextSecurityTokenResolver (0x1000, true);
92 outOfBandTokenResolver = resolver;
93 SecurityContextSecurityTokenAuthenticator sc =
94 new SecurityContextSecurityTokenAuthenticator ();
95 return new SecureConversationSecurityTokenAuthenticator (requirement, sc, resolver);
97 if (requirement.TokenType == ServiceModelSecurityTokenTypes.AnonymousSslnego)
98 return CreateSslTokenAuthenticator (requirement);
99 if (requirement.TokenType == ServiceModelSecurityTokenTypes.MutualSslnego)
100 return CreateSslTokenAuthenticator (requirement);
101 if (requirement.TokenType == ServiceModelSecurityTokenTypes.Spnego)
102 return CreateSpnegoTokenAuthenticator (requirement);
104 throw new NotImplementedException ("Not implemented token type: " + requirement.TokenType);
107 SpnegoSecurityTokenAuthenticator CreateSpnegoTokenAuthenticator (SecurityTokenRequirement requirement)
109 SpnegoSecurityTokenAuthenticator a =
110 new SpnegoSecurityTokenAuthenticator (this, requirement);
111 InitializeAuthenticatorCommunicationObject (a.Communication, requirement);
115 SslSecurityTokenAuthenticator CreateSslTokenAuthenticator (SecurityTokenRequirement requirement)
117 SslSecurityTokenAuthenticator a =
118 new SslSecurityTokenAuthenticator (this, requirement);
119 InitializeAuthenticatorCommunicationObject (a.Communication, requirement);
123 UserNameSecurityTokenAuthenticator CreateUserNameAuthenticator (SecurityTokenRequirement requirement)
125 UserNamePasswordServiceCredential c = ServiceCredentials.UserNameAuthentication;
126 switch (c.UserNamePasswordValidationMode) {
127 case UserNamePasswordValidationMode.MembershipProvider:
128 if (c.MembershipProvider == null)
129 throw new InvalidOperationException ("For MembershipProvider validation mode, MembershipProvider is required to create a user name token authenticator.");
130 return new CustomUserNameSecurityTokenAuthenticator (UserNamePasswordValidator.CreateMembershipProviderValidator (c.MembershipProvider));
131 case UserNamePasswordValidationMode.Windows:
132 return new WindowsUserNameSecurityTokenAuthenticator (c.IncludeWindowsGroups);
134 if (c.CustomUserNamePasswordValidator == null)
135 throw new InvalidOperationException ("For Custom validation mode, CustomUserNamePasswordValidator is required to create a user name token authenticator.");
136 return new CustomUserNameSecurityTokenAuthenticator (c.CustomUserNamePasswordValidator);
140 X509SecurityTokenAuthenticator CreateX509Authenticator (SecurityTokenRequirement requirement)
142 X509CertificateInitiatorServiceCredential c = ServiceCredentials.ClientCertificate;
143 switch (c.Authentication.CertificateValidationMode) {
144 case X509CertificateValidationMode.Custom:
145 if (c.Authentication.CustomCertificateValidator == null)
146 throw new InvalidOperationException ("For Custom certificate validation mode, CustomCertificateValidator is required to create a token authenticator for X509 certificate.");
147 return new X509SecurityTokenAuthenticator (c.Authentication.CustomCertificateValidator);
148 case X509CertificateValidationMode.None:
149 return new X509SecurityTokenAuthenticator (X509CertificateValidator.None);
150 case X509CertificateValidationMode.PeerOrChainTrust:
151 return new X509SecurityTokenAuthenticator (X509CertificateValidator.PeerOrChainTrust);
152 case X509CertificateValidationMode.ChainTrust:
153 return new X509SecurityTokenAuthenticator (X509CertificateValidator.ChainTrust);
155 return new X509SecurityTokenAuthenticator (X509CertificateValidator.PeerTrust);
159 void InitializeAuthenticatorCommunicationObject (AuthenticatorCommunicationObject p, SecurityTokenRequirement r)
161 p.ListenUri = r.GetProperty<Uri> (ReqType.ListenUriProperty);
163 // FIXME: use it somewhere, probably to build
164 // IssuerBinding. However, there is also IssuerBinding
165 // property. SecureConversationSecurityBindingElement
167 SecurityBindingElement sbe =
168 r.GetProperty<SecurityBindingElement> (ReqType.SecurityBindingElementProperty);
169 p.SecurityBindingElement = sbe;
172 // I doubt the binding is acquired this way ...
174 if (!r.TryGetProperty<Binding> (ReqType.IssuerBindingProperty, out binding))
175 binding = new CustomBinding (
176 new TextMessageEncodingBindingElement (),
177 new HttpTransportBindingElement ());
178 p.IssuerBinding = binding;
180 // not sure if it is used only for this purpose though ...
181 BindingContext ctx = r.GetProperty<BindingContext> (ReqType.IssuerBindingContextProperty);
182 foreach (IEndpointBehavior b in ctx.BindingParameters.FindAll<IEndpointBehavior> ())
183 p.IssuerChannelBehaviors.Add (b);
186 SecurityTokenVersion ver =
187 r.GetProperty<SecurityTokenVersion> (ReqType.MessageSecurityVersionProperty);
188 p.SecurityTokenSerializer =
189 CreateSecurityTokenSerializer (ver);
192 // seems like they are optional here ... (but possibly
194 EndpointAddress address;
195 if (!r.TryGetProperty<EndpointAddress> (ReqType.IssuerAddressProperty, out address))
196 address = p.TargetAddress;
197 p.IssuerAddress = address;
200 // It is somehow not checked as mandatory ...
201 SecurityAlgorithmSuite suite = null;
202 r.TryGetProperty<SecurityAlgorithmSuite> (ReqType.SecurityAlgorithmSuiteProperty, out suite);
203 p.SecurityAlgorithmSuite = suite;
206 #region CreateSecurityTokenProvider()
209 public override SecurityTokenProvider CreateSecurityTokenProvider (SecurityTokenRequirement requirement)
211 if (IsIssuedSecurityTokenRequirement (requirement))
212 return CreateIssuedTokenProvider (requirement);
214 // not supported: UserName, Rsa, AnonymousSslnego, SecureConv
216 // huh, they are not constants but properties.
217 if (requirement.TokenType == SecurityTokenTypes.X509Certificate)
218 return CreateX509SecurityTokenProvider (requirement);
219 else if (requirement.TokenType == ServiceModelSecurityTokenTypes.MutualSslnego) {
221 throw new NotImplementedException ();
222 } else if (requirement.TokenType == ServiceModelSecurityTokenTypes.SecurityContext) {
224 throw new NotImplementedException ();
225 } else if (requirement.TokenType == ServiceModelSecurityTokenTypes.AnonymousSslnego) {
226 throw new NotSupportedException (String.Format ("Token type '{0}' is not supported", requirement.TokenType));
227 } else if (requirement.TokenType == ServiceModelSecurityTokenTypes.Spnego) {
229 throw new NotImplementedException ();
230 } else if (requirement.TokenType == ServiceModelSecurityTokenTypes.SspiCredential) {
232 throw new NotImplementedException ();
233 } else if (requirement.TokenType == SecurityTokenTypes.Saml) {
235 throw new NotImplementedException ();
236 } else if (requirement.TokenType == SecurityTokenTypes.Kerberos) {
238 throw new NotImplementedException ();
240 throw new NotSupportedException (String.Format ("Securirty token requirement '{0}' is not supported", requirement));
243 X509SecurityTokenProvider CreateX509SecurityTokenProvider (SecurityTokenRequirement requirement)
246 requirement.TryGetProperty<bool> (ReqType.IsInitiatorProperty, out isInitiator);
247 // when it is initiator, then it is for MutualCertificateDuplex.
248 X509Certificate2 cert;
250 cert = credentials.ClientCertificate.Certificate;
252 throw new InvalidOperationException ("Client certificate is not provided in ServiceCredentials.");
253 if (cert.PrivateKey == null)
254 throw new ArgumentException ("Client certificate for MutualCertificateDuplex does not have a private key which is required for key exchange.");
256 cert = credentials.ServiceCertificate.Certificate;
258 throw new InvalidOperationException ("Service certificate is not provided in ServiceCredentials.");
259 if (cert.PrivateKey == null)
260 throw new ArgumentException ("Service certificate does not have a private key which is required for key exchange.");
262 X509SecurityTokenProvider p =
263 new X509SecurityTokenProvider (cert);
267 IssuedSecurityTokenProvider CreateIssuedProviderBase (SecurityTokenRequirement r)
269 IssuedSecurityTokenProvider p =
270 new IssuedSecurityTokenProvider ();
272 p.TargetAddress = r.GetProperty<EndpointAddress> (ReqType.TargetAddressProperty);
274 // FIXME: use it somewhere, probably to build
275 // IssuerBinding. However, there is also IssuerBinding
276 // property. SecureConversationSecurityBindingElement
278 SecurityBindingElement sbe =
279 r.GetProperty<SecurityBindingElement> (ReqType.SecurityBindingElementProperty);
281 // I doubt the binding is acquired this way ...
283 if (!r.TryGetProperty<Binding> (ReqType.IssuerBindingProperty, out binding))
284 binding = new CustomBinding (sbe,
285 new TextMessageEncodingBindingElement (),
286 new HttpTransportBindingElement ());
287 p.IssuerBinding = binding;
289 // not sure if it is used only for this purpose though ...
290 BindingContext ctx = r.GetProperty<BindingContext> (ReqType.IssuerBindingContextProperty);
291 foreach (IEndpointBehavior b in ctx.BindingParameters.FindAll<IEndpointBehavior> ())
292 p.IssuerChannelBehaviors.Add (b);
294 SecurityTokenVersion ver =
295 r.GetProperty<SecurityTokenVersion> (ReqType.MessageSecurityVersionProperty);
296 p.SecurityTokenSerializer =
297 CreateSecurityTokenSerializer (ver);
299 // seems like they are optional here ... (but possibly
301 EndpointAddress address;
302 if (!r.TryGetProperty<EndpointAddress> (ReqType.IssuerAddressProperty, out address))
303 address = p.TargetAddress;
304 p.IssuerAddress = address;
306 // It is somehow not checked as mandatory ...
307 SecurityAlgorithmSuite suite = null;
308 r.TryGetProperty<SecurityAlgorithmSuite> (ReqType.SecurityAlgorithmSuiteProperty, out suite);
309 p.SecurityAlgorithmSuite = suite;
314 // FIXME: it is far from done.
315 SecurityTokenProvider CreateSecureConversationProvider (SecurityTokenRequirement r)
317 IssuedSecurityTokenProvider p =
318 CreateIssuedProviderBase (r);
320 // FIXME: use it somewhere.
321 int keySize = r.KeySize;
326 IssuedSecurityTokenProvider CreateIssuedTokenProvider (SecurityTokenRequirement requirement)
328 IssuedSecurityTokenProvider p =
329 new IssuedSecurityTokenProvider ();
330 // FIXME: fill properties
331 EndpointAddress address;
332 if (requirement.TryGetProperty<EndpointAddress> (ReqType.IssuerAddressProperty, out address))
333 p.IssuerAddress = address;
334 if (requirement.TryGetProperty<EndpointAddress> (ReqType.TargetAddressProperty, out address))
335 p.TargetAddress = address;
337 if (requirement.TryGetProperty<Binding> (ReqType.IssuerBindingProperty, out binding))
338 p.IssuerBinding = binding;
339 MessageSecurityVersion ver;
340 if (requirement.TryGetProperty<MessageSecurityVersion> (ReqType.MessageSecurityVersionProperty, out ver))
341 p.SecurityTokenSerializer = CreateSecurityTokenSerializer (ver.SecurityTokenVersion);
342 SecurityAlgorithmSuite suite;
343 if (requirement.TryGetProperty<SecurityAlgorithmSuite> (ReqType.SecurityAlgorithmSuiteProperty, out suite))
344 p.SecurityAlgorithmSuite = suite;
350 [MonoTODO ("pass correct arguments to WSSecurityTokenSerializer..ctor()")]
351 public override SecurityTokenSerializer CreateSecurityTokenSerializer (SecurityTokenVersion version)
353 bool bsp = version.GetSecuritySpecifications ().Contains (Constants.WSBasicSecurityProfileCore1);
354 SecurityVersion ver =
355 version.GetSecuritySpecifications ().Contains (Constants.Wss11Namespace) ?
356 SecurityVersion.WSSecurity11 :
357 SecurityVersion.WSSecurity10;
359 // FIXME: pass correct arguments.
360 return new WSSecurityTokenSerializer (ver, bsp, null,
361 ServiceCredentials.SecureConversationAuthentication.SecurityStateEncoder,
363 int.MaxValue, int.MaxValue, int.MaxValue);
366 protected internal bool IsIssuedSecurityTokenRequirement (
367 SecurityTokenRequirement requirement)
369 SecurityTokenParameters ret;
370 if (!requirement.TryGetProperty<SecurityTokenParameters> (ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty, out ret))
372 return ret is IssuedSecurityTokenParameters;