1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //-----------------------------------------------------------------------------
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
;
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
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
;
38 /// Default constructor
40 public RequestSecurityToken() : this(String
.Empty
, String
.Empty
, String
.Empty
, 0, Constants
.Trust
.KeyTypes
.Symmetric
, null, null, null)
45 /// Parameterized constructor
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
;
65 public string RequestType
67 get { return requestType; }
68 set { requestType = value; }
73 get { return keyType; }
74 set { keyType = value; }
77 public SecurityToken ProofKey
79 get { return proofKey; }
80 set { proofKey = value; }
84 /// The SecurityToken that represents entropy provided by the requester.
85 /// Null if the requester did not provide entropy.
87 public SecurityToken RequestorEntropy
89 get { return requestorEntropy; }
90 set { requestorEntropy = value; }
94 public bool IsProofKeyAsymmetric()
96 return Constants
.Trust
.KeyTypes
.Public
== keyType
;
100 /// Reads a wst:RequestSecurityToken element, its attributes and children and
101 /// creates a RequestSecurityToken instance with the appropriate values
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
112 /// Writes out an XML representation of the instance.
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
;
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
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
185 /// Reads the wst:RequestSecurityToken element
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
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
;
208 string keyType
= Constants
.Trust
.KeyTypes
.Symmetric
;
209 EndpointAddress appliesTo
= null;
210 SecurityToken entropy
= null;
211 SecurityToken proofKey
= null;
213 // Enter a read loop...
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
&&
226 requestType
= xr
.ReadContentAsString();
228 else if (Constants
.Trust
.Elements
.TokenType
== xr
.LocalName
&&
232 tokenType
= xr
.ReadContentAsString();
234 else if (Constants
.Trust
.Elements
.KeySize
== xr
.LocalName
&&
238 keySize
= xr
.ReadContentAsInt();
240 else if (Constants
.Trust
.Elements
.KeyType
== xr
.LocalName
&&
244 keyType
= xr
.ReadContentAsString();
246 else if (Constants
.Trust
.Elements
.Entropy
== xr
.LocalName
&&
249 entropy
= ProcessEntropyElement(xr
);
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
&&
262 appliesTo
= ProcessAppliesToElement(xr
);
266 Console
.WriteLine("Not processing element: {0}:{1}", xr
.NamespaceURI
, xr
.LocalName
);
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
)
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
);
289 /// Reads a wst:Entropy element and constructs a SecurityToken
290 /// Assumes that the provided entropy is never more than 1Kb in size
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
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...
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...
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
)
352 /// Reads a wsp:AppliesTo element
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
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...
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
)
411 // Return the EndpointAddress