File: WSTrustChannelFactory.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (511 lines) | stat: -rw-r--r-- 21,675 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
//------------------------------------------------------------------------------
//     Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------

namespace System.ServiceModel.Security
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IdentityModel.Protocols.WSTrust;
    using System.IdentityModel.Selectors;
    using System.IdentityModel.Tokens;
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Description;
    using IM = System.IdentityModel;

    /// <summary>
    /// A <see cref="ChannelFactory" /> that produces <see cref="WSTrustChannel" /> objects used to 
    /// communicate to a WS-Trust endpoint.
    /// </summary>
    [ComVisible(false)]
    public class WSTrustChannelFactory : ChannelFactory<IWSTrustChannelContract>
    {
        //
        // NOTE: The properties on this class are designed to facilitate ease of use of the component and
        //       to reduce the complexity of the constructors. The base class already gifts us with 8 constructor
        //       overloads.
        //
        //       Therefore, it is advisable that the fields *not* be used unless absolutely required.
        //

        /// <summary>
        /// These fields represent the property values that are "locked down" once the first channel is created.
        /// </summary>
        class WSTrustChannelLockedProperties
        {
            public TrustVersion TrustVersion;
            public WSTrustSerializationContext Context;
            public WSTrustRequestSerializer RequestSerializer;
            public WSTrustResponseSerializer ResponseSerializer;
        }

        //
        // Once we create a channel, our properties can be locked down.
        //
        object _factoryLock = new object();
        bool _locked = false;
        WSTrustChannelLockedProperties _lockedProperties;

        //
        // The TrustVersion property can be set to an instance of TrustVersion.WSTrust13 or TrustVersion.WSTrustFeb2005
        // to generate the built-in serializers for these trust namespaces.
        //
        TrustVersion _trustVersion;

        //
        // These fields contain the values used to construct the WSTrustSerializationContext used by the channels
        // we generate.
        //
        // _securityTokenResolver and _useKeyTokenResolver imply special behavior if they are null; however,
        // _securityTokenHandlerCollectionManager is not permitted to be null.
        //
        SecurityTokenResolver _securityTokenResolver;
        SecurityTokenResolver _useKeyTokenResolver;
        SecurityTokenHandlerCollectionManager _securityTokenHandlerCollectionManager
            = SecurityTokenHandlerCollectionManager.CreateDefaultSecurityTokenHandlerCollectionManager();

        //
        // These serializers determine how the channels serialize RST and RSTR messages.
        //
        WSTrustRequestSerializer _wsTrustRequestSerializer;
        WSTrustResponseSerializer _wsTrustResponseSerializer;

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class.
        /// </summary>
        public WSTrustChannelFactory()
            : base()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified endpoint 
        /// configuration name.
        /// </summary>
        /// <param name="endpointConfigurationName">The configuration name used for the endpoint.</param>
        public WSTrustChannelFactory(string endpointConfigurationName)
            : base(endpointConfigurationName)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class.
        /// </summary>
        /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
        public WSTrustChannelFactory(Binding binding)
            : base(binding)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified endpoint.
        /// </summary>
        /// <param name="endpoint">The <see cref="ServiceEndpoint" />for the channels produced by the factory.</param>
        public WSTrustChannelFactory(ServiceEndpoint endpoint)
            : base(endpoint)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class associated with a specified 
        /// name for the endpoint configuration and remote address.
        /// </summary>
        /// <param name="endpointConfigurationName">The configuration name used for the endpoint.</param>
        /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
        public WSTrustChannelFactory(string endpointConfigurationName, EndpointAddress remoteAddress)
            : base(endpointConfigurationName, remoteAddress)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified binding 
        /// and endpoint address.
        /// </summary>
        /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
        /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>        
        public WSTrustChannelFactory(Binding binding, EndpointAddress remoteAddress)
            : base(binding, remoteAddress)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WSTrustChannelFactory" /> class with a specified binding
        /// and remote address.
        /// </summary>
        /// <param name="binding">The <see cref="Binding" /> specified for the channels produced by the factory</param>
        /// <param name="remoteAddress">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
        public WSTrustChannelFactory(Binding binding, string remoteAddress)
            : base(binding, remoteAddress)
        {
        }

        /// <summary>
        /// Gets or sets the version of WS-Trust the created channels will use for serializing messages.
        /// </summary>
        /// <remarks>
        /// <para>If this property is not set, created channels will use the <see cref="TrustVersion" /> set on any
        /// <see cref="SecurityBindingElement" /> found on the channel factory's Endpoint object if one exists.
        /// </para>
        /// <para>This class will not support changing the value of this property after a channel is created.</para>
        /// </remarks>        
        public TrustVersion TrustVersion
        {
            get
            {
                return _trustVersion;
            }
            set
            {
                lock (_factoryLock)
                {
                    if (_locked)
                    {
                        throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
                    }
                    _trustVersion = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="SecurityTokenHandlerCollectionManager" /> containing the set of
        /// <see cref="SecurityTokenHandler" /> objects used by created channels for serializing and validating 
        /// tokens found in  WS-Trust messages.
        /// </summary>
        /// <remarks>
        /// This class will not support changing the value of this property after a channel is created.        
        /// </remarks> 
        public SecurityTokenHandlerCollectionManager SecurityTokenHandlerCollectionManager
        {
            get
            {
                return _securityTokenHandlerCollectionManager;
            }
            set
            {
                if (value == null)
                {
                    throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                }

                lock (_factoryLock)
                {
                    if (_locked)
                    {
                        throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
                    }
                    _securityTokenHandlerCollectionManager = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="SecurityTokenResolver"/> used to resolve security token references found in most
        /// elements of WS-Trust messages.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If this property is not set created channels will use the ClientCertificate set on the factory's 
        /// Endpoint's ClientCredentials behavior to create a resolver. If no such certificate is found, an empty
        /// resolver is used.
        /// </para>
        /// <para>
        /// This class will not support changing the value of this property after a channel is created.
        /// </para>
        /// </remarks>
        public SecurityTokenResolver SecurityTokenResolver
        {
            get
            {
                return _securityTokenResolver;
            }
            set
            {
                lock (_factoryLock)
                {
                    if (_locked)
                    {
                        throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
                    }
                    _securityTokenResolver = value;
                }
            }
        }

        /// <summary>
        /// The <see cref="SecurityTokenResolver"/> used to resolve security token references found in the
        /// UseKey element of RST messages as well as the RenewTarget element found in RST messages.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If this property is not set an empty resolver is used.
        /// </para>
        /// <para>
        /// This class will not support changing the value of this property after a channel is created.
        /// </para>
        /// </remarks>
        public SecurityTokenResolver UseKeyTokenResolver
        {
            get
            {
                return _useKeyTokenResolver;
            }
            set
            {
                lock (_factoryLock)
                {
                    if (_locked)
                    {
                        throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
                    }
                    _useKeyTokenResolver = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the WSTrustRequestSerializer to use for serializing RequestSecurityTokens messages.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If this property is not set, either <see cref="WSTrust13RequestSerializer" /> or 
        /// <see cref="WSTrustFeb2005RequestSerializer" /> will be used. The serializer will correspond to the 
        /// version of WS-Trust indicated by the <see cref="TrustVersion" /> property.
        /// </para>
        /// <para>
        /// This class will not support changing the value of this property after a channel is created.
        /// </para>
        /// </remarks>
        public WSTrustRequestSerializer WSTrustRequestSerializer
        {
            get
            {
                return _wsTrustRequestSerializer;
            }
            set
            {
                lock (_factoryLock)
                {
                    if (_locked)
                    {
                        throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
                    }
                    _wsTrustRequestSerializer = value;
                }
            }
        }

        /// <summary>
        /// Gets or sets the WSTrustResponseSerializer to use for serializing RequestSecurityTokensResponse messages.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If this property is not set, either <see cref="WSTrust13ResponseSerializer" /> or 
        /// <see cref="WSTrustFeb2005ResponseSerializer" /> will be used. The serializer will correspond to the 
        /// version of WS-Trust indicated by the <see cref="TrustVersion" /> property.
        /// </para>
        /// <para>
        /// This class will not support changing the value of this property after a channel is created.
        /// </para>
        /// </remarks>
        public WSTrustResponseSerializer WSTrustResponseSerializer
        {
            get
            {
                return _wsTrustResponseSerializer;
            }
            set
            {
                lock (_factoryLock)
                {
                    if (_locked)
                    {
                        throw IM.DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID3287));
                    }
                    _wsTrustResponseSerializer = value;
                }
            }
        }

        /// <summary>
        /// Creates a <see cref="WSTrustChannel" /> that is used to send messages to a service at a specific 
        /// endpoint address through a specified transport address.
        /// </summary>
        /// <param name="address">The <see cref="EndpointAddress" /> that provides the location of the service.</param>
        /// <param name="via">The <see cref="Uri" /> that contains the transport address to which the channel sends messages.</param>
        /// <returns></returns>
        public override IWSTrustChannelContract CreateChannel(EndpointAddress address, Uri via)
        {
            IWSTrustChannelContract innerChannel = base.CreateChannel(address, via);

            WSTrustChannelLockedProperties lockedProperties = GetLockedProperties();
            return CreateTrustChannel(innerChannel,
                                       lockedProperties.TrustVersion,
                                       lockedProperties.Context,
                                       lockedProperties.RequestSerializer,
                                       lockedProperties.ResponseSerializer);
        }

        /// <summary>
        /// Creates a <see cref="WSTrustChannel" /> using parameters that reflect the configuration of
        /// this factory.
        /// </summary>
        /// <param name="innerChannel">The channel created by the base class capable of sending and 
        /// receiving messages.</param>
        /// <param name="trustVersion">The version of WS-Trust that should be used.</param>
        /// <param name="context">
        /// The <see cref="WSTrustSerializationContext" /> that should be used to serialize WS-Trust messages.
        /// </param>
        /// <param name="requestSerializer">
        /// The <see cref="WSTrustRequestSerializer" /> that should be used to serialize WS-Trust request messages.
        /// </param>
        /// <param name="responseSerializer">
        /// The <see cref="WSTrustResponseSerializer" /> that should be used to serialize WS-Trust response messages.
        /// </param>
        /// <returns></returns>
        protected virtual WSTrustChannel CreateTrustChannel(IWSTrustChannelContract innerChannel,
                                                             TrustVersion trustVersion,
                                                             WSTrustSerializationContext context,
                                                             WSTrustRequestSerializer requestSerializer,
                                                             WSTrustResponseSerializer responseSerializer)
        {
            return new WSTrustChannel(this, innerChannel, trustVersion, context, requestSerializer, responseSerializer);
        }

        private WSTrustChannelLockedProperties GetLockedProperties()
        {
            lock (_factoryLock)
            {
                if (_lockedProperties == null)
                {
                    WSTrustChannelLockedProperties tmpLockedProperties = new WSTrustChannelLockedProperties();
                    tmpLockedProperties.TrustVersion = GetTrustVersion();
                    tmpLockedProperties.Context = CreateSerializationContext();
                    tmpLockedProperties.RequestSerializer = GetRequestSerializer(tmpLockedProperties.TrustVersion);
                    tmpLockedProperties.ResponseSerializer = GetResponseSerializer(tmpLockedProperties.TrustVersion);

                    _lockedProperties = tmpLockedProperties;
                    _locked = true;
                }
                return _lockedProperties;
            }
        }

        private WSTrustRequestSerializer GetRequestSerializer(TrustVersion trustVersion)
        {
            Fx.Assert(trustVersion != null, "trustVersion != null");

            if (_wsTrustRequestSerializer != null)
            {
                return _wsTrustRequestSerializer;
            }

            if (trustVersion == TrustVersion.WSTrust13)
            {
                return new WSTrust13RequestSerializer();
            }
            else if (trustVersion == TrustVersion.WSTrustFeb2005)
            {
                return new WSTrustFeb2005RequestSerializer();
            }
            else
            {
                throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new NotSupportedException(SR.GetString(SR.ID3137, trustVersion.ToString())));
            }
        }

        private WSTrustResponseSerializer GetResponseSerializer(TrustVersion trustVersion)
        {
            Fx.Assert(trustVersion != null, "trustVersion != null");

            if (_wsTrustResponseSerializer != null)
            {
                return _wsTrustResponseSerializer;
            }

            if (trustVersion == TrustVersion.WSTrust13)
            {
                return new WSTrust13ResponseSerializer();
            }
            else if (trustVersion == TrustVersion.WSTrustFeb2005)
            {
                return new WSTrustFeb2005ResponseSerializer();
            }
            else
            {
                throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.ID3137, trustVersion.ToString())));
            }
        }

        private TrustVersion GetTrustVersion()
        {
            TrustVersion trustVersion = _trustVersion;

            if (trustVersion == null)
            {
                BindingElementCollection elements = Endpoint.Binding.CreateBindingElements();
                SecurityBindingElement sbe = elements.Find<SecurityBindingElement>();
                if (null == sbe)
                {
                    throw IM.DiagnosticUtility.ExceptionUtility.ThrowHelperError( new InvalidOperationException( SR.GetString(SR.ID3269)));
                }
                trustVersion = sbe.MessageSecurityVersion.TrustVersion;
            }

            return trustVersion;
        }

        /// <summary>
        /// Creates a <see cref="WSTrustSerializationContext" /> used by <see cref="WSTrustChannel" /> objects created
        /// by this factory.
        /// </summary>
        /// <remarks>
        /// <para>
        /// If <see cref="WSTrustChannelFactory.SecurityTokenResolver" /> is set to null, the 
        /// ClientCertificate set on the factory's  Endpoint's ClientCredentials behavior will be used to 
        /// create a resolver. If no such certificate is found, an empty resolver is used.
        /// </para>
        /// <para>
        /// If <see cref="WSTrustChannelFactory.UseKeyTokenResolver" /> is set to null, an empty resolver
        /// will be used.
        /// </para>
        /// </remarks>
        /// <returns>A WSTrustSerializationContext initialized with the trust client's properties.</returns>
        protected virtual WSTrustSerializationContext CreateSerializationContext()
        {
            //
            // Create a resolver with the ClientCredential's ClientCertificate if a resolver is not set.
            //
            SecurityTokenResolver resolver = _securityTokenResolver;
            if (resolver == null)
            {
                ClientCredentials factoryCredentials = Credentials;
                if (null != factoryCredentials.ClientCertificate && null != factoryCredentials.ClientCertificate.Certificate)
                {
                    List<SecurityToken> clientCredentialTokens = new List<SecurityToken>();
                    clientCredentialTokens.Add(new X509SecurityToken(factoryCredentials.ClientCertificate.Certificate));
                    resolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(clientCredentialTokens.AsReadOnly(), false);
                }
            }

            //
            // If it is _still_ null, then make it empty.
            //
            if (resolver == null)
            {
                resolver = EmptySecurityTokenResolver.Instance;
            }

            //
            // UseKeyTokenResolver is empty if null.
            //
            SecurityTokenResolver useKeyResolver = _useKeyTokenResolver ?? EmptySecurityTokenResolver.Instance;

            return new WSTrustSerializationContext(_securityTokenHandlerCollectionManager, resolver, useKeyResolver);
        }
    }
}