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