WsSecurityTokenSerializerAdapter.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics;
  7. using System.IdentityModel;
  8. using System.IdentityModel.Policy;
  9. using System.IdentityModel.Selectors;
  10. using System.IdentityModel.Tokens;
  11. using System.Security.Claims;
  12. using System.Runtime;
  13. using System.ServiceModel;
  14. using System.ServiceModel.Security;
  15. using System.ServiceModel.Security.Tokens;
  16. using System.Xml;
  17. namespace System.ServiceModel.Security
  18. {
  19. /// <summary>
  20. /// This class derives from System.ServiceModel.Security.WSSecurityTokenSerializer and wraps a collection of SecurityTokenHandlers.
  21. /// Any call to this serilaizer is delegated to the token handler and delegated to the base class if no token handler
  22. /// is registered to handle this particular token or KeyIdentifier.
  23. /// </summary>
  24. class WsSecurityTokenSerializerAdapter : WSSecurityTokenSerializer
  25. {
  26. SecureConversationVersion _scVersion;
  27. SecurityTokenHandlerCollection _securityTokenHandlers;
  28. bool _mapExceptionsToSoapFaults;
  29. ExceptionMapper _exceptionMapper = new ExceptionMapper();
  30. /// <summary>
  31. /// Initializes an instance of <see cref="WsSecurityTokenSerializerAdapter"/>
  32. /// </summary>
  33. /// <param name="securityTokenHandlerCollection">
  34. /// The <see cref="SecurityTokenHandlerCollection" /> containing the set of <see cref="SecurityTokenHandler" />
  35. /// objects used for serializing and validating tokens found in WS-Trust messages.
  36. /// </param>
  37. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection )
  38. : this( securityTokenHandlerCollection, MessageSecurityVersion.Default.SecurityVersion )
  39. {
  40. }
  41. /// <summary>
  42. /// Initializes an instance of <see cref="WsSecurityTokenSerializerAdapter"/>
  43. /// </summary>
  44. /// <param name="securityTokenHandlerCollection">
  45. /// The <see cref="SecurityTokenHandlerCollection" /> containing the set of <see cref="SecurityTokenHandler" />
  46. /// objects used for serializing and validating tokens found in WS-Trust messages.
  47. /// </param>
  48. /// <param name="securityVersion">The SecurityTokenVersion of the base WSSecurityTokenSerializer.</param>
  49. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection, SecurityVersion securityVersion )
  50. : this( securityTokenHandlerCollection, securityVersion, true, new SamlSerializer(), null, null )
  51. {
  52. }
  53. /// <summary>
  54. /// Initializes an instance of <see cref="WsSecurityTokenSerializerAdapter"/>
  55. /// </summary>
  56. /// <param name="securityTokenHandlerCollection">
  57. /// The <see cref="SecurityTokenHandlerCollection" /> containing the set of <see cref="SecurityTokenHandler" />
  58. /// objects used for serializing and validating tokens found in WS-Trust messages.
  59. /// </param>
  60. /// <param name="securityVersion">The SecurityVersion of the base WSSecurityTokenSerializer.</param>
  61. /// <param name="emitBspAttributes">Flag that determines if the serailization shoudl be BSP compliant.</param>
  62. /// <param name="samlSerializer">Serializer for SAML 1.1 tokens.</param>
  63. /// <param name="stateEncoder">SecurityStateEncoder used for resolving SCT.</param>
  64. /// <param name="knownTypes">The collection of known claim types.</param>
  65. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection, SecurityVersion securityVersion, bool emitBspAttributes, SamlSerializer samlSerializer, SecurityStateEncoder stateEncoder, IEnumerable<Type> knownTypes )
  66. : this( securityTokenHandlerCollection, securityVersion, TrustVersion.WSTrust13, SecureConversationVersion.WSSecureConversation13, emitBspAttributes, samlSerializer, stateEncoder, knownTypes )
  67. {
  68. }
  69. /// <summary>
  70. /// Initializes an instance of <see cref="WsSecurityTokenSerializerAdapter"/>
  71. /// </summary>
  72. /// <param name="securityTokenHandlerCollection">
  73. /// The <see cref="SecurityTokenHandlerCollection" /> containing the set of <see cref="SecurityTokenHandler" />
  74. /// objects used for serializing and validating tokens found in WS-Trust messages.
  75. /// </param>
  76. /// <param name="securityVersion">The SecurityVersion of the base WSSecurityTokenSerializer.</param>
  77. /// <param name="trustVersion">The TrustVersion of the serializer uses.</param>
  78. /// <param name="secureConversationVersion">The SecureConversationVersion of the serializer.</param>
  79. /// <param name="emitBspAttributes">Flag that determines if the serailization shoudl be BSP compliant.</param>
  80. /// <param name="samlSerializer">Serializer for SAML 1.1 tokens.</param>
  81. /// <param name="stateEncoder">SecurityStateEncoder used for resolving SCT.</param>
  82. /// <param name="knownTypes">The collection of known claim types.</param>
  83. public WsSecurityTokenSerializerAdapter( SecurityTokenHandlerCollection securityTokenHandlerCollection, SecurityVersion securityVersion, TrustVersion trustVersion, SecureConversationVersion secureConversationVersion, bool emitBspAttributes, SamlSerializer samlSerializer, SecurityStateEncoder stateEncoder, IEnumerable<Type> knownTypes )
  84. : base( securityVersion, trustVersion, secureConversationVersion, emitBspAttributes, samlSerializer, stateEncoder, knownTypes )
  85. {
  86. if ( securityTokenHandlerCollection == null )
  87. {
  88. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "securityTokenHandlerCollection" );
  89. }
  90. _scVersion = secureConversationVersion;
  91. _securityTokenHandlers = securityTokenHandlerCollection;
  92. }
  93. /// <summary>
  94. /// Gets and Sets the property that describes if exceptions
  95. /// should be mapped to SOAP Fault exceptions. Default is false.
  96. /// </summary>
  97. public bool MapExceptionsToSoapFaults
  98. {
  99. get
  100. {
  101. return _mapExceptionsToSoapFaults;
  102. }
  103. set
  104. {
  105. _mapExceptionsToSoapFaults = value;
  106. }
  107. }
  108. /// <summary>
  109. /// Gets the SecurityTokenHandlerCollection.
  110. /// </summary>
  111. public SecurityTokenHandlerCollection SecurityTokenHandlers
  112. {
  113. get
  114. {
  115. return _securityTokenHandlers;
  116. }
  117. }
  118. /// <summary>
  119. /// Gets or sets the ExceptionMapper to be used when throwing exceptions.
  120. /// </summary>
  121. public ExceptionMapper ExceptionMapper
  122. {
  123. get
  124. {
  125. return _exceptionMapper;
  126. }
  127. set
  128. {
  129. if ( value == null )
  130. {
  131. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "value" );
  132. }
  133. _exceptionMapper = value;
  134. }
  135. }
  136. /// <summary>
  137. /// Checks if one of the wrapped SecurityTokenHandlers or the base WSSecurityTokenSerializer
  138. /// can read the security token.
  139. /// </summary>
  140. /// <param name="reader">Reader to a Security token.</param>
  141. /// <returns>'True' if the serializer can read the given Security Token.</returns>
  142. /// <exception cref="ArgumentNullException">The input parameter 'reader' is null.</exception>
  143. protected override bool CanReadTokenCore( XmlReader reader )
  144. {
  145. if ( reader == null )
  146. {
  147. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" );
  148. }
  149. if ( _securityTokenHandlers.CanReadToken( reader ) )
  150. {
  151. return true;
  152. }
  153. return base.CanReadTokenCore( reader );
  154. }
  155. /// <summary>
  156. /// Checks if one of the wrapped SecurityTokenHandlers or the base WSSecurityTokenSerializer
  157. /// can write the given security token.
  158. /// </summary>
  159. /// <param name="token">SecurityToken instance.</param>
  160. /// <returns>'True' if the serializer can write the given security token.</returns>
  161. /// <exception cref="ArgumentNullException">The input parameter 'token' is null.</exception>
  162. protected override bool CanWriteTokenCore( SecurityToken token )
  163. {
  164. if ( token == null )
  165. {
  166. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "token" );
  167. }
  168. if ( _securityTokenHandlers.CanWriteToken( token ) )
  169. {
  170. return true;
  171. }
  172. return base.CanWriteTokenCore( token );
  173. }
  174. /// <summary>
  175. /// Deserializes the SecurityToken from the given XmlReader.
  176. /// </summary>
  177. /// <param name="reader">Reader to a Security token.</param>
  178. /// <param name="tokenResolver">Instance of SecurityTokenResolver.</param>
  179. /// <returns>'True' if the serializer can read the given Security Token.</returns>
  180. /// <exception cref="ArgumentNullException">The input parameter 'reader' is null.</exception>
  181. protected override SecurityToken ReadTokenCore( XmlReader reader, SecurityTokenResolver tokenResolver )
  182. {
  183. if ( reader == null )
  184. {
  185. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" );
  186. }
  187. try
  188. {
  189. foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers )
  190. {
  191. if ( securityTokenHandler.CanReadToken( reader ) )
  192. {
  193. SecurityToken token = securityTokenHandler.ReadToken( reader, tokenResolver );
  194. SessionSecurityToken sessionToken = token as SessionSecurityToken;
  195. if ( sessionToken != null )
  196. {
  197. if ( sessionToken.SecureConversationVersion.AbsoluteUri != _scVersion.Namespace.Value )
  198. {
  199. throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation( SR.GetString( SR.ID4053, sessionToken.SecureConversationVersion, _scVersion ) );
  200. }
  201. return SecurityContextSecurityTokenHelper.ConvertSessionTokenToSecurityContextSecurityToken(sessionToken);
  202. }
  203. else
  204. {
  205. return token;
  206. }
  207. }
  208. }
  209. return base.ReadTokenCore( reader, tokenResolver );
  210. }
  211. catch ( Exception ex )
  212. {
  213. if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) )
  214. {
  215. throw;
  216. }
  217. Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." );
  218. // This should never happen. ExceptionMapper will handle the exception, in which case,
  219. // a fault exception is thrown or the original exception gets thrown.
  220. }
  221. return null;
  222. }
  223. /// <summary>
  224. /// Serializes the SecurityToken to the XmlWriter.
  225. /// </summary>
  226. /// <param name="writer">XmlWriter to write to.</param>
  227. /// <param name="token">The SecurityToken to serializer.</param>
  228. /// <exception cref="ArgumentNullException">The input parameter 'writer' or 'token' is null.</exception>
  229. protected override void WriteTokenCore( XmlWriter writer, SecurityToken token )
  230. {
  231. if ( writer == null )
  232. {
  233. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "writer" );
  234. }
  235. if ( token == null )
  236. {
  237. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "token" );
  238. }
  239. try
  240. {
  241. //
  242. // Wire the session handler for SCT
  243. //
  244. SecurityContextSecurityToken sct = token as SecurityContextSecurityToken;
  245. if ( sct != null )
  246. {
  247. //
  248. // Bare SCT tokens are wrapped with a SessionSecurityToken.
  249. // The property SessionSecurityToken.IsSecurityContextSecurityTokenWrapper will be true.
  250. //
  251. token = SecurityContextSecurityTokenHelper.ConvertSctToSessionToken( sct, _scVersion );
  252. }
  253. SecurityTokenHandler securityTokenHandler = _securityTokenHandlers[token];
  254. if ( ( securityTokenHandler != null ) && ( securityTokenHandler.CanWriteToken ) )
  255. {
  256. securityTokenHandler.WriteToken( writer, token );
  257. return;
  258. }
  259. base.WriteTokenCore( writer, token );
  260. }
  261. catch ( Exception ex )
  262. {
  263. if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) )
  264. {
  265. throw;
  266. }
  267. Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." );
  268. // This should never happen. ExceptionMapper will handle the exception, in which case,
  269. // a fault exception is thrown or the original exception gets thrown.
  270. }
  271. }
  272. /// <summary>
  273. /// Checks if one of the wrapped SecurityTokenHandlers or the base WSSecurityTokenSerializer
  274. /// can read the security key identifier.
  275. /// </summary>
  276. /// <param name="reader">Reader pointing at a Security Key Identifier {ds:Keyinfo}.</param>
  277. /// <returns>'True' if the serializer can read the given Security Key Identifier.</returns>
  278. /// <exception cref="ArgumentNullException">The <paramref name="reader"/> is null.</exception>
  279. protected override bool CanReadKeyIdentifierCore( XmlReader reader )
  280. {
  281. if ( reader == null )
  282. {
  283. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" );
  284. }
  285. if ( reader.IsStartElement( XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace ) )
  286. {
  287. return true;
  288. }
  289. else
  290. {
  291. return base.CanReadKeyIdentifierCore( reader );
  292. }
  293. }
  294. /// <summary>
  295. /// Reads an SecurityKeyIdentifier from a XML stream.
  296. /// </summary>
  297. /// <param name="reader">An XML reader positioned at an SecurityKeyIdentifier (ds: KeyInfo) as defined in 'http://www.w3.org/TR/xmldsig-core'.</param>
  298. /// <returns>SecurityKeyIdentifier.</returns>
  299. /// <exception cref="ArgumentNullException">The <paramref name="reader"/> is null.</exception>
  300. /// <exception cref="InvalidOperationException">If the <paramref name="reader"/> is not positioned at KeyInfo element.</exception>
  301. protected override SecurityKeyIdentifier ReadKeyIdentifierCore( XmlReader reader )
  302. {
  303. if ( reader == null )
  304. {
  305. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" );
  306. }
  307. if ( reader.IsStartElement( XmlSignatureConstants.Elements.KeyInfo, XmlSignatureConstants.Namespace ) )
  308. {
  309. KeyInfo keyInfo = new KeyInfo( this );
  310. keyInfo.ReadXml( XmlDictionaryReader.CreateDictionaryReader( reader ) );
  311. return keyInfo.KeyIdentifier;
  312. }
  313. else
  314. {
  315. throw DiagnosticUtility.ExceptionUtility.ThrowHelperXml( reader, SR.GetString( SR.ID4192 ) );
  316. }
  317. }
  318. /// <summary>
  319. /// Checks if the wrapped SecurityTokenHandler or the base WSSecurityTokenSerializer can read the
  320. /// SecurityKeyIdentifierClause.
  321. /// </summary>
  322. /// <param name="reader">Reader to a SecurityKeyIdentifierClause.</param>
  323. /// <returns>'True' if the SecurityKeyIdentifierCause can be read.</returns>
  324. /// <exception cref="ArgumentNullException">The input parameter 'reader' is null.</exception>
  325. protected override bool CanReadKeyIdentifierClauseCore( XmlReader reader )
  326. {
  327. if ( reader == null )
  328. {
  329. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" );
  330. }
  331. foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers )
  332. {
  333. if ( securityTokenHandler.CanReadKeyIdentifierClause( reader ) )
  334. {
  335. return true;
  336. }
  337. }
  338. return base.CanReadKeyIdentifierClauseCore( reader );
  339. }
  340. /// <summary>
  341. /// Checks if the wrapped SecurityTokenHandler or the base WSSecurityTokenSerializer can write the
  342. /// given SecurityKeyIdentifierClause.
  343. /// </summary>
  344. /// <param name="keyIdentifierClause">SecurityKeyIdentifierClause to be checked.</param>
  345. /// <returns>'True' if the SecurityTokenKeyIdentifierClause can be written.</returns>
  346. /// <exception cref="ArgumentNullException">The input parameter 'keyIdentifierClause' is null.</exception>
  347. protected override bool CanWriteKeyIdentifierClauseCore( SecurityKeyIdentifierClause keyIdentifierClause )
  348. {
  349. if ( keyIdentifierClause == null )
  350. {
  351. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "keyIdentifierClause" );
  352. }
  353. foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers )
  354. {
  355. if ( securityTokenHandler.CanWriteKeyIdentifierClause( keyIdentifierClause ) )
  356. {
  357. return true;
  358. }
  359. }
  360. return base.CanWriteKeyIdentifierClauseCore( keyIdentifierClause );
  361. }
  362. /// <summary>
  363. /// Deserializes a SecurityKeyIdentifierClause from the given reader.
  364. /// </summary>
  365. /// <param name="reader">XmlReader to a SecurityKeyIdentifierClause.</param>
  366. /// <returns>The deserialized SecurityKeyIdentifierClause.</returns>
  367. /// <exception cref="ArgumentNullException">The input parameter 'reader' is null.</exception>
  368. protected override SecurityKeyIdentifierClause ReadKeyIdentifierClauseCore( XmlReader reader )
  369. {
  370. if ( reader == null )
  371. {
  372. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "reader" );
  373. }
  374. try
  375. {
  376. foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers )
  377. {
  378. if ( securityTokenHandler.CanReadKeyIdentifierClause( reader ) )
  379. {
  380. return securityTokenHandler.ReadKeyIdentifierClause( reader );
  381. }
  382. }
  383. return base.ReadKeyIdentifierClauseCore( reader );
  384. }
  385. catch ( Exception ex )
  386. {
  387. if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) )
  388. {
  389. throw;
  390. }
  391. Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." );
  392. // This should never happen. ExceptionMapper will handle the exception, in which case,
  393. // a fault exception is thrown or the original exception gets thrown.
  394. }
  395. return null;
  396. }
  397. /// <summary>
  398. /// Serializes the given SecurityKeyIdentifierClause in a XmlWriter.
  399. /// </summary>
  400. /// <param name="writer">XmlWriter to write into.</param>
  401. /// <param name="keyIdentifierClause">SecurityKeyIdentifierClause to be written.</param>
  402. /// <exception cref="ArgumentNullException">The input parameter 'writer' or 'keyIdentifierClause' is null.</exception>
  403. protected override void WriteKeyIdentifierClauseCore( XmlWriter writer, SecurityKeyIdentifierClause keyIdentifierClause )
  404. {
  405. if ( writer == null )
  406. {
  407. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "writer" );
  408. }
  409. if ( keyIdentifierClause == null )
  410. {
  411. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull( "keyIdentifierClause" );
  412. }
  413. try
  414. {
  415. foreach ( SecurityTokenHandler securityTokenHandler in _securityTokenHandlers )
  416. {
  417. if ( securityTokenHandler.CanWriteKeyIdentifierClause( keyIdentifierClause ) )
  418. {
  419. securityTokenHandler.WriteKeyIdentifierClause( writer, keyIdentifierClause );
  420. return;
  421. }
  422. }
  423. base.WriteKeyIdentifierClauseCore( writer, keyIdentifierClause );
  424. }
  425. catch ( Exception ex )
  426. {
  427. if ( !( MapExceptionsToSoapFaults && _exceptionMapper.HandleSecurityTokenProcessingException( ex ) ) )
  428. {
  429. throw;
  430. }
  431. Fx.Assert( false, "ExceptionMapper did not handle an exception correctly." );
  432. // This should never happen. ExceptionMapper will handle the exception, in which case,
  433. // a fault exception is thrown or the original exception gets thrown.
  434. }
  435. }
  436. }
  437. }