History

Added support for GSF configuration files on Mono

ritchiecarroll committed 12 years ago

Commit 2bbd6cd1 parent ef6432e13 files · +615 −136Browse files

Unified · Split

13 files
  1. Source/GridSolutionsFramework.sln +17 −1
  2. Source/Libraries/GSF.Core/Common.cs +14 −0
  3. Source/Libraries/GSF.Core/Configuration/CategorizedSettingsElement.cs +17 −0
  4. Source/Libraries/GSF.Core/Configuration/CategorizedSettingsElementCollection.cs +18 −6
  5. Source/Libraries/GSF.Core/Configuration/CategorizedSettingsSection.cs +174 −14
  6. Source/Libraries/GSF.Core/Configuration/ConfigurationFile.cs +49 −33
  7. Source/Libraries/GSF.Core/Identity/UnixUserInfo.cs +113 −57
  8. Source/Libraries/GSF.Core/Xml/XmlExtensions.cs +35 −25
  9. Source/Tools/ConfigTest/App.config +14 −0
  10. Source/Tools/ConfigTest/ConfigTest.csproj +71 −0
  11. Source/Tools/ConfigTest/ConfigTest.csproj.vspscc +10 −0
  12. Source/Tools/ConfigTest/Program.cs +47 −0
  13. Source/Tools/ConfigTest/Properties/AssemblyInfo.cs +36 −0
Source/GridSolutionsFramework.sln+17−1
@@ -297,9 +297,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnixTools", "Tools\UnixTool · 296 unmodified lines
297EndProject297EndProject
298Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserInfoTest", "Tools\UserInfoTest\UserInfoTest.csproj", "{CD74CE4C-6319-4946-889A-413DC51B03F6}"298Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UserInfoTest", "Tools\UserInfoTest\UserInfoTest.csproj", "{CD74CE4C-6319-4946-889A-413DC51B03F6}"
299EndProject299EndProject
300Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigTest", "Tools\ConfigTest\ConfigTest.csproj", "{B38AC5E5-B880-43E9-8F88-107294F3E69F}"
301EndProject
300Global302Global
301 GlobalSection(TeamFoundationVersionControl) = preSolution303 GlobalSection(TeamFoundationVersionControl) = preSolution
302 SccNumberOfProjects = 86304 SccNumberOfProjects = 87
303 SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}305 SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
304 SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs07306 SccTeamFoundationServer = https://tfs.codeplex.com/tfs/tfs07
305 SccLocalPath0 = .307 SccLocalPath0 = .
@@ -643,6 +645,10 @@ Global · 337 unmodified lines
643 SccProjectTopLevelParentUniqueName85 = GridSolutionsFramework.sln645 SccProjectTopLevelParentUniqueName85 = GridSolutionsFramework.sln
644 SccProjectName85 = Tools/UserInfoTest646 SccProjectName85 = Tools/UserInfoTest
645 SccLocalPath85 = Tools\\UserInfoTest647 SccLocalPath85 = Tools\\UserInfoTest
648 SccProjectUniqueName86 = Tools\\ConfigTest\\ConfigTest.csproj
649 SccProjectTopLevelParentUniqueName86 = GridSolutionsFramework.sln
650 SccProjectName86 = Tools/ConfigTest
651 SccLocalPath86 = Tools\\ConfigTest
646 EndGlobalSection652 EndGlobalSection
647 GlobalSection(TestCaseManagementSettings) = postSolution653 GlobalSection(TestCaseManagementSettings) = postSolution
648 CategoryFile = GSF.Core.Tests.vsmdi654 CategoryFile = GSF.Core.Tests.vsmdi
@@ -1542,6 +1548,15 @@ Global · 893 unmodified lines
1542 {CD74CE4C-6319-4946-889A-413DC51B03F6}.Release|Any CPU.ActiveCfg = Release|Any CPU1548 {CD74CE4C-6319-4946-889A-413DC51B03F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
1543 {CD74CE4C-6319-4946-889A-413DC51B03F6}.Release|Any CPU.Build.0 = Release|Any CPU1549 {CD74CE4C-6319-4946-889A-413DC51B03F6}.Release|Any CPU.Build.0 = Release|Any CPU
1544 {CD74CE4C-6319-4946-889A-413DC51B03F6}.Release|x86.ActiveCfg = Release|Any CPU1550 {CD74CE4C-6319-4946-889A-413DC51B03F6}.Release|x86.ActiveCfg = Release|Any CPU
1551 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1552 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Debug|Any CPU.Build.0 = Debug|Any CPU
1553 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Debug|x86.ActiveCfg = Debug|Any CPU
1554 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Mono|Any CPU.ActiveCfg = Release|Any CPU
1555 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Mono|Any CPU.Build.0 = Release|Any CPU
1556 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Mono|x86.ActiveCfg = Release|Any CPU
1557 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Release|Any CPU.ActiveCfg = Release|Any CPU
1558 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Release|Any CPU.Build.0 = Release|Any CPU
1559 {B38AC5E5-B880-43E9-8F88-107294F3E69F}.Release|x86.ActiveCfg = Release|Any CPU
1545 EndGlobalSection1560 EndGlobalSection
1546 GlobalSection(SolutionProperties) = preSolution1561 GlobalSection(SolutionProperties) = preSolution
1547 HideSolutionNode = FALSE1562 HideSolutionNode = FALSE
@@ -1638,6 +1653,7 @@ Global · 90 unmodified lines
1638 {4508009C-7011-4981-B35F-594F42CC0D1F} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}1653 {4508009C-7011-4981-B35F-594F42CC0D1F} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}
1639 {5A047659-4C24-4B72-A9F3-6553D91F95DC} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}1654 {5A047659-4C24-4B72-A9F3-6553D91F95DC} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}
1640 {CD74CE4C-6319-4946-889A-413DC51B03F6} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}1655 {CD74CE4C-6319-4946-889A-413DC51B03F6} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}
1656 {B38AC5E5-B880-43E9-8F88-107294F3E69F} = {B48642A1-1163-4E1D-948A-50EE19DCD38D}
1641 {AEB62271-270D-4F3E-B596-2297B382A95F} = {99F344EA-D35D-42C8-882B-B495527B5F40}1657 {AEB62271-270D-4F3E-B596-2297B382A95F} = {99F344EA-D35D-42C8-882B-B495527B5F40}
1642 {4F46CF24-163D-4541-9EBF-C291053C0948} = {99F344EA-D35D-42C8-882B-B495527B5F40}1658 {4F46CF24-163D-4541-9EBF-C291053C0948} = {99F344EA-D35D-42C8-882B-B495527B5F40}
1643 {94F36768-E9A0-4783-BB0F-8C2C1771352E} = {AEB62271-270D-4F3E-B596-2297B382A95F}1659 {94F36768-E9A0-4783-BB0F-8C2C1771352E} = {AEB62271-270D-4F3E-B596-2297B382A95F}
Source/Libraries/GSF.Core/Common.cs+14−0
@@ -135,12 +135,26 @@ namespace GSF · 134 unmodified lines
135 /// Determines if the current system is a POSIX style environment.135 /// Determines if the current system is a POSIX style environment.
136 /// </summary>136 /// </summary>
137 /// <remarks>137 /// <remarks>
138 /// <para>
139 /// Since a .NET application compiled under Mono can run under both Windows and Unix style platforms,
140 /// you can use this property to easily determine the current operating environment.
141 /// </para>
142 /// <para>
138 /// This property will return <c>true</c> for both MacOSX and Unix environments. Use the Platform property143 /// This property will return <c>true</c> for both MacOSX and Unix environments. Use the Platform property
139 /// of the <see cref="System.Environment.OSVersion"/> to determine more specific platform type, e.g., 144 /// of the <see cref="System.Environment.OSVersion"/> to determine more specific platform type, e.g.,
140 /// MacOSX or Unix. Note that all flavors of Linux will show up as <see cref="PlatformID.Unix"/>.145 /// MacOSX or Unix. Note that all flavors of Linux will show up as <see cref="PlatformID.Unix"/>.
146 /// </para>
141 /// </remarks> 147 /// </remarks>
142 public static readonly bool IsPosixEnvironment = (Path.DirectorySeparatorChar == '/'); // This is how Mono source often checks this148 public static readonly bool IsPosixEnvironment = (Path.DirectorySeparatorChar == '/'); // This is how Mono source often checks this
143 149
150 /// <summary>
151 /// Determines if the code base is currently running under Mono.
152 /// </summary>
153 /// <remarks>
154 /// You can use this property to make a run-time determination if Windows or Mono based .NET is being used.
155 /// </remarks>
156 public static bool IsMono = ((object)Type.GetType("Mono.Runtime") != null);
157
144 /// <summary>Returns one of two strongly-typed objects.</summary>158 /// <summary>Returns one of two strongly-typed objects.</summary>
145 /// <returns>One of two objects, depending on the evaluation of given expression.</returns>159 /// <returns>One of two objects, depending on the evaluation of given expression.</returns>
146 /// <param name="expression">The expression you want to evaluate.</param>160 /// <param name="expression">The expression you want to evaluate.</param>
Source/Libraries/GSF.Core/Configuration/CategorizedSettingsElement.cs+17−0
@@ -170,6 +170,7 @@ namespace GSF.Configuration · 169 unmodified lines
170 set170 set
171 {171 {
172 base["name"] = value;172 base["name"] = value;
173 Modified = true;
173 }174 }
174 }175 }
175 176
@@ -229,6 +230,8 @@ namespace GSF.Configuration · 53 unmodified lines
229 else230 else
230 // Setting is user specific so update setting in user settings store.231 // Setting is user specific so update setting in user settings store.
231 Category.Section.File.UserSettings.Write(Category.Name, Name, value);232 Category.Section.File.UserSettings.Write(Category.Name, Name, value);
233
234 Modified = true;
232 }235 }
233 }236 }
234 237
@@ -250,6 +253,7 @@ namespace GSF.Configuration · 15 unmodified lines
250 return;253 return;
251 254
252 base["description"] = value;255 base["description"] = value;
256 Modified = true;
253 }257 }
254 }258 }
255 259
@@ -271,6 +275,7 @@ namespace GSF.Configuration · 15 unmodified lines
271 return;275 return;
272 276
273 base["encrypted"] = value;277 base["encrypted"] = value;
278 Modified = true;
274 }279 }
275 }280 }
276 281
@@ -291,6 +296,16 @@ namespace GSF.Configuration · 14 unmodified lines
291 return;296 return;
292 297
293 base["scope"] = value;298 base["scope"] = value;
299 Modified = true;
300 }
301 }
302
303 internal bool Modified
304 {
305 set
306 {
307 if ((object)m_category != null)
308 m_category.Modified = value;
294 }309 }
295 }310 }
296 311
@@ -311,6 +326,7 @@ namespace GSF.Configuration · 14 unmodified lines
311 string decryptedValue = Value;326 string decryptedValue = Value;
312 m_cryptoKey = cryptoKey;327 m_cryptoKey = cryptoKey;
313 Value = decryptedValue;328 Value = decryptedValue;
329 Modified = true;
314 }330 }
315 }331 }
316 332
@@ -357,6 +373,7 @@ namespace GSF.Configuration · 40 unmodified lines
357 this.Encrypted = encrypted;373 this.Encrypted = encrypted;
358 this.Value = Common.TypeConvertToString(value, m_category.Section.File.Culture);374 this.Value = Common.TypeConvertToString(value, m_category.Section.File.Culture);
359 this.Description = description;375 this.Description = description;
376 Modified = true;
360 }377 }
361 378
362 /// <summary>379 /// <summary>
Source/Libraries/GSF.Core/Configuration/CategorizedSettingsElementCollection.cs+18−6
@@ -111,6 +111,7 @@ namespace GSF.Configuration · 110 unmodified lines
111 base.BaseRemoveAt(index);111 base.BaseRemoveAt(index);
112 112
113 base.BaseAdd(index, value);113 base.BaseAdd(index, value);
114 Modified = true;
114 }115 }
115 }116 }
116 117
@@ -137,23 +138,29 @@ namespace GSF.Configuration · 20 unmodified lines
137 {138 {
138 get139 get
139 {140 {
141 // Add setting since it's not there
140 if (ensureExistance && (object)base.BaseGet(name) == null)142 if (ensureExistance && (object)base.BaseGet(name) == null)
141 {
142 // Add setting since it's not there.
143 Add(name, string.Empty);143 Add(name, string.Empty);
144 }
145 144
146 CategorizedSettingsElement setting = (CategorizedSettingsElement)base.BaseGet(name);145 CategorizedSettingsElement setting = (CategorizedSettingsElement)base.BaseGet(name);
146
147 // Set the crypto key for the setting
147 if ((object)setting != null)148 if ((object)setting != null)
148 {
149 // Set the crypto key for the setting.
150 setting.SetCryptoKey(m_cryptoKey);149 setting.SetCryptoKey(m_cryptoKey);
151 }
152 150
153 return setting;151 return setting;
154 }152 }
155 }153 }
156 154
155 internal bool Modified
156 {
157 set
158 {
159 if ((object)m_section != null)
160 m_section.Modified = value;
161 }
162 }
163
157 #endregion164 #endregion
158 165
159 #region [ Methods ]166 #region [ Methods ]
@@ -242,6 +249,7 @@ namespace GSF.Configuration · 82 unmodified lines
242 setting.Category = this;249 setting.Category = this;
243 setting.SetCryptoKey(m_cryptoKey);250 setting.SetCryptoKey(m_cryptoKey);
244 base.BaseAdd(setting);251 base.BaseAdd(setting);
252 Modified = true;
245 }253 }
246 }254 }
247 255
@@ -252,6 +260,7 @@ namespace GSF.Configuration · 4 unmodified lines
252 public void Remove(string name)260 public void Remove(string name)
253 {261 {
254 base.BaseRemove(name);262 base.BaseRemove(name);
263 Modified = true;
255 }264 }
256 265
257 /// <summary>266 /// <summary>
@@ -263,6 +272,7 @@ namespace GSF.Configuration · 5 unmodified lines
263 if (base.BaseIndexOf(setting) >= 0)272 if (base.BaseIndexOf(setting) >= 0)
264 {273 {
265 Remove(setting.Name);274 Remove(setting.Name);
275 Modified = true;
266 }276 }
267 }277 }
268 278
@@ -273,6 +283,7 @@ namespace GSF.Configuration · 4 unmodified lines
273 public void RemoveAt(int index)283 public void RemoveAt(int index)
274 {284 {
275 base.BaseRemoveAt(index);285 base.BaseRemoveAt(index);
286 Modified = true;
276 }287 }
277 288
278 /// <summary>289 /// <summary>
@@ -281,6 +292,7 @@ namespace GSF.Configuration · 2 unmodified lines
281 public void Clear()292 public void Clear()
282 {293 {
283 base.BaseClear();294 base.BaseClear();
295 Modified = true;
284 }296 }
285 297
286 /// <summary>298 /// <summary>
Source/Libraries/GSF.Core/Configuration/CategorizedSettingsSection.cs+174−14
@@ -38,10 +38,14 @@ · 37 unmodified lines
38//******************************************************************************************************38//******************************************************************************************************
39 39
40using System;40using System;
41using System.Collections.Generic;
41using System.Configuration;42using System.Configuration;
42using System.IO;43using System.IO;
44using System.Text;
43using System.Xml;45using System.Xml;
46using GSF.Collections;
44using GSF.IO;47using GSF.IO;
48using GSF.Xml;
45 49
46namespace GSF.Configuration50namespace GSF.Configuration
47{51{
@@ -59,9 +63,19 @@ namespace GSF.Configuration · 11 unmodified lines
59 // Fields63 // Fields
60 private string m_cryptoKey;64 private string m_cryptoKey;
61 private ConfigurationFile m_file;65 private ConfigurationFile m_file;
66 private readonly Dictionary<string, CategorizedSettingsElementCollection> m_sections;
62 67
63 #endregion68 #endregion
64 69
70 /// <summary>
71 /// Creates a new <see cref="CategorizedSettingsSection"/>.
72 /// </summary>
73 public CategorizedSettingsSection()
74 {
75 if (Common.IsMono)
76 m_sections = new Dictionary<string, CategorizedSettingsElementCollection>();
77 }
78
65 #region [ Properties ]79 #region [ Properties ]
66 80
67 /// <summary>81 /// <summary>
@@ -99,18 +113,42 @@ namespace GSF.Configuration · 31 unmodified lines
99 // Make the first letter of category name lower case, if not already.113 // Make the first letter of category name lower case, if not already.
100 char[] nameChars = name.ToCharArray();114 char[] nameChars = name.ToCharArray();
101 nameChars[0] = char.ToLower(nameChars[0]);115 nameChars[0] = char.ToLower(nameChars[0]);
116
102 // Do not allow spaces in the name so that underlying .Net configuration API does not break.117 // Do not allow spaces in the name so that underlying .Net configuration API does not break.
103 name = (new string(nameChars)).RemoveWhiteSpace();118 name = (new string(nameChars)).RemoveWhiteSpace();
104 ConfigurationProperty configProperty = new ConfigurationProperty(name, typeof(CategorizedSettingsElementCollection));
105 119
106 base.Properties.Add(configProperty);120 ConfigurationProperty configProperty = new ConfigurationProperty(name, typeof(CategorizedSettingsElementCollection));
107 CategorizedSettingsElementCollection settingsCategory = null;121 CategorizedSettingsElementCollection settingsCategory = null;
108 if ((object)base[configProperty] != null)122
123 if ((object)m_sections == null)
109 {124 {
110 settingsCategory = (CategorizedSettingsElementCollection)base[configProperty];125 base.Properties.Add(configProperty);
111 settingsCategory.Name = name;126
112 settingsCategory.Section = this;127 if ((object)base[configProperty] != null)
113 settingsCategory.SetCryptoKey(m_cryptoKey);128 {
129 settingsCategory = (CategorizedSettingsElementCollection)base[configProperty];
130 settingsCategory.Name = name;
131 settingsCategory.Section = this;
132 settingsCategory.SetCryptoKey(m_cryptoKey);
133 }
134 }
135 else
136 {
137 settingsCategory = m_sections.GetOrAdd(name, sectionName =>
138 {
139 base.Properties.Add(configProperty);
140
141 CategorizedSettingsElementCollection settings = new CategorizedSettingsElementCollection
142 {
143 Name = sectionName,
144 Section = this,
145 };
146
147 settings.SetCryptoKey(m_cryptoKey);
148 Modified = true;
149
150 return settings;
151 });
114 }152 }
115 153
116 return settingsCategory;154 return settingsCategory;
@@ -129,6 +167,15 @@ namespace GSF.Configuration · 12 unmodified lines
129 }167 }
130 }168 }
131 169
170 internal bool Modified
171 {
172 set
173 {
174 if ((object)m_sections != null && (object)m_file != null && value)
175 m_file.m_forceSave = true;
176 }
177 }
178
132 #endregion179 #endregion
133 180
134 #region [ Methods ]181 #region [ Methods ]
@@ -159,7 +206,10 @@ namespace GSF.Configuration · 24 unmodified lines
159 }206 }
160 207
161 // Remove category from property bag.208 // Remove category from property bag.
162 base.Properties.Remove(settingsCategory.Name);209 if ((object)m_sections == null)
210 base.Properties.Remove(settingsCategory.Name);
211 else
212 m_sections.Remove(settingsCategory.Name);
163 }213 }
164 214
165 /// <summary>215 /// <summary>
@@ -181,19 +231,129 @@ namespace GSF.Configuration · 15 unmodified lines
181 // when the category elements are being deserialized.231 // when the category elements are being deserialized.
182 if ((object)configSection.DocumentElement != null)232 if ((object)configSection.DocumentElement != null)
183 {233 {
184 XmlNodeList nodeList = configSection.DocumentElement.SelectNodes("*");234 XmlNodeList categories = configSection.DocumentElement.SelectNodes("*");
185 235
186 if ((object)nodeList != null)236 if ((object)categories != null)
187 {237 {
188 foreach (XmlNode category in nodeList)238 foreach (XmlNode category in categories)
189 base.Properties.Add(new ConfigurationProperty(category.Name, typeof(CategorizedSettingsElementCollection)));239 {
240 ConfigurationProperty configProperty = new ConfigurationProperty(category.Name, typeof(CategorizedSettingsElementCollection));
241
242 base.Properties.Add(configProperty);
243
244 if ((object)m_sections != null)
245 {
246 CategorizedSettingsElementCollection settingsCategory = new CategorizedSettingsElementCollection
247 {
248 Name = category.Name,
249 Section = this,
250 };
251
252 settingsCategory.SetCryptoKey(m_cryptoKey);
253 m_sections.Add(category.Name, settingsCategory);
254
255 // Read all elements within this category section
256 XmlNodeList elements = category.SelectNodes("*");
257 SettingScope scope;
258
259 if ((object)elements != null)
260 {
261 foreach (XmlNode element in elements)
262 {
263 CategorizedSettingsElement categorySetting = new CategorizedSettingsElement(settingsCategory);
264
265 categorySetting.Name = element.GetAttributeValue("name");
266 categorySetting.Value = element.GetAttributeValue("value");
267 categorySetting.Description = element.GetAttributeValue("description") ?? "";
268 categorySetting.Encrypted = element.GetAttributeValue("encrypted").ToNonNullNorWhiteSpace("false").ParseBoolean();
269
270 if (Enum.TryParse(element.GetAttributeValue("scope").ToNonNullNorWhiteSpace("Application"), out scope))
271 categorySetting.Scope = scope;
272 else
273 categorySetting.Scope = SettingScope.Application;
274
275 settingsCategory.Add(categorySetting);
276 }
277 }
278 }
279 }
190 }280 }
191 }281 }
192 282
193 configSectionStream.Seek(0, SeekOrigin.Begin);283 if ((object)m_sections == null)
284 {
285 configSectionStream.Seek(0, SeekOrigin.Begin);
286 base.DeserializeSection(XmlReader.Create(configSectionStream));
287 }
288 }
289 }
290
291 /// <summary>
292 /// Creates an XML string containing an unmerged view of the <see cref="ConfigurationSection"/> object as a single section to write to a file.
293 /// </summary>
294 /// <returns>
295 /// An XML string containing an unmerged view of the <see cref="ConfigurationSection"/> object.
296 /// </returns>
297 /// <param name="parentElement">The <see cref="ConfigurationElement"/> instance to use as the parent when performing the un-merge.</param>
298 /// <param name="name">The name of the section to create.</param>
299 /// <param name="saveMode">The <see cref="ConfigurationSaveMode"/> instance to use when writing to a string.</param>
300 protected override string SerializeSection(ConfigurationElement parentElement, string name, ConfigurationSaveMode saveMode)
301 {
302 if ((object)m_sections != null)
303 {
304 const string tempRoot = "__tempRoot__";
305
306 using (BlockAllocatedMemoryStream stream = new BlockAllocatedMemoryStream())
307 {
308 XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8);
309
310 writer.Indentation = 2;
311 writer.Formatting = Formatting.Indented;
312
313 // Add a temporary root so that indentation is at the desired level
314 writer.WriteStartElement(tempRoot);
315 writer.WriteStartElement(name);
194 316
195 base.DeserializeSection(XmlReader.Create(configSectionStream));317 foreach (string section in m_sections.Keys)
318 {
319 CategorizedSettingsElementCollection categorySettings = this[section];
320
321 // Add category section
322 writer.WriteStartElement(section);
323
324 // Write each category value
325 foreach (CategorizedSettingsElement categorySetting in categorySettings)
326 {
327 // <add name="TestConfigParam" value="-1.0" description="Parameter description." encrypted="false" scope="User"/>
328 writer.WriteStartElement("add");
329
330 writer.WriteAttributeString("name", categorySetting.Name);
331 writer.WriteAttributeString("value", categorySetting.Value);
332 writer.WriteAttributeString("description", categorySetting.Description ?? "");
333 writer.WriteAttributeString("encrypted", categorySetting.Encrypted.ToString());
334
335 if (categorySetting.Scope == SettingScope.User)
336 writer.WriteAttributeString("scope", categorySetting.Scope.ToString());
337
338 writer.WriteEndElement();
339 }
340
341 writer.WriteEndElement();
342 }
343
344 writer.WriteEndElement();
345 writer.WriteEndElement();
346
347 writer.Flush();
348
349 string settings = Encoding.UTF8.GetString(stream.ToArray());
350
351 // Remove temporary root
352 return settings.Replace(string.Format("<{0}>", tempRoot), "").Replace(string.Format("</{0}>", tempRoot), "");
353 }
196 }354 }
355
356 return base.SerializeSection(parentElement, name, ConfigurationSaveMode.Full);
197 }357 }
198 358
199 #endregion359 #endregion
Source/Libraries/GSF.Core/Configuration/ConfigurationFile.cs+49−33
@@ -64,7 +64,6 @@ using System.Configuration; · 63 unmodified lines
64using System.Globalization;64using System.Globalization;
65using System.IO;65using System.IO;
66using System.Text;66using System.Text;
67using System.Threading;
68using System.Web.Configuration;67using System.Web.Configuration;
69using System.Web.Hosting;68using System.Web.Hosting;
70using System.Xml;69using System.Xml;
@@ -177,7 +176,6 @@ namespace GSF.Configuration · 106 unmodified lines
177 #region [ Members ]176 #region [ Members ]
178 177
179 // Nested Types178 // Nested Types
180
181 internal class UserConfigurationFile179 internal class UserConfigurationFile
182 {180 {
183 private readonly string m_fileName;181 private readonly string m_fileName;
@@ -229,6 +227,7 @@ namespace GSF.Configuration · 45 unmodified lines
229 public void Write(string category, string name, string value)227 public void Write(string category, string name, string value)
230 {228 {
231 XmlNode node = GetSetting(category, name);229 XmlNode node = GetSetting(category, name);
230
232 if ((object)node != null)231 if ((object)node != null)
233 {232 {
234 // Setting exists so update it.233 // Setting exists so update it.
@@ -242,18 +241,20 @@ namespace GSF.Configuration · 7 unmodified lines
242 setting.SetAttributeValue("value", value);241 setting.SetAttributeValue("value", value);
243 m_settings.GetXmlNode(category).AppendChild(setting);242 m_settings.GetXmlNode(category).AppendChild(setting);
244 }243 }
244
245 m_settingsModified = true;245 m_settingsModified = true;
246 }246 }
247 247
248 public string Read(string category, string name, string defaultValue)248 public string Read(string category, string name, string defaultValue)
249 {249 {
250 XmlNode node = GetSetting(category, name);250 XmlNode node = GetSetting(category, name);
251 if ((object)node != null)251
252 // Setting exists so return its value.252 // If setting exists, return its value
253 if ((object)node != null && (object)node.Attributes != null)
253 return node.Attributes["value"].Value;254 return node.Attributes["value"].Value;
254 else255
255 // Setting doesn't exist so return the default.256 // Setting doesn't exist so return the default
256 return defaultValue;257 return defaultValue;
257 }258 }
258 259
259 public XmlNode GetSetting(string category, string name)260 public XmlNode GetSetting(string category, string name)
@@ -272,7 +273,8 @@ namespace GSF.Configuration · 12 unmodified lines
272 private System.Configuration.Configuration m_configuration;273 private System.Configuration.Configuration m_configuration;
273 private UserConfigurationFile m_userConfiguration;274 private UserConfigurationFile m_userConfiguration;
274 private volatile ConfigurationSaveMode m_saveMode;275 private volatile ConfigurationSaveMode m_saveMode;
275 private LongSynchronizedOperation m_saveOperation;276 private readonly LongSynchronizedOperation m_saveOperation;
277 internal bool m_forceSave;
276 278
277 #endregion279 #endregion
278 280
@@ -288,7 +290,7 @@ namespace GSF.Configuration · 9 unmodified lines
288 290
289 m_configuration = GetConfiguration(configFilePath);291 m_configuration = GetConfiguration(configFilePath);
290 292
291 if (m_configuration.HasFile)293 if (m_configuration.HasFile && File.Exists(m_configuration.FilePath))
292 ValidateConfigurationFile(m_configuration.FilePath);294 ValidateConfigurationFile(m_configuration.FilePath);
293 else295 else
294 CreateConfigurationFile(m_configuration.FilePath);296 CreateConfigurationFile(m_configuration.FilePath);
@@ -364,7 +366,7 @@ namespace GSF.Configuration · 69 unmodified lines
364 /// </summary>366 /// </summary>
365 public void Save()367 public void Save()
366 {368 {
367 Save(ConfigurationSaveMode.Modified);369 Save(m_forceSave ? ConfigurationSaveMode.Full : ConfigurationSaveMode.Modified);
368 }370 }
369 371
370 /// <summary>372 /// <summary>
@@ -373,8 +375,7 @@ namespace GSF.Configuration · 2 unmodified lines
373 /// <param name="saveMode">One of the <see cref="ConfigurationSaveMode"/> values.</param>375 /// <param name="saveMode">One of the <see cref="ConfigurationSaveMode"/> values.</param>
374 public void Save(ConfigurationSaveMode saveMode)376 public void Save(ConfigurationSaveMode saveMode)
375 {377 {
376 if (m_saveMode == ConfigurationSaveMode.Minimal || saveMode == ConfigurationSaveMode.Full)378 m_saveMode = saveMode;
377 m_saveMode = saveMode;
378 379
379 // Since the static open method always returns the same instance for the same configuration files,380 // Since the static open method always returns the same instance for the same configuration files,
380 // synchronizing the instance will sync all saves.381 // synchronizing the instance will sync all saves.
@@ -385,9 +386,10 @@ namespace GSF.Configuration · 4 unmodified lines
385 {386 {
386 // Perform configuration save387 // Perform configuration save
387 ConfigurationSaveMode saveMode = m_saveMode;388 ConfigurationSaveMode saveMode = m_saveMode;
388 m_configuration.Save(saveMode);389 m_configuration.Save(saveMode, m_forceSave);
389 m_userConfiguration.Save(saveMode == ConfigurationSaveMode.Full);390 m_userConfiguration.Save(saveMode == ConfigurationSaveMode.Full);
390 m_saveMode = ConfigurationSaveMode.Minimal;391 m_saveMode = ConfigurationSaveMode.Minimal;
392 m_forceSave = false;
391 }393 }
392 394
393 /// <summary>395 /// <summary>
@@ -436,7 +438,7 @@ namespace GSF.Configuration · 42 unmodified lines
436 private System.Configuration.Configuration GetConfiguration(string configFilePath)438 private System.Configuration.Configuration GetConfiguration(string configFilePath)
437 {439 {
438 ApplicationType appType = Common.GetApplicationType();440 ApplicationType appType = Common.GetApplicationType();
439 System.Configuration.Configuration configuration = null;441 System.Configuration.Configuration configuration;
440 442
441 if ((object)configFilePath != null)443 if ((object)configFilePath != null)
442 {444 {
@@ -475,13 +477,15 @@ namespace GSF.Configuration · 32 unmodified lines
475 if (!string.IsNullOrEmpty(configFilePath))477 if (!string.IsNullOrEmpty(configFilePath))
476 {478 {
477 XmlTextWriter configFileWriter = new XmlTextWriter(configFilePath, Encoding.UTF8);479 XmlTextWriter configFileWriter = new XmlTextWriter(configFilePath, Encoding.UTF8);
478 configFileWriter.Indentation = 4;480 configFileWriter.Indentation = 2;
479 configFileWriter.Formatting = Formatting.Indented;481 configFileWriter.Formatting = Formatting.Indented;
482
480 // Populates the very basic information required in a config file.483 // Populates the very basic information required in a config file.
481 configFileWriter.WriteStartDocument();484 configFileWriter.WriteStartDocument();
482 configFileWriter.WriteStartElement("configuration");485 configFileWriter.WriteStartElement("configuration");
483 configFileWriter.WriteEndElement();486 configFileWriter.WriteEndElement();
484 configFileWriter.WriteEndDocument();487 configFileWriter.WriteEndDocument();
488
485 // Closes the config file.489 // Closes the config file.
486 configFileWriter.Close();490 configFileWriter.Close();
487 491
@@ -505,32 +509,44 @@ namespace GSF.Configuration · 17 unmodified lines
505 // Make sure that the config file has the necessary section information under <customSections />509 // Make sure that the config file has the necessary section information under <customSections />
506 // that is required by the .Net configuration API to process our custom <categorizedSettings />510 // that is required by the .Net configuration API to process our custom <categorizedSettings />
507 // section. The configuration API will raise an exception if it doesn't find this section.511 // section. The configuration API will raise an exception if it doesn't find this section.
508 if (configFile.DocumentElement.SelectNodes("configSections").Count == 0)512 if ((object)configFile.DocumentElement != null)
509 {513 {
510 // Adds a <configSections> node, if one is not present.514 XmlNodeList configSections = configFile.DocumentElement.SelectNodes("configSections");
511 configFile.DocumentElement.InsertBefore(configFile.CreateElement("configSections"), configFile.DocumentElement.FirstChild);
512 515
513 configFileModified = true;516 if ((object)configSections != null && configSections.Count == 0)
514 }517 {
515 XmlNode configSectionsNode = configFile.DocumentElement.SelectSingleNode("configSections");518 // Add a <configSections> node, if one is not present.
516 if (configSectionsNode.SelectNodes("section[@name = \'" + CustomSectionName + "\']").Count == 0)519 if ((object)configFile.DocumentElement != null)
517 {520 {
518 // Adds the <section> node that specifies the DLL that handles the <categorizedSettings> node in521 // ReSharper disable once PossibleNullReferenceException
519 // the config file, if one is not present.522 configFile.DocumentElement.InsertBefore(configFile.CreateElement("configSections"), configFile.DocumentElement.FirstChild);
520 XmlNode node = configFile.CreateElement("section");523 configFileModified = true;
521 node.SetAttributeValue("name", CustomSectionName);524 }
522 node.SetAttributeValue("type", CustomSectionType);525 }
523 configSectionsNode.AppendChild(node);526
524 527 XmlNode configSectionsNode = configFile.DocumentElement.SelectSingleNode("configSections");
525 configFileModified = true;528
529 if ((object)configSectionsNode != null)
530 {
531 XmlNodeList section = configSectionsNode.SelectNodes("section[@name = \'" + CustomSectionName + "\']");
532
533 if ((object)section != null && section.Count == 0)
534 {
535 // Adds the <section> node that specifies the DLL that handles the <categorizedSettings> node in
536 // the config file, if one is not present.
537 XmlNode node = configFile.CreateElement("section");
538 node.SetAttributeValue("name", CustomSectionName);
539 node.SetAttributeValue("type", CustomSectionType);
540 configSectionsNode.AppendChild(node);
541 configFileModified = true;
542 }
543 }
526 }544 }
527 545
528 // 11/14/2006 - PCP: We'll save the config file only it was modified. This will prevent ASP.Net546 // 11/14/2006 - PCP: We'll save the config file only it was modified. This will prevent ASP.Net
529 // web sites from restarting every time a configuration element is accessed.547 // web sites from restarting every time a configuration element is accessed.
530 if (configFileModified)548 if (configFileModified)
531 {
532 configFile.Save(configFilePath);549 configFile.Save(configFilePath);
533 }
534 }550 }
535 else551 else
536 {552 {
Source/Libraries/GSF.Core/Identity/UnixUserInfo.cs+113−57
@@ -54,11 +54,15 @@ namespace GSF.Identity · 53 unmodified lines
54 #region [ Members ]54 #region [ Members ]
55 55
56 // Nested Types56 // Nested Types
57
58 // ReSharper disable UnusedMember.Local
57 private class UnixIdentity : WindowsIdentity59 private class UnixIdentity : WindowsIdentity
58 {60 {
59 #region [ Members ]61 #region [ Members ]
60 62
61 // Fields63 // Fields
64 private readonly string m_domain;
65 private readonly string m_userName;
62 private LdapConnection m_connection;66 private LdapConnection m_connection;
63 private string m_providerType;67 private string m_providerType;
64 private string m_ldapRoot;68 private string m_ldapRoot;
@@ -70,22 +74,51 @@ namespace GSF.Identity · 5 unmodified lines
70 74
71 #region [ Constructors ]75 #region [ Constructors ]
72 76
73 public UnixIdentity(string userName, LdapConnection connection = null)77 public UnixIdentity(string domain, string userName, LdapConnection connection = null)
74 : base(GetUserIDAsToken(userName), null, WindowsAccountType.Normal, true)78 : base(GetUserIDAsToken(domain, userName), null, WindowsAccountType.Normal, true)
75 {79 {
80 m_domain = domain;
81 m_userName = userName;
76 Connection = connection;82 Connection = connection;
77 83
78 // Cache shadow information before possible reduction in privileges84 if (UserInfo.IsLocalDomain(domain))
79 if (GetLocalUserPasswordInformation(userName, ref m_userPasswordInformation, out m_accountStatus) == 0)85 {
80 m_loadedUserPasswordInformation = true;86 // Cache shadow information for local user before possible reduction in privileges
81 else87 if (GetLocalUserPasswordInformation(userName, ref m_userPasswordInformation, out m_accountStatus) == 0)
82 m_accountStatus = AccountStatus.Disabled;88 m_loadedUserPasswordInformation = true;
89 else
90 m_accountStatus = AccountStatus.Disabled;
91 }
83 }92 }
84 93
85 #endregion94 #endregion
86 95
87 #region [ Properties ]96 #region [ Properties ]
88 97
98 public string Domain
99 {
100 get
101 {
102 return m_domain;
103 }
104 }
105
106 public string UserName
107 {
108 get
109 {
110 return m_userName;
111 }
112 }
113
114 public string LoginID
115 {
116 get
117 {
118 return string.Format("{0}\\{1}", m_domain, m_userName);
119 }
120 }
121
89 public string ProviderType122 public string ProviderType
90 {123 {
91 get124 get
@@ -115,7 +148,7 @@ namespace GSF.Identity · 23 unmodified lines
115 148
116 if ((object)m_connection != null)149 if ((object)m_connection != null)
117 {150 {
118 // Extract LDAP root distinguished name151 // Extract LDAP search root distinguished name
119 StringBuilder ldapRoot = new StringBuilder();152 StringBuilder ldapRoot = new StringBuilder();
120 string[] elements = m_connection.GetSchemaDN().Split(',');153 string[] elements = m_connection.GetSchemaDN().Split(',');
121 154
@@ -169,9 +202,14 @@ namespace GSF.Identity · 47 unmodified lines
169 202
170 #region [ Static ]203 #region [ Static ]
171 204
172 private static IntPtr GetUserIDAsToken(string userName)205 private static IntPtr GetUserIDAsToken(string domain, string userName)
173 {206 {
174 uint userID;207 uint userID;
208
209 // TODO: What to do if Linux stores mapped LDAP users as userName@domain? Format setting in config file?
210 if (!UserInfo.IsLocalDomain(domain))
211 userName = string.Format("{0}\\{1}", domain, userName);
212
175 return GetLocalUserID(userName, out userID) == 0 ? new IntPtr(userID) : IntPtr.Zero;213 return GetLocalUserID(userName, out userID) == 0 ? new IntPtr(userID) : IntPtr.Zero;
176 }214 }
177 215
@@ -707,13 +745,14 @@ namespace GSF.Identity · 529 unmodified lines
707 745
708 // Pick up current user or impersonated user principal746 // Pick up current user or impersonated user principal
709 WindowsPrincipal principal = Thread.CurrentPrincipal as WindowsPrincipal;747 WindowsPrincipal principal = Thread.CurrentPrincipal as WindowsPrincipal;
748 UnixIdentity identity = null;
710 749
711 if ((object)principal != null)750 if ((object)principal != null)
712 {751 {
713 UnixIdentity identity = principal.Identity as UnixIdentity;752 identity = principal.Identity as UnixIdentity;
714 753
715 // If domain user has already been authenticated, we should already have an active LDAP connection754 // If domain user has already been authenticated, we should already have an active LDAP connection
716 if ((object)identity != null)755 if ((object)identity != null && identity.LoginID.Equals(m_parent.LoginID, StringComparison.InvariantCultureIgnoreCase))
717 {756 {
718 m_connection = identity.Connection;757 m_connection = identity.Connection;
719 m_ldapRoot = identity.LdapRoot ?? m_parent.Domain;758 m_ldapRoot = identity.LdapRoot ?? m_parent.Domain;
@@ -741,7 +780,18 @@ namespace GSF.Identity · 21 unmodified lines
741 }780 }
742 else781 else
743 {782 {
744 throw new InvalidOperationException("Failed to get a valid LDAP connection");783 // If PAM authentication succeeded but no LDAP connection can be found, we attempt to treat this user as local
784 if ((object)identity != null && identity.LoginID.Equals(m_parent.LoginID, StringComparison.InvariantCultureIgnoreCase))
785 {
786 m_isLocalAccount = true;
787 m_enabled = true;
788 m_domainRespondsForUser = false;
789 m_parent.UserAccountControl = -1;
790 }
791 else
792 {
793 throw new InvalidOperationException("No valid LDAP connection was found or user is not authenticated");
794 }
745 }795 }
746 }796 }
747 catch (Exception ex)797 catch (Exception ex)
@@ -749,7 +799,7 @@ namespace GSF.Identity · 1 unmodified line
749 m_userEntry = null;799 m_userEntry = null;
750 m_domainRespondsForUser = false;800 m_domainRespondsForUser = false;
751 801
752 throw new InitializationException(string.Format("Failed to initialize directory entry for domain user '{0}'", m_parent.LoginID), ex);802 throw new InitializationException(string.Format("Failed to initialize LDAP entry for domain user '{0}': {1}", m_parent.LoginID, ex.Message), ex);
753 }803 }
754 finally804 finally
755 {805 {
@@ -880,7 +930,7 @@ namespace GSF.Identity · 124 unmodified lines
880 return s_builtInLocalGroups;930 return s_builtInLocalGroups;
881 }931 }
882 932
883 public static IPrincipal AuthenticateUser(string domain, string username, string password, out string errorMessage)933 public static IPrincipal AuthenticateUser(string domain, string userName, string password, out string errorMessage)
884 {934 {
885 WindowsPrincipal principal = null;935 WindowsPrincipal principal = null;
886 int responseCode;936 int responseCode;
@@ -888,28 +938,33 @@ namespace GSF.Identity · 1 unmodified line
888 938
889 if (UserInfo.IsLocalDomain(domain))939 if (UserInfo.IsLocalDomain(domain))
890 {940 {
891 responseCode = AuthenticateUser(username, password);941 // Set the domain as the local machine if one is not specified
942 if (string.IsNullOrEmpty(domain))
943 domain = Environment.MachineName;
944
945 responseCode = AuthenticateUser(userName, password);
892 946
893 if (responseCode == 0)947 if (responseCode == 0)
894 principal = new WindowsPrincipal(new UnixIdentity(username));948 principal = new WindowsPrincipal(new UnixIdentity(domain, userName));
895 else949 else
896 errorMessage = string.Format("Failed to authenticate \"{0}\": {1}", username, GetPAMErrorMessage(responseCode));950 errorMessage = string.Format("Failed to authenticate \"{0}\": {1}", userName, GetPAMErrorMessage(responseCode));
897 }951 }
898 else952 else
899 {953 {
900 // Attempt PAM based authentication first - if configured, this will be the best option954 // Attempt PAM based authentication first - if configured, this will be the best option
901 string domainUserName = string.Format("{0}\\{1}", domain, username);955 string domainUserName = string.Format("{0}\\{1}", domain, userName);
902 956
903 responseCode = AuthenticateUser(domainUserName, password);957 responseCode = AuthenticateUser(domainUserName, password);
904 958
905 if (responseCode == 0)959 if (responseCode == 0)
906 principal = new WindowsPrincipal(new UnixIdentity(domainUserName));960 principal = new WindowsPrincipal(new UnixIdentity(domain, userName));
907 961
908 string ldapPath = GetLdapPath();962 // Try really hard to find a configured LDAP host
963 string ldapHost = GetLdapHost();
909 964
910 // If LDAP path cannot be determined, no LdapConnection can be established - if authentication965 // If LDAP host cannot be determined, no LdapConnection can be established - if authentication
911 // succeeded, user will be treated as a local user966 // succeeded, user will be treated as a local user
912 if ((object)ldapPath == null)967 if ((object)ldapHost == null)
913 {968 {
914 if ((object)principal == null)969 if ((object)principal == null)
915 errorMessage = string.Format("Failed to authenticate \"{0}\": {1}", domainUserName, GetPAMErrorMessage(responseCode));970 errorMessage = string.Format("Failed to authenticate \"{0}\": {1}", domainUserName, GetPAMErrorMessage(responseCode));
@@ -924,18 +979,18 @@ namespace GSF.Identity · 8 unmodified lines
924 // Attempt LDAP account authentication 979 // Attempt LDAP account authentication
925 LdapConnection connection = new LdapConnection();980 LdapConnection connection = new LdapConnection();
926 981
927 if (ldapPath.StartsWith("LDAP", StringComparison.OrdinalIgnoreCase))982 if (ldapHost.StartsWith("LDAP", StringComparison.OrdinalIgnoreCase))
928 {983 {
929 Uri ldapURI = new Uri(ldapPath);984 Uri ldapURI = new Uri(ldapHost);
930 ldapPath = ldapURI.Host + (ldapURI.Port == 0 ? "" : ":" + ldapURI.Port);985 ldapHost = ldapURI.Host + (ldapURI.Port == 0 ? "" : ":" + ldapURI.Port);
931 }986 }
932 987
933 // If host LDAP path contains suffixed port number, this will be preferred over specified 389 default988 // If host LDAP path contains suffixed port number, this will be preferred over specified 389 default
934 connection.Connect(ldapPath, 389);989 connection.Connect(ldapHost, 389);
935 connection.Bind(string.Format("{0}@{1}", username, domain), password);990 connection.Bind(string.Format("{0}@{1}", userName, domain), password);
936 991
937 if ((object)principal == null)992 if ((object)principal == null)
938 principal = new WindowsPrincipal(new UnixIdentity(domainUserName, connection));993 principal = new WindowsPrincipal(new UnixIdentity(domain, userName, connection));
939 else994 else
940 ((UnixIdentity)principal.Identity).Connection = connection;995 ((UnixIdentity)principal.Identity).Connection = connection;
941 }996 }
@@ -951,11 +1006,11 @@ namespace GSF.Identity · 9 unmodified lines
951 return principal;1006 return principal;
952 }1007 }
953 1008
954 private static string GetLdapPath()1009 private static string GetLdapHost()
955 {1010 {
956 string ldapPath = null;1011 string ldapHost = null;
957 1012
958 // Attempt to derive an LDAP path from a Samba configuration @ /etc/samba/smb.conf looking for key "realm"1013 // Attempt to derive an LDAP host from a Samba configuration @ /etc/samba/smb.conf looking for key "realm"
959 try1014 try
960 {1015 {
961 const string smbConfFileName = "/etc/samba/smb.conf";1016 const string smbConfFileName = "/etc/samba/smb.conf";
@@ -979,7 +1034,7 @@ namespace GSF.Identity · 17 unmodified lines
979 string[] parts = line.Split('=');1034 string[] parts = line.Split('=');
980 1035
981 if (parts.Length > 1)1036 if (parts.Length > 1)
982 ldapPath = parts[1].Trim();1037 ldapHost = parts[1].Trim();
983 1038
984 break;1039 break;
985 }1040 }
@@ -991,11 +1046,11 @@ namespace GSF.Identity · 5 unmodified lines
991 }1046 }
992 catch1047 catch
993 {1048 {
994 ldapPath = null;1049 ldapHost = null;
995 }1050 }
996 1051
997 // If LDAP path has not been derived yet, attempt to derive an LDAP path from an OpenLDAP configuration @ /etc/openldap/ldap.conf looking for key "URI"1052 // If LDAP host has not been derived yet, attempt to derive an LDAP host from an OpenLDAP configuration @ /etc/openldap/ldap.conf looking for key "URI"
998 if (string.IsNullOrEmpty(ldapPath))1053 if (string.IsNullOrEmpty(ldapHost))
999 {1054 {
1000 try1055 try
1001 {1056 {
@@ -1017,7 +1072,7 @@ namespace GSF.Identity · 15 unmodified lines
1017 1072
1018 if (line.StartsWith("URI", StringComparison.OrdinalIgnoreCase) && line.Length > 3)1073 if (line.StartsWith("URI", StringComparison.OrdinalIgnoreCase) && line.Length > 3)
1019 {1074 {
1020 ldapPath = line.Substring(3).Trim();1075 ldapHost = line.Substring(3).Trim();
1021 break;1076 break;
1022 }1077 }
1023 }1078 }
@@ -1028,12 +1083,12 @@ namespace GSF.Identity · 4 unmodified lines
1028 }1083 }
1029 catch1084 catch
1030 {1085 {
1031 ldapPath = null;1086 ldapHost = null;
1032 }1087 }
1033 }1088 }
1034 1089
1035 // If LDAP path has not been derived yet, attempt to derive an LDAP path from a Centrify DirectControl Express adinfo call looking for key "Joined to domain:"1090 // If LDAP host has not been derived yet, attempt to derive an LDAP host from a Centrify DirectControl Express adinfo call looking for key "Joined to domain:"
1036 if (string.IsNullOrEmpty(ldapPath))1091 if (string.IsNullOrEmpty(ldapHost))
1037 {1092 {
1038 try1093 try
1039 {1094 {
@@ -1054,7 +1109,7 @@ namespace GSF.Identity · 14 unmodified lines
1054 string[] parts = line.Split(':');1109 string[] parts = line.Split(':');
1055 1110
1056 if (parts.Length > 1)1111 if (parts.Length > 1)
1057 ldapPath = parts[1].Trim();1112 ldapHost = parts[1].Trim();
1058 1113
1059 break;1114 break;
1060 }1115 }
@@ -1065,12 +1120,12 @@ namespace GSF.Identity · 4 unmodified lines
1065 }1120 }
1066 catch1121 catch
1067 {1122 {
1068 ldapPath = null;1123 ldapHost = null;
1069 }1124 }
1070 }1125 }
1071 1126
1072 // If LDAP path has not been derived yet, attempt to derive an LDAP path from a LikewiseOpen / Beyond Trust lw-get-status call looking for key "Domain:"1127 // If LDAP host has not been derived yet, attempt to derive an LDAP host from a LikewiseOpen / Beyond Trust lw-get-status call looking for key "Domain:"
1073 if (string.IsNullOrEmpty(ldapPath))1128 if (string.IsNullOrEmpty(ldapHost))
1074 {1129 {
1075 try1130 try
1076 {1131 {
@@ -1091,7 +1146,7 @@ namespace GSF.Identity · 14 unmodified lines
1091 string[] parts = line.Split(':');1146 string[] parts = line.Split(':');
1092 1147
1093 if (parts.Length > 1)1148 if (parts.Length > 1)
1094 ldapPath = parts[1].Trim();1149 ldapHost = parts[1].Trim();
1095 1150
1096 break;1151 break;
1097 }1152 }
@@ -1102,12 +1157,12 @@ namespace GSF.Identity · 4 unmodified lines
1102 }1157 }
1103 catch1158 catch
1104 {1159 {
1105 ldapPath = null;1160 ldapHost = null;
1106 }1161 }
1107 }1162 }
1108 1163
1109 // If LDAP path has not been derived yet, attempt to derive an LDAP path from the configuration for known GSF security providers1164 // If LDAP host has not been derived yet, attempt to derive an LDAP host from the configuration for known GSF security providers
1110 if (string.IsNullOrEmpty(ldapPath))1165 if (string.IsNullOrEmpty(ldapHost))
1111 {1166 {
1112 try1167 try
1113 {1168 {
@@ -1119,37 +1174,37 @@ namespace GSF.Identity · 5 unmodified lines
1119 {1174 {
1120 // In AdoSecurityProvider the ConnectionString setting is used for database connection1175 // In AdoSecurityProvider the ConnectionString setting is used for database connection
1121 // to load role based security -- so it adds a new setting for actual LdapPath1176 // to load role based security -- so it adds a new setting for actual LdapPath
1122 ldapPath = settings["LdapPath"].Value;1177 ldapHost = settings["LdapPath"].Value;
1123 }1178 }
1124 catch1179 catch
1125 {1180 {
1126 ldapPath = null;1181 ldapHost = null;
1127 }1182 }
1128 1183
1129 // Otherwise, attempt to get LDAP path defined by LdapSecurityProvider1184 // Otherwise, attempt to get LDAP path defined by LdapSecurityProvider
1130 if ((object)ldapPath == null)1185 if ((object)ldapHost == null)
1131 {1186 {
1132 string ldapConnectionString = settings["ConnectionString"].Value;1187 string ldapConnectionString = settings["ConnectionString"].Value;
1133 1188
1134 if (ldapConnectionString.StartsWith("LDAP://", StringComparison.OrdinalIgnoreCase) ||1189 if (ldapConnectionString.StartsWith("LDAP://", StringComparison.OrdinalIgnoreCase) ||
1135 ldapConnectionString.StartsWith("LDAPS://", StringComparison.OrdinalIgnoreCase))1190 ldapConnectionString.StartsWith("LDAPS://", StringComparison.OrdinalIgnoreCase))
1136 ldapPath = ldapConnectionString;1191 ldapHost = ldapConnectionString;
1137 1192
1138 foreach (KeyValuePair<string, string> pair in ldapConnectionString.ParseKeyValuePairs())1193 foreach (KeyValuePair<string, string> pair in ldapConnectionString.ParseKeyValuePairs())
1139 {1194 {
1140 if (pair.Value.StartsWith("LDAP://", StringComparison.OrdinalIgnoreCase) ||1195 if (pair.Value.StartsWith("LDAP://", StringComparison.OrdinalIgnoreCase) ||
1141 pair.Value.StartsWith("LDAPS://", StringComparison.OrdinalIgnoreCase))1196 pair.Value.StartsWith("LDAPS://", StringComparison.OrdinalIgnoreCase))
1142 ldapPath = pair.Value;1197 ldapHost = pair.Value;
1143 }1198 }
1144 }1199 }
1145 }1200 }
1146 catch1201 catch
1147 {1202 {
1148 ldapPath = null;1203 ldapHost = null;
1149 }1204 }
1150 }1205 }
1151 1206
1152 return ldapPath;1207 return ldapHost;
1153 }1208 }
1154 1209
1155 public static WindowsImpersonationContext ImpersonateUser(string domain, string userName, string password)1210 public static WindowsImpersonationContext ImpersonateUser(string domain, string userName, string password)
@@ -1535,7 +1590,8 @@ namespace GSF.Identity · 379 unmodified lines
1535 1590
1536 private static int GetCachedLocalUserPasswordInformation(string userName, out UserPasswordInformation userPasswordInformation, out AccountStatus accountStatus)1591 private static int GetCachedLocalUserPasswordInformation(string userName, out UserPasswordInformation userPasswordInformation, out AccountStatus accountStatus)
1537 {1592 {
1538 // Attempt to pick up Unix user principal identity in case shadow information has already been parsed1593 // Attempt to retrieve Unix user principal identity in case shadow information has already been parsed, in most
1594 // cases we will have already reduced rights needed to read this information so we pick up pre-parsed info
1539 WindowsPrincipal principal = Thread.CurrentPrincipal as WindowsPrincipal;1595 WindowsPrincipal principal = Thread.CurrentPrincipal as WindowsPrincipal;
1540 1596
1541 if ((object)principal != null)1597 if ((object)principal != null)
@@ -1543,7 +1599,7 @@ namespace GSF.Identity · 1 unmodified line
1543 UnixIdentity identity = principal.Identity as UnixIdentity;1599 UnixIdentity identity = principal.Identity as UnixIdentity;
1544 1600
1545 // If user has already been authenticated, we can load pre-parsed shadow information1601 // If user has already been authenticated, we can load pre-parsed shadow information
1546 if ((object)identity != null && identity.LoadedUserPasswordInformation)1602 if ((object)identity != null && identity.LoadedUserPasswordInformation && identity.UserName.Equals(userName, StringComparison.InvariantCultureIgnoreCase))
1547 {1603 {
1548 userPasswordInformation = identity.UserPasswordInformation;1604 userPasswordInformation = identity.UserPasswordInformation;
1549 accountStatus = identity.AccountStatus;1605 accountStatus = identity.AccountStatus;
@@ -1614,7 +1670,7 @@ namespace GSF.Identity · 64 unmodified lines
1614 case PAMResponseCode.PAM_AUTHTOK_DISABLE_AGING:1670 case PAMResponseCode.PAM_AUTHTOK_DISABLE_AGING:
1615 return "Authentication token aging has been disabled for at least one of the modules.";1671 return "Authentication token aging has been disabled for at least one of the modules.";
1616 case PAMResponseCode.PAM_PERM_DENIED:1672 case PAMResponseCode.PAM_PERM_DENIED:
1617 return "Permission denied.";1673 return "Permission denied. Validate user credentials.";
1618 case PAMResponseCode.PAM_TRY_AGAIN:1674 case PAMResponseCode.PAM_TRY_AGAIN:
1619 return "Not all of the modules were in a position to update the authentication token(s). None of the user's authentication tokens were updated.";1675 return "Not all of the modules were in a position to update the authentication token(s). None of the user's authentication tokens were updated.";
1620 default:1676 default:
Source/Libraries/GSF.Core/Xml/XmlExtensions.cs+35−25
@@ -30,8 +30,6 @@ · 29 unmodified lines
30// Edited Comments.30// Edited Comments.
31// 09/14/2009 - Stephen C. Wills31// 09/14/2009 - Stephen C. Wills
32// Added new header and license agreement.32// Added new header and license agreement.
33// 12/14/2012 - Starlynn Danyelle Gilliam
34// Modifed Header.
35//33//
36//******************************************************************************************************34//******************************************************************************************************
37 35
@@ -105,15 +103,21 @@ namespace GSF.Xml · 67 unmodified lines
105 {103 {
106 XmlNodeList nodes = parentNode.SelectNodes(xpath);104 XmlNodeList nodes = parentNode.SelectNodes(xpath);
107 105
108 if (nodes.Count == 0)106 if ((object)nodes != null)
109 {107 {
110 node = parentNode.OwnerDocument.CreateElement(xpath);108 if (nodes.Count == 0)
111 parentNode.AppendChild(node);109 {
112 isDirty = true;110 if ((object)parentNode.OwnerDocument != null)
113 }111 {
114 else112 node = parentNode.OwnerDocument.CreateElement(xpath);
115 {113 parentNode.AppendChild(node);
116 node = nodes[0];114 isDirty = true;
115 }
116 }
117 else
118 {
119 node = nodes[0];
120 }
117 }121 }
118 }122 }
119 else123 else
@@ -135,16 +139,15 @@ namespace GSF.Xml · 15 unmodified lines
135 /// <returns>A <see cref="System.String"/> value returned for the attribute's value.</returns>139 /// <returns>A <see cref="System.String"/> value returned for the attribute's value.</returns>
136 public static string GetAttributeValue(this XmlNode node, string name)140 public static string GetAttributeValue(this XmlNode node, string name)
137 {141 {
138 XmlAttribute attr = node.Attributes[name];142 if ((object)node == null || (object)node.Attributes == null)
143 return null;
139 144
140 if ((object)attr == null)145 XmlAttribute attribute = node.Attributes[name];
141 {146
147 if ((object)attribute == null)
142 return null;148 return null;
143 }149
144 else150 return attribute.Value;
145 {
146 return attr.Value;
147 }
148 }151 }
149 152
150 /// <summary>Safely sets an XML node's attribute.</summary>153 /// <summary>Safely sets an XML node's attribute.</summary>
@@ -154,19 +157,26 @@ namespace GSF.Xml · 3 unmodified lines
154 /// <param name="value">A <see cref="System.String"/> value to set the node attribute's value to.</param>157 /// <param name="value">A <see cref="System.String"/> value to set the node attribute's value to.</param>
155 public static void SetAttributeValue(this XmlNode node, string name, string value)158 public static void SetAttributeValue(this XmlNode node, string name, string value)
156 {159 {
157 XmlAttribute attr = node.Attributes[name];160 if ((object)node == null || (object)node.Attributes == null)
161 return;
162
163 XmlAttribute attribute = node.Attributes[name];
158 164
159 if ((object)attr == null)165 if ((object)attribute == null)
160 {166 {
161 // Add the attribute.167 // Add the attribute.
162 attr = node.OwnerDocument.CreateAttribute(name);168 if ((object)node.OwnerDocument != null)
163 node.Attributes.Append(attr);169 {
170 attribute = node.OwnerDocument.CreateAttribute(name);
171 attribute.Value = value;
172 node.Attributes.Append(attribute);
173 }
164 }174 }
165 if ((object)attr != null)175 else
166 {176 {
167 // Set the attribute value.177 // Set the attribute value.
168 attr.Value = value;178 attribute.Value = value;
169 node.Attributes.SetNamedItem(attr);179 node.Attributes.SetNamedItem(attribute);
170 }180 }
171 }181 }
172 182
Source/Tools/ConfigTest/App.config+14−0
@@ -0,0 +1,14 @@
1<?xml version="1.0" encoding="utf-8" ?>
2<configuration>
3 <configSections>
4 <section name="categorizedSettings" type="GSF.Configuration.CategorizedSettingsSection, GSF.Core" />
5 </configSections>
6 <categorizedSettings>
7 <systemSettings>
8 <add name="connectionString" value="nope" description="Test" encrypted="false" />
9 </systemSettings>
10 </categorizedSettings>
11 <startup>
12 <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
13 </startup>
14</configuration>
Source/Tools/ConfigTest/ConfigTest.csproj+71−0
@@ -0,0 +1,71 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4 <PropertyGroup>
5 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7 <ProjectGuid>{B38AC5E5-B880-43E9-8F88-107294F3E69F}</ProjectGuid>
8 <OutputType>Exe</OutputType>
9 <AppDesignerFolder>Properties</AppDesignerFolder>
10 <RootNamespace>ConfigTest</RootNamespace>
11 <AssemblyName>ConfigTest</AssemblyName>
12 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
13 <FileAlignment>512</FileAlignment>
14 <SccProjectName>SAK</SccProjectName>
15 <SccLocalPath>SAK</SccLocalPath>
16 <SccAuxPath>SAK</SccAuxPath>
17 <SccProvider>SAK</SccProvider>
18 </PropertyGroup>
19 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
20 <PlatformTarget>AnyCPU</PlatformTarget>
21 <DebugSymbols>true</DebugSymbols>
22 <DebugType>full</DebugType>
23 <Optimize>false</Optimize>
24 <OutputPath>bin\Debug\</OutputPath>
25 <DefineConstants>DEBUG;TRACE</DefineConstants>
26 <ErrorReport>prompt</ErrorReport>
27 <WarningLevel>4</WarningLevel>
28 </PropertyGroup>
29 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
30 <PlatformTarget>AnyCPU</PlatformTarget>
31 <DebugType>pdbonly</DebugType>
32 <Optimize>true</Optimize>
33 <OutputPath>bin\Release\</OutputPath>
34 <DefineConstants>TRACE</DefineConstants>
35 <ErrorReport>prompt</ErrorReport>
36 <WarningLevel>4</WarningLevel>
37 </PropertyGroup>
38 <ItemGroup>
39 <Reference Include="System" />
40 <Reference Include="System.Configuration" />
41 <Reference Include="System.Core" />
42 <Reference Include="System.Xml.Linq" />
43 <Reference Include="System.Data.DataSetExtensions" />
44 <Reference Include="Microsoft.CSharp" />
45 <Reference Include="System.Data" />
46 <Reference Include="System.Xml" />
47 </ItemGroup>
48 <ItemGroup>
49 <Compile Include="Program.cs" />
50 <Compile Include="Properties\AssemblyInfo.cs" />
51 </ItemGroup>
52 <ItemGroup>
53 <None Include="App.config">
54 <SubType>Designer</SubType>
55 </None>
56 </ItemGroup>
57 <ItemGroup>
58 <ProjectReference Include="..\..\Libraries\GSF.Core\GSF.Core.csproj">
59 <Project>{ff3fcba6-f01a-4ec2-bc3f-6ba832afcf88}</Project>
60 <Name>GSF.Core</Name>
61 </ProjectReference>
62 </ItemGroup>
63 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
64 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
65 Other similar extension points exist, see Microsoft.Common.targets.
66 <Target Name="BeforeBuild">
67 </Target>
68 <Target Name="AfterBuild">
69 </Target>
70 -->
71</Project>
Source/Tools/ConfigTest/ConfigTest.csproj.vspscc+10−0
@@ -0,0 +1,10 @@
1""
2{
3"FILE_VERSION" = "9237"
4"ENLISTMENT_CHOICE" = "NEVER"
5"PROJECT_FILE_RELATIVE_PATH" = ""
6"NUMBER_OF_EXCLUDED_FILES" = "0"
7"ORIGINAL_PROJECT_FILE_PATH" = ""
8"NUMBER_OF_NESTED_PROJECTS" = "0"
9"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
10}
Source/Tools/ConfigTest/Program.cs+47−0
@@ -0,0 +1,47 @@
1using System;
2using GSF.Configuration;
3
4namespace ConfigTest
5{
6 class Program
7 {
8 static void Main(string[] args)
9 {
10 ConfigurationFile config = ConfigurationFile.Current;
11 CategorizedSettingsElementCollection settings = config.Settings["systemSettings"];
12 CategorizedSettingsElementCollection examples = config.Settings["examples"];
13
14 settings.Add("connectionString", "abc=123", "My device connection string");
15 settings.Add("property2", "clever", "Smack, smack!");
16 examples.Add("newProperty", "test", "New property description");
17 examples.Add("areWeThereYet", "never", "Why?");
18
19 string connectionString = settings["connectionString"].ValueAs("default");
20 string property2 = settings["property2"].ValueAs("default2");
21 string newProperty = examples["newProperty"].ValueAs("default3");
22 string areWeThereYet = examples["areWeThereYet"].ValueAs("default4");
23
24 Console.WriteLine();
25 Console.WriteLine("systemSettings.connectionString setting = " + connectionString);
26 Console.WriteLine("systemSettings.property2 setting = " + property2);
27 Console.WriteLine("examples.newProperty = " + newProperty);
28 Console.WriteLine("examples.areWeThereYet = " + areWeThereYet);
29
30 Console.WriteLine();
31 Console.WriteLine("Updating setting to new random value...");
32 settings["connectionString", true].Value = Guid.NewGuid().ToString();
33
34 Console.WriteLine();
35 Console.WriteLine("New setting: " + settings["connectionString"].Value);
36
37 Console.WriteLine();
38 Console.WriteLine("Saving updated configuration settings...");
39
40 config.Save();
41
42 Console.WriteLine();
43 Console.WriteLine("Press any key to continue...");
44 Console.ReadKey();
45 }
46 }
47}
Source/Tools/ConfigTest/Properties/AssemblyInfo.cs+36−0
@@ -0,0 +1,36 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("ConfigTest")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("")]
12[assembly: AssemblyProduct("ConfigTest")]
13[assembly: AssemblyCopyright("Copyright © 2014")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("0324eeb3-dfef-49df-adce-f55c3deaa6a1")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32// You can specify all the values or you can default the Build and Revision Numbers
33// by using the '*' as shown below:
34// [assembly: AssemblyVersion("1.0.*")]
35[assembly: AssemblyVersion("1.0.0.0")]
36[assembly: AssemblyFileVersion("1.0.0.0")]

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t