WSTrustMessageConverters.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. //
  2. // WSTrustMessageConverters.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // Copyright (C) 2006-2007 Novell, Inc.
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. using System;
  29. using System.Reflection;
  30. using System.Security.Cryptography;
  31. using System.IdentityModel.Selectors;
  32. using System.IdentityModel.Tokens;
  33. using System.Security.Cryptography.Xml;
  34. using System.ServiceModel;
  35. using System.ServiceModel.Channels;
  36. using System.ServiceModel.Description;
  37. using System.ServiceModel.Security;
  38. using System.ServiceModel.Security.Tokens;
  39. using System.Xml;
  40. using System.Xml.Serialization;
  41. namespace System.ServiceModel.Description
  42. {
  43. class WSTrustRequestSecurityTokenReader : IDisposable
  44. {
  45. WstRequestSecurityToken req = new WstRequestSecurityToken ();
  46. XmlDictionaryReader reader;
  47. SecurityTokenSerializer serializer;
  48. public WSTrustRequestSecurityTokenReader (XmlDictionaryReader reader, SecurityTokenSerializer serializer)
  49. {
  50. this.reader = reader;
  51. this.serializer = serializer;
  52. }
  53. public WstRequestSecurityToken Value {
  54. get { return req; }
  55. }
  56. string LineInfo ()
  57. {
  58. IXmlLineInfo li = reader as IXmlLineInfo;
  59. return li != null && li.HasLineInfo () ?
  60. String.Format ("({0},{1})", li.LineNumber, li.LinePosition) : String.Empty;
  61. }
  62. public void Dispose ()
  63. {
  64. reader.Close ();
  65. }
  66. public WstRequestSecurityToken Read ()
  67. {
  68. reader.MoveToContent ();
  69. req.Context = reader.GetAttribute ("Context");
  70. reader.ReadStartElement ("RequestSecurityToken", Constants.WstNamespace);
  71. do {
  72. reader.MoveToContent ();
  73. switch (reader.NodeType) {
  74. case XmlNodeType.EndElement:
  75. reader.Read (); // consume RequestSecurityToken end element.
  76. return req;
  77. case XmlNodeType.Element:
  78. ReadTokenContent ();
  79. break;
  80. default:
  81. throw new XmlException (String.Format ("Unexpected request XML {0} node, name {1}{2}", reader.NodeType, reader.Name, LineInfo ()));
  82. }
  83. } while (true);
  84. }
  85. void ReadTokenContent ()
  86. {
  87. switch (reader.NamespaceURI) {
  88. case Constants.WstNamespace:
  89. switch (reader.LocalName) {
  90. case "RequestType":
  91. req.RequestType = reader.ReadElementContentAsString ();
  92. return;
  93. case "Entropy":
  94. ReadEntropy ();
  95. return;
  96. case "KeySize":
  97. req.KeySize = reader.ReadElementContentAsInt ();
  98. return;
  99. case "KeyType":
  100. req.KeyType = reader.ReadElementContentAsString ();
  101. return;
  102. case "TokenType":
  103. string tokenType = reader.ReadElementContentAsString ();
  104. if (tokenType != Constants.WsscContextToken)
  105. throw new SecurityTokenException (String.Format ("Unexpected TokenType: {0}", tokenType));
  106. return;
  107. case "ComputedKeyAlgorithm":
  108. req.ComputedKeyAlgorithm = reader.ReadElementContentAsString ();
  109. return;
  110. case "BinaryExchange":
  111. ReadBinaryExchange ();
  112. return;
  113. }
  114. break;
  115. case Constants.WspNamespace:
  116. switch (reader.LocalName) {
  117. case "AppliesTo":
  118. ReadAppliesTo ();
  119. return;
  120. }
  121. break;
  122. }
  123. throw new XmlException (String.Format ("Unexpected RequestSecurityToken content element. Name is {0} and namespace URI is {1}{2}", reader.Name, reader.NamespaceURI, LineInfo ()));
  124. }
  125. protected void ReadBinaryExchange ()
  126. {
  127. if (reader.IsEmptyElement)
  128. throw new XmlException (String.Format ("Binary content is expected in 'BinaryExchange' element.{0}", LineInfo ()));
  129. WstBinaryExchange b = new WstBinaryExchange (reader.GetAttribute ("ValueType"));
  130. b.EncodingType = reader.GetAttribute ("EncodingType");
  131. b.Value = Convert.FromBase64String (reader.ReadElementContentAsString ());
  132. req.BinaryExchange = b;
  133. }
  134. void ReadEntropy ()
  135. {
  136. if (reader.IsEmptyElement)
  137. throw new XmlException (String.Format ("WS-Trust Entropy element is empty.{2}", LineInfo ()));
  138. reader.ReadStartElement ("Entropy", Constants.WstNamespace);
  139. reader.MoveToContent ();
  140. req.Entropy = serializer.ReadToken (reader, null);
  141. // after reading a token, </Entropy> should follow.
  142. reader.MoveToContent ();
  143. reader.ReadEndElement ();
  144. }
  145. void ReadAppliesTo ()
  146. {
  147. WspAppliesTo aTo = new WspAppliesTo ();
  148. if (reader.IsEmptyElement)
  149. throw new XmlException (String.Format ("WS-Policy AppliesTo element is empty.{2}", LineInfo ()));
  150. reader.ReadStartElement ();
  151. reader.MoveToContent ();
  152. reader.ReadStartElement ("EndpointReference", Constants.WsaNamespace);
  153. reader.MoveToContent ();
  154. WsaEndpointReference er = new WsaEndpointReference ();
  155. er.Address = reader.ReadElementContentAsString ("Address", Constants.WsaNamespace);
  156. reader.MoveToContent ();
  157. reader.ReadEndElement (); // </EndpointReference>
  158. aTo.EndpointReference = er;
  159. reader.MoveToContent ();
  160. reader.ReadEndElement (); // </wsp:AppliesTo>
  161. req.AppliesTo = aTo;
  162. }
  163. }
  164. // FIXME: it might be extraneous - currently used only for IssuedToken
  165. class WstRequestSecurityTokenWriter : BodyWriter
  166. {
  167. WstRequestSecurityToken value;
  168. SecurityTokenSerializer serializer;
  169. public WstRequestSecurityTokenWriter (WstRequestSecurityToken value, SecurityTokenSerializer serializer)
  170. : base (true)
  171. {
  172. this.value = value;
  173. this.serializer = serializer;
  174. }
  175. protected override void OnWriteBodyContents (XmlDictionaryWriter w)
  176. {
  177. w.WriteStartElement ("RequestSecurityToken", Constants.WstNamespace);
  178. w.WriteEndElement ();
  179. }
  180. }
  181. class WSTrustRequestSecurityTokenResponseReader : IDisposable
  182. {
  183. string negotiation_type;
  184. WstRequestSecurityTokenResponse res;
  185. XmlDictionaryReader reader;
  186. SecurityTokenSerializer serializer;
  187. SecurityTokenResolver resolver;
  188. public WSTrustRequestSecurityTokenResponseReader (
  189. string negotiationType,
  190. XmlDictionaryReader reader,
  191. SecurityTokenSerializer serializer,
  192. SecurityTokenResolver resolver)
  193. {
  194. this.negotiation_type = negotiationType;
  195. this.reader = reader;
  196. this.serializer = serializer;
  197. this.resolver = resolver;
  198. res = new WstRequestSecurityTokenResponse (serializer);
  199. }
  200. public WstRequestSecurityTokenResponse Value {
  201. get { return res; }
  202. }
  203. string LineInfo ()
  204. {
  205. IXmlLineInfo li = reader as IXmlLineInfo;
  206. return li != null && li.HasLineInfo () ?
  207. String.Format ("({0},{1})", li.LineNumber, li.LinePosition) : String.Empty;
  208. }
  209. public void Dispose ()
  210. {
  211. reader.Close ();
  212. }
  213. public WstRequestSecurityTokenResponse Read ()
  214. {
  215. reader.MoveToContent ();
  216. res.Context = reader.GetAttribute ("Context");
  217. reader.ReadStartElement ("RequestSecurityTokenResponse", Constants.WstNamespace);
  218. do {
  219. reader.MoveToContent ();
  220. switch (reader.NodeType) {
  221. case XmlNodeType.EndElement:
  222. reader.Read (); // consume RequestSecurityTokenResponse end element.
  223. return res;
  224. case XmlNodeType.Element:
  225. ReadTokenContent ();
  226. break;
  227. default:
  228. throw new XmlException (String.Format ("Unexpected request XML {0} node, name {1}{2}", reader.NodeType, reader.Name, LineInfo ()));
  229. }
  230. } while (true);
  231. }
  232. void ReadTokenContent ()
  233. {
  234. switch (reader.NamespaceURI) {
  235. case Constants.WstNamespace:
  236. switch (reader.LocalName) {
  237. case "RequestedSecurityToken":
  238. res.RequestedSecurityToken = (SecurityContextSecurityToken) ReadToken ();
  239. return;
  240. case "RequestedProofToken":
  241. #if true // FIXME: we can't handle it right now
  242. string ens = EncryptedXml.XmlEncNamespaceUrl;
  243. reader.Read ();
  244. reader.ReadStartElement ("EncryptedKey", ens);
  245. string alg = reader.GetAttribute ("Algorithm");
  246. bool isEmpty = reader.IsEmptyElement;
  247. reader.ReadStartElement ("EncryptionMethod", ens);
  248. if (alg != negotiation_type)
  249. throw new XmlException (String.Format ("EncryptionMethod '{0}' is not supported in RequestedProofToken.", alg));
  250. if (!isEmpty)
  251. reader.ReadEndElement ();
  252. reader.ReadStartElement ("CipherData", ens);
  253. reader.ReadStartElement ("CipherValue", ens);
  254. byte [] pt = reader.ReadContentAsBase64 ();
  255. res.RequestedProofToken = pt;
  256. reader.ReadEndElement ();
  257. reader.ReadEndElement ();
  258. reader.ReadEndElement ();// EncryptedKey
  259. reader.ReadEndElement ();// RPT
  260. #else
  261. reader.Read ();
  262. reader.MoveToContent ();
  263. if (serializer.CanReadToken (reader))
  264. res.RequestedProofToken = serializer.ReadToken (reader, resolver);
  265. else
  266. res.RequestedProofToken = serializer.ReadKeyIdentifierClause (reader);
  267. reader.ReadEndElement ();
  268. #endif
  269. return;
  270. case "BinaryExchange":
  271. ReadBinaryExchange ();
  272. return;
  273. case "TokenType":
  274. res.TokenType = reader.ReadElementContentAsString ();
  275. return;
  276. case "Lifetime":
  277. ReadLifetime ();
  278. return;
  279. case "KeySize":
  280. res.KeySize = reader.ReadElementContentAsInt ();
  281. return;
  282. case "RequestedAttachedReference":
  283. res.RequestedAttachedReference = ReadTokenReference ();
  284. return;
  285. case "RequestedUnattachedReference":
  286. res.RequestedUnattachedReference = ReadTokenReference ();
  287. return;
  288. case "Authenticator":
  289. ReadAuthenticator ();
  290. return;
  291. }
  292. break;
  293. }
  294. throw new XmlException (String.Format ("Unexpected RequestSecurityTokenResponse content element. Name is {0} and namespace URI is {1} {2}", reader.Name, reader.NamespaceURI, LineInfo ()));
  295. }
  296. void ReadAuthenticator ()
  297. {
  298. if (reader.IsEmptyElement)
  299. throw new XmlException (String.Format ("WS-Trust 'Authenticator' element is expected to have contents. {0}", LineInfo ()));
  300. reader.Read ();
  301. reader.MoveToContent ();
  302. res.Authenticator = Convert.FromBase64String (reader.ReadElementContentAsString ("CombinedHash", Constants.WstNamespace));
  303. reader.ReadEndElement ();
  304. }
  305. void ReadLifetime ()
  306. {
  307. WstLifetime lt = new WstLifetime ();
  308. res.Lifetime = lt;
  309. if (reader.IsEmptyElement)
  310. throw new XmlException (String.Format ("WS-Trust 'Lifetime' element is expected to have contents. {0}", LineInfo ()));
  311. reader.Read ();
  312. while (true) {
  313. reader.MoveToContent ();
  314. if (reader.NodeType != XmlNodeType.Element)
  315. break;
  316. if (reader.NamespaceURI == Constants.WsuNamespace) {
  317. switch (reader.LocalName) {
  318. case "Created":
  319. lt.Created = XmlConvert.ToDateTime (reader.ReadElementContentAsString (), XmlDateTimeSerializationMode.RoundtripKind);
  320. continue;
  321. case "Expires":
  322. lt.Expires = XmlConvert.ToDateTime (reader.ReadElementContentAsString (), XmlDateTimeSerializationMode.RoundtripKind);
  323. continue;
  324. }
  325. }
  326. throw new XmlException (String.Format ("Unexpected Lifetime content. Name is {0} and namespace URI is {1} {2}", reader.Name, reader.NamespaceURI, LineInfo ()));
  327. }
  328. reader.ReadEndElement ();
  329. }
  330. SecurityToken ReadToken ()
  331. {
  332. if (reader.IsEmptyElement)
  333. throw new XmlException (String.Format ("Security token body is expected in '{0}' element. {1}", reader.LocalName, LineInfo ()));
  334. reader.Read ();
  335. reader.MoveToContent ();
  336. SecurityToken token = serializer.ReadToken (reader, resolver);
  337. reader.ReadEndElement ();
  338. return token;
  339. }
  340. SecurityKeyIdentifierClause ReadTokenReference ()
  341. {
  342. if (reader.IsEmptyElement)
  343. throw new XmlException (String.Format ("Content is expected in 'RequestedAttachedReference' element. {0}", LineInfo ()));
  344. reader.Read ();
  345. SecurityKeyIdentifierClause ret = serializer.ReadKeyIdentifierClause (reader);
  346. reader.ReadEndElement ();
  347. return ret;
  348. }
  349. void ReadBinaryExchange ()
  350. {
  351. if (reader.IsEmptyElement)
  352. throw new XmlException (String.Format ("Binary content is expected in 'BinaryExchange' element.{0}", LineInfo ()));
  353. WstBinaryExchange b = new WstBinaryExchange (reader.GetAttribute ("ValueType"));
  354. b.EncodingType = reader.GetAttribute ("EncodingType");
  355. b.Value = Convert.FromBase64String (reader.ReadElementContentAsString ());
  356. res.BinaryExchange = b;
  357. }
  358. }
  359. // FIXME: it might be extraneous - currently unused
  360. internal class WstRequestSecurityTokenResponseWriter : BodyWriter
  361. {
  362. WstRequestSecurityTokenResponse res;
  363. SecurityTokenSerializer serializer;
  364. public WstRequestSecurityTokenResponseWriter (WstRequestSecurityTokenResponse res, SecurityTokenSerializer serializer)
  365. : base (true)
  366. {
  367. this.res = res;
  368. this.serializer = serializer;
  369. }
  370. protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
  371. {
  372. try {
  373. writer.WriteStartElement ("RequestSecurityTokenResponse", Constants.WstNamespace);
  374. // RequestedSecurityToken
  375. writer.WriteStartElement ("RequestedSecurityToken", Constants.WstNamespace);
  376. serializer.WriteToken (writer, res.RequestedSecurityToken);
  377. writer.WriteEndElement ();
  378. /*
  379. // Entropy
  380. writer.WriteStartElement ("Entropy", Constants.WstNamespace);
  381. // FIXME: keep generated key
  382. serializer.WriteToken (writer,
  383. new BinarySecretSecurityToken (Rijndael.Create ().Key));
  384. writer.WriteEndElement ();
  385. */
  386. writer.WriteEndElement ();
  387. } catch (Exception ex) {
  388. Console.WriteLine (ex);
  389. throw;
  390. }
  391. }
  392. }
  393. }