1 //
2 // ConfigUtil.cs
3 //
4 // Author:
5 //	Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2006 Novell, Inc.  http://www.novell.com
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.Configuration;
30 using System.Collections.Generic;
31 using System.Linq;
32 using System.Reflection;
33 using System.Security.Cryptography.X509Certificates;
34 using System.ServiceModel.Channels;
35 using System.ServiceModel.Configuration;
36 using System.ServiceModel.Description;
37 using System.ServiceModel.Dispatcher;
38 #if !XAMMAC_4_5
39 using System.Web.Configuration;
40 #endif
41 
42 using SysConfig = System.Configuration.Configuration;
43 
44 namespace System.ServiceModel.Configuration
45 {
46 	internal static class ConfigUtil
47 	{
48 #if !XAMMAC_4_5
GetSection(string name)49 		static object GetSection (string name)
50 		{
51 			if (ServiceHostingEnvironment.InAspNet)
52 				return WebConfigurationManager.GetSection (name);
53 			else
54 				return ConfigurationManager.GetSection (name);
55 		}
56 
57 		public static BindingsSection BindingsSection {
58 			get {
59 				return (BindingsSection) GetSection ("system.serviceModel/bindings");
60 			}
61 		}
62 
63 		public static ClientSection ClientSection {
64 			get { return (ClientSection) GetSection ("system.serviceModel/client"); }
65 		}
66 
67 		public static ServicesSection ServicesSection {
68 			get { return (ServicesSection) GetSection ("system.serviceModel/services"); }
69 		}
70 
71 		public static BehaviorsSection BehaviorsSection {
72 			get { return (BehaviorsSection) GetSection ("system.serviceModel/behaviors"); }
73 		}
74 
75 		public static DiagnosticSection DiagnosticSection {
76 			get { return (DiagnosticSection) GetSection ("system.serviceModel/diagnostics"); }
77 		}
78 
79 		public static ExtensionsSection ExtensionsSection {
80 			get { return (ExtensionsSection) GetSection ("system.serviceModel/extensions"); }
81 		}
82 
83 		public static ProtocolMappingSection ProtocolMappingSection {
84 			get {
85 				return (ProtocolMappingSection) GetSection ("system.serviceModel/protocolMapping");
86 			}
87 		}
88 
89 		public static StandardEndpointsSection StandardEndpointsSection {
90 			get {
91 				return (StandardEndpointsSection) GetSection ("system.serviceModel/standardEndpoints");
92 			}
93 		}
94 
CreateBinding(string binding, string bindingConfiguration)95 		public static Binding CreateBinding (string binding, string bindingConfiguration)
96 		{
97 			BindingCollectionElement section = ConfigUtil.BindingsSection [binding];
98 			if (section == null)
99 				throw new ArgumentException (String.Format ("binding section for {0} was not found.", binding));
100 
101 			Binding b = section.GetDefault ();
102 
103 			foreach (IBindingConfigurationElement el in section.ConfiguredBindings)
104 				if (el.Name == bindingConfiguration)
105 					el.ApplyConfiguration (b);
106 
107 			return b;
108 		}
109 
110 		static readonly List<Assembly> cached_assemblies = new List<Assembly> ();
111 		static readonly List<NamedConfigType> cached_named_config_types = new List<NamedConfigType> ();
112 
GetTypeFromConfigString(string name, NamedConfigCategory category)113 		public static Type GetTypeFromConfigString (string name, NamedConfigCategory category)
114 		{
115 			Type type = Type.GetType (name);
116 			if (type != null)
117 				return type;
118 			foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
119 				var cache = cached_named_config_types.FirstOrDefault (c => c.Name == name && c.Category == category);
120 				if (cache != null)
121 					return cache.Type;
122 
123 				if ((type = ass.GetType (name)) != null)
124 					return type;
125 
126 				if (cached_assemblies.Contains (ass))
127 					continue;
128 				if (!ass.IsDynamic)
129 					cached_assemblies.Add (ass);
130 
131 				foreach (var t in ass.GetTypes ()) {
132 					if (cached_named_config_types.Any (ct => ct.Type == t))
133 						continue;
134 
135 					NamedConfigType c = null;
136 					var sca = t.GetCustomAttribute<ServiceContractAttribute> (false);
137 					if (sca != null && !String.IsNullOrEmpty (sca.ConfigurationName)) {
138 						c = new NamedConfigType () { Category = NamedConfigCategory.Contract, Name = sca.ConfigurationName, Type = t };
139 						cached_named_config_types.Add (c);
140 					}
141 
142 					// If we need more category, add to here.
143 
144 					if (c != null && c.Name == name && c.Category == category)
145 						cache = c; // do not break and continue caching (as the assembly is being cached)
146 				}
147 				if (cache != null)
148 					return cache.Type;
149 			}
150 			return null;
151 		}
152 
GetBindingByProtocolMapping(Uri address)153 		public static Binding GetBindingByProtocolMapping (Uri address)
154 		{
155 			ProtocolMappingElement el = ConfigUtil.ProtocolMappingSection.ProtocolMappingCollection [address.Scheme];
156 			if (el == null)
157 				return null;
158 			return ConfigUtil.CreateBinding (el.Binding, el.BindingConfiguration);
159 		}
160 
ConfigureStandardEndpoint(ContractDescription cd, ChannelEndpointElement element)161 		public static ServiceEndpoint ConfigureStandardEndpoint (ContractDescription cd, ChannelEndpointElement element)
162 		{
163 			string kind = element.Kind;
164 			string endpointConfiguration = element.EndpointConfiguration;
165 
166 			EndpointCollectionElement section = ConfigUtil.StandardEndpointsSection [kind];
167 			if (section == null)
168 				throw new ArgumentException (String.Format ("standard endpoint section for '{0}' was not found.", kind));
169 
170 			StandardEndpointElement e = section.GetDefaultStandardEndpointElement ();
171 
172 			ServiceEndpoint inst = e.CreateServiceEndpoint (cd);
173 
174 			foreach (StandardEndpointElement el in section.ConfiguredEndpoints) {
175 				if (el.Name == endpointConfiguration) {
176 					el.InitializeAndValidate (element);
177 					el.ApplyConfiguration (inst, element);
178 					break;
179 				}
180 			}
181 
182 			return inst;
183 		}
184 
ConfigureStandardEndpoint(ContractDescription cd, ServiceEndpointElement element)185 		public static ServiceEndpoint ConfigureStandardEndpoint (ContractDescription cd, ServiceEndpointElement element)
186 		{
187 			string kind = element.Kind;
188 			string endpointConfiguration = element.EndpointConfiguration;
189 
190 			EndpointCollectionElement section = ConfigUtil.StandardEndpointsSection [kind];
191 			if (section == null)
192 				throw new ArgumentException (String.Format ("standard endpoint section for '{0}' was not found.", kind));
193 
194 			StandardEndpointElement e = section.GetDefaultStandardEndpointElement ();
195 
196 			ServiceEndpoint inst = e.CreateServiceEndpoint (cd);
197 
198 			foreach (StandardEndpointElement el in section.ConfiguredEndpoints) {
199 				if (el.Name == endpointConfiguration) {
200 					el.InitializeAndValidate (element);
201 					el.ApplyConfiguration (inst, element);
202 					break;
203 				}
204 			}
205 
206 			return inst;
207 		}
208 
CreateEndpointBehaviors(string bindingConfiguration)209 		public static KeyedByTypeCollection<IEndpointBehavior>  CreateEndpointBehaviors (string bindingConfiguration)
210 		{
211 			var ec = BehaviorsSection.EndpointBehaviors [bindingConfiguration];
212 			if (ec == null)
213 				return null;
214 			var c = new KeyedByTypeCollection<IEndpointBehavior> ();
215 			foreach (var bxe in ec)
216 				c.Add ((IEndpointBehavior) bxe.CreateBehavior ());
217 			return c;
218 		}
219 
CreateInstance(this EndpointAddressElementBase el)220 		public static EndpointAddress CreateInstance (this EndpointAddressElementBase el)
221 		{
222 			return new EndpointAddress (el.Address, el.Identity.CreateInstance (), el.Headers.Headers);
223 		}
224 
CopyFrom(this ChannelEndpointElement to, ChannelEndpointElement from)225 		public static void CopyFrom (this ChannelEndpointElement to, ChannelEndpointElement from)
226 		{
227 			to.Address = from.Address;
228 			to.BehaviorConfiguration = from.BehaviorConfiguration;
229 			to.Binding = from.Binding;
230 			to.BindingConfiguration = from.BindingConfiguration;
231 			to.Contract = from.Contract;
232 			if (from.Headers != null)
233 				to.Headers.Headers = from.Headers.Headers;
234 			if (from.Identity != null)
235 				to.Identity.InitializeFrom (from.Identity.CreateInstance ());
236 			to.Name = from.Name;
237 		}
238 
CreateEndpointAddress(this ChannelEndpointElement el)239 		public static EndpointAddress CreateEndpointAddress (this ChannelEndpointElement el)
240 		{
241 			return new EndpointAddress (el.Address, el.Identity != null ? el.Identity.CreateInstance () : null, el.Headers.Headers);
242 		}
243 
CreateEndpointAddress(this ServiceEndpointElement el)244 		public static EndpointAddress CreateEndpointAddress (this ServiceEndpointElement el)
245 		{
246 			return new EndpointAddress (el.Address, el.Identity != null ? el.Identity.CreateInstance () : null, el.Headers.Headers);
247 		}
248 #endif
249 
CreateInstance(this IdentityElement el)250 		public static EndpointIdentity CreateInstance (this IdentityElement el)
251 		{
252 			if (el.Certificate != null)
253 				return new X509CertificateEndpointIdentity (el.Certificate.CreateInstance ());
254 			else if (el.CertificateReference != null)
255 				return new X509CertificateEndpointIdentity (el.CertificateReference.CreateInstance ());
256 			else if (el.Dns != null)
257 				return new DnsEndpointIdentity (el.Dns.Value);
258 			else if (el.Rsa != null)
259 				return new RsaEndpointIdentity (el.Rsa.Value);
260 			else if (el.ServicePrincipalName != null)
261 				return new SpnEndpointIdentity (el.ServicePrincipalName.Value);
262 			else if (el.UserPrincipalName != null)
263 				return new UpnEndpointIdentity (el.UserPrincipalName.Value);
264 			else
265 				return null;
266 		}
267 
CreateCertificateFrom(StoreLocation storeLocation, StoreName storeName, X509FindType findType, Object findValue)268 		public static X509Certificate2 CreateCertificateFrom (StoreLocation storeLocation, StoreName storeName, X509FindType findType, Object findValue)
269 		{
270 			var store = new X509Store (storeName, storeLocation);
271 			store.Open (OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
272 			try {
273 				foreach (var c in store.Certificates.Find (findType, findValue, false))
274 					return c;
275 				throw new InvalidOperationException (String.Format ("Specified X509 certificate with find type {0} and find value {1} was not found in X509 store {2} location {3}", findType, findValue, storeName, storeLocation));
276 			} finally {
277 				store.Close ();
278 			}
279 		}
280 
CreateInstance(this CertificateElement el)281 		public static X509Certificate2 CreateInstance (this CertificateElement el)
282 		{
283 			return new X509Certificate2 (Convert.FromBase64String (el.EncodedValue));
284 		}
285 
CreateInstance(this CertificateReferenceElement el)286 		public static X509Certificate2 CreateInstance (this CertificateReferenceElement el)
287 		{
288 			return CreateCertificateFrom (el.StoreLocation, el.StoreName, el.X509FindType, el.FindValue);
289 		}
290 
CreateInstance(this X509ClientCertificateCredentialsElement el)291 		public static X509Certificate2 CreateInstance (this X509ClientCertificateCredentialsElement el)
292 		{
293 			return CreateCertificateFrom (el.StoreLocation, el.StoreName, el.X509FindType, el.FindValue);
294 		}
295 
CreateInstance(this X509ScopedServiceCertificateElement el)296 		public static X509Certificate2 CreateInstance (this X509ScopedServiceCertificateElement el)
297 		{
298 			return CreateCertificateFrom (el.StoreLocation, el.StoreName, el.X509FindType, el.FindValue);
299 		}
300 
CreateInstance(this X509DefaultServiceCertificateElement el)301 		public static X509Certificate2 CreateInstance (this X509DefaultServiceCertificateElement el)
302 		{
303 			return CreateCertificateFrom (el.StoreLocation, el.StoreName, el.X509FindType, el.FindValue);
304 		}
305 
306 #if !XAMMAC_4_5
FindCollectionElement(Binding binding, SysConfig config)307 		public static BindingCollectionElement FindCollectionElement (Binding binding, SysConfig config)
308 		{
309 			var section = (BindingsSection) config.GetSection ("system.serviceModel/bindings");
310 			foreach (var element in section.BindingCollections) {
311 				if (binding.GetType ().Equals (element.BindingType))
312 					return element;
313 			}
314 
315 			return null;
316 		}
317 #endif
318 	}
319 
320 	enum NamedConfigCategory
321 	{
322 		None,
323 		Contract
324 	}
325 
326 	class NamedConfigType
327 	{
328 		public NamedConfigCategory Category { get; set; }
329 		public string Name { get; set; }
330 		public Type Type { get; set; }
331 	}
332 
333 }
334