1 //
2 // ServiceCredentialsSecurityTokenManager.cs
3 //
4 // Author:
5 //	Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2006 Novell, Inc.  http://www.novell.com
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27 //
28 using System;
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;
37 
38 using ReqType = System.ServiceModel.Security.Tokens.ServiceModelSecurityTokenRequirement;
39 
40 namespace System.ServiceModel.Security
41 {
42 	public class ServiceCredentialsSecurityTokenManager : SecurityTokenManager, IEndpointIdentityProvider
43 	{
44 		ServiceCredentials credentials;
45 
ServiceCredentialsSecurityTokenManager( ServiceCredentials parent)46 		public ServiceCredentialsSecurityTokenManager (
47 			ServiceCredentials parent)
48 		{
49 			this.credentials = parent;
50 		}
51 
52 		public ServiceCredentials ServiceCredentials {
53 			get { return credentials; }
54 		}
55 
56 		[MonoTODO]
GetIdentityOfSelf( SecurityTokenRequirement tokenRequirement)57 		public virtual EndpointIdentity GetIdentityOfSelf (
58 			SecurityTokenRequirement tokenRequirement)
59 		{
60 			throw new NotImplementedException ();
61 		}
62 
63 		[MonoTODO]
CreateSecurityTokenAuthenticator( SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)64 		public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator (
65 			SecurityTokenRequirement tokenRequirement,
66 			out SecurityTokenResolver outOfBandTokenResolver)
67 		{
68 			outOfBandTokenResolver = null;
69 			if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
70 				return CreateUserNameAuthenticator (tokenRequirement);
71 			if (tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate)
72 				return CreateX509Authenticator (tokenRequirement);
73 			if (tokenRequirement.TokenType == SecurityTokenTypes.Rsa)
74 				return new RsaSecurityTokenAuthenticator ();
75 			if (tokenRequirement.TokenType == ServiceModelSecurityTokenTypes.SecureConversation) {
76 				SecurityBindingElement binding;
77 				if (!tokenRequirement.TryGetProperty<SecurityBindingElement> (ReqType.SecurityBindingElementProperty, out binding))
78 					throw new ArgumentException ("SecurityBindingElement is required in the security token requirement");
79 				SecureConversationSecurityTokenParameters issuedParams;
80 				if (!tokenRequirement.TryGetProperty<SecureConversationSecurityTokenParameters> (ReqType.IssuedSecurityTokenParametersProperty, out issuedParams))
81 					throw new ArgumentException ("IssuedSecurityTokenParameters are required in the security token requirement");
82 				BindingContext issuerBC;
83 				if (!tokenRequirement.TryGetProperty<BindingContext> (ReqType.IssuerBindingContextProperty, out issuerBC))
84 					throw new ArgumentException ("IssuerBindingContext is required in the security token requirement");
85 				SecurityTokenVersion secVer;
86 				if (!tokenRequirement.TryGetProperty<SecurityTokenVersion> (ReqType.MessageSecurityVersionProperty, out secVer))
87 					throw new ArgumentException ("MessageSecurityVersion property (of type SecurityTokenVersion) is required in the security token requirement");
88 
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 (tokenRequirement, sc, resolver);
96 			}
97 			if (tokenRequirement.TokenType == ServiceModelSecurityTokenTypes.AnonymousSslnego)
98 				return CreateSslTokenAuthenticator (tokenRequirement);
99 			if (tokenRequirement.TokenType == ServiceModelSecurityTokenTypes.MutualSslnego)
100 				return CreateSslTokenAuthenticator (tokenRequirement);
101 			if (tokenRequirement.TokenType == ServiceModelSecurityTokenTypes.Spnego)
102 				return CreateSpnegoTokenAuthenticator (tokenRequirement);
103 			else
104 				throw new NotImplementedException ("Not implemented token type: " + tokenRequirement.TokenType);
105 		}
106 
CreateSpnegoTokenAuthenticator(SecurityTokenRequirement requirement)107 		SpnegoSecurityTokenAuthenticator CreateSpnegoTokenAuthenticator (SecurityTokenRequirement requirement)
108 		{
109 			SpnegoSecurityTokenAuthenticator a =
110 				new SpnegoSecurityTokenAuthenticator (this, requirement);
111 			InitializeAuthenticatorCommunicationObject (a.Communication, requirement);
112 			return a;
113 		}
114 
CreateSslTokenAuthenticator(SecurityTokenRequirement requirement)115 		SslSecurityTokenAuthenticator CreateSslTokenAuthenticator (SecurityTokenRequirement requirement)
116 		{
117 			SslSecurityTokenAuthenticator a =
118 				new SslSecurityTokenAuthenticator (this, requirement);
119 			InitializeAuthenticatorCommunicationObject (a.Communication, requirement);
120 			return a;
121 		}
122 
CreateUserNameAuthenticator(SecurityTokenRequirement requirement)123 		UserNameSecurityTokenAuthenticator CreateUserNameAuthenticator (SecurityTokenRequirement requirement)
124 		{
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);
133 			default:
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);
137 			}
138 		}
139 
CreateX509Authenticator(SecurityTokenRequirement requirement)140 		X509SecurityTokenAuthenticator CreateX509Authenticator (SecurityTokenRequirement requirement)
141 		{
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);
154 			default:
155 				return new X509SecurityTokenAuthenticator (X509CertificateValidator.PeerTrust);
156 			}
157 		}
158 
InitializeAuthenticatorCommunicationObject(AuthenticatorCommunicationObject p, SecurityTokenRequirement r)159 		void InitializeAuthenticatorCommunicationObject (AuthenticatorCommunicationObject p, SecurityTokenRequirement r)
160 		{
161 			p.ListenUri = r.GetProperty<Uri> (ReqType.ListenUriProperty);
162 
163 			// FIXME: use it somewhere, probably to build
164 			// IssuerBinding. However, there is also IssuerBinding
165 			// property. SecureConversationSecurityBindingElement
166 			// as well.
167 			SecurityBindingElement sbe =
168 				r.GetProperty<SecurityBindingElement> (ReqType.SecurityBindingElementProperty);
169 			p.SecurityBindingElement = sbe;
170 
171 /*
172 			// I doubt the binding is acquired this way ...
173 			Binding binding;
174 			if (!r.TryGetProperty<Binding> (ReqType.IssuerBindingProperty, out binding))
175 				binding = new CustomBinding (
176 					new TextMessageEncodingBindingElement (),
177 					new HttpTransportBindingElement ());
178 			p.IssuerBinding = binding;
179 
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);
184 */
185 
186 			SecurityTokenVersion ver =
187 				r.GetProperty<SecurityTokenVersion> (ReqType.MessageSecurityVersionProperty);
188 			p.SecurityTokenSerializer =
189 				CreateSecurityTokenSerializer (ver);
190 
191 /*
192 			// seems like they are optional here ... (but possibly
193 			// used later)
194 			EndpointAddress address;
195 			if (!r.TryGetProperty<EndpointAddress> (ReqType.IssuerAddressProperty, out address))
196 				address = p.TargetAddress;
197 			p.IssuerAddress = address;
198 */
199 
200 			// It is somehow not checked as mandatory ...
201 			SecurityAlgorithmSuite suite = null;
202 			r.TryGetProperty<SecurityAlgorithmSuite> (ReqType.SecurityAlgorithmSuiteProperty, out suite);
203 			p.SecurityAlgorithmSuite = suite;
204 		}
205 
206 		#region CreateSecurityTokenProvider()
207 
208 		[MonoTODO]
CreateSecurityTokenProvider(SecurityTokenRequirement requirement)209 		public override SecurityTokenProvider CreateSecurityTokenProvider (SecurityTokenRequirement requirement)
210 		{
211 			if (IsIssuedSecurityTokenRequirement (requirement))
212 				return CreateIssuedTokenProvider (requirement);
213 
214 			// not supported: UserName, Rsa, AnonymousSslnego, SecureConv
215 
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) {
220 				// FIXME: implement
221 				throw new NotImplementedException ();
222 			} else if (requirement.TokenType == ServiceModelSecurityTokenTypes.SecurityContext) {
223 				// FIXME: implement
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) {
228 				// FIXME: implement
229 				throw new NotImplementedException ();
230 			} else if (requirement.TokenType == ServiceModelSecurityTokenTypes.SspiCredential) {
231 				// FIXME: implement
232 				throw new NotImplementedException ();
233 			} else if (requirement.TokenType == SecurityTokenTypes.Saml) {
234 				// FIXME: implement
235 				throw new NotImplementedException ();
236 			} else if (requirement.TokenType == SecurityTokenTypes.Kerberos) {
237 				// FIXME: implement
238 				throw new NotImplementedException ();
239 			}
240 			throw new NotSupportedException (String.Format ("Securirty token requirement '{0}' is not supported", requirement));
241 		}
242 
CreateX509SecurityTokenProvider(SecurityTokenRequirement requirement)243 		X509SecurityTokenProvider CreateX509SecurityTokenProvider (SecurityTokenRequirement requirement)
244 		{
245 			bool isInitiator;
246 			requirement.TryGetProperty<bool> (ReqType.IsInitiatorProperty, out isInitiator);
247 			// when it is initiator, then it is for MutualCertificateDuplex.
248 			X509Certificate2 cert;
249 			if (isInitiator) {
250 				cert = credentials.ClientCertificate.Certificate;
251 				if (cert == null)
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.");
255 			} else {
256 				cert = credentials.ServiceCertificate.Certificate;
257 				if (cert == null)
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.");
261 			}
262 			X509SecurityTokenProvider p =
263 				new X509SecurityTokenProvider (cert);
264 			return p;
265 		}
266 
CreateIssuedProviderBase(SecurityTokenRequirement r)267 		IssuedSecurityTokenProvider CreateIssuedProviderBase (SecurityTokenRequirement r)
268 		{
269 			IssuedSecurityTokenProvider p =
270 				new IssuedSecurityTokenProvider ();
271 
272 			p.TargetAddress = r.GetProperty<EndpointAddress> (ReqType.TargetAddressProperty);
273 
274 			// FIXME: use it somewhere, probably to build
275 			// IssuerBinding. However, there is also IssuerBinding
276 			// property. SecureConversationSecurityBindingElement
277 			// as well.
278 			SecurityBindingElement sbe =
279 				r.GetProperty<SecurityBindingElement> (ReqType.SecurityBindingElementProperty);
280 
281 			// I doubt the binding is acquired this way ...
282 			Binding binding;
283 			if (!r.TryGetProperty<Binding> (ReqType.IssuerBindingProperty, out binding))
284 				binding = new CustomBinding (sbe,
285 					new TextMessageEncodingBindingElement (),
286 					new HttpTransportBindingElement ());
287 			p.IssuerBinding = binding;
288 
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);
293 
294 			SecurityTokenVersion ver =
295 				r.GetProperty<SecurityTokenVersion> (ReqType.MessageSecurityVersionProperty);
296 			p.SecurityTokenSerializer =
297 				CreateSecurityTokenSerializer (ver);
298 
299 			// seems like they are optional here ... (but possibly
300 			// used later)
301 			EndpointAddress address;
302 			if (!r.TryGetProperty<EndpointAddress> (ReqType.IssuerAddressProperty, out address))
303 				address = p.TargetAddress;
304 			p.IssuerAddress = address;
305 
306 			// It is somehow not checked as mandatory ...
307 			SecurityAlgorithmSuite suite = null;
308 			r.TryGetProperty<SecurityAlgorithmSuite> (ReqType.SecurityAlgorithmSuiteProperty, out suite);
309 			p.SecurityAlgorithmSuite = suite;
310 
311 			return p;
312 		}
313 
314 		// FIXME: it is far from done.
CreateSecureConversationProvider(SecurityTokenRequirement r)315 		SecurityTokenProvider CreateSecureConversationProvider (SecurityTokenRequirement r)
316 		{
317 			IssuedSecurityTokenProvider p =
318 				CreateIssuedProviderBase (r);
319 
320 			// FIXME: use it somewhere.
321 			int keySize = r.KeySize;
322 
323 			return p;
324 		}
325 
CreateIssuedTokenProvider(SecurityTokenRequirement requirement)326 		IssuedSecurityTokenProvider CreateIssuedTokenProvider (SecurityTokenRequirement requirement)
327 		{
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;
336 			Binding binding;
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;
345 			return p;
346 		}
347 
348 		#endregion
349 
350 		[MonoTODO ("pass correct arguments to WSSecurityTokenSerializer..ctor()")]
CreateSecurityTokenSerializer(SecurityTokenVersion version)351 		public override SecurityTokenSerializer CreateSecurityTokenSerializer (SecurityTokenVersion version)
352 		{
353 			bool bsp = version.GetSecuritySpecifications ().Contains (Constants.WSBasicSecurityProfileCore1);
354 			SecurityVersion ver =
355 				version.GetSecuritySpecifications ().Contains (Constants.Wss11Namespace) ?
356 				SecurityVersion.WSSecurity11 :
357 				SecurityVersion.WSSecurity10;
358 
359 			// FIXME: pass correct arguments.
360 			return new WSSecurityTokenSerializer (ver, bsp, null,
361 				ServiceCredentials.SecureConversationAuthentication.SecurityStateEncoder,
362 				Type.EmptyTypes,
363 				int.MaxValue, int.MaxValue, int.MaxValue);
364 		}
365 
IsIssuedSecurityTokenRequirement( SecurityTokenRequirement requirement)366 		protected internal bool IsIssuedSecurityTokenRequirement (
367 			SecurityTokenRequirement requirement)
368 		{
369 			SecurityTokenParameters ret;
370 			if (!requirement.TryGetProperty<SecurityTokenParameters> (ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty, out ret))
371 				return false;
372 			return ret is IssuedSecurityTokenParameters;
373 		}
374 	}
375 }
376