| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- //
- // WSTrustMessageConverters.cs
- //
- // Author:
- // Atsushi Enomoto <[email protected]>
- //
- // Copyright (C) 2006-2007 Novell, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Reflection;
- using System.Security.Cryptography;
- using System.IdentityModel.Selectors;
- using System.IdentityModel.Tokens;
- using System.Security.Cryptography.Xml;
- using System.ServiceModel;
- using System.ServiceModel.Channels;
- using System.ServiceModel.Description;
- using System.ServiceModel.Security;
- using System.ServiceModel.Security.Tokens;
- using System.Xml;
- using System.Xml.Serialization;
- namespace System.ServiceModel.Description
- {
- class WSTrustRequestSecurityTokenReader : IDisposable
- {
- WstRequestSecurityToken req = new WstRequestSecurityToken ();
- XmlDictionaryReader reader;
- SecurityTokenSerializer serializer;
- public WSTrustRequestSecurityTokenReader (XmlDictionaryReader reader, SecurityTokenSerializer serializer)
- {
- this.reader = reader;
- this.serializer = serializer;
- }
- public WstRequestSecurityToken Value {
- get { return req; }
- }
- string LineInfo ()
- {
- IXmlLineInfo li = reader as IXmlLineInfo;
- return li != null && li.HasLineInfo () ?
- String.Format ("({0},{1})", li.LineNumber, li.LinePosition) : String.Empty;
- }
- public void Dispose ()
- {
- reader.Close ();
- }
- public WstRequestSecurityToken Read ()
- {
- reader.MoveToContent ();
- req.Context = reader.GetAttribute ("Context");
- reader.ReadStartElement ("RequestSecurityToken", Constants.WstNamespace);
- do {
- reader.MoveToContent ();
- switch (reader.NodeType) {
- case XmlNodeType.EndElement:
- reader.Read (); // consume RequestSecurityToken end element.
- return req;
- case XmlNodeType.Element:
- ReadTokenContent ();
- break;
- default:
- throw new XmlException (String.Format ("Unexpected request XML {0} node, name {1}{2}", reader.NodeType, reader.Name, LineInfo ()));
- }
- } while (true);
- }
- void ReadTokenContent ()
- {
- switch (reader.NamespaceURI) {
- case Constants.WstNamespace:
- switch (reader.LocalName) {
- case "RequestType":
- req.RequestType = reader.ReadElementContentAsString ();
- return;
- case "Entropy":
- ReadEntropy ();
- return;
- case "KeySize":
- req.KeySize = reader.ReadElementContentAsInt ();
- return;
- case "KeyType":
- req.KeyType = reader.ReadElementContentAsString ();
- return;
- case "TokenType":
- string tokenType = reader.ReadElementContentAsString ();
- if (tokenType != Constants.WsscContextToken)
- throw new SecurityTokenException (String.Format ("Unexpected TokenType: {0}", tokenType));
- return;
- case "ComputedKeyAlgorithm":
- req.ComputedKeyAlgorithm = reader.ReadElementContentAsString ();
- return;
- case "BinaryExchange":
- ReadBinaryExchange ();
- return;
- }
- break;
- case Constants.WspNamespace:
- switch (reader.LocalName) {
- case "AppliesTo":
- ReadAppliesTo ();
- return;
- }
- break;
- }
- throw new XmlException (String.Format ("Unexpected RequestSecurityToken content element. Name is {0} and namespace URI is {1}{2}", reader.Name, reader.NamespaceURI, LineInfo ()));
- }
- protected void ReadBinaryExchange ()
- {
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("Binary content is expected in 'BinaryExchange' element.{0}", LineInfo ()));
- WstBinaryExchange b = new WstBinaryExchange (reader.GetAttribute ("ValueType"));
- b.EncodingType = reader.GetAttribute ("EncodingType");
- b.Value = Convert.FromBase64String (reader.ReadElementContentAsString ());
- req.BinaryExchange = b;
- }
- void ReadEntropy ()
- {
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("WS-Trust Entropy element is empty.{2}", LineInfo ()));
- reader.ReadStartElement ("Entropy", Constants.WstNamespace);
- reader.MoveToContent ();
- req.Entropy = serializer.ReadToken (reader, null);
- // after reading a token, </Entropy> should follow.
- reader.MoveToContent ();
- reader.ReadEndElement ();
- }
- void ReadAppliesTo ()
- {
- WspAppliesTo aTo = new WspAppliesTo ();
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("WS-Policy AppliesTo element is empty.{2}", LineInfo ()));
- reader.ReadStartElement ();
- reader.MoveToContent ();
- reader.ReadStartElement ("EndpointReference", Constants.WsaNamespace);
- reader.MoveToContent ();
- WsaEndpointReference er = new WsaEndpointReference ();
- er.Address = reader.ReadElementContentAsString ("Address", Constants.WsaNamespace);
- reader.MoveToContent ();
- reader.ReadEndElement (); // </EndpointReference>
- aTo.EndpointReference = er;
- reader.MoveToContent ();
- reader.ReadEndElement (); // </wsp:AppliesTo>
- req.AppliesTo = aTo;
- }
- }
- // FIXME: it might be extraneous - currently used only for IssuedToken
- class WstRequestSecurityTokenWriter : BodyWriter
- {
- WstRequestSecurityToken value;
- SecurityTokenSerializer serializer;
- public WstRequestSecurityTokenWriter (WstRequestSecurityToken value, SecurityTokenSerializer serializer)
- : base (true)
- {
- this.value = value;
- this.serializer = serializer;
- }
- protected override void OnWriteBodyContents (XmlDictionaryWriter w)
- {
- w.WriteStartElement ("RequestSecurityToken", Constants.WstNamespace);
- w.WriteEndElement ();
- }
- }
- class WSTrustRequestSecurityTokenResponseReader : IDisposable
- {
- string negotiation_type;
- WstRequestSecurityTokenResponse res;
- XmlDictionaryReader reader;
- SecurityTokenSerializer serializer;
- SecurityTokenResolver resolver;
- public WSTrustRequestSecurityTokenResponseReader (
- string negotiationType,
- XmlDictionaryReader reader,
- SecurityTokenSerializer serializer,
- SecurityTokenResolver resolver)
- {
- this.negotiation_type = negotiationType;
- this.reader = reader;
- this.serializer = serializer;
- this.resolver = resolver;
- res = new WstRequestSecurityTokenResponse (serializer);
- }
- public WstRequestSecurityTokenResponse Value {
- get { return res; }
- }
- string LineInfo ()
- {
- IXmlLineInfo li = reader as IXmlLineInfo;
- return li != null && li.HasLineInfo () ?
- String.Format ("({0},{1})", li.LineNumber, li.LinePosition) : String.Empty;
- }
- public void Dispose ()
- {
- reader.Close ();
- }
- public WstRequestSecurityTokenResponse Read ()
- {
- reader.MoveToContent ();
- res.Context = reader.GetAttribute ("Context");
- reader.ReadStartElement ("RequestSecurityTokenResponse", Constants.WstNamespace);
- do {
- reader.MoveToContent ();
- switch (reader.NodeType) {
- case XmlNodeType.EndElement:
- reader.Read (); // consume RequestSecurityTokenResponse end element.
- return res;
- case XmlNodeType.Element:
- ReadTokenContent ();
- break;
- default:
- throw new XmlException (String.Format ("Unexpected request XML {0} node, name {1}{2}", reader.NodeType, reader.Name, LineInfo ()));
- }
- } while (true);
- }
- void ReadTokenContent ()
- {
- switch (reader.NamespaceURI) {
- case Constants.WstNamespace:
- switch (reader.LocalName) {
- case "RequestedSecurityToken":
- res.RequestedSecurityToken = (SecurityContextSecurityToken) ReadToken ();
- return;
- case "RequestedProofToken":
- #if true // FIXME: we can't handle it right now
- string ens = EncryptedXml.XmlEncNamespaceUrl;
- reader.Read ();
- reader.ReadStartElement ("EncryptedKey", ens);
- string alg = reader.GetAttribute ("Algorithm");
- bool isEmpty = reader.IsEmptyElement;
- reader.ReadStartElement ("EncryptionMethod", ens);
- if (alg != negotiation_type)
- throw new XmlException (String.Format ("EncryptionMethod '{0}' is not supported in RequestedProofToken.", alg));
- if (!isEmpty)
- reader.ReadEndElement ();
- reader.ReadStartElement ("CipherData", ens);
- reader.ReadStartElement ("CipherValue", ens);
- byte [] pt = reader.ReadContentAsBase64 ();
- res.RequestedProofToken = pt;
- reader.ReadEndElement ();
- reader.ReadEndElement ();
- reader.ReadEndElement ();// EncryptedKey
- reader.ReadEndElement ();// RPT
- #else
- reader.Read ();
- reader.MoveToContent ();
- if (serializer.CanReadToken (reader))
- res.RequestedProofToken = serializer.ReadToken (reader, resolver);
- else
- res.RequestedProofToken = serializer.ReadKeyIdentifierClause (reader);
- reader.ReadEndElement ();
- #endif
- return;
- case "BinaryExchange":
- ReadBinaryExchange ();
- return;
- case "TokenType":
- res.TokenType = reader.ReadElementContentAsString ();
- return;
- case "Lifetime":
- ReadLifetime ();
- return;
- case "KeySize":
- res.KeySize = reader.ReadElementContentAsInt ();
- return;
- case "RequestedAttachedReference":
- res.RequestedAttachedReference = ReadTokenReference ();
- return;
- case "RequestedUnattachedReference":
- res.RequestedUnattachedReference = ReadTokenReference ();
- return;
- case "Authenticator":
- ReadAuthenticator ();
- return;
- }
- break;
- }
- throw new XmlException (String.Format ("Unexpected RequestSecurityTokenResponse content element. Name is {0} and namespace URI is {1} {2}", reader.Name, reader.NamespaceURI, LineInfo ()));
- }
- void ReadAuthenticator ()
- {
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("WS-Trust 'Authenticator' element is expected to have contents. {0}", LineInfo ()));
- reader.Read ();
- reader.MoveToContent ();
- res.Authenticator = Convert.FromBase64String (reader.ReadElementContentAsString ("CombinedHash", Constants.WstNamespace));
- reader.ReadEndElement ();
- }
- void ReadLifetime ()
- {
- WstLifetime lt = new WstLifetime ();
- res.Lifetime = lt;
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("WS-Trust 'Lifetime' element is expected to have contents. {0}", LineInfo ()));
- reader.Read ();
- while (true) {
- reader.MoveToContent ();
- if (reader.NodeType != XmlNodeType.Element)
- break;
- if (reader.NamespaceURI == Constants.WsuNamespace) {
- switch (reader.LocalName) {
- case "Created":
- lt.Created = XmlConvert.ToDateTime (reader.ReadElementContentAsString (), XmlDateTimeSerializationMode.RoundtripKind);
- continue;
- case "Expires":
- lt.Expires = XmlConvert.ToDateTime (reader.ReadElementContentAsString (), XmlDateTimeSerializationMode.RoundtripKind);
- continue;
- }
- }
- throw new XmlException (String.Format ("Unexpected Lifetime content. Name is {0} and namespace URI is {1} {2}", reader.Name, reader.NamespaceURI, LineInfo ()));
- }
- reader.ReadEndElement ();
- }
- SecurityToken ReadToken ()
- {
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("Security token body is expected in '{0}' element. {1}", reader.LocalName, LineInfo ()));
- reader.Read ();
- reader.MoveToContent ();
- SecurityToken token = serializer.ReadToken (reader, resolver);
- reader.ReadEndElement ();
- return token;
- }
- SecurityKeyIdentifierClause ReadTokenReference ()
- {
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("Content is expected in 'RequestedAttachedReference' element. {0}", LineInfo ()));
- reader.Read ();
- SecurityKeyIdentifierClause ret = serializer.ReadKeyIdentifierClause (reader);
- reader.ReadEndElement ();
- return ret;
- }
- void ReadBinaryExchange ()
- {
- if (reader.IsEmptyElement)
- throw new XmlException (String.Format ("Binary content is expected in 'BinaryExchange' element.{0}", LineInfo ()));
- WstBinaryExchange b = new WstBinaryExchange (reader.GetAttribute ("ValueType"));
- b.EncodingType = reader.GetAttribute ("EncodingType");
- b.Value = Convert.FromBase64String (reader.ReadElementContentAsString ());
- res.BinaryExchange = b;
- }
- }
- // FIXME: it might be extraneous - currently unused
- internal class WstRequestSecurityTokenResponseWriter : BodyWriter
- {
- WstRequestSecurityTokenResponse res;
- SecurityTokenSerializer serializer;
- public WstRequestSecurityTokenResponseWriter (WstRequestSecurityTokenResponse res, SecurityTokenSerializer serializer)
- : base (true)
- {
- this.res = res;
- this.serializer = serializer;
- }
- protected override void OnWriteBodyContents (XmlDictionaryWriter writer)
- {
- try {
- writer.WriteStartElement ("RequestSecurityTokenResponse", Constants.WstNamespace);
- // RequestedSecurityToken
- writer.WriteStartElement ("RequestedSecurityToken", Constants.WstNamespace);
- serializer.WriteToken (writer, res.RequestedSecurityToken);
- writer.WriteEndElement ();
- /*
- // Entropy
- writer.WriteStartElement ("Entropy", Constants.WstNamespace);
- // FIXME: keep generated key
- serializer.WriteToken (writer,
- new BinarySecretSecurityToken (Rijndael.Create ().Key));
- writer.WriteEndElement ();
- */
- writer.WriteEndElement ();
- } catch (Exception ex) {
- Console.WriteLine (ex);
- throw;
- }
- }
- }
- }
|