added samples
[windows-sources.git] / sdk / samples / WCFSamples / TechnologySamples / Basic / Binding / WS / FederationHttp / CS / RSTRSTR / RequestSecurityToken.cs
blob3acee7108496e2d7240a5d1901da0032b2f68809
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
4 using System;
6 using System.Collections.Generic;
8 using System.IdentityModel.Tokens;
10 using System.Runtime.Serialization;
12 using System.Security.Cryptography;
13 using System.Security.Permissions;
15 using System.ServiceModel;
16 using System.ServiceModel.Channels;
17 using System.ServiceModel.Security.Tokens;
19 using System.Text;
21 using System.Xml;
23 [assembly: SecurityPermission(
24 SecurityAction.RequestMinimum, Execution = true)]
25 namespace Microsoft.ServiceModel.Samples
27 // This class is specific to the February 2005 version of WS-Trust.
28 public class RequestSecurityToken : RequestSecurityTokenBase
30 // Private members.
31 private string keyType; // Tracks the type of the proof key (if any).
32 private string requestType; // Tracks the request type (for example, Issue, Renew, Cancel).
33 private SecurityToken requestorEntropy;
34 private SecurityToken proofKey;
36 // Constructors
37 /// <summary>
38 /// Default constructor
39 /// </summary>
40 public RequestSecurityToken() : this(String.Empty, String.Empty, String.Empty, 0, Constants.Trust.KeyTypes.Symmetric, null, null, null)
44 /// <summary>
45 /// Parameterized constructor
46 /// </summary>
47 /// <param name="context">The value of the wst:RequestSecurityToken/@Context attribute</param>
48 /// <param name="tokenType">The content of the wst:RequestSecurityToken/wst:TokenType element</param>
49 /// <param name="requestType"></param>
50 /// <param name="keySize">The content of the wst:RequestSecurityToken/wst:KeySize element</param>
51 /// <param name="keyType"></param>
52 /// <param name="proofKey"></param>
53 /// <param name="entropy">A SecurityToken that represents entropy provided by the requester in the wst:RequestSecurityToken/wst:Entropy element</param>
54 /// <param name="claimTypeRequirements"></param>
55 /// <param name="appliesTo">The content of the wst:RequestSecurityToken/wst:KeySize element</param>
56 public RequestSecurityToken(string context, string tokenType, string requestType, int keySize, string keyType , SecurityToken proofKey, SecurityToken entropy, EndpointAddress appliesTo) : base ( context, tokenType,keySize, appliesTo )
58 this.keyType = keyType;
59 this.proofKey = proofKey;
60 this.requestType = requestType;
61 this.requestorEntropy = entropy;
64 // public properties
65 public string RequestType
67 get { return requestType; }
68 set { requestType = value; }
71 public string KeyType
73 get { return keyType; }
74 set { keyType = value; }
77 public SecurityToken ProofKey
79 get { return proofKey; }
80 set { proofKey = value; }
83 /// <summary>
84 /// The SecurityToken that represents entropy provided by the requester.
85 /// Null if the requester did not provide entropy.
86 /// </summary>
87 public SecurityToken RequestorEntropy
89 get { return requestorEntropy; }
90 set { requestorEntropy = value; }
93 // public methods
94 public bool IsProofKeyAsymmetric()
96 return Constants.Trust.KeyTypes.Public == keyType;
99 /// <summary>
100 /// Reads a wst:RequestSecurityToken element, its attributes and children and
101 /// creates a RequestSecurityToken instance with the appropriate values
102 /// </summary>
103 /// <param name="xr">An XmlReader positioned on wst:RequestSecurityToken</param>
104 /// <returns>A RequestSecurityToken instance, initialized with the data read from the XmlReader</returns>
105 public static RequestSecurityToken CreateFrom(XmlReader xr)
107 return ProcessRequestSecurityTokenElement(xr);
110 // Methods of BodyWriter
111 /// <summary>
112 /// Writes out an XML representation of the instance.
113 /// </summary>
114 /// <param name="writer">The writer to be used to write out the XML content</param>
115 protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
117 // Write out the wst:RequestSecurityToken start tag
118 writer.WriteStartElement(Constants.Trust.Elements.RequestSecurityToken, Constants.Trust.NamespaceUri);
120 // If we have a non-null, non-empty tokenType...
121 if (this.TokenType != null && this.TokenType.Length > 0)
123 // Write out the wst:TokenType start tag
124 writer.WriteStartElement(Constants.Trust.Elements.TokenType, Constants.Trust.NamespaceUri);
125 // Write out the tokenType string
126 writer.WriteString(this.TokenType);
127 writer.WriteEndElement(); // wst:TokenType
130 // If we have a non-null, non-empty requestType...
131 if (this.requestType != null && this.requestType.Length > 0)
133 // Write out the wst:RequestType start tag
134 writer.WriteStartElement(Constants.Trust.Elements.RequestType, Constants.Trust.NamespaceUri);
135 // Write out the requestType string
136 writer.WriteString(this.requestType);
137 writer.WriteEndElement(); // wst:RequestType
140 // If we have a non-null appliesTo
141 if (this.AppliesTo != null)
143 // Write out the wsp:AppliesTo start tag
144 writer.WriteStartElement(Constants.Policy.Elements.AppliesTo, Constants.Policy.NamespaceUri);
145 // Write the appliesTo in WS-Addressing 1.0 format
146 this.AppliesTo.WriteTo(AddressingVersion.WSAddressing10, writer);
147 writer.WriteEndElement(); // wsp:AppliesTo
150 if (this.requestorEntropy!=null)
152 writer.WriteStartElement(Constants.Trust.Elements.Entropy, Constants.Trust.NamespaceUri);
153 BinarySecretSecurityToken bsst = this.requestorEntropy as BinarySecretSecurityToken;
154 if (bsst!=null)
156 writer.WriteStartElement(Constants.Trust.Elements.BinarySecret, Constants.Trust.NamespaceUri);
157 byte[] key = bsst.GetKeyBytes();
158 writer.WriteBase64(key, 0, key.Length);
159 writer.WriteEndElement(); // wst:BinarySecret
161 writer.WriteEndElement(); // wst:Entropy
164 if (this.keyType != null && this.keyType.Length > 0)
166 writer.WriteStartElement(Constants.Trust.Elements.KeyType, Constants.Trust.NamespaceUri);
167 writer.WriteString(this.keyType);
168 writer.WriteEndElement(); // wst:KeyType
171 if (this.KeySize> 0)
173 writer.WriteStartElement(Constants.Trust.Elements.KeySize, Constants.Trust.NamespaceUri);
174 writer.WriteValue(this.KeySize );
175 writer.WriteEndElement(); // wst:KeySize
178 writer.WriteEndElement(); // wst:RequestSecurityToken
182 // private methods
184 /// <summary>
185 /// Reads the wst:RequestSecurityToken element
186 /// </summary>
187 /// <param name="xr">An XmlReader, positioned on the start tag of wst:RequestSecurityToken</param>
188 /// <returns>A RequestSecurityToken instance, initialized with the data read from the XmlReader</returns>
189 private static RequestSecurityToken ProcessRequestSecurityTokenElement(XmlReader xr)
191 // If provided XmlReader is null, throw an exception
192 if (xr == null)
193 throw new ArgumentNullException("xr");
195 // If the wst:RequestSecurityToken element is empty, then throw an exception.
196 if (xr.IsEmptyElement)
197 throw new ArgumentException("wst:RequestSecurityToken element was empty. Unable to create RequestSecurityToken object");
199 // Store the initial depth so we can exit this function when we reach the corresponding end-tag
200 int initialDepth = xr.Depth;
202 // Extract the @Context attribute value.
203 string context = xr.GetAttribute(Constants.Trust.Attributes.Context, String.Empty);
205 string tokenType = String.Empty;
206 string requestType = String.Empty;
207 int keySize = 0;
208 string keyType = Constants.Trust.KeyTypes.Symmetric;
209 EndpointAddress appliesTo = null;
210 SecurityToken entropy = null;
211 SecurityToken proofKey = null;
213 // Enter a read loop...
214 while (xr.Read())
216 // Process element start tags
217 if (XmlNodeType.Element == xr.NodeType)
219 // Process WS-Trust elements
220 if (Constants.Trust.NamespaceUri == xr.NamespaceURI)
222 if (Constants.Trust.Elements.RequestType == xr.LocalName &&
223 !xr.IsEmptyElement)
225 xr.Read();
226 requestType = xr.ReadContentAsString();
228 else if (Constants.Trust.Elements.TokenType == xr.LocalName &&
229 !xr.IsEmptyElement)
231 xr.Read();
232 tokenType = xr.ReadContentAsString();
234 else if (Constants.Trust.Elements.KeySize == xr.LocalName &&
235 !xr.IsEmptyElement)
237 xr.Read();
238 keySize = xr.ReadContentAsInt();
240 else if (Constants.Trust.Elements.KeyType == xr.LocalName &&
241 !xr.IsEmptyElement)
243 xr.Read();
244 keyType = xr.ReadContentAsString();
246 else if (Constants.Trust.Elements.Entropy == xr.LocalName &&
247 !xr.IsEmptyElement)
249 entropy = ProcessEntropyElement(xr);
251 else
253 Console.WriteLine("Not processing element: {0}:{1}", xr.NamespaceURI, xr.LocalName);
256 // Process WS-Policy elements
257 else if (Constants.Policy.NamespaceUri == xr.NamespaceURI)
259 if (Constants.Policy.Elements.AppliesTo == xr.LocalName &&
260 !xr.IsEmptyElement)
262 appliesTo = ProcessAppliesToElement(xr);
264 else
266 Console.WriteLine("Not processing element: {0}:{1}", xr.NamespaceURI, xr.LocalName);
269 else
271 Console.WriteLine("Not processing element: {0}:{1}", xr.NamespaceURI, xr.LocalName);
275 // Look for the end-tag that corresponds to the start-tag the reader was positioned
276 // on when the method was called
277 if (Constants.Trust.Elements.RequestSecurityToken == xr.LocalName &&
278 Constants.Trust.NamespaceUri == xr.NamespaceURI &&
279 xr.Depth == initialDepth &&
280 XmlNodeType.EndElement == xr.NodeType )
281 break;
284 // Construct a new RequestSecurityToken based on the values read and return it
285 return new RequestSecurityToken(context, tokenType, requestType, keySize, keyType, proofKey, entropy, appliesTo);
288 /// <summary>
289 /// Reads a wst:Entropy element and constructs a SecurityToken
290 /// Assumes that the provided entropy is never more than 1Kb in size
291 /// </summary>
292 /// <param name="xr">An XmlReader positioned on the start tag of wst:Entropy</param>
293 /// <returns>A SecurityToken that contains the entropy value</returns>
294 private static SecurityToken ProcessEntropyElement(XmlReader xr)
296 // If provided XmlReader is null, throw an exception
297 if (xr == null)
298 throw new ArgumentNullException("xr");
300 // If the wst:Entropy element is empty, then throw an exception.
301 if (xr.IsEmptyElement)
302 throw new ArgumentException("wst:Entropy element was empty. Unable to create SecurityToken object");
304 // Store the initial depth so we can exit this function when we reach the corresponding end-tag
305 int initialDepth = xr.Depth;
307 // Set our return value to null
308 SecurityToken st = null;
310 // Enter a read loop...
311 while (xr.Read())
313 // Look for a non-empty wst:BinarySecret element
314 if (Constants.Trust.Elements.BinarySecret == xr.LocalName &&
315 Constants.Trust.NamespaceUri == xr.NamespaceURI &&
316 !xr.IsEmptyElement &&
317 XmlNodeType.Element == xr.NodeType)
319 // Allocate a 1024 byte buffer for the entropy
320 byte[] temp = new byte[1024];
322 // Move reader to content of wst:BinarySecret element...
323 xr.Read();
325 // ...and read that content as base64. Store the actual number of bytes we get.
326 int nBytes = xr.ReadContentAsBase64(temp, 0, temp.Length);
328 // Allocate a new array of the correct size to hold the provided entropy
329 byte[] entropy = new byte[nBytes];
331 // Copy the entropy from the temporary array into the new array.
332 for (int i = 0; i < nBytes; i++)
333 entropy[i] = temp[i];
335 // Create new BinarySecretSecurityToken from the provided entropy
336 st = new BinarySecretSecurityToken(entropy);
339 // Look for the end-tag that corresponds to the start-tag the reader was positioned
340 // on when the method was called. When we find it, break out of the read loop.
341 if (Constants.Trust.Elements.Entropy == xr.LocalName &&
342 Constants.Trust.NamespaceUri == xr.NamespaceURI &&
343 xr.Depth == initialDepth &&
344 XmlNodeType.EndElement == xr.NodeType)
345 break;
348 return st;
351 /// <summary>
352 /// Reads a wsp:AppliesTo element
353 /// </summary>
354 /// <param name="xr">An XmlReader positioned on the start tag of wsp:AppliesTo</param>
355 /// <returns>An EndpointAddress</returns>
356 private static EndpointAddress ProcessAppliesToElement(XmlReader xr)
358 // If provided XmlReader is null, throw an exception
359 if (xr == null)
360 throw new ArgumentNullException("xr");
362 // If the wsp:AppliesTo element is empty, then throw an exception.
363 if (xr.IsEmptyElement)
364 throw new ArgumentException("wsp:AppliesTo element was empty. Unable to create EndpointAddress object");
366 // Store the initial depth so we can exit this function when we reach the corresponding end-tag
367 int initialDepth = xr.Depth;
369 // Set our return value to null
370 EndpointAddress ea = null;
372 // Enter a read loop...
373 while (xr.Read())
375 // Look for a WS-Addressing 1.0 Endpoint Reference...
376 if (Constants.Addressing.Elements.EndpointReference == xr.LocalName &&
377 Constants.Addressing.NamespaceUri == xr.NamespaceURI &&
378 !xr.IsEmptyElement &&
379 XmlNodeType.Element == xr.NodeType)
381 // Create a DataContractSerializer for an EndpointAddress10
382 DataContractSerializer dcs = new DataContractSerializer(typeof(EndpointAddress10));
383 // Read the EndpointAddress10 from the DataContractSerializer
384 EndpointAddress10 ea10 = (EndpointAddress10)dcs.ReadObject(xr, false);
385 // Convert the EndpointAddress10 into an EndpointAddress
386 ea = ea10.ToEndpointAddress();
388 // Look for a WS-Addressing 2004/08 Endpoint Reference...
389 else if (Constants.Addressing.Elements.EndpointReference == xr.LocalName &&
390 Constants.Addressing.NamespaceUriAugust2004 == xr.NamespaceURI &&
391 !xr.IsEmptyElement &&
392 XmlNodeType.Element == xr.NodeType)
394 // Create a DataContractSerializer for an EndpointAddressAugust2004
395 DataContractSerializer dcs = new DataContractSerializer(typeof(EndpointAddressAugust2004));
396 // Read the EndpointAddressAugust2004 from the DataContractSerializer
397 EndpointAddressAugust2004 eaAugust2004 = (EndpointAddressAugust2004)dcs.ReadObject(xr, false);
398 // Convert the EndpointAddressAugust2004 into an EndpointAddress
399 ea = eaAugust2004.ToEndpointAddress();
402 // Look for the end-tag that corresponds to the start-tag the reader was positioned
403 // on when the method was called. When we find it, break out of the read loop.
404 if (Constants.Policy.Elements.AppliesTo == xr.LocalName &&
405 Constants.Policy.NamespaceUri == xr.NamespaceURI &&
406 xr.Depth == initialDepth &&
407 XmlNodeType.EndElement == xr.NodeType)
408 break;
411 // Return the EndpointAddress
412 return ea;