NegotiationTokenAuthenticator.cs 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Security
  5. {
  6. using System.Collections.Generic;
  7. using System.Collections.ObjectModel;
  8. using System.Diagnostics;
  9. using System.Globalization;
  10. using System.IdentityModel.Policy;
  11. using System.IdentityModel.Tokens;
  12. using System.Runtime;
  13. using System.ServiceModel;
  14. using System.ServiceModel.Channels;
  15. using System.ServiceModel.Description;
  16. using System.ServiceModel.Diagnostics;
  17. using System.ServiceModel.Dispatcher;
  18. using System.ServiceModel.Security.Tokens;
  19. using System.Xml;
  20. abstract class NegotiationTokenAuthenticator<T> : CommunicationObjectSecurityTokenAuthenticator, IIssuanceSecurityTokenAuthenticator, ISecurityContextSecurityTokenCacheProvider
  21. where T : NegotiationTokenAuthenticatorState
  22. {
  23. internal const string defaultServerMaxNegotiationLifetimeString = "00:01:00";
  24. internal const string defaultServerIssuedTokenLifetimeString = "10:00:00";
  25. internal const string defaultServerIssuedTransitionTokenLifetimeString = "00:15:00";
  26. internal const int defaultServerMaxActiveNegotiations = 128;
  27. internal static readonly TimeSpan defaultServerMaxNegotiationLifetime = TimeSpan.Parse(defaultServerMaxNegotiationLifetimeString, CultureInfo.InvariantCulture);
  28. internal static readonly TimeSpan defaultServerIssuedTokenLifetime = TimeSpan.Parse(defaultServerIssuedTokenLifetimeString, CultureInfo.InvariantCulture);
  29. internal static readonly TimeSpan defaultServerIssuedTransitionTokenLifetime = TimeSpan.Parse(defaultServerIssuedTransitionTokenLifetimeString, CultureInfo.InvariantCulture);
  30. internal const int defaultServerMaxCachedTokens = 1000;
  31. internal const bool defaultServerMaintainState = true;
  32. internal static readonly SecurityStandardsManager defaultStandardsManager = SecurityStandardsManager.DefaultInstance;
  33. internal static readonly SecurityStateEncoder defaultSecurityStateEncoder = new DataProtectionSecurityStateEncoder();
  34. NegotiationTokenAuthenticatorStateCache<T> stateCache;
  35. RenewedSecurityTokenHandler renewedSecurityTokenHandler;
  36. NegotiationHost negotiationHost;
  37. bool encryptStateInServiceToken;
  38. TimeSpan serviceTokenLifetime;
  39. int maximumCachedNegotiationState;
  40. TimeSpan negotiationTimeout;
  41. bool isClientAnonymous;
  42. SecurityStandardsManager standardsManager;
  43. SecurityAlgorithmSuite securityAlgorithmSuite;
  44. SecurityTokenParameters issuedSecurityTokenParameters;
  45. ISecurityContextSecurityTokenCache issuedTokenCache;
  46. BindingContext issuerBindingContext;
  47. Uri listenUri;
  48. string sctUri;
  49. AuditLogLocation auditLogLocation;
  50. bool suppressAuditFailure;
  51. AuditLevel messageAuthenticationAuditLevel;
  52. SecurityStateEncoder securityStateEncoder;
  53. SecurityContextCookieSerializer cookieSerializer;
  54. IMessageFilterTable<EndpointAddress> endpointFilterTable;
  55. IssuedSecurityTokenHandler issuedSecurityTokenHandler;
  56. int maxMessageSize;
  57. IList<Type> knownTypes;
  58. int maximumConcurrentNegotiations;
  59. List<IChannel> activeNegotiationChannels1;
  60. List<IChannel> activeNegotiationChannels2;
  61. IOThreadTimer idlingNegotiationSessionTimer;
  62. bool isTimerCancelled;
  63. protected NegotiationTokenAuthenticator() : base()
  64. {
  65. InitializeDefaults();
  66. }
  67. public IssuedSecurityTokenHandler IssuedSecurityTokenHandler
  68. {
  69. get
  70. {
  71. return this.issuedSecurityTokenHandler;
  72. }
  73. set
  74. {
  75. this.issuedSecurityTokenHandler = value;
  76. }
  77. }
  78. public RenewedSecurityTokenHandler RenewedSecurityTokenHandler
  79. {
  80. get
  81. {
  82. return this.renewedSecurityTokenHandler;
  83. }
  84. set
  85. {
  86. this.renewedSecurityTokenHandler = value;
  87. }
  88. }
  89. // settings
  90. public bool EncryptStateInServiceToken
  91. {
  92. get
  93. {
  94. return this.encryptStateInServiceToken;
  95. }
  96. set
  97. {
  98. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  99. this.encryptStateInServiceToken = value;
  100. }
  101. }
  102. public TimeSpan ServiceTokenLifetime
  103. {
  104. get
  105. {
  106. return this.serviceTokenLifetime;
  107. }
  108. set
  109. {
  110. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  111. if (value <= TimeSpan.Zero)
  112. {
  113. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero)));
  114. }
  115. if (TimeoutHelper.IsTooLarge(value))
  116. {
  117. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value,
  118. SR.GetString(SR.SFxTimeoutOutOfRangeTooBig)));
  119. }
  120. this.serviceTokenLifetime = value;
  121. }
  122. }
  123. public int MaximumCachedNegotiationState
  124. {
  125. get
  126. {
  127. return this.maximumCachedNegotiationState;
  128. }
  129. set
  130. {
  131. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  132. if (value < 0)
  133. {
  134. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeNonNegative)));
  135. }
  136. this.maximumCachedNegotiationState = value;
  137. }
  138. }
  139. public int MaximumConcurrentNegotiations
  140. {
  141. get
  142. {
  143. return this.maximumConcurrentNegotiations;
  144. }
  145. set
  146. {
  147. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  148. if (value < 0)
  149. {
  150. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.ValueMustBeNonNegative)));
  151. }
  152. this.maximumConcurrentNegotiations = value;
  153. }
  154. }
  155. public TimeSpan NegotiationTimeout
  156. {
  157. get
  158. {
  159. return this.negotiationTimeout;
  160. }
  161. set
  162. {
  163. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  164. if (value <= TimeSpan.Zero)
  165. {
  166. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", SR.GetString(SR.TimeSpanMustbeGreaterThanTimeSpanZero)));
  167. }
  168. if (TimeoutHelper.IsTooLarge(value))
  169. {
  170. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("value", value,
  171. SR.GetString(SR.SFxTimeoutOutOfRangeTooBig)));
  172. }
  173. this.negotiationTimeout = value;
  174. }
  175. }
  176. public bool IsClientAnonymous
  177. {
  178. get
  179. {
  180. return this.isClientAnonymous;
  181. }
  182. set
  183. {
  184. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  185. this.isClientAnonymous = value;
  186. }
  187. }
  188. public SecurityAlgorithmSuite SecurityAlgorithmSuite
  189. {
  190. get
  191. {
  192. return this.securityAlgorithmSuite;
  193. }
  194. set
  195. {
  196. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  197. this.securityAlgorithmSuite = value;
  198. }
  199. }
  200. public IMessageFilterTable<EndpointAddress> EndpointFilterTable
  201. {
  202. get
  203. {
  204. return this.endpointFilterTable;
  205. }
  206. set
  207. {
  208. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  209. this.endpointFilterTable = value;
  210. }
  211. }
  212. ISecurityContextSecurityTokenCache ISecurityContextSecurityTokenCacheProvider.TokenCache
  213. {
  214. get
  215. {
  216. return this.IssuedTokenCache;
  217. }
  218. }
  219. public virtual XmlDictionaryString RequestSecurityTokenAction
  220. {
  221. get
  222. {
  223. return this.StandardsManager.TrustDriver.RequestSecurityTokenAction;
  224. }
  225. }
  226. public virtual XmlDictionaryString RequestSecurityTokenResponseAction
  227. {
  228. get
  229. {
  230. return this.StandardsManager.TrustDriver.RequestSecurityTokenResponseAction;
  231. }
  232. }
  233. public virtual XmlDictionaryString RequestSecurityTokenResponseFinalAction
  234. {
  235. get
  236. {
  237. return this.StandardsManager.TrustDriver.RequestSecurityTokenResponseFinalAction;
  238. }
  239. }
  240. public SecurityStandardsManager StandardsManager
  241. {
  242. get
  243. {
  244. return this.standardsManager;
  245. }
  246. set
  247. {
  248. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  249. this.standardsManager = (value != null ? value : SecurityStandardsManager.DefaultInstance);
  250. }
  251. }
  252. public SecurityTokenParameters IssuedSecurityTokenParameters
  253. {
  254. get
  255. {
  256. return this.issuedSecurityTokenParameters;
  257. }
  258. set
  259. {
  260. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  261. this.issuedSecurityTokenParameters = value;
  262. }
  263. }
  264. public ISecurityContextSecurityTokenCache IssuedTokenCache
  265. {
  266. get { return this.issuedTokenCache; }
  267. set
  268. {
  269. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  270. this.issuedTokenCache = value;
  271. }
  272. }
  273. public AuditLogLocation AuditLogLocation
  274. {
  275. get
  276. {
  277. return this.auditLogLocation;
  278. }
  279. set
  280. {
  281. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  282. this.auditLogLocation = value;
  283. }
  284. }
  285. public bool SuppressAuditFailure
  286. {
  287. get
  288. {
  289. return this.suppressAuditFailure;
  290. }
  291. set
  292. {
  293. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  294. this.suppressAuditFailure = value;
  295. }
  296. }
  297. public AuditLevel MessageAuthenticationAuditLevel
  298. {
  299. get
  300. {
  301. return this.messageAuthenticationAuditLevel;
  302. }
  303. set
  304. {
  305. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  306. this.messageAuthenticationAuditLevel = value;
  307. }
  308. }
  309. public BindingContext IssuerBindingContext
  310. {
  311. get { return this.issuerBindingContext; }
  312. set
  313. {
  314. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  315. if (value == null)
  316. {
  317. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
  318. }
  319. this.issuerBindingContext = value.Clone();
  320. }
  321. }
  322. public Uri ListenUri
  323. {
  324. get { return this.listenUri; }
  325. set
  326. {
  327. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  328. this.listenUri = value;
  329. }
  330. }
  331. public SecurityStateEncoder SecurityStateEncoder
  332. {
  333. get { return this.securityStateEncoder; }
  334. set
  335. {
  336. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  337. this.securityStateEncoder = value;
  338. }
  339. }
  340. public IList<Type> KnownTypes
  341. {
  342. get { return this.knownTypes; }
  343. set
  344. {
  345. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  346. if (value != null)
  347. {
  348. this.knownTypes = new Collection<Type>(value);
  349. }
  350. else
  351. {
  352. this.knownTypes = null;
  353. }
  354. }
  355. }
  356. public int MaxMessageSize
  357. {
  358. get { return this.maxMessageSize; }
  359. set
  360. {
  361. this.CommunicationObject.ThrowIfDisposedOrImmutable();
  362. this.maxMessageSize = value;
  363. }
  364. }
  365. protected string SecurityContextTokenUri
  366. {
  367. get
  368. {
  369. this.CommunicationObject.ThrowIfNotOpened();
  370. return this.sctUri;
  371. }
  372. }
  373. Object ThisLock
  374. {
  375. get
  376. {
  377. return this.CommunicationObject;
  378. }
  379. }
  380. // helpers
  381. protected SecurityContextSecurityToken IssueSecurityContextToken(UniqueId contextId, string id, byte[] key,
  382. DateTime tokenEffectiveTime, DateTime tokenExpirationTime,
  383. ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode)
  384. {
  385. return IssueSecurityContextToken(contextId, id, key, tokenEffectiveTime, tokenExpirationTime, null,
  386. tokenEffectiveTime, tokenExpirationTime, authorizationPolicies, isCookieMode);
  387. }
  388. protected SecurityContextSecurityToken IssueSecurityContextToken(UniqueId contextId, string id, byte[] key,
  389. DateTime tokenEffectiveTime, DateTime tokenExpirationTime, UniqueId keyGeneration, DateTime keyEffectiveTime,
  390. DateTime keyExpirationTime, ReadOnlyCollection<IAuthorizationPolicy> authorizationPolicies, bool isCookieMode)
  391. {
  392. this.CommunicationObject.ThrowIfClosedOrNotOpen();
  393. if (this.securityStateEncoder == null && isCookieMode)
  394. {
  395. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SctCookieNotSupported)));
  396. }
  397. byte[] cookieBlob = (isCookieMode) ? this.cookieSerializer.CreateCookieFromSecurityContext(contextId, id, key, tokenEffectiveTime, tokenExpirationTime, keyGeneration,
  398. keyEffectiveTime, keyExpirationTime, authorizationPolicies) : null;
  399. SecurityContextSecurityToken issuedToken = new SecurityContextSecurityToken(contextId, id, key, tokenEffectiveTime, tokenExpirationTime,
  400. authorizationPolicies, isCookieMode, cookieBlob, keyGeneration, keyEffectiveTime, keyExpirationTime);
  401. return issuedToken;
  402. }
  403. void InitializeDefaults()
  404. {
  405. this.encryptStateInServiceToken = !defaultServerMaintainState;
  406. this.serviceTokenLifetime = defaultServerIssuedTokenLifetime;
  407. this.maximumCachedNegotiationState = defaultServerMaxActiveNegotiations;
  408. this.negotiationTimeout = defaultServerMaxNegotiationLifetime;
  409. this.isClientAnonymous = false;
  410. this.standardsManager = defaultStandardsManager;
  411. this.securityStateEncoder = defaultSecurityStateEncoder;
  412. this.maximumConcurrentNegotiations = defaultServerMaxActiveNegotiations;
  413. // we rely on the transport encoders to enforce the message size except in the
  414. // mixed mode nego case, where the client is unauthenticated and the maxMessageSize is too
  415. // large to be a mitigation
  416. this.maxMessageSize = Int32.MaxValue;
  417. }
  418. public override void OnClose(TimeSpan timeout)
  419. {
  420. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  421. if (this.negotiationHost != null)
  422. {
  423. this.negotiationHost.Close(timeoutHelper.RemainingTime());
  424. this.negotiationHost = null;
  425. }
  426. lock (ThisLock)
  427. {
  428. if (this.idlingNegotiationSessionTimer != null && !this.isTimerCancelled)
  429. {
  430. this.isTimerCancelled = true;
  431. this.idlingNegotiationSessionTimer.Cancel();
  432. }
  433. }
  434. base.OnClose(timeoutHelper.RemainingTime());
  435. }
  436. public override void OnAbort()
  437. {
  438. if (this.negotiationHost != null)
  439. {
  440. this.negotiationHost.Abort();
  441. this.negotiationHost = null;
  442. }
  443. lock (ThisLock)
  444. {
  445. if (this.idlingNegotiationSessionTimer != null && !this.isTimerCancelled)
  446. {
  447. this.isTimerCancelled = true;
  448. this.idlingNegotiationSessionTimer.Cancel();
  449. }
  450. }
  451. base.OnAbort();
  452. }
  453. public override void OnOpen(TimeSpan timeout)
  454. {
  455. if (this.IssuerBindingContext == null)
  456. {
  457. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuerBuildContextNotSet, this.GetType())));
  458. }
  459. if (this.IssuedSecurityTokenParameters == null)
  460. {
  461. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuedSecurityTokenParametersNotSet, this.GetType())));
  462. }
  463. if (this.SecurityAlgorithmSuite == null)
  464. {
  465. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SecurityAlgorithmSuiteNotSet, this.GetType())));
  466. }
  467. if (this.IssuedTokenCache == null)
  468. {
  469. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.IssuedTokenCacheNotSet, this.GetType())));
  470. }
  471. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  472. this.SetupServiceHost();
  473. negotiationHost.Open(timeoutHelper.RemainingTime());
  474. this.stateCache = new NegotiationTokenAuthenticatorStateCache<T>(this.NegotiationTimeout, this.MaximumCachedNegotiationState);
  475. this.sctUri = this.StandardsManager.SecureConversationDriver.TokenTypeUri;
  476. if (this.SecurityStateEncoder != null)
  477. {
  478. this.cookieSerializer = new SecurityContextCookieSerializer(this.SecurityStateEncoder, this.KnownTypes);
  479. }
  480. if (this.negotiationTimeout < TimeSpan.MaxValue)
  481. {
  482. lock (ThisLock)
  483. {
  484. this.activeNegotiationChannels1 = new List<IChannel>();
  485. this.activeNegotiationChannels2 = new List<IChannel>();
  486. this.idlingNegotiationSessionTimer = new IOThreadTimer(new Action<object>(this.OnIdlingNegotiationSessionTimer), this, false);
  487. this.isTimerCancelled = false;
  488. this.idlingNegotiationSessionTimer.Set(this.negotiationTimeout);
  489. }
  490. }
  491. base.OnOpen(timeoutHelper.RemainingTime());
  492. }
  493. protected override bool CanValidateTokenCore(SecurityToken token)
  494. {
  495. return (token is SecurityContextSecurityToken);
  496. }
  497. protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateTokenCore(SecurityToken token)
  498. {
  499. SecurityContextSecurityToken sct = (SecurityContextSecurityToken)token;
  500. return sct.AuthorizationPolicies;
  501. }
  502. protected abstract Binding GetNegotiationBinding(Binding binding);
  503. protected abstract bool IsMultiLegNegotiation { get; }
  504. protected abstract MessageFilter GetListenerFilter();
  505. void SetupServiceHost()
  506. {
  507. ChannelBuilder channelBuilder = new ChannelBuilder(this.IssuerBindingContext.Clone(), true);
  508. channelBuilder.Binding.Elements.Insert(0, new ReplyAdapterBindingElement());
  509. channelBuilder.Binding = new CustomBinding(this.GetNegotiationBinding(channelBuilder.Binding));
  510. negotiationHost = new NegotiationHost(this, this.ListenUri, channelBuilder, this.GetListenerFilter());
  511. }
  512. // message processing abstract method
  513. protected abstract BodyWriter ProcessRequestSecurityToken(Message request, RequestSecurityToken requestSecurityToken, out T negotiationState);
  514. protected abstract BodyWriter ProcessRequestSecurityTokenResponse(T negotiationState, Message request, RequestSecurityTokenResponse requestSecurityTokenResponse);
  515. // message handlers
  516. protected virtual void ParseMessageBody(Message message, out string context, out RequestSecurityToken requestSecurityToken, out RequestSecurityTokenResponse requestSecurityTokenResponse)
  517. {
  518. requestSecurityToken = null;
  519. requestSecurityTokenResponse = null;
  520. if (message.Headers.Action == this.RequestSecurityTokenAction.Value)
  521. {
  522. XmlDictionaryReader reader = message.GetReaderAtBodyContents();
  523. using (reader)
  524. {
  525. requestSecurityToken = RequestSecurityToken.CreateFrom(this.StandardsManager, reader);
  526. message.ReadFromBodyContentsToEnd(reader);
  527. }
  528. context = requestSecurityToken.Context;
  529. }
  530. else if (message.Headers.Action == this.RequestSecurityTokenResponseAction.Value)
  531. {
  532. XmlDictionaryReader reader = message.GetReaderAtBodyContents();
  533. using (reader)
  534. {
  535. requestSecurityTokenResponse = RequestSecurityTokenResponse.CreateFrom(this.StandardsManager, reader);
  536. message.ReadFromBodyContentsToEnd(reader);
  537. }
  538. context = requestSecurityTokenResponse.Context;
  539. }
  540. else
  541. {
  542. throw TraceUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.InvalidActionForNegotiationMessage, message.Headers.Action)), message);
  543. }
  544. }
  545. static Message CreateReply(Message request, XmlDictionaryString action, BodyWriter body)
  546. {
  547. if (request.Headers.MessageId != null)
  548. {
  549. Message reply = Message.CreateMessage(request.Version, ActionHeader.Create(action, request.Version.Addressing), body);
  550. reply.InitializeReply(request);
  551. return reply;
  552. }
  553. else
  554. {
  555. // the message id may not be present if MapToHttp is true
  556. return Message.CreateMessage(request.Version, ActionHeader.Create(action, request.Version.Addressing), body);
  557. }
  558. }
  559. void OnTokenIssued(SecurityToken token)
  560. {
  561. if (this.issuedSecurityTokenHandler != null)
  562. {
  563. this.issuedSecurityTokenHandler(token, null);
  564. }
  565. }
  566. void AddNegotiationChannelForIdleTracking()
  567. {
  568. if (OperationContext.Current.SessionId == null)
  569. {
  570. return;
  571. }
  572. lock (ThisLock)
  573. {
  574. if (this.idlingNegotiationSessionTimer == null)
  575. {
  576. return;
  577. }
  578. IChannel channel = OperationContext.Current.Channel;
  579. if (!this.activeNegotiationChannels1.Contains(channel) && !this.activeNegotiationChannels2.Contains(channel))
  580. {
  581. this.activeNegotiationChannels1.Add(channel);
  582. }
  583. if (this.isTimerCancelled)
  584. {
  585. this.isTimerCancelled = false;
  586. this.idlingNegotiationSessionTimer.Set(this.negotiationTimeout);
  587. }
  588. }
  589. }
  590. void RemoveNegotiationChannelFromIdleTracking()
  591. {
  592. if (OperationContext.Current.SessionId == null)
  593. {
  594. return;
  595. }
  596. lock (ThisLock)
  597. {
  598. if (this.idlingNegotiationSessionTimer == null)
  599. {
  600. return;
  601. }
  602. IChannel channel = OperationContext.Current.Channel;
  603. this.activeNegotiationChannels1.Remove(channel);
  604. this.activeNegotiationChannels2.Remove(channel);
  605. if (this.activeNegotiationChannels1.Count == 0 && this.activeNegotiationChannels2.Count == 0)
  606. {
  607. this.isTimerCancelled = true;
  608. this.idlingNegotiationSessionTimer.Cancel();
  609. }
  610. }
  611. }
  612. void OnIdlingNegotiationSessionTimer(object state)
  613. {
  614. lock (ThisLock)
  615. {
  616. if (this.isTimerCancelled || (this.CommunicationObject.State != CommunicationState.Opened && this.CommunicationObject.State != CommunicationState.Opening))
  617. {
  618. return;
  619. }
  620. try
  621. {
  622. for (int i = 0; i < this.activeNegotiationChannels2.Count; ++i)
  623. {
  624. this.activeNegotiationChannels2[i].Abort();
  625. }
  626. List<IChannel> temp = this.activeNegotiationChannels2;
  627. temp.Clear();
  628. this.activeNegotiationChannels2 = this.activeNegotiationChannels1;
  629. this.activeNegotiationChannels1 = temp;
  630. }
  631. #pragma warning suppress 56500
  632. catch (Exception e)
  633. {
  634. if (Fx.IsFatal(e))
  635. {
  636. throw;
  637. }
  638. }
  639. finally
  640. {
  641. if (this.CommunicationObject.State == CommunicationState.Opened || this.CommunicationObject.State == CommunicationState.Opening)
  642. {
  643. if (this.activeNegotiationChannels1.Count == 0 && this.activeNegotiationChannels2.Count == 0)
  644. {
  645. this.isTimerCancelled = true;
  646. this.idlingNegotiationSessionTimer.Cancel();
  647. }
  648. else
  649. {
  650. this.idlingNegotiationSessionTimer.Set(this.negotiationTimeout);
  651. }
  652. }
  653. }
  654. }
  655. }
  656. Message ProcessRequestCore(Message request)
  657. {
  658. if (request == null)
  659. {
  660. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("request");
  661. }
  662. Uri to = null;
  663. RequestSecurityToken rst = null;
  664. RequestSecurityTokenResponse rstr = null;
  665. string context = null;
  666. bool disposeRequest = false;
  667. bool isNegotiationFailure = true;
  668. T negotiationState = null;
  669. try
  670. {
  671. // validate the message size if needed
  672. if (this.maxMessageSize < int.MaxValue)
  673. {
  674. string action = request.Headers.Action;
  675. try
  676. {
  677. using (MessageBuffer buffer = request.CreateBufferedCopy(this.maxMessageSize))
  678. {
  679. request = buffer.CreateMessage();
  680. disposeRequest = true;
  681. }
  682. }
  683. catch (QuotaExceededException e)
  684. {
  685. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SR.GetString(SR.SecurityNegotiationMessageTooLarge, action, this.maxMessageSize), e));
  686. }
  687. }
  688. try
  689. {
  690. to = request.Headers.To;
  691. ParseMessageBody(request, out context, out rst, out rstr);
  692. // check if there is existing state
  693. if (context != null)
  694. {
  695. negotiationState = this.stateCache.GetState(context);
  696. }
  697. else
  698. {
  699. negotiationState = null;
  700. }
  701. bool disposeState = false;
  702. BodyWriter replyBody;
  703. try
  704. {
  705. if (rst != null)
  706. {
  707. if (negotiationState != null)
  708. {
  709. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.NegotiationStateAlreadyPresent, context)));
  710. }
  711. replyBody = this.ProcessRequestSecurityToken(request, rst, out negotiationState);
  712. lock (negotiationState.ThisLock)
  713. {
  714. if (negotiationState.IsNegotiationCompleted)
  715. {
  716. // if session-sct add it to cache and add a redirect header
  717. if (!negotiationState.ServiceToken.IsCookieMode)
  718. {
  719. this.IssuedTokenCache.AddContext(negotiationState.ServiceToken);
  720. }
  721. this.OnTokenIssued(negotiationState.ServiceToken);
  722. SecurityTraceRecordHelper.TraceServiceSecurityNegotiationCompleted(request, this, negotiationState.ServiceToken);
  723. disposeState = true;
  724. }
  725. else
  726. {
  727. this.stateCache.AddState(context, negotiationState);
  728. disposeState = false;
  729. }
  730. AddNegotiationChannelForIdleTracking();
  731. }
  732. }
  733. else
  734. {
  735. if (negotiationState == null)
  736. {
  737. throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new SecurityNegotiationException(SR.GetString(SR.CannotFindNegotiationState, context)));
  738. }
  739. lock (negotiationState.ThisLock)
  740. {
  741. replyBody = this.ProcessRequestSecurityTokenResponse(negotiationState, request, rstr);
  742. if (negotiationState.IsNegotiationCompleted)
  743. {
  744. // if session-sct add it to cache and add a redirect header
  745. if (!negotiationState.ServiceToken.IsCookieMode)
  746. {
  747. this.IssuedTokenCache.AddContext(negotiationState.ServiceToken);
  748. }
  749. this.OnTokenIssued(negotiationState.ServiceToken);
  750. SecurityTraceRecordHelper.TraceServiceSecurityNegotiationCompleted(request, this, negotiationState.ServiceToken);
  751. disposeState = true;
  752. }
  753. else
  754. {
  755. disposeState = false;
  756. }
  757. }
  758. }
  759. if (negotiationState.IsNegotiationCompleted && null != this.ListenUri)
  760. {
  761. if (AuditLevel.Success == (this.messageAuthenticationAuditLevel & AuditLevel.Success))
  762. {
  763. string primaryIdentity = negotiationState.GetRemoteIdentityName();
  764. SecurityAuditHelper.WriteSecurityNegotiationSuccessEvent(this.auditLogLocation,
  765. this.suppressAuditFailure, request, request.Headers.To, request.Headers.Action,
  766. primaryIdentity, this.GetType().Name);
  767. }
  768. }
  769. isNegotiationFailure = false;
  770. }
  771. catch (Exception exception)
  772. {
  773. if (Fx.IsFatal(exception))
  774. throw;
  775. if (PerformanceCounters.PerformanceCountersEnabled && null != this.ListenUri)
  776. {
  777. PerformanceCounters.AuthenticationFailed(request, this.ListenUri);
  778. }
  779. if (AuditLevel.Failure == (this.messageAuthenticationAuditLevel & AuditLevel.Failure))
  780. {
  781. try
  782. {
  783. string primaryIdentity = (negotiationState != null) ? negotiationState.GetRemoteIdentityName() : String.Empty;
  784. SecurityAuditHelper.WriteSecurityNegotiationFailureEvent(this.auditLogLocation,
  785. this.suppressAuditFailure, request, request.Headers.To, request.Headers.Action,
  786. primaryIdentity, this.GetType().Name, exception);
  787. }
  788. #pragma warning suppress 56500
  789. catch (Exception auditException)
  790. {
  791. if (Fx.IsFatal(auditException))
  792. throw;
  793. DiagnosticUtility.TraceHandledException(auditException, TraceEventType.Error);
  794. }
  795. }
  796. disposeState = true;
  797. throw;
  798. }
  799. finally
  800. {
  801. if (disposeState)
  802. {
  803. if (negotiationState != null)
  804. {
  805. if (context != null)
  806. {
  807. stateCache.RemoveState(context);
  808. }
  809. negotiationState.Dispose();
  810. }
  811. }
  812. }
  813. return CreateReply(request, (replyBody is RequestSecurityTokenResponseCollection) ? RequestSecurityTokenResponseFinalAction : RequestSecurityTokenResponseAction, replyBody);
  814. }
  815. finally
  816. {
  817. if (disposeRequest)
  818. {
  819. request.Close();
  820. }
  821. }
  822. }
  823. finally
  824. {
  825. if (isNegotiationFailure)
  826. {
  827. AddNegotiationChannelForIdleTracking();
  828. }
  829. else if (negotiationState != null && negotiationState.IsNegotiationCompleted)
  830. {
  831. RemoveNegotiationChannelFromIdleTracking();
  832. }
  833. }
  834. }
  835. // negotiation failure methods
  836. Message HandleNegotiationException(Message request, Exception e)
  837. {
  838. SecurityTraceRecordHelper.TraceServiceSecurityNegotiationFailure<T>(
  839. EventTraceActivityHelper.TryExtractActivity(request),
  840. this,
  841. e);
  842. return CreateFault(request, e);
  843. }
  844. Message CreateFault(Message request, Exception e)
  845. {
  846. MessageVersion version = request.Version;
  847. FaultCode subCode;
  848. FaultReason reason;
  849. bool isSenderFault;
  850. if (e is SecurityTokenValidationException || e is System.ComponentModel.Win32Exception)
  851. {
  852. subCode = new FaultCode(TrustApr2004Strings.FailedAuthenticationFaultCode, TrustFeb2005Strings.Namespace);
  853. reason = new FaultReason(SR.GetString(SR.FailedAuthenticationTrustFaultCode), CultureInfo.CurrentCulture);
  854. isSenderFault = true;
  855. }
  856. else if (e is QuotaExceededException)
  857. {
  858. // send a receiver fault so that the sender can retry
  859. subCode = new FaultCode(DotNetSecurityStrings.SecurityServerTooBusyFault, DotNetSecurityStrings.Namespace);
  860. reason = new FaultReason(SR.GetString(SR.NegotiationQuotasExceededFaultReason), CultureInfo.CurrentCulture);
  861. isSenderFault = false;
  862. }
  863. else
  864. {
  865. subCode = new FaultCode(TrustApr2004Strings.InvalidRequestFaultCode, TrustFeb2005Strings.Namespace);
  866. reason = new FaultReason(SR.GetString(SR.InvalidRequestTrustFaultCode), CultureInfo.CurrentCulture);
  867. isSenderFault = true;
  868. }
  869. FaultCode faultCode;
  870. if (isSenderFault)
  871. {
  872. faultCode = FaultCode.CreateSenderFaultCode(subCode);
  873. }
  874. else
  875. {
  876. faultCode = FaultCode.CreateReceiverFaultCode(subCode);
  877. }
  878. MessageFault fault = MessageFault.CreateFault(faultCode, reason);
  879. Message faultReply = Message.CreateMessage(version, fault, version.Addressing.DefaultFaultAction);
  880. faultReply.Headers.RelatesTo = request.Headers.MessageId;
  881. return faultReply;
  882. }
  883. class NegotiationHost : ServiceHostBase
  884. {
  885. NegotiationTokenAuthenticator<T> authenticator;
  886. Uri listenUri;
  887. ChannelBuilder channelBuilder;
  888. MessageFilter listenerFilter;
  889. public NegotiationHost(NegotiationTokenAuthenticator<T> authenticator, Uri listenUri, ChannelBuilder channelBuilder, MessageFilter listenerFilter)
  890. {
  891. this.authenticator = authenticator;
  892. this.listenUri = listenUri;
  893. this.channelBuilder = channelBuilder;
  894. this.listenerFilter = listenerFilter;
  895. }
  896. protected override ServiceDescription CreateDescription(out IDictionary<string, ContractDescription> implementedContracts)
  897. {
  898. implementedContracts = null;
  899. return null;
  900. }
  901. protected override void InitializeRuntime()
  902. {
  903. MessageFilter contractFilter = this.listenerFilter;
  904. int filterPriority = 10;
  905. Type[] endpointChannelTypes = new Type[] { typeof(IReplyChannel),
  906. typeof(IDuplexChannel),
  907. typeof(IReplySessionChannel),
  908. typeof(IDuplexSessionChannel) };
  909. IChannelListener listener = null;
  910. BindingParameterCollection parameters = new BindingParameterCollection(this.channelBuilder.BindingParameters);
  911. Binding binding = this.channelBuilder.Binding;
  912. binding.ReceiveTimeout = this.authenticator.NegotiationTimeout;
  913. parameters.Add(new ChannelDemuxerFilter(contractFilter, filterPriority));
  914. DispatcherBuilder.MaybeCreateListener(true, endpointChannelTypes, binding, parameters,
  915. this.listenUri, "", ListenUriMode.Explicit, this.ServiceThrottle, out listener);
  916. if (listener == null)
  917. {
  918. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotCreateTwoWayListenerForNegotiation)));
  919. }
  920. ChannelDispatcher channelDispatcher = new ChannelDispatcher(listener, null, binding);
  921. channelDispatcher.MessageVersion = binding.MessageVersion;
  922. channelDispatcher.ManualAddressing = true;
  923. channelDispatcher.ServiceThrottle = new ServiceThrottle(this);
  924. channelDispatcher.ServiceThrottle.MaxConcurrentCalls = this.authenticator.MaximumConcurrentNegotiations;
  925. channelDispatcher.ServiceThrottle.MaxConcurrentSessions = this.authenticator.MaximumConcurrentNegotiations;
  926. EndpointDispatcher endpointDispatcher = new EndpointDispatcher(new EndpointAddress(this.listenUri), "SecurityNegotiationContract", NamingHelper.DefaultNamespace, true);
  927. endpointDispatcher.DispatchRuntime.SingletonInstanceContext = new InstanceContext(null, this.authenticator, false);
  928. endpointDispatcher.DispatchRuntime.ConcurrencyMode = ConcurrencyMode.Multiple;
  929. endpointDispatcher.AddressFilter = new MatchAllMessageFilter();
  930. endpointDispatcher.ContractFilter = contractFilter;
  931. endpointDispatcher.FilterPriority = filterPriority;
  932. endpointDispatcher.DispatchRuntime.PrincipalPermissionMode = PrincipalPermissionMode.None;
  933. endpointDispatcher.DispatchRuntime.InstanceContextProvider = new SingletonInstanceContextProvider(endpointDispatcher.DispatchRuntime);
  934. endpointDispatcher.DispatchRuntime.SynchronizationContext = null;
  935. DispatchOperation operation = new DispatchOperation(endpointDispatcher.DispatchRuntime, "*", MessageHeaders.WildcardAction, MessageHeaders.WildcardAction);
  936. operation.Formatter = new MessageOperationFormatter();
  937. operation.Invoker = new NegotiationSyncInvoker(this.authenticator);
  938. endpointDispatcher.DispatchRuntime.UnhandledDispatchOperation = operation;
  939. channelDispatcher.Endpoints.Add(endpointDispatcher);
  940. this.ChannelDispatchers.Add(channelDispatcher);
  941. }
  942. class NegotiationSyncInvoker : IOperationInvoker
  943. {
  944. NegotiationTokenAuthenticator<T> parent;
  945. internal NegotiationSyncInvoker(NegotiationTokenAuthenticator<T> parent)
  946. {
  947. this.parent = parent;
  948. }
  949. public bool IsSynchronous { get { return true; } }
  950. public object[] AllocateInputs()
  951. {
  952. return EmptyArray<object>.Allocate(1);
  953. }
  954. public object Invoke(object instance, object[] inputs, out object[] outputs)
  955. {
  956. Message request = (Message)inputs[0];
  957. outputs = EmptyArray<object>.Allocate(0);
  958. try
  959. {
  960. return parent.ProcessRequestCore(request);
  961. }
  962. catch (Exception e)
  963. {
  964. if (Fx.IsFatal(e))
  965. {
  966. throw;
  967. }
  968. return parent.HandleNegotiationException(request, e);
  969. }
  970. }
  971. public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
  972. {
  973. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  974. }
  975. public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
  976. {
  977. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException());
  978. }
  979. }
  980. }
  981. }
  982. }