IssuanceTokenProviderBase.cs 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Security
  5. {
  6. using System.Collections.ObjectModel;
  7. using System.Diagnostics;
  8. using System.Globalization;
  9. using System.IdentityModel.Tokens;
  10. using System.Runtime;
  11. using System.Runtime.Diagnostics;
  12. using System.ServiceModel;
  13. using System.ServiceModel.Channels;
  14. using System.ServiceModel.Diagnostics;
  15. using System.Xml;
  16. using System.ServiceModel.Diagnostics.Application;
  17. // IssuanceTokenProviderBase is a base class for token providers that fetch tokens from
  18. // another party.
  19. // This class manages caching of tokens, async messaging, concurrency
  20. abstract class IssuanceTokenProviderBase<T> : CommunicationObjectSecurityTokenProvider
  21. where T : IssuanceTokenProviderState
  22. {
  23. internal const string defaultClientMaxTokenCachingTimeString = "10675199.02:48:05.4775807";
  24. internal const bool defaultClientCacheTokens = true;
  25. internal const int defaultServiceTokenValidityThresholdPercentage = 60;
  26. // if an issuer is explicitly specified it will be used otherwise target is the issuer
  27. EndpointAddress issuerAddress;
  28. // the target service's address and via
  29. EndpointAddress targetAddress;
  30. Uri via = null;
  31. // This controls whether the token provider caches the service tokens it obtains
  32. bool cacheServiceTokens = defaultClientCacheTokens;
  33. // This is a fudge factor that controls how long the client can use a service token
  34. int serviceTokenValidityThresholdPercentage = defaultServiceTokenValidityThresholdPercentage;
  35. // the maximum time that the client is willing to cache service tokens
  36. TimeSpan maxServiceTokenCachingTime;
  37. SecurityStandardsManager standardsManager;
  38. SecurityAlgorithmSuite algorithmSuite;
  39. ChannelProtectionRequirements applicationProtectionRequirements;
  40. SecurityToken cachedToken;
  41. Object thisLock = new Object();
  42. string sctUri;
  43. protected IssuanceTokenProviderBase()
  44. : base()
  45. {
  46. this.cacheServiceTokens = defaultClientCacheTokens;
  47. this.serviceTokenValidityThresholdPercentage = defaultServiceTokenValidityThresholdPercentage;
  48. this.maxServiceTokenCachingTime = DefaultClientMaxTokenCachingTime;
  49. this.standardsManager = null;
  50. }
  51. // settings
  52. public EndpointAddress IssuerAddress
  53. {
  54. get
  55. {
  56. return this.issuerAddress;
  57. }
  58. set
  59. {
  60. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  61. this.issuerAddress = value;
  62. }
  63. }
  64. public EndpointAddress TargetAddress
  65. {
  66. get
  67. {
  68. return this.targetAddress;
  69. }
  70. set
  71. {
  72. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  73. this.targetAddress = value;
  74. }
  75. }
  76. public bool CacheServiceTokens
  77. {
  78. get
  79. {
  80. return this.cacheServiceTokens;
  81. }
  82. set
  83. {
  84. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  85. this.cacheServiceTokens = value;
  86. }
  87. }
  88. internal static TimeSpan DefaultClientMaxTokenCachingTime
  89. {
  90. get
  91. {
  92. Fx.Assert(TimeSpan.Parse(defaultClientMaxTokenCachingTimeString, CultureInfo.InvariantCulture) == TimeSpan.MaxValue, "TimeSpan value not correct");
  93. return TimeSpan.MaxValue;
  94. }
  95. }
  96. public int ServiceTokenValidityThresholdPercentage
  97. {
  98. get
  99. {
  100. return this.serviceTokenValidityThresholdPercentage;
  101. }
  102. set
  103. {
  104. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  105. if (value <= 0 || value > 100)
  106. {
  107. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeInRange, 1, 100)));
  108. }
  109. this.serviceTokenValidityThresholdPercentage = value;
  110. }
  111. }
  112. public SecurityAlgorithmSuite SecurityAlgorithmSuite
  113. {
  114. get
  115. {
  116. return this.algorithmSuite;
  117. }
  118. set
  119. {
  120. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  121. this.algorithmSuite = value;
  122. }
  123. }
  124. public TimeSpan MaxServiceTokenCachingTime
  125. {
  126. get
  127. {
  128. return this.maxServiceTokenCachingTime;
  129. }
  130. set
  131. {
  132. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  133. if (value <= TimeSpan.Zero)
  134. {
  135. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero)));
  136. }
  137. if (TimeoutHelper.IsTooLarge(value))
  138. {
  139. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value,
  140. SR.GetString(SR.SFxTimeoutOutOfRangeTooBig)));
  141. }
  142. this.maxServiceTokenCachingTime = value;
  143. }
  144. }
  145. public SecurityStandardsManager StandardsManager
  146. {
  147. get
  148. {
  149. if (this.standardsManager == null)
  150. return SecurityStandardsManager.DefaultInstance;
  151. return this.standardsManager;
  152. }
  153. set
  154. {
  155. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  156. this.standardsManager = value;
  157. }
  158. }
  159. public ChannelProtectionRequirements ApplicationProtectionRequirements
  160. {
  161. get
  162. {
  163. return this.applicationProtectionRequirements;
  164. }
  165. set
  166. {
  167. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  168. this.applicationProtectionRequirements = value;
  169. }
  170. }
  171. public Uri Via
  172. {
  173. get
  174. {
  175. return this.via;
  176. }
  177. set
  178. {
  179. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  180. this.via = value;
  181. }
  182. }
  183. public override bool SupportsTokenCancellation
  184. {
  185. get
  186. {
  187. return true;
  188. }
  189. }
  190. protected Object ThisLock
  191. {
  192. get { return this.thisLock; }
  193. }
  194. protected virtual bool IsMultiLegNegotiation
  195. {
  196. get { return true; }
  197. }
  198. protected abstract MessageVersion MessageVersion
  199. {
  200. get;
  201. }
  202. protected abstract bool RequiresManualReplyAddressing
  203. {
  204. get;
  205. }
  206. public abstract XmlDictionaryString RequestSecurityTokenAction
  207. {
  208. get;
  209. }
  210. public abstract XmlDictionaryString RequestSecurityTokenResponseAction
  211. {
  212. get;
  213. }
  214. protected string SecurityContextTokenUri
  215. {
  216. get
  217. {
  218. ThrowIfCreated();
  219. return this.sctUri;
  220. }
  221. }
  222. protected void ThrowIfCreated()
  223. {
  224. CommunicationState state = this.CommunicationObject.State;
  225. if (state == CommunicationState.Created)
  226. {
  227. Exception e = new InvalidOperationException(SR.GetString(SR.CommunicationObjectCannotBeUsed, this.GetType().ToString(), state.ToString()));
  228. throw TraceUtility.ThrowHelperError(e, Guid.Empty, this);
  229. }
  230. }
  231. protected void ThrowIfClosedOrCreated()
  232. {
  233. this.CommunicationObject.ThrowIfClosed();
  234. ThrowIfCreated();
  235. }
  236. // ISecurityCommunicationObject methods
  237. public override void OnOpen(TimeSpan timeout)
  238. {
  239. if (this.targetAddress == null)
  240. {
  241. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.TargetAddressIsNotSet, this.GetType())));
  242. }
  243. if (this.SecurityAlgorithmSuite == null)
  244. {
  245. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityAlgorithmSuiteNotSet, this.GetType())));
  246. }
  247. this.sctUri = this.StandardsManager.SecureConversationDriver.TokenTypeUri;
  248. }
  249. // helper methods
  250. protected void EnsureEndpointAddressDoesNotRequireEncryption(EndpointAddress target)
  251. {
  252. if (this.ApplicationProtectionRequirements == null
  253. || this.ApplicationProtectionRequirements.OutgoingEncryptionParts == null)
  254. {
  255. return;
  256. }
  257. MessagePartSpecification channelEncryptionParts = this.ApplicationProtectionRequirements.OutgoingEncryptionParts.ChannelParts;
  258. if (channelEncryptionParts == null)
  259. {
  260. return;
  261. }
  262. for (int i = 0; i < this.targetAddress.Headers.Count; ++i)
  263. {
  264. AddressHeader header = target.Headers[i];
  265. if (channelEncryptionParts.IsHeaderIncluded(header.Name, header.Namespace))
  266. {
  267. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.SecurityNegotiationCannotProtectConfidentialEndpointHeader, target, header.Name, header.Namespace)));
  268. }
  269. }
  270. }
  271. DateTime GetServiceTokenEffectiveExpirationTime(SecurityToken serviceToken)
  272. {
  273. // if the token never expires, return the max date time
  274. // else return effective expiration time
  275. if (serviceToken.ValidTo.ToUniversalTime() >= SecurityUtils.MaxUtcDateTime)
  276. {
  277. return serviceToken.ValidTo;
  278. }
  279. TimeSpan interval = serviceToken.ValidTo.ToUniversalTime() - serviceToken.ValidFrom.ToUniversalTime();
  280. long serviceTokenTicksInterval = interval.Ticks;
  281. long effectiveTicksInterval = Convert.ToInt64((double)this.ServiceTokenValidityThresholdPercentage / 100.0 * (double)serviceTokenTicksInterval, NumberFormatInfo.InvariantInfo);
  282. DateTime effectiveExpirationTime = TimeoutHelper.Add(serviceToken.ValidFrom.ToUniversalTime(), new TimeSpan(effectiveTicksInterval));
  283. DateTime maxCachingTime = TimeoutHelper.Add(serviceToken.ValidFrom.ToUniversalTime(), this.MaxServiceTokenCachingTime);
  284. if (effectiveExpirationTime <= maxCachingTime)
  285. {
  286. return effectiveExpirationTime;
  287. }
  288. else
  289. {
  290. return maxCachingTime;
  291. }
  292. }
  293. bool IsServiceTokenTimeValid(SecurityToken serviceToken)
  294. {
  295. DateTime effectiveExpirationTime = GetServiceTokenEffectiveExpirationTime(serviceToken);
  296. return (DateTime.UtcNow <= effectiveExpirationTime);
  297. }
  298. SecurityToken GetCurrentServiceToken()
  299. {
  300. if (this.CacheServiceTokens && this.cachedToken != null && IsServiceTokenTimeValid(cachedToken))
  301. {
  302. return this.cachedToken;
  303. }
  304. else
  305. {
  306. return null;
  307. }
  308. }
  309. static protected void ThrowIfFault(Message message, EndpointAddress target)
  310. {
  311. SecurityUtils.ThrowIfNegotiationFault(message, target);
  312. }
  313. protected override IAsyncResult BeginGetTokenCore(TimeSpan timeout, AsyncCallback callback, object state)
  314. {
  315. this.CommunicationObject.ThrowIfClosedOrNotOpen();
  316. IAsyncResult asyncResult;
  317. lock (ThisLock)
  318. {
  319. SecurityToken token = GetCurrentServiceToken();
  320. if (token != null)
  321. {
  322. SecurityTraceRecordHelper.TraceUsingCachedServiceToken(this, token, this.targetAddress);
  323. asyncResult = new CompletedAsyncResult<SecurityToken>(token, callback, state);
  324. }
  325. else
  326. {
  327. asyncResult = BeginNegotiation(timeout, callback, state);
  328. }
  329. }
  330. return asyncResult;
  331. }
  332. protected override SecurityToken EndGetTokenCore(IAsyncResult result)
  333. {
  334. if (result is CompletedAsyncResult<SecurityToken>)
  335. {
  336. return CompletedAsyncResult<SecurityToken>.End(result);
  337. }
  338. else
  339. {
  340. return this.EndNegotiation(result);
  341. }
  342. }
  343. protected override SecurityToken GetTokenCore(TimeSpan timeout)
  344. {
  345. this.CommunicationObject.ThrowIfClosedOrNotOpen();
  346. SecurityToken result;
  347. lock (ThisLock)
  348. {
  349. result = GetCurrentServiceToken();
  350. if (result != null)
  351. {
  352. SecurityTraceRecordHelper.TraceUsingCachedServiceToken(this, result, this.targetAddress);
  353. }
  354. }
  355. if (result == null)
  356. {
  357. result = DoNegotiation(timeout);
  358. }
  359. return result;
  360. }
  361. protected override void CancelTokenCore(TimeSpan timeout, SecurityToken token)
  362. {
  363. if (this.CacheServiceTokens)
  364. {
  365. lock (ThisLock)
  366. {
  367. if (Object.ReferenceEquals(token, this.cachedToken))
  368. {
  369. this.cachedToken = null;
  370. }
  371. }
  372. }
  373. }
  374. // Negotiation state creation methods
  375. protected abstract bool CreateNegotiationStateCompletesSynchronously(EndpointAddress target, Uri via);
  376. protected abstract IAsyncResult BeginCreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout, AsyncCallback callback, object state);
  377. protected abstract T CreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout);
  378. protected abstract T EndCreateNegotiationState(IAsyncResult result);
  379. // Negotiation message processing methods
  380. protected abstract BodyWriter GetFirstOutgoingMessageBody(T negotiationState, out MessageProperties properties);
  381. protected abstract BodyWriter GetNextOutgoingMessageBody(Message incomingMessage, T negotiationState);
  382. protected abstract bool WillInitializeChannelFactoriesCompleteSynchronously(EndpointAddress target);
  383. protected abstract void InitializeChannelFactories(EndpointAddress target, TimeSpan timeout);
  384. protected abstract IAsyncResult BeginInitializeChannelFactories(EndpointAddress target, TimeSpan timeout, AsyncCallback callback, object state);
  385. protected abstract void EndInitializeChannelFactories(IAsyncResult result);
  386. protected abstract IRequestChannel CreateClientChannel(EndpointAddress target, Uri via);
  387. void PrepareRequest(Message nextMessage)
  388. {
  389. PrepareRequest(nextMessage, null);
  390. }
  391. void PrepareRequest(Message nextMessage, RequestSecurityToken rst)
  392. {
  393. if (rst != null && !rst.IsReadOnly)
  394. {
  395. rst.Message = nextMessage;
  396. }
  397. RequestReplyCorrelator.PrepareRequest(nextMessage);
  398. if (this.RequiresManualReplyAddressing)
  399. {
  400. // if we are on HTTP, we need to explicitly add a reply-to header for interop
  401. nextMessage.Headers.ReplyTo = EndpointAddress.AnonymousAddress;
  402. }
  403. }
  404. /*
  405. * Negotiation consists of the following steps (some may be async in the async case):
  406. * 1. Create negotiation state
  407. * 2. Initialize channel factories
  408. * 3. Create an channel
  409. * 4. Open the channel
  410. * 5. Create the next message to send to server
  411. * 6. Send the message and get reply
  412. * 8. Process incoming message and get next outgoing message.
  413. * 9. If no outgoing message, then negotiation is over. Go to step 11.
  414. * 10. Goto step 6
  415. * 11. Close the IRequest channel and complete
  416. */
  417. protected SecurityToken DoNegotiation(TimeSpan timeout)
  418. {
  419. ThrowIfClosedOrCreated();
  420. SecurityTraceRecordHelper.TraceBeginSecurityNegotiation(this, this.targetAddress);
  421. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  422. IRequestChannel rstChannel = null;
  423. T negotiationState = null;
  424. TimeSpan timeLeft = timeout;
  425. int legs = 1;
  426. try
  427. {
  428. negotiationState = this.CreateNegotiationState(this.targetAddress, this.via, timeoutHelper.RemainingTime());
  429. InitializeNegotiationState(negotiationState);
  430. this.InitializeChannelFactories(negotiationState.RemoteAddress, timeoutHelper.RemainingTime());
  431. rstChannel = this.CreateClientChannel(negotiationState.RemoteAddress, this.via);
  432. rstChannel.Open(timeoutHelper.RemainingTime());
  433. Message nextOutgoingMessage = null;
  434. Message incomingMessage = null;
  435. SecurityToken serviceToken = null;
  436. for (;;)
  437. {
  438. nextOutgoingMessage = this.GetNextOutgoingMessage(incomingMessage, negotiationState);
  439. if (incomingMessage != null)
  440. {
  441. incomingMessage.Close();
  442. }
  443. if (nextOutgoingMessage != null)
  444. {
  445. using (nextOutgoingMessage)
  446. {
  447. EventTraceActivity eventTraceActivity = null;
  448. if (TD.MessageSentToTransportIsEnabled())
  449. {
  450. eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(nextOutgoingMessage);
  451. }
  452. TraceUtility.ProcessOutgoingMessage(nextOutgoingMessage, eventTraceActivity);
  453. timeLeft = timeoutHelper.RemainingTime();
  454. incomingMessage = rstChannel.Request(nextOutgoingMessage, timeLeft);
  455. if (incomingMessage == null)
  456. {
  457. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(SR.GetString(SR.FailToRecieveReplyFromNegotiation)));
  458. }
  459. if (eventTraceActivity == null && TD.MessageReceivedFromTransportIsEnabled())
  460. {
  461. eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(incomingMessage);
  462. }
  463. TraceUtility.ProcessIncomingMessage(incomingMessage, eventTraceActivity);
  464. }
  465. legs += 2;
  466. }
  467. else
  468. {
  469. if (!negotiationState.IsNegotiationCompleted)
  470. {
  471. throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.NoNegotiationMessageToSend)), incomingMessage);
  472. }
  473. try
  474. {
  475. rstChannel.Close(timeoutHelper.RemainingTime());
  476. }
  477. catch (CommunicationException e)
  478. {
  479. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  480. rstChannel.Abort();
  481. }
  482. catch (TimeoutException e)
  483. {
  484. if (TD.CloseTimeoutIsEnabled())
  485. {
  486. TD.CloseTimeout(e.Message);
  487. }
  488. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  489. rstChannel.Abort();
  490. }
  491. rstChannel = null;
  492. this.ValidateAndCacheServiceToken(negotiationState);
  493. serviceToken = negotiationState.ServiceToken;
  494. SecurityTraceRecordHelper.TraceEndSecurityNegotiation(this, serviceToken, this.targetAddress);
  495. break;
  496. }
  497. }
  498. return serviceToken;
  499. }
  500. catch (Exception e)
  501. {
  502. if (Fx.IsFatal(e))
  503. {
  504. throw;
  505. }
  506. if (e is TimeoutException)
  507. {
  508. e = new TimeoutException(SR.GetString(SR.ClientSecurityNegotiationTimeout, timeout, legs, timeLeft), e);
  509. }
  510. EndpointAddress temp = (negotiationState == null) ? null : negotiationState.RemoteAddress;
  511. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(WrapExceptionIfRequired(e, temp, this.issuerAddress));
  512. }
  513. finally
  514. {
  515. Cleanup(rstChannel, negotiationState);
  516. }
  517. }
  518. void InitializeNegotiationState(T negotiationState)
  519. {
  520. negotiationState.TargetAddress = this.targetAddress;
  521. if (negotiationState.Context == null && this.IsMultiLegNegotiation)
  522. {
  523. negotiationState.Context = SecurityUtils.GenerateId();
  524. }
  525. if (this.IssuerAddress != null)
  526. {
  527. negotiationState.RemoteAddress = this.IssuerAddress;
  528. }
  529. else
  530. {
  531. negotiationState.RemoteAddress = negotiationState.TargetAddress;
  532. }
  533. }
  534. Message GetNextOutgoingMessage(Message incomingMessage, T negotiationState)
  535. {
  536. BodyWriter nextMessageBody;
  537. MessageProperties nextMessageProperties = null;
  538. if (incomingMessage == null)
  539. {
  540. nextMessageBody = this.GetFirstOutgoingMessageBody(negotiationState, out nextMessageProperties);
  541. }
  542. else
  543. {
  544. nextMessageBody = this.GetNextOutgoingMessageBody(incomingMessage, negotiationState);
  545. }
  546. if (nextMessageBody != null)
  547. {
  548. Message nextMessage;
  549. if (incomingMessage == null)
  550. {
  551. nextMessage = Message.CreateMessage(this.MessageVersion, ActionHeader.Create(this.RequestSecurityTokenAction, this.MessageVersion.Addressing), nextMessageBody);
  552. }
  553. else
  554. {
  555. nextMessage = Message.CreateMessage(this.MessageVersion, ActionHeader.Create(this.RequestSecurityTokenResponseAction, this.MessageVersion.Addressing), nextMessageBody);
  556. }
  557. if (nextMessageProperties != null)
  558. {
  559. nextMessage.Properties.CopyProperties(nextMessageProperties);
  560. }
  561. PrepareRequest(nextMessage, nextMessageBody as RequestSecurityToken);
  562. return nextMessage;
  563. }
  564. else
  565. {
  566. return null;
  567. }
  568. }
  569. void Cleanup(IChannel rstChannel, T negotiationState)
  570. {
  571. if (negotiationState != null)
  572. {
  573. negotiationState.Dispose();
  574. }
  575. if (rstChannel != null)
  576. {
  577. rstChannel.Abort();
  578. }
  579. }
  580. protected IAsyncResult BeginNegotiation(TimeSpan timeout, AsyncCallback callback, object state)
  581. {
  582. ThrowIfClosedOrCreated();
  583. SecurityTraceRecordHelper.TraceBeginSecurityNegotiation(this, this.targetAddress);
  584. return new SecurityNegotiationAsyncResult(this, timeout, callback, state);
  585. }
  586. protected SecurityToken EndNegotiation(IAsyncResult result)
  587. {
  588. SecurityToken token = SecurityNegotiationAsyncResult.End(result);
  589. SecurityTraceRecordHelper.TraceEndSecurityNegotiation(this, token, this.targetAddress);
  590. return token;
  591. }
  592. protected virtual void ValidateKeySize(GenericXmlSecurityToken issuedToken)
  593. {
  594. if (this.SecurityAlgorithmSuite == null)
  595. {
  596. return;
  597. }
  598. ReadOnlyCollection<SecurityKey> issuedKeys = issuedToken.SecurityKeys;
  599. if (issuedKeys != null && issuedKeys.Count == 1)
  600. {
  601. SymmetricSecurityKey symmetricKey = issuedKeys[0] as SymmetricSecurityKey;
  602. if (symmetricKey != null)
  603. {
  604. if (this.SecurityAlgorithmSuite.IsSymmetricKeyLengthSupported(symmetricKey.KeySize))
  605. {
  606. return;
  607. }
  608. else
  609. {
  610. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.InvalidIssuedTokenKeySize, symmetricKey.KeySize)));
  611. }
  612. }
  613. }
  614. else
  615. {
  616. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.CannotObtainIssuedTokenKeySize)));
  617. }
  618. }
  619. static bool ShouldWrapException(Exception e)
  620. {
  621. return (e is System.ComponentModel.Win32Exception
  622. || e is XmlException
  623. || e is InvalidOperationException
  624. || e is ArgumentException
  625. || e is QuotaExceededException
  626. || e is System.Security.SecurityException
  627. || e is System.Security.Cryptography.CryptographicException
  628. || e is SecurityTokenException);
  629. }
  630. static Exception WrapExceptionIfRequired(Exception e, EndpointAddress targetAddress, EndpointAddress issuerAddress)
  631. {
  632. if (ShouldWrapException(e))
  633. {
  634. Uri targetUri;
  635. if (targetAddress != null)
  636. {
  637. targetUri = targetAddress.Uri;
  638. }
  639. else
  640. {
  641. targetUri = null;
  642. }
  643. Uri issuerUri;
  644. if (issuerAddress != null)
  645. {
  646. issuerUri = issuerAddress.Uri;
  647. }
  648. else
  649. {
  650. issuerUri = targetUri;
  651. }
  652. // => issuerUri != null
  653. if (targetUri != null)
  654. {
  655. e = new SecurityNegotiationException(SR.GetString(SR.SoapSecurityNegotiationFailedForIssuerAndTarget, issuerUri, targetUri), e);
  656. }
  657. else
  658. {
  659. e = new SecurityNegotiationException(SR.GetString(SR.SoapSecurityNegotiationFailed), e);
  660. }
  661. }
  662. return e;
  663. }
  664. void ValidateAndCacheServiceToken(T negotiationState)
  665. {
  666. this.ValidateKeySize(negotiationState.ServiceToken);
  667. lock (ThisLock)
  668. {
  669. if (this.CacheServiceTokens)
  670. {
  671. this.cachedToken = negotiationState.ServiceToken;
  672. }
  673. }
  674. }
  675. class SecurityNegotiationAsyncResult : AsyncResult
  676. {
  677. static AsyncCallback createNegotiationStateCallback = Fx.ThunkCallback(new AsyncCallback(CreateNegotiationStateCallback));
  678. static AsyncCallback initializeChannelFactoriesCallback = Fx.ThunkCallback(new AsyncCallback(InitializeChannelFactoriesCallback));
  679. static AsyncCallback closeChannelCallback = Fx.ThunkCallback(new AsyncCallback(CloseChannelCallback));
  680. static AsyncCallback sendRequestCallback = Fx.ThunkCallback(new AsyncCallback(SendRequestCallback));
  681. static AsyncCallback openChannelCallback = Fx.ThunkCallback(new AsyncCallback(OpenChannelCallback));
  682. TimeSpan timeout;
  683. TimeoutHelper timeoutHelper;
  684. SecurityToken serviceToken;
  685. IssuanceTokenProviderBase<T> tokenProvider;
  686. IRequestChannel rstChannel;
  687. T negotiationState;
  688. Message nextOutgoingMessage;
  689. EndpointAddress target;
  690. EndpointAddress issuer;
  691. Uri via;
  692. public SecurityNegotiationAsyncResult(IssuanceTokenProviderBase<T> tokenProvider, TimeSpan timeout, AsyncCallback callback, object state)
  693. : base(callback, state)
  694. {
  695. this.timeout = timeout;
  696. timeoutHelper = new TimeoutHelper(timeout);
  697. this.tokenProvider = tokenProvider;
  698. this.target = tokenProvider.targetAddress;
  699. this.issuer = tokenProvider.issuerAddress;
  700. this.via = tokenProvider.via;
  701. bool completeSelf = false;
  702. try
  703. {
  704. completeSelf = this.StartNegotiation();
  705. }
  706. #pragma warning suppress 56500 // covered by FxCOP
  707. catch (Exception e)
  708. {
  709. if (Fx.IsFatal(e))
  710. {
  711. throw;
  712. }
  713. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(this.OnSyncNegotiationFailure(e));
  714. }
  715. if (completeSelf)
  716. {
  717. this.OnNegotiationComplete();
  718. Complete(true);
  719. }
  720. }
  721. bool StartNegotiation()
  722. {
  723. if (this.tokenProvider.CreateNegotiationStateCompletesSynchronously(this.target, this.via))
  724. {
  725. this.negotiationState = this.tokenProvider.CreateNegotiationState(target, this.via, timeoutHelper.RemainingTime());
  726. }
  727. else
  728. {
  729. IAsyncResult createStateResult = this.tokenProvider.BeginCreateNegotiationState(target, this.via, timeoutHelper.RemainingTime(), createNegotiationStateCallback, this);
  730. if (!createStateResult.CompletedSynchronously)
  731. {
  732. return false;
  733. }
  734. this.negotiationState = this.tokenProvider.EndCreateNegotiationState(createStateResult);
  735. }
  736. return this.OnCreateStateComplete();
  737. }
  738. static void CreateNegotiationStateCallback(IAsyncResult result)
  739. {
  740. if (result.CompletedSynchronously)
  741. {
  742. return;
  743. }
  744. SecurityNegotiationAsyncResult self = (SecurityNegotiationAsyncResult)result.AsyncState;
  745. bool completeSelf = false;
  746. Exception completionException = null;
  747. try
  748. {
  749. self.negotiationState = self.tokenProvider.EndCreateNegotiationState(result);
  750. completeSelf = self.OnCreateStateComplete();
  751. if (completeSelf)
  752. {
  753. self.OnNegotiationComplete();
  754. }
  755. }
  756. #pragma warning suppress 56500 // covered by FxCOP
  757. catch (Exception e)
  758. {
  759. if (Fx.IsFatal(e))
  760. throw;
  761. completeSelf = true;
  762. completionException = self.OnAsyncNegotiationFailure(e);
  763. }
  764. if (completeSelf)
  765. {
  766. self.Complete(false, completionException);
  767. }
  768. }
  769. bool OnCreateStateComplete()
  770. {
  771. this.tokenProvider.InitializeNegotiationState(negotiationState);
  772. return InitializeChannelFactories();
  773. }
  774. bool InitializeChannelFactories()
  775. {
  776. if (this.tokenProvider.WillInitializeChannelFactoriesCompleteSynchronously(negotiationState.RemoteAddress))
  777. {
  778. this.tokenProvider.InitializeChannelFactories(negotiationState.RemoteAddress, timeoutHelper.RemainingTime());
  779. }
  780. else
  781. {
  782. IAsyncResult result = this.tokenProvider.BeginInitializeChannelFactories(negotiationState.RemoteAddress, timeoutHelper.RemainingTime(), initializeChannelFactoriesCallback, this);
  783. if (!result.CompletedSynchronously)
  784. {
  785. return false;
  786. }
  787. this.tokenProvider.EndInitializeChannelFactories(result);
  788. }
  789. return this.OnChannelFactoriesInitialized();
  790. }
  791. static void InitializeChannelFactoriesCallback(IAsyncResult result)
  792. {
  793. if (result.CompletedSynchronously)
  794. {
  795. return;
  796. }
  797. SecurityNegotiationAsyncResult self = (SecurityNegotiationAsyncResult)result.AsyncState;
  798. bool completeSelf = false;
  799. Exception completionException = null;
  800. try
  801. {
  802. self.tokenProvider.EndInitializeChannelFactories(result);
  803. completeSelf = self.OnChannelFactoriesInitialized();
  804. if (completeSelf)
  805. {
  806. self.OnNegotiationComplete();
  807. }
  808. }
  809. #pragma warning suppress 56500 // covered by FxCOP
  810. catch (Exception e)
  811. {
  812. if (Fx.IsFatal(e))
  813. throw;
  814. completeSelf = true;
  815. completionException = self.OnAsyncNegotiationFailure(e);
  816. }
  817. if (completeSelf)
  818. {
  819. self.Complete(false, completionException);
  820. }
  821. }
  822. bool OnChannelFactoriesInitialized()
  823. {
  824. this.rstChannel = this.tokenProvider.CreateClientChannel(negotiationState.RemoteAddress, this.via);
  825. this.nextOutgoingMessage = null;
  826. return this.OnRequestChannelCreated();
  827. }
  828. bool OnRequestChannelCreated()
  829. {
  830. IAsyncResult result = rstChannel.BeginOpen(timeoutHelper.RemainingTime(), openChannelCallback, this);
  831. if (!result.CompletedSynchronously)
  832. {
  833. return false;
  834. }
  835. rstChannel.EndOpen(result);
  836. return this.OnRequestChannelOpened();
  837. }
  838. static void OpenChannelCallback(IAsyncResult result)
  839. {
  840. if (result.CompletedSynchronously)
  841. {
  842. return;
  843. }
  844. SecurityNegotiationAsyncResult self = (SecurityNegotiationAsyncResult)result.AsyncState;
  845. bool completeSelf = false;
  846. Exception completionException = null;
  847. try
  848. {
  849. self.rstChannel.EndOpen(result);
  850. completeSelf = self.OnRequestChannelOpened();
  851. if (completeSelf)
  852. {
  853. self.OnNegotiationComplete();
  854. }
  855. }
  856. #pragma warning suppress 56500 // covered by FxCOP
  857. catch (Exception e)
  858. {
  859. if (Fx.IsFatal(e))
  860. throw;
  861. completeSelf = true;
  862. completionException = self.OnAsyncNegotiationFailure(e);
  863. }
  864. if (completeSelf)
  865. {
  866. self.Complete(false, completionException);
  867. }
  868. }
  869. bool OnRequestChannelOpened()
  870. {
  871. return this.SendRequest();
  872. }
  873. bool SendRequest()
  874. {
  875. if (this.nextOutgoingMessage == null)
  876. {
  877. return this.DoNegotiation(null);
  878. }
  879. else
  880. {
  881. this.tokenProvider.PrepareRequest(this.nextOutgoingMessage);
  882. bool closeMessage = true;
  883. Message incomingMessage = null;
  884. IAsyncResult result = null;
  885. try
  886. {
  887. result = this.rstChannel.BeginRequest(this.nextOutgoingMessage, timeoutHelper.RemainingTime(), sendRequestCallback, this);
  888. if (!result.CompletedSynchronously)
  889. {
  890. closeMessage = false;
  891. return false;
  892. }
  893. incomingMessage = rstChannel.EndRequest(result);
  894. }
  895. finally
  896. {
  897. if (closeMessage && this.nextOutgoingMessage != null)
  898. {
  899. this.nextOutgoingMessage.Close();
  900. }
  901. }
  902. using (incomingMessage)
  903. {
  904. if (incomingMessage == null)
  905. {
  906. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.FailToRecieveReplyFromNegotiation)));
  907. }
  908. return this.DoNegotiation(incomingMessage);
  909. }
  910. }
  911. }
  912. static void SendRequestCallback(IAsyncResult result)
  913. {
  914. if (result.CompletedSynchronously)
  915. {
  916. return;
  917. }
  918. SecurityNegotiationAsyncResult self = (SecurityNegotiationAsyncResult)result.AsyncState;
  919. bool completeSelf = false;
  920. Exception completionException = null;
  921. try
  922. {
  923. Message incomingMessage = null;
  924. try
  925. {
  926. incomingMessage = self.rstChannel.EndRequest(result);
  927. }
  928. finally
  929. {
  930. if (self.nextOutgoingMessage != null)
  931. {
  932. self.nextOutgoingMessage.Close();
  933. }
  934. }
  935. using (incomingMessage)
  936. {
  937. if (incomingMessage == null)
  938. {
  939. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.FailToRecieveReplyFromNegotiation)));
  940. }
  941. completeSelf = self.DoNegotiation(incomingMessage);
  942. }
  943. if (completeSelf)
  944. {
  945. self.OnNegotiationComplete();
  946. }
  947. }
  948. #pragma warning suppress 56500 // covered by FxCOP
  949. catch (Exception e)
  950. {
  951. if (Fx.IsFatal(e))
  952. throw;
  953. completeSelf = true;
  954. completionException = self.OnAsyncNegotiationFailure(e);
  955. }
  956. if (completeSelf)
  957. {
  958. self.Complete(false, completionException);
  959. }
  960. }
  961. bool DoNegotiation(Message incomingMessage)
  962. {
  963. this.nextOutgoingMessage = this.tokenProvider.GetNextOutgoingMessage(incomingMessage, this.negotiationState);
  964. if (this.nextOutgoingMessage != null)
  965. {
  966. return SendRequest();
  967. }
  968. else
  969. {
  970. if (!negotiationState.IsNegotiationCompleted)
  971. {
  972. throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.NoNegotiationMessageToSend)), incomingMessage);
  973. }
  974. return this.CloseRequestChannel();
  975. }
  976. }
  977. bool CloseRequestChannel()
  978. {
  979. IAsyncResult result = rstChannel.BeginClose(timeoutHelper.RemainingTime(), closeChannelCallback, this);
  980. if (!result.CompletedSynchronously)
  981. {
  982. return false;
  983. }
  984. rstChannel.EndClose(result);
  985. return true;
  986. }
  987. static void CloseChannelCallback(IAsyncResult result)
  988. {
  989. if (result.CompletedSynchronously)
  990. {
  991. return;
  992. }
  993. SecurityNegotiationAsyncResult self = (SecurityNegotiationAsyncResult)result.AsyncState;
  994. bool completeSelf = false;
  995. Exception completionException = null;
  996. try
  997. {
  998. self.rstChannel.EndClose(result);
  999. self.OnNegotiationComplete();
  1000. completeSelf = true;
  1001. }
  1002. #pragma warning suppress 56500 // covered by FxCOP
  1003. catch (Exception e)
  1004. {
  1005. if (Fx.IsFatal(e))
  1006. throw;
  1007. completeSelf = true;
  1008. completionException = self.OnAsyncNegotiationFailure(e);
  1009. }
  1010. if (completeSelf)
  1011. {
  1012. self.Complete(false, completionException);
  1013. }
  1014. }
  1015. void Cleanup()
  1016. {
  1017. this.tokenProvider.Cleanup(this.rstChannel, this.negotiationState);
  1018. this.rstChannel = null;
  1019. this.negotiationState = null;
  1020. }
  1021. Exception OnAsyncNegotiationFailure(Exception e)
  1022. {
  1023. EndpointAddress pinnedEpr = null;
  1024. try
  1025. {
  1026. pinnedEpr = (this.negotiationState == null) ? null : this.negotiationState.RemoteAddress;
  1027. Cleanup();
  1028. }
  1029. catch (CommunicationException ex)
  1030. {
  1031. DiagnosticUtility.TraceHandledException(ex, TraceEventType.Information);
  1032. }
  1033. return IssuanceTokenProviderBase<T>.WrapExceptionIfRequired(e, pinnedEpr, this.issuer);
  1034. }
  1035. Exception OnSyncNegotiationFailure(Exception e)
  1036. {
  1037. EndpointAddress pinnedTarget = (this.negotiationState == null) ? null : this.negotiationState.RemoteAddress;
  1038. return IssuanceTokenProviderBase<T>.WrapExceptionIfRequired(e, pinnedTarget, this.issuer);
  1039. }
  1040. void OnNegotiationComplete()
  1041. {
  1042. using (negotiationState)
  1043. {
  1044. SecurityToken token = negotiationState.ServiceToken;
  1045. this.tokenProvider.ValidateAndCacheServiceToken(negotiationState);
  1046. this.serviceToken = token;
  1047. }
  1048. }
  1049. public static SecurityToken End(IAsyncResult result)
  1050. {
  1051. SecurityNegotiationAsyncResult self = AsyncResult.End<SecurityNegotiationAsyncResult>(result);
  1052. return self.serviceToken;
  1053. }
  1054. }
  1055. }
  1056. }