MessageSecurityOverHttp.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel
  5. {
  6. using System.Runtime;
  7. using System.Runtime.CompilerServices;
  8. using System.ServiceModel.Channels;
  9. using System.ServiceModel.Security;
  10. using System.ServiceModel.Security.Tokens;
  11. using System.ComponentModel;
  12. public class MessageSecurityOverHttp
  13. {
  14. internal const MessageCredentialType DefaultClientCredentialType = MessageCredentialType.Windows;
  15. internal const bool DefaultNegotiateServiceCredential = true;
  16. MessageCredentialType clientCredentialType;
  17. bool negotiateServiceCredential;
  18. SecurityAlgorithmSuite algorithmSuite;
  19. bool wasAlgorithmSuiteSet;
  20. public MessageSecurityOverHttp()
  21. {
  22. clientCredentialType = DefaultClientCredentialType;
  23. negotiateServiceCredential = DefaultNegotiateServiceCredential;
  24. algorithmSuite = SecurityAlgorithmSuite.Default;
  25. }
  26. public MessageCredentialType ClientCredentialType
  27. {
  28. get { return this.clientCredentialType; }
  29. set
  30. {
  31. if (!MessageCredentialTypeHelper.IsDefined(value))
  32. {
  33. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value"));
  34. }
  35. this.clientCredentialType = value;
  36. }
  37. }
  38. public bool NegotiateServiceCredential
  39. {
  40. get { return this.negotiateServiceCredential; }
  41. set { this.negotiateServiceCredential = value; }
  42. }
  43. public SecurityAlgorithmSuite AlgorithmSuite
  44. {
  45. get { return this.algorithmSuite; }
  46. set
  47. {
  48. if (value == null)
  49. {
  50. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  51. }
  52. this.algorithmSuite = value;
  53. wasAlgorithmSuiteSet = true;
  54. }
  55. }
  56. internal bool WasAlgorithmSuiteSet
  57. {
  58. get { return this.wasAlgorithmSuiteSet; }
  59. }
  60. protected virtual bool IsSecureConversationEnabled()
  61. {
  62. return true;
  63. }
  64. [MethodImpl(MethodImplOptions.NoInlining)]
  65. internal SecurityBindingElement CreateSecurityBindingElement(bool isSecureTransportMode, bool isReliableSession, MessageSecurityVersion version)
  66. {
  67. if (isReliableSession && !this.IsSecureConversationEnabled())
  68. {
  69. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecureConversationRequiredByReliableSession)));
  70. }
  71. SecurityBindingElement result;
  72. SecurityBindingElement oneShotSecurity;
  73. bool isKerberosSelected = false;
  74. bool emitBspAttributes = true;
  75. if (isSecureTransportMode)
  76. {
  77. switch (this.clientCredentialType)
  78. {
  79. case MessageCredentialType.None:
  80. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ClientCredentialTypeMustBeSpecifiedForMixedMode)));
  81. case MessageCredentialType.UserName:
  82. oneShotSecurity = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
  83. break;
  84. case MessageCredentialType.Certificate:
  85. oneShotSecurity = SecurityBindingElement.CreateCertificateOverTransportBindingElement();
  86. break;
  87. case MessageCredentialType.Windows:
  88. oneShotSecurity = SecurityBindingElement.CreateSspiNegotiationOverTransportBindingElement(true);
  89. break;
  90. case MessageCredentialType.IssuedToken:
  91. oneShotSecurity = SecurityBindingElement.CreateIssuedTokenOverTransportBindingElement(IssuedSecurityTokenParameters.CreateInfoCardParameters(new SecurityStandardsManager(new WSSecurityTokenSerializer(emitBspAttributes)), this.algorithmSuite));
  92. break;
  93. default:
  94. Fx.Assert("unknown ClientCredentialType");
  95. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  96. }
  97. if (this.IsSecureConversationEnabled())
  98. {
  99. result = SecurityBindingElement.CreateSecureConversationBindingElement(oneShotSecurity, true);
  100. }
  101. else
  102. {
  103. result = oneShotSecurity;
  104. }
  105. }
  106. else
  107. {
  108. if (negotiateServiceCredential)
  109. {
  110. switch (this.clientCredentialType)
  111. {
  112. case MessageCredentialType.None:
  113. oneShotSecurity = SecurityBindingElement.CreateSslNegotiationBindingElement(false, true);
  114. break;
  115. case MessageCredentialType.UserName:
  116. oneShotSecurity = SecurityBindingElement.CreateUserNameForSslBindingElement(true);
  117. break;
  118. case MessageCredentialType.Certificate:
  119. oneShotSecurity = SecurityBindingElement.CreateSslNegotiationBindingElement(true, true);
  120. break;
  121. case MessageCredentialType.Windows:
  122. oneShotSecurity = SecurityBindingElement.CreateSspiNegotiationBindingElement(true);
  123. break;
  124. case MessageCredentialType.IssuedToken:
  125. oneShotSecurity = SecurityBindingElement.CreateIssuedTokenForSslBindingElement(IssuedSecurityTokenParameters.CreateInfoCardParameters(new SecurityStandardsManager(new WSSecurityTokenSerializer(emitBspAttributes)), this.algorithmSuite), true);
  126. break;
  127. default:
  128. Fx.Assert("unknown ClientCredentialType");
  129. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  130. }
  131. }
  132. else
  133. {
  134. switch (this.clientCredentialType)
  135. {
  136. case MessageCredentialType.None:
  137. oneShotSecurity = SecurityBindingElement.CreateAnonymousForCertificateBindingElement();
  138. break;
  139. case MessageCredentialType.UserName:
  140. oneShotSecurity = SecurityBindingElement.CreateUserNameForCertificateBindingElement();
  141. break;
  142. case MessageCredentialType.Certificate:
  143. oneShotSecurity = SecurityBindingElement.CreateMutualCertificateBindingElement();
  144. break;
  145. case MessageCredentialType.Windows:
  146. oneShotSecurity = SecurityBindingElement.CreateKerberosBindingElement();
  147. isKerberosSelected = true;
  148. break;
  149. case MessageCredentialType.IssuedToken:
  150. oneShotSecurity = SecurityBindingElement.CreateIssuedTokenForCertificateBindingElement(IssuedSecurityTokenParameters.CreateInfoCardParameters(new SecurityStandardsManager(new WSSecurityTokenSerializer(emitBspAttributes)), this.algorithmSuite));
  151. break;
  152. default:
  153. Fx.Assert("unknown ClientCredentialType");
  154. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  155. }
  156. }
  157. if (this.IsSecureConversationEnabled())
  158. {
  159. result = SecurityBindingElement.CreateSecureConversationBindingElement(oneShotSecurity, true);
  160. }
  161. else
  162. {
  163. result = oneShotSecurity;
  164. }
  165. }
  166. // set the algorithm suite and issued token params if required
  167. if (wasAlgorithmSuiteSet || (!isKerberosSelected))
  168. {
  169. result.DefaultAlgorithmSuite = oneShotSecurity.DefaultAlgorithmSuite = this.AlgorithmSuite;
  170. }
  171. else if (isKerberosSelected)
  172. {
  173. result.DefaultAlgorithmSuite = oneShotSecurity.DefaultAlgorithmSuite = SecurityAlgorithmSuite.KerberosDefault;
  174. }
  175. result.IncludeTimestamp = true;
  176. oneShotSecurity.MessageSecurityVersion = version;
  177. result.MessageSecurityVersion = version;
  178. if (!isReliableSession)
  179. {
  180. result.LocalServiceSettings.ReconnectTransportOnFailure = false;
  181. result.LocalClientSettings.ReconnectTransportOnFailure = false;
  182. }
  183. else
  184. {
  185. result.LocalServiceSettings.ReconnectTransportOnFailure = true;
  186. result.LocalClientSettings.ReconnectTransportOnFailure = true;
  187. }
  188. if (this.IsSecureConversationEnabled())
  189. {
  190. // issue the transition SCT for a short duration only
  191. oneShotSecurity.LocalServiceSettings.IssuedCookieLifetime = SpnegoTokenAuthenticator.defaultServerIssuedTransitionTokenLifetime;
  192. }
  193. return result;
  194. }
  195. internal static bool TryCreate<TSecurity>(SecurityBindingElement sbe, bool isSecureTransportMode, bool isReliableSession, out TSecurity messageSecurity)
  196. where TSecurity : MessageSecurityOverHttp
  197. {
  198. Fx.Assert(null != sbe, string.Empty);
  199. messageSecurity = null;
  200. // do not check local settings: sbe.LocalServiceSettings and sbe.LocalClientSettings
  201. if (!sbe.IncludeTimestamp)
  202. {
  203. return false;
  204. }
  205. // Do not check MessageSecurityVersion: it maybe changed by the wrapper element and gets checked later in the SecuritySection.AreBindingsMatching()
  206. if (sbe.SecurityHeaderLayout != SecurityProtocolFactory.defaultSecurityHeaderLayout)
  207. {
  208. return false;
  209. }
  210. bool negotiateServiceCredential = DefaultNegotiateServiceCredential;
  211. MessageCredentialType clientCredentialType;
  212. SecurityAlgorithmSuite algorithmSuite = SecurityAlgorithmSuite.Default;
  213. bool isSecureConversation;
  214. SecurityBindingElement bootstrapSecurity;
  215. if (!SecurityBindingElement.IsSecureConversationBinding(sbe, true, out bootstrapSecurity))
  216. {
  217. isSecureConversation = false;
  218. bootstrapSecurity = sbe;
  219. }
  220. else
  221. {
  222. isSecureConversation = true;
  223. }
  224. if (!isSecureConversation && typeof(TSecurity).Equals(typeof(MessageSecurityOverHttp)))
  225. {
  226. return false;
  227. }
  228. if (!isSecureConversation && isReliableSession)
  229. {
  230. return false;
  231. }
  232. if (isSecureTransportMode && !(bootstrapSecurity is TransportSecurityBindingElement))
  233. {
  234. return false;
  235. }
  236. IssuedSecurityTokenParameters infocardParameters;
  237. if (isSecureTransportMode)
  238. {
  239. if (SecurityBindingElement.IsUserNameOverTransportBinding(bootstrapSecurity))
  240. {
  241. clientCredentialType = MessageCredentialType.UserName;
  242. }
  243. else if (SecurityBindingElement.IsCertificateOverTransportBinding(bootstrapSecurity))
  244. {
  245. clientCredentialType = MessageCredentialType.Certificate;
  246. }
  247. else if (SecurityBindingElement.IsSspiNegotiationOverTransportBinding(bootstrapSecurity, true))
  248. {
  249. clientCredentialType = MessageCredentialType.Windows;
  250. }
  251. else if (SecurityBindingElement.IsIssuedTokenOverTransportBinding(bootstrapSecurity, out infocardParameters))
  252. {
  253. if (!IssuedSecurityTokenParameters.IsInfoCardParameters(
  254. infocardParameters,
  255. new SecurityStandardsManager(
  256. sbe.MessageSecurityVersion,
  257. new WSSecurityTokenSerializer(
  258. sbe.MessageSecurityVersion.SecurityVersion,
  259. sbe.MessageSecurityVersion.TrustVersion,
  260. sbe.MessageSecurityVersion.SecureConversationVersion,
  261. true,
  262. null, null, null))))
  263. {
  264. return false;
  265. }
  266. clientCredentialType = MessageCredentialType.IssuedToken;
  267. }
  268. else
  269. {
  270. // the standard binding does not support None client credential type in mixed mode
  271. return false;
  272. }
  273. }
  274. else
  275. {
  276. if (SecurityBindingElement.IsSslNegotiationBinding(bootstrapSecurity, false, true))
  277. {
  278. negotiateServiceCredential = true;
  279. clientCredentialType = MessageCredentialType.None;
  280. }
  281. else if (SecurityBindingElement.IsUserNameForSslBinding(bootstrapSecurity, true))
  282. {
  283. negotiateServiceCredential = true;
  284. clientCredentialType = MessageCredentialType.UserName;
  285. }
  286. else if (SecurityBindingElement.IsSslNegotiationBinding(bootstrapSecurity, true, true))
  287. {
  288. negotiateServiceCredential = true;
  289. clientCredentialType = MessageCredentialType.Certificate;
  290. }
  291. else if (SecurityBindingElement.IsSspiNegotiationBinding(bootstrapSecurity, true))
  292. {
  293. negotiateServiceCredential = true;
  294. clientCredentialType = MessageCredentialType.Windows;
  295. }
  296. else if (SecurityBindingElement.IsIssuedTokenForSslBinding(bootstrapSecurity, true, out infocardParameters))
  297. {
  298. if (!IssuedSecurityTokenParameters.IsInfoCardParameters(
  299. infocardParameters,
  300. new SecurityStandardsManager(
  301. sbe.MessageSecurityVersion,
  302. new WSSecurityTokenSerializer(
  303. sbe.MessageSecurityVersion.SecurityVersion,
  304. sbe.MessageSecurityVersion.TrustVersion,
  305. sbe.MessageSecurityVersion.SecureConversationVersion,
  306. true,
  307. null, null, null))))
  308. {
  309. return false;
  310. }
  311. negotiateServiceCredential = true;
  312. clientCredentialType = MessageCredentialType.IssuedToken;
  313. }
  314. else if (SecurityBindingElement.IsUserNameForCertificateBinding(bootstrapSecurity))
  315. {
  316. negotiateServiceCredential = false;
  317. clientCredentialType = MessageCredentialType.UserName;
  318. }
  319. else if (SecurityBindingElement.IsMutualCertificateBinding(bootstrapSecurity))
  320. {
  321. negotiateServiceCredential = false;
  322. clientCredentialType = MessageCredentialType.Certificate;
  323. }
  324. else if (SecurityBindingElement.IsKerberosBinding(bootstrapSecurity))
  325. {
  326. negotiateServiceCredential = false;
  327. clientCredentialType = MessageCredentialType.Windows;
  328. }
  329. else if (SecurityBindingElement.IsIssuedTokenForCertificateBinding(bootstrapSecurity, out infocardParameters))
  330. {
  331. if (!IssuedSecurityTokenParameters.IsInfoCardParameters(
  332. infocardParameters,
  333. new SecurityStandardsManager(
  334. sbe.MessageSecurityVersion,
  335. new WSSecurityTokenSerializer(
  336. sbe.MessageSecurityVersion.SecurityVersion,
  337. sbe.MessageSecurityVersion.TrustVersion,
  338. sbe.MessageSecurityVersion.SecureConversationVersion,
  339. true,
  340. null, null, null))))
  341. {
  342. return false;
  343. }
  344. negotiateServiceCredential = false;
  345. clientCredentialType = MessageCredentialType.IssuedToken;
  346. }
  347. else if (SecurityBindingElement.IsAnonymousForCertificateBinding(bootstrapSecurity))
  348. {
  349. negotiateServiceCredential = false;
  350. clientCredentialType = MessageCredentialType.None;
  351. }
  352. else
  353. {
  354. return false;
  355. }
  356. }
  357. // Do not check any Local* settings
  358. // Do not check DefaultAlgorithmSuite: is it often changed after the Security element is created, it will verified by SecuritySectionBase.AreBindingsMatching().
  359. if (typeof(NonDualMessageSecurityOverHttp).Equals(typeof(TSecurity)))
  360. {
  361. messageSecurity = (TSecurity)(object)new NonDualMessageSecurityOverHttp();
  362. ((NonDualMessageSecurityOverHttp)(object)messageSecurity).EstablishSecurityContext = isSecureConversation;
  363. }
  364. else
  365. {
  366. messageSecurity = (TSecurity)(object)new MessageSecurityOverHttp();
  367. }
  368. messageSecurity.ClientCredentialType = clientCredentialType;
  369. messageSecurity.NegotiateServiceCredential = negotiateServiceCredential;
  370. messageSecurity.AlgorithmSuite = sbe.DefaultAlgorithmSuite;
  371. return true;
  372. }
  373. internal bool InternalShouldSerialize()
  374. {
  375. return this.ShouldSerializeAlgorithmSuite()
  376. || this.ShouldSerializeClientCredentialType()
  377. || ShouldSerializeNegotiateServiceCredential();
  378. }
  379. [EditorBrowsable(EditorBrowsableState.Never)]
  380. public bool ShouldSerializeAlgorithmSuite()
  381. {
  382. return this.AlgorithmSuite != SecurityAlgorithmSuite.Default;
  383. }
  384. [EditorBrowsable(EditorBrowsableState.Never)]
  385. public bool ShouldSerializeClientCredentialType()
  386. {
  387. return this.ClientCredentialType != DefaultClientCredentialType;
  388. }
  389. [EditorBrowsable(EditorBrowsableState.Never)]
  390. public bool ShouldSerializeNegotiateServiceCredential()
  391. {
  392. return this.NegotiateServiceCredential != DefaultNegotiateServiceCredential;
  393. }
  394. }
  395. }