Merge lp:~mandel/ubuntuone-windows-installer/add_ubuntu_sso_service_keyring into lp:ubuntuone-windows-installer/beta
- add_ubuntu_sso_service_keyring
- Merge into beta
Proposed by
Manuel de la Peña
Status: | Merged |
---|---|
Approved by: | Vincenzo Di Somma |
Approved revision: | 63 |
Merged at revision: | 84 |
Proposed branch: | lp:~mandel/ubuntuone-windows-installer/add_ubuntu_sso_service_keyring |
Merge into: | lp:ubuntuone-windows-installer/beta |
Diff against target: |
1686 lines (+1486/-11) 16 files modified
.bzrignore (+2/-0) main.build (+10/-2) src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj (+74/-0) src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs (+409/-0) src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs (+36/-0) src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj (+19/-0) src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs (+65/-0) src/Canonical.Ubuntu.SSO/IDataProtector.cs (+48/-0) src/Canonical.Ubuntu.SSO/IKeyring.cs (+8/-7) src/Canonical.Ubuntu.SSO/IRegistryKey.cs (+171/-0) src/Canonical.Ubuntu.SSO/Keyring.cs (+282/-0) src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs (+1/-2) src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs (+261/-0) src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs (+38/-0) src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs (+50/-0) src/UbuntuOne.sln (+12/-0) |
To merge this branch: | bzr merge lp:~mandel/ubuntuone-windows-installer/add_ubuntu_sso_service_keyring |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vincenzo Di Somma (community) | Approve | ||
Rick McBride (community) | Approve | ||
Review via email: mp+35276@code.launchpad.net |
Commit message
Description of the change
Adds the implementation of the keyring on windows so that we can securely store the Ubuntu SSO tokens.
To post a comment you must log in.
Revision history for this message
Rick McBride (rmcbride) wrote : | # |
Revision history for this message
Rick McBride (rmcbride) wrote : | # |
See above. Looks like something is wrong.
review:
Needs Fixing
- 62. By Manuel de la Peña
-
Merged with trunk.
- 63. By Manuel de la Peña
-
Re-references the NUnit dll.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.bzrignore' |
2 | --- .bzrignore 2010-09-08 11:23:58 +0000 |
3 | +++ .bzrignore 2010-09-17 16:23:44 +0000 |
4 | @@ -8,6 +8,8 @@ |
5 | src/_ReSharper.UbuntuOne |
6 | src/Canonical.Ubuntu.SSO/bin |
7 | src/Canonical.Ubuntu.SSO/obj |
8 | +src/Canonical.Ubuntu.SSO.Tests/bin |
9 | +src/Canonical.Ubuntu.SSO.Tests/obj |
10 | src/Canonical.UbuntuOne.Client/bin |
11 | src/Canonical.UbuntuOne.Client/obj |
12 | src/Canonical.UbuntuOne.Client.Test/obj |
13 | |
14 | === modified file 'main.build' |
15 | --- main.build 2010-09-02 10:27:49 +0000 |
16 | +++ main.build 2010-09-17 16:23:44 +0000 |
17 | @@ -156,7 +156,7 @@ |
18 | program="nunit-console.exe" |
19 | commandline="Canonical.UbuntuOne.ProcessDispatcher.Tests.dll /xml=../../../../test-results/Canonical.UbuntuOne.ProcessDispatcher.Tests-Result.xml" /> |
20 | |
21 | - <echo>Canonical.UbuntuOne.Client.Test</echo> |
22 | + <echo>Executing Canonical.UbuntuOne.Client.Test</echo> |
23 | <exec basedir="tools/NUnit" |
24 | managed="true" |
25 | workingdir="src/Canonical.UbuntuOne.Client.Test/bin/${enviroment}" |
26 | @@ -169,12 +169,20 @@ |
27 | <copy file="src/Canonical.UbuntuOne.Client.Views/bin/${enviroment}/AvalonLibrary.dll" |
28 | tofile="src/UbuntuOneClient.Tests/bin/${enviroment}/AvalonLibrary.dll" /> |
29 | |
30 | - <echo>UbuntuOneClient.Tests</echo> |
31 | + <echo>Executing UbuntuOneClient.Tests</echo> |
32 | <exec basedir="tools/NUnit" |
33 | managed="true" |
34 | workingdir="src/UbuntuOneClient.Tests/bin/${enviroment}" |
35 | program="nunit-console.exe" |
36 | commandline="UbuntuOneClient.Tests.dll /xml=../../../../test-results/UbuntuOneClient.Tests-Result.xml" /> |
37 | + |
38 | + <echo>Executing Canonical.Ubuntu.SSO.Tests</echo> |
39 | + <exec basedir="tools/NUnit" |
40 | + managed="true" |
41 | + workingdir="src/Canonical.Ubuntu.SSO.Tests/bin/${enviroment}" |
42 | + program="nunit-console.exe" |
43 | + commandline="Canonical.Ubuntu.SSO.Tests.dll /xml=../../../../test-results/Canonical.Ubuntu.SSO.Tests-Result.xml" /> |
44 | + |
45 | </target> |
46 | <target name="package_python" |
47 | description="Creates the exe binary that embeds the python libs that will be used to perform the sync operation in the windows platform"> |
48 | |
49 | === added directory 'src/Canonical.Ubuntu.SSO.Tests' |
50 | === added file 'src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj' |
51 | --- src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj 1970-01-01 00:00:00 +0000 |
52 | +++ src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj 2010-09-17 16:23:44 +0000 |
53 | @@ -0,0 +1,74 @@ |
54 | +<?xml version="1.0" encoding="utf-8"?> |
55 | +<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
56 | + <PropertyGroup> |
57 | + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
58 | + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
59 | + <ProductVersion>9.0.21022</ProductVersion> |
60 | + <SchemaVersion>2.0</SchemaVersion> |
61 | + <ProjectGuid>{17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}</ProjectGuid> |
62 | + <OutputType>Library</OutputType> |
63 | + <AppDesignerFolder>Properties</AppDesignerFolder> |
64 | + <RootNamespace>Canonical.Ubuntu.SSO.Tests</RootNamespace> |
65 | + <AssemblyName>Canonical.Ubuntu.SSO.Tests</AssemblyName> |
66 | + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> |
67 | + <FileAlignment>512</FileAlignment> |
68 | + </PropertyGroup> |
69 | + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
70 | + <DebugSymbols>true</DebugSymbols> |
71 | + <DebugType>full</DebugType> |
72 | + <Optimize>false</Optimize> |
73 | + <OutputPath>bin\Debug\</OutputPath> |
74 | + <DefineConstants>DEBUG;TRACE</DefineConstants> |
75 | + <ErrorReport>prompt</ErrorReport> |
76 | + <WarningLevel>4</WarningLevel> |
77 | + </PropertyGroup> |
78 | + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
79 | + <DebugType>pdbonly</DebugType> |
80 | + <Optimize>true</Optimize> |
81 | + <OutputPath>bin\Release\</OutputPath> |
82 | + <DefineConstants>TRACE</DefineConstants> |
83 | + <ErrorReport>prompt</ErrorReport> |
84 | + <WarningLevel>4</WarningLevel> |
85 | + </PropertyGroup> |
86 | + <ItemGroup> |
87 | + <Reference Include="nunit.framework, Version=2.5.5.10112, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL"> |
88 | + <SpecificVersion>False</SpecificVersion> |
89 | + <HintPath>..\..\lib\Nunit\nunit.framework.dll</HintPath> |
90 | + </Reference> |
91 | + <Reference Include="Rhino.Mocks, Version=3.6.0.0, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL"> |
92 | + <SpecificVersion>False</SpecificVersion> |
93 | + <HintPath>..\..\lib\RhinoMocks\Rhino.Mocks.dll</HintPath> |
94 | + </Reference> |
95 | + <Reference Include="System" /> |
96 | + <Reference Include="System.Core"> |
97 | + <RequiredTargetFramework>3.5</RequiredTargetFramework> |
98 | + </Reference> |
99 | + <Reference Include="System.Security" /> |
100 | + <Reference Include="System.Xml.Linq"> |
101 | + <RequiredTargetFramework>3.5</RequiredTargetFramework> |
102 | + </Reference> |
103 | + <Reference Include="System.Data.DataSetExtensions"> |
104 | + <RequiredTargetFramework>3.5</RequiredTargetFramework> |
105 | + </Reference> |
106 | + <Reference Include="System.Data" /> |
107 | + <Reference Include="System.Xml" /> |
108 | + </ItemGroup> |
109 | + <ItemGroup> |
110 | + <Compile Include="KeyringFixture.cs" /> |
111 | + <Compile Include="Properties\AssemblyInfo.cs" /> |
112 | + </ItemGroup> |
113 | + <ItemGroup> |
114 | + <ProjectReference Include="..\Canonical.Ubuntu.SSO\Canonical.Ubuntu.SSO.csproj"> |
115 | + <Project>{9460A771-2589-45DA-9618-9FE8BB7D16E8}</Project> |
116 | + <Name>Canonical.Ubuntu.SSO</Name> |
117 | + </ProjectReference> |
118 | + </ItemGroup> |
119 | + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
120 | + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
121 | + Other similar extension points exist, see Microsoft.Common.targets. |
122 | + <Target Name="BeforeBuild"> |
123 | + </Target> |
124 | + <Target Name="AfterBuild"> |
125 | + </Target> |
126 | + --> |
127 | +</Project> |
128 | \ No newline at end of file |
129 | |
130 | === added file 'src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs' |
131 | --- src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs 1970-01-01 00:00:00 +0000 |
132 | +++ src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs 2010-09-17 16:23:44 +0000 |
133 | @@ -0,0 +1,409 @@ |
134 | +/* |
135 | + * Copyright 2010 Canonical Ltd. |
136 | + * |
137 | + * This file is part of UbuntuOne on Windows. |
138 | + * |
139 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
140 | + * it under the terms of the GNU Lesser General Public License version |
141 | + * as published by the Free Software Foundation. |
142 | + * |
143 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
144 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
145 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
146 | + * GNU Lesser General Public License for more details. |
147 | + * |
148 | + * You should have received a copy of the GNU Lesser General Public License |
149 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
150 | + * |
151 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
152 | + */ |
153 | +using System.Linq; |
154 | +using System.Security.Cryptography; |
155 | +using System.Text; |
156 | +using NUnit.Framework; |
157 | +using Rhino.Mocks; |
158 | + |
159 | +namespace Canonical.Ubuntu.SSO.Tests |
160 | +{ |
161 | + [TestFixture] |
162 | + public class KeyringFixture |
163 | + { |
164 | + #region Variables |
165 | + |
166 | + private MockRepository _mocks; |
167 | + private IRegistryKey _userRegistry; |
168 | + private IRegistryKey _keyringsRoot; |
169 | + private IRegistryKey _keyringKey; |
170 | + private IDataProtector _dataProtector; |
171 | + private Keyring _keyring; |
172 | + |
173 | + #endregion |
174 | + |
175 | + #region Setup & TearDown |
176 | + |
177 | + [SetUp] |
178 | + public void Setup() |
179 | + { |
180 | + _mocks = new MockRepository(); |
181 | + _userRegistry = _mocks.StrictMock<IRegistryKey>(); |
182 | + _keyringsRoot = _mocks.StrictMock<IRegistryKey>(); |
183 | + _keyringKey = _mocks.StrictMock<IRegistryKey>(); |
184 | + _dataProtector = _mocks.StrictMock<IDataProtector>(); |
185 | + _keyring = new Keyring(_userRegistry) { DataProtector = _dataProtector }; |
186 | + } |
187 | + |
188 | + #endregion |
189 | + |
190 | + #region Tests |
191 | + |
192 | + [Test] |
193 | + public void DisposeTest() |
194 | + { |
195 | + using (_mocks.Record()) |
196 | + { |
197 | + Expect.Call(() => _userRegistry.Dispose()) |
198 | + .Repeat.Once(); |
199 | + } |
200 | + using (_mocks.Playback()) |
201 | + { |
202 | + // we ensure that we always dispose the registry key to ensure no |
203 | + // memory leaks. |
204 | + _keyring.Dispose(); |
205 | + } |
206 | + } |
207 | + |
208 | + [TestCase("Default", "UbuntuOne", "myPassword")] |
209 | + [TestCase("Default", "Mandel", "Secret")] |
210 | + [TestCase("Test", "Leo", "MySecret")] |
211 | + public void CreateSecretNoRootPathPresentTest(string keyringName, string applicationName, string secret) |
212 | + { |
213 | + using (_mocks.Record()) |
214 | + { |
215 | + using (_mocks.Ordered()) |
216 | + { |
217 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
218 | + .Return(new[] {"Blah", "BlahBlah"}) |
219 | + .Repeat.Twice(); |
220 | + |
221 | + Expect.Call(_userRegistry.CreateSubKey(Keyring.RootPath)) |
222 | + .Return(_keyringsRoot) |
223 | + .Repeat.Once(); |
224 | + |
225 | + Expect.Call(_keyringsRoot.CreateSubKey(keyringName)) |
226 | + .Return(_keyringKey) |
227 | + .Repeat.Once(); |
228 | + |
229 | + Expect.Call(() => _keyringKey.Dispose()) |
230 | + .Repeat.Any(); |
231 | + |
232 | + Expect.Call(() => _keyringsRoot.Dispose()) |
233 | + .Repeat.Any(); |
234 | + |
235 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
236 | + .Return(_keyringsRoot) |
237 | + .Repeat.Once(); |
238 | + |
239 | + Expect.Call(_keyringsRoot.OpenSubKey(keyringName)) |
240 | + .Return(_keyringKey) |
241 | + .Repeat.Once(); |
242 | + |
243 | + Expect.Call(_dataProtector.Protect(secret, |
244 | + Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser)) |
245 | + .Return(secret) |
246 | + .Repeat.Once(); |
247 | + |
248 | + Expect.Call(() => _keyringKey.SetValue(applicationName, secret)) |
249 | + .Repeat.Once(); |
250 | + |
251 | + } |
252 | + |
253 | + } |
254 | + using (_mocks.Playback()) |
255 | + { |
256 | + _keyring.CreateSecret(keyringName, applicationName, secret); |
257 | + } |
258 | + } |
259 | + |
260 | + [TestCase("Default", "UbuntuOne", "myPassword")] |
261 | + [TestCase("Default", "Mandel", "Secret")] |
262 | + [TestCase("Test", "Leo", "MySecret")] |
263 | + public void CreateSecretNoKeyringPresentTest(string keyringName, string applicationName, string secret) |
264 | + { |
265 | + using (_mocks.Record()) |
266 | + { |
267 | + using(_mocks.Ordered()) |
268 | + { |
269 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
270 | + .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath}) |
271 | + .Repeat.Once(); |
272 | + |
273 | + Expect.Call(() => _keyringsRoot.Dispose()) |
274 | + .Repeat.Any(); |
275 | + |
276 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
277 | + .Return(_keyringsRoot) |
278 | + .Repeat.Once(); |
279 | + |
280 | + Expect.Call(_keyringsRoot.GetSubKeyNames()) |
281 | + .Return(new string[] { }) |
282 | + .Repeat.Once(); |
283 | + |
284 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
285 | + .Return(_keyringsRoot) |
286 | + .Repeat.Once(); |
287 | + |
288 | + Expect.Call(_keyringsRoot.CreateSubKey(keyringName)) |
289 | + .Return(_keyringKey) |
290 | + .Repeat.Once(); |
291 | + |
292 | + Expect.Call(() => _keyringKey.Dispose()) |
293 | + .Repeat.Any(); |
294 | + |
295 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
296 | + .Return(_keyringsRoot) |
297 | + .Repeat.Once(); |
298 | + |
299 | + Expect.Call(_keyringsRoot.OpenSubKey(keyringName)) |
300 | + .Return(_keyringKey) |
301 | + .Repeat.Once(); |
302 | + |
303 | + Expect.Call(_dataProtector.Protect(secret, |
304 | + Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser)) |
305 | + .Return(secret) |
306 | + .Repeat.Once(); |
307 | + |
308 | + Expect.Call(() => _keyringKey.SetValue(applicationName, secret)) |
309 | + .Repeat.Once(); |
310 | + |
311 | + } |
312 | + } |
313 | + using (_mocks.Playback()) |
314 | + { |
315 | + _keyring.CreateSecret(keyringName, applicationName, secret); |
316 | + } |
317 | + } |
318 | + |
319 | + [TestCase("Default", "UbuntuOne", "myPassword")] |
320 | + [TestCase("Default", "Mandel", "Secret")] |
321 | + [TestCase("Test", "Leo", "MySecret")] |
322 | + public void CreateSecretPresentKeyringTest(string keyringName, string applicationName, string secret) |
323 | + { |
324 | + using(_mocks.Record()) |
325 | + { |
326 | + using(_mocks.Ordered()) |
327 | + { |
328 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
329 | + .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath }) |
330 | + .Repeat.Once(); |
331 | + |
332 | + Expect.Call(() => _keyringsRoot.Dispose()) |
333 | + .Repeat.Any(); |
334 | + |
335 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
336 | + .Return(_keyringsRoot) |
337 | + .Repeat.Once(); |
338 | + |
339 | + Expect.Call(_keyringsRoot.GetSubKeyNames()) |
340 | + .Return(new[] { keyringName}) |
341 | + .Repeat.Once(); |
342 | + |
343 | + Expect.Call(() => _keyringKey.Dispose()) |
344 | + .Repeat.Any(); |
345 | + |
346 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
347 | + .Return(_keyringsRoot) |
348 | + .Repeat.Once(); |
349 | + |
350 | + Expect.Call(_keyringsRoot.OpenSubKey(keyringName)) |
351 | + .Return(_keyringKey) |
352 | + .Repeat.Once(); |
353 | + |
354 | + Expect.Call(_dataProtector.Protect(secret, |
355 | + Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser)) |
356 | + .Return(secret) |
357 | + .Repeat.Once(); |
358 | + |
359 | + Expect.Call(() => _keyringKey.SetValue(applicationName, secret)) |
360 | + .Repeat.Once(); |
361 | + } |
362 | + } |
363 | + using(_mocks.Playback()) |
364 | + { |
365 | + _keyring.CreateSecret(keyringName, applicationName, secret); |
366 | + } |
367 | + } |
368 | + |
369 | + [TestCase("Default", "UbuntuOne")] |
370 | + [TestCase("Keyring", "AppNAme")] |
371 | + public void GetSecretByNameNotKeyringTest(string keyringName, string applicationName) |
372 | + { |
373 | + using(_mocks.Record()) |
374 | + { |
375 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
376 | + .Return(new[] { "Blah", "BlahBlah" }) |
377 | + .Repeat.Once(); |
378 | + } |
379 | + using(_mocks.Playback()) |
380 | + { |
381 | + var secret = _keyring.GetSecretByName(keyringName, applicationName); |
382 | + Assert.IsEmpty(secret); |
383 | + } |
384 | + } |
385 | + |
386 | + [TestCase("Default", "UbuntuOne")] |
387 | + [TestCase("Keyring", "AppNAme")] |
388 | + public void GetSecretByNameKeyringExistsTest(string keyringName, string applicationName) |
389 | + { |
390 | + using (_mocks.Record()) |
391 | + { |
392 | + using (_mocks.Ordered()) |
393 | + { |
394 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
395 | + .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath }) |
396 | + .Repeat.Once(); |
397 | + |
398 | + Expect.Call(() => _keyringsRoot.Dispose()) |
399 | + .Repeat.Any(); |
400 | + |
401 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
402 | + .Return(_keyringsRoot) |
403 | + .Repeat.Once(); |
404 | + |
405 | + Expect.Call(_keyringsRoot.GetSubKeyNames()) |
406 | + .Return(new[] { keyringName }) |
407 | + .Repeat.Once(); |
408 | + |
409 | + Expect.Call(() => _keyringKey.Dispose()) |
410 | + .Repeat.Any(); |
411 | + |
412 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
413 | + .Return(_keyringsRoot) |
414 | + .Repeat.Once(); |
415 | + |
416 | + Expect.Call(_keyringsRoot.OpenSubKey(keyringName)) |
417 | + .Return(_keyringKey) |
418 | + .Repeat.Once(); |
419 | + |
420 | + Expect.Call(_keyringKey.GetValue(applicationName)) |
421 | + .Return(applicationName) |
422 | + .Repeat.Once(); |
423 | + |
424 | + Expect.Call(_dataProtector.Unprotect("", |
425 | + Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser)) |
426 | + .IgnoreArguments() |
427 | + .Return(applicationName) |
428 | + .Repeat.Once(); |
429 | + |
430 | + } |
431 | + } |
432 | + using (_mocks.Playback()) |
433 | + { |
434 | + var secret = _keyring.GetSecretByName(keyringName, applicationName); |
435 | + Assert.AreEqual(applicationName, secret); |
436 | + } |
437 | + } |
438 | + |
439 | + [Test] |
440 | + public void GetKeyringsTest() |
441 | + { |
442 | + var keyrings = new[] {"Default", "Test", "Test1"}; |
443 | + |
444 | + using(_mocks.Record()) |
445 | + { |
446 | + // make it such that the root is present |
447 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
448 | + .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath }) |
449 | + .Repeat.Once(); |
450 | + |
451 | + Expect.Call(() => _keyringsRoot.Dispose()) |
452 | + .Repeat.Any(); |
453 | + |
454 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
455 | + .Return(_keyringsRoot) |
456 | + .Repeat.Once(); |
457 | + |
458 | + Expect.Call(_keyringsRoot.GetSubKeyNames()) |
459 | + .Return(keyrings) |
460 | + .Repeat.Once(); |
461 | + |
462 | + } |
463 | + using(_mocks.Playback()) |
464 | + { |
465 | + Assert.AreSame(_keyring.GetKeyrings(), keyrings); |
466 | + } |
467 | + } |
468 | + |
469 | + [Test] |
470 | + public void GetKeyringsNotRootTest() |
471 | + { |
472 | + using (_mocks.Record()) |
473 | + { |
474 | + // make it such that the root is present |
475 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
476 | + .Return(new[] { "Blah", "BlahBlah"}) |
477 | + .Repeat.Once(); |
478 | + } |
479 | + using (_mocks.Playback()) |
480 | + { |
481 | + Assert.AreEqual(0, _keyring.GetKeyrings().Count()); |
482 | + } |
483 | + } |
484 | + |
485 | + [TestCase("Default")] |
486 | + [TestCase("Test")] |
487 | + public void GetApplicationsTest(string keyringName) |
488 | + { |
489 | + var applications = new[] {"Ubuntu One", "Test", "Default"}; |
490 | + using(_mocks.Record()) |
491 | + { |
492 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
493 | + .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath }) |
494 | + .Repeat.Once(); |
495 | + |
496 | + Expect.Call(() => _keyringsRoot.Dispose()) |
497 | + .Repeat.Any(); |
498 | + |
499 | + Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath)) |
500 | + .Return(_keyringsRoot) |
501 | + .Repeat.Twice(); |
502 | + |
503 | + Expect.Call(_keyringsRoot.GetSubKeyNames()) |
504 | + .Return(new[] { keyringName }) |
505 | + .Repeat.Once(); |
506 | + |
507 | + Expect.Call(_keyringsRoot.OpenSubKey(keyringName)) |
508 | + .Return(_keyringKey) |
509 | + .Repeat.Once(); |
510 | + |
511 | + Expect.Call(_keyringKey.GetSubKeyNames()) |
512 | + .Return(applications) |
513 | + .Repeat.Once(); |
514 | + |
515 | + Expect.Call(() => _keyringKey.Dispose()) |
516 | + .Repeat.Any(); |
517 | + } |
518 | + using(_mocks.Playback()) |
519 | + { |
520 | + Assert.AreSame(applications, _keyring.GetApplications(keyringName)); |
521 | + } |
522 | + } |
523 | + |
524 | + [Test] |
525 | + public void GetApplicationNotKeyringTest() |
526 | + { |
527 | + using (_mocks.Record()) |
528 | + { |
529 | + // make it such that the root is present |
530 | + Expect.Call(_userRegistry.GetSubKeyNames()) |
531 | + .Return(new[] { "Blah", "BlahBlah" }) |
532 | + .Repeat.Once(); |
533 | + } |
534 | + using(_mocks.Playback()) |
535 | + { |
536 | + Assert.AreEqual(0, _keyring.GetApplications("Test").Count()); |
537 | + } |
538 | + } |
539 | + |
540 | + #endregion |
541 | + } |
542 | +} |
543 | |
544 | === added directory 'src/Canonical.Ubuntu.SSO.Tests/Properties' |
545 | === added file 'src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs' |
546 | --- src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs 1970-01-01 00:00:00 +0000 |
547 | +++ src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs 2010-09-17 16:23:44 +0000 |
548 | @@ -0,0 +1,36 @@ |
549 | +using System.Reflection; |
550 | +using System.Runtime.CompilerServices; |
551 | +using System.Runtime.InteropServices; |
552 | + |
553 | +// General Information about an assembly is controlled through the following |
554 | +// set of attributes. Change these attribute values to modify the information |
555 | +// associated with an assembly. |
556 | +[assembly: AssemblyTitle("Canonical.Ubuntu.SSO.Tests")] |
557 | +[assembly: AssemblyDescription("")] |
558 | +[assembly: AssemblyConfiguration("")] |
559 | +[assembly: AssemblyCompany("")] |
560 | +[assembly: AssemblyProduct("Canonical.Ubuntu.SSO.Tests")] |
561 | +[assembly: AssemblyCopyright("Copyright © 2010")] |
562 | +[assembly: AssemblyTrademark("")] |
563 | +[assembly: AssemblyCulture("")] |
564 | + |
565 | +// Setting ComVisible to false makes the types in this assembly not visible |
566 | +// to COM components. If you need to access a type in this assembly from |
567 | +// COM, set the ComVisible attribute to true on that type. |
568 | +[assembly: ComVisible(false)] |
569 | + |
570 | +// The following GUID is for the ID of the typelib if this project is exposed to COM |
571 | +[assembly: Guid("055a2726-2682-4018-8c48-e1795da59ab2")] |
572 | + |
573 | +// Version information for an assembly consists of the following four values: |
574 | +// |
575 | +// Major Version |
576 | +// Minor Version |
577 | +// Build Number |
578 | +// Revision |
579 | +// |
580 | +// You can specify all the values or you can default the Build and Revision Numbers |
581 | +// by using the '*' as shown below: |
582 | +// [assembly: AssemblyVersion("1.0.*")] |
583 | +[assembly: AssemblyVersion("1.0.0.0")] |
584 | +[assembly: AssemblyFileVersion("1.0.0.0")] |
585 | |
586 | === modified file 'src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj' |
587 | --- src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj 2010-09-08 11:23:58 +0000 |
588 | +++ src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj 2010-09-17 16:23:44 +0000 |
589 | @@ -31,10 +31,15 @@ |
590 | <WarningLevel>4</WarningLevel> |
591 | </PropertyGroup> |
592 | <ItemGroup> |
593 | + <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL"> |
594 | + <SpecificVersion>False</SpecificVersion> |
595 | + <HintPath>..\..\lib\log4net\log4net.dll</HintPath> |
596 | + </Reference> |
597 | <Reference Include="System" /> |
598 | <Reference Include="System.Core"> |
599 | <RequiredTargetFramework>3.5</RequiredTargetFramework> |
600 | </Reference> |
601 | + <Reference Include="System.Security" /> |
602 | <Reference Include="System.Xml.Linq"> |
603 | <RequiredTargetFramework>3.5</RequiredTargetFramework> |
604 | </Reference> |
605 | @@ -45,17 +50,31 @@ |
606 | <Reference Include="System.Xml" /> |
607 | </ItemGroup> |
608 | <ItemGroup> |
609 | + <Compile Include="..\Version.cs"> |
610 | + <Link>Properties\Version.cs</Link> |
611 | + </Compile> |
612 | <Compile Include="CredentialsDeniedEventArgs.cs" /> |
613 | <Compile Include="CredentialsErrorEventArgs.cs" /> |
614 | <Compile Include="CredentialsFoundEventArgs.cs" /> |
615 | + <Compile Include="DPAPIDataProtector.cs" /> |
616 | + <Compile Include="IDataProtector.cs" /> |
617 | <Compile Include="ILoginOrRegisterView.cs" /> |
618 | <Compile Include="ILoginView.cs" /> |
619 | + <Compile Include="IRegistryKey.cs" /> |
620 | + <Compile Include="Keyring.cs" /> |
621 | <Compile Include="LoginCredentialsEventArgs.cs" /> |
622 | + <Compile Include="RegistryKeyWrapper.cs" /> |
623 | <Compile Include="SSOCredentialsProvider.cs" /> |
624 | <Compile Include="IKeyring.cs" /> |
625 | <Compile Include="ISSOCredentialsProvider.cs" /> |
626 | <Compile Include="Properties\AssemblyInfo.cs" /> |
627 | </ItemGroup> |
628 | + <ItemGroup> |
629 | + <ProjectReference Include="..\Canonical.UbuntuOne.Common\Canonical.UbuntuOne.Common.csproj"> |
630 | + <Project>{11353FF8-8E5A-488E-9CB1-873DADD232B9}</Project> |
631 | + <Name>Canonical.UbuntuOne.Common</Name> |
632 | + </ProjectReference> |
633 | + </ItemGroup> |
634 | <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
635 | <!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
636 | Other similar extension points exist, see Microsoft.Common.targets. |
637 | |
638 | === added file 'src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs' |
639 | --- src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs 1970-01-01 00:00:00 +0000 |
640 | +++ src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs 2010-09-17 16:23:44 +0000 |
641 | @@ -0,0 +1,65 @@ |
642 | +/* |
643 | + * Copyright 2010 Canonical Ltd. |
644 | + * |
645 | + * This file is part of UbuntuOne on Windows. |
646 | + * |
647 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
648 | + * it under the terms of the GNU Lesser General Public License version |
649 | + * as published by the Free Software Foundation. |
650 | + * |
651 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
652 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
653 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
654 | + * GNU Lesser General Public License for more details. |
655 | + * |
656 | + * You should have received a copy of the GNU Lesser General Public License |
657 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
658 | + * |
659 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
660 | + */ |
661 | + |
662 | +using System.Security.Cryptography; |
663 | +using System.Text; |
664 | + |
665 | +namespace Canonical.Ubuntu.SSO |
666 | +{ |
667 | + /// <summary> |
668 | + /// Implementation of the IDataProtector that uses the DAPI api to perform the protection. |
669 | + /// </summary> |
670 | + public class DPAPIDataProtector : IDataProtector |
671 | + { |
672 | + #region Implementation of IDataProtector |
673 | + |
674 | + /// <summary> |
675 | + /// Protects the userData parameter and returns a string. |
676 | + /// </summary> |
677 | + /// <param name="userData">A string containing data to protect. </param> |
678 | + /// <param name="optionalEntropy">An additional byte array used to encrypt the data. </param> |
679 | + /// <param name="scope">One of the DataProtectionScope values.</param> |
680 | + /// <returns>A string representing the encrypted data.</returns> |
681 | + public string Protect(string userData, byte[] optionalEntropy, DataProtectionScope scope) |
682 | + { |
683 | + var userDataBytes = Encoding.UTF8.GetBytes(userData); |
684 | + var encryptedBytes = ProtectedData.Protect(userDataBytes, optionalEntropy, scope); |
685 | + var enc = new UTF8Encoding(false); |
686 | + return enc.GetString(encryptedBytes); |
687 | + } |
688 | + |
689 | + /// <summary> |
690 | + /// Unprotects the encryptedData parameter and returns a string. |
691 | + /// </summary> |
692 | + /// <param name="encryptedData">A string containing data encrypted using the Protect method.</param> |
693 | + /// <param name="optionalEntropy">An additional byte array used to encrypt the data.</param> |
694 | + /// <param name="scope">One of the DataProtectionScope values. </param> |
695 | + /// <returns>A string representing the unprotected data.</returns> |
696 | + public string Unprotect(string encryptedData, byte[] optionalEntropy, DataProtectionScope scope) |
697 | + { |
698 | + var encryptedDataBytes = Encoding.UTF8.GetBytes(encryptedData); |
699 | + var userDataBytes = ProtectedData.Unprotect(encryptedDataBytes, optionalEntropy, scope); |
700 | + var enc = new UTF8Encoding(false); |
701 | + return enc.GetString(userDataBytes); |
702 | + } |
703 | + |
704 | + #endregion |
705 | + } |
706 | +} |
707 | |
708 | === added file 'src/Canonical.Ubuntu.SSO/IDataProtector.cs' |
709 | --- src/Canonical.Ubuntu.SSO/IDataProtector.cs 1970-01-01 00:00:00 +0000 |
710 | +++ src/Canonical.Ubuntu.SSO/IDataProtector.cs 2010-09-17 16:23:44 +0000 |
711 | @@ -0,0 +1,48 @@ |
712 | +/* |
713 | + * Copyright 2010 Canonical Ltd. |
714 | + * |
715 | + * This file is part of UbuntuOne on Windows. |
716 | + * |
717 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
718 | + * it under the terms of the GNU Lesser General Public License version |
719 | + * as published by the Free Software Foundation. |
720 | + * |
721 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
722 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
723 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
724 | + * GNU Lesser General Public License for more details. |
725 | + * |
726 | + * You should have received a copy of the GNU Lesser General Public License |
727 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
728 | + * |
729 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
730 | + */ |
731 | +using System.Security.Cryptography; |
732 | + |
733 | +namespace Canonical.Ubuntu.SSO |
734 | +{ |
735 | + /// <summary> |
736 | + /// Interface to be implemented by those objects that are able to encryp and decrypt users |
737 | + /// data to protect it. |
738 | + /// </summary> |
739 | + public interface IDataProtector |
740 | + { |
741 | + /// <summary> |
742 | + /// Protects the userData parameter and returns a string. |
743 | + /// </summary> |
744 | + /// <param name="userData">A string containing data to protect. </param> |
745 | + /// <param name="optionalEntropy">An additional byte array used to encrypt the data. </param> |
746 | + /// <param name="scope">One of the DataProtectionScope values.</param> |
747 | + /// <returns>A string representing the encrypted data.</returns> |
748 | + string Protect(string userData, byte[] optionalEntropy, DataProtectionScope scope); |
749 | + |
750 | + /// <summary> |
751 | + /// Unprotects the encryptedData parameter and returns a string. |
752 | + /// </summary> |
753 | + /// <param name="encryptedData">A string containing data encrypted using the Protect method.</param> |
754 | + /// <param name="optionalEntropy">An additional byte array used to encrypt the data.</param> |
755 | + /// <param name="scope">One of the DataProtectionScope values. </param> |
756 | + /// <returns>A string representing the unprotected data.</returns> |
757 | + string Unprotect(string encryptedData, byte[] optionalEntropy, DataProtectionScope scope); |
758 | + } |
759 | +} |
760 | |
761 | === modified file 'src/Canonical.Ubuntu.SSO/IKeyring.cs' |
762 | --- src/Canonical.Ubuntu.SSO/IKeyring.cs 2010-09-09 09:11:07 +0000 |
763 | +++ src/Canonical.Ubuntu.SSO/IKeyring.cs 2010-09-17 16:23:44 +0000 |
764 | @@ -17,6 +17,7 @@ |
765 | * |
766 | * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
767 | */ |
768 | +using System; |
769 | using System.Collections.Generic; |
770 | |
771 | namespace Canonical.Ubuntu.SSO |
772 | @@ -25,7 +26,7 @@ |
773 | /// Interface to be implemented by a class that allows to store data in the registry of the |
774 | /// current user and makes the class behave like a keyring. |
775 | /// </summary> |
776 | - public interface IKeyring |
777 | + public interface IKeyring : IDisposable |
778 | { |
779 | /// <summary> |
780 | /// Creates a new secret in the the keyring with the given name for a given applciation. |
781 | @@ -36,11 +37,11 @@ |
782 | void CreateSecret(string keyringName, string applicationName, string secret); |
783 | |
784 | /// <summary> |
785 | - /// |
786 | + /// Gets the secret froma keyring using the name of the application that stored it. |
787 | /// </summary> |
788 | - /// <param name="keyringName"></param> |
789 | - /// <param name="applicationName"></param> |
790 | - /// <returns></returns> |
791 | + /// <param name="keyringName">The name of the keyring where the secret was stored.</param> |
792 | + /// <param name="applicationName">the name of the application that stored the secret.</param> |
793 | + /// <returns>An empty string if the secret does not exist, the secret otherwhise.</returns> |
794 | string GetSecretByName(string keyringName, string applicationName); |
795 | |
796 | /// <summary> |
797 | @@ -52,8 +53,8 @@ |
798 | /// <summary> |
799 | /// Gets a list with all the applications in a keyring. |
800 | /// </summary> |
801 | - /// <param name="keyring">The name of the keyring that is queried.</param> |
802 | + /// <param name="keyringName">The name of the keyring that is queried.</param> |
803 | /// <returns>An enumerable with all the applications in the keyring.</returns> |
804 | - IEnumerable<string> GetApplications(string keyring); |
805 | + IEnumerable<string> GetApplications(string keyringName); |
806 | } |
807 | } |
808 | |
809 | === added file 'src/Canonical.Ubuntu.SSO/IRegistryKey.cs' |
810 | --- src/Canonical.Ubuntu.SSO/IRegistryKey.cs 1970-01-01 00:00:00 +0000 |
811 | +++ src/Canonical.Ubuntu.SSO/IRegistryKey.cs 2010-09-17 16:23:44 +0000 |
812 | @@ -0,0 +1,171 @@ |
813 | +/* |
814 | + * Copyright 2010 Canonical Ltd. |
815 | + * |
816 | + * This file is part of UbuntuOne on Windows. |
817 | + * |
818 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
819 | + * it under the terms of the GNU Lesser General Public License version |
820 | + * as published by the Free Software Foundation. |
821 | + * |
822 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
823 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
824 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
825 | + * GNU Lesser General Public License for more details. |
826 | + * |
827 | + * You should have received a copy of the GNU Lesser General Public License |
828 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
829 | + * |
830 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
831 | + */ |
832 | + |
833 | +using System; |
834 | +using Microsoft.Win32; |
835 | + |
836 | +namespace Canonical.Ubuntu.SSO |
837 | +{ |
838 | + /// <summary> |
839 | + /// Interface that represents a class that allows to perform the access to |
840 | + /// the registry keys of the machine. |
841 | + /// </summary> |
842 | + public interface IRegistryKey : IDisposable |
843 | + { |
844 | + #region Properties |
845 | + |
846 | + /// <summary> |
847 | + /// Retrieves the name of the key. |
848 | + /// </summary> |
849 | + string Name { get; } |
850 | + |
851 | + /// <summary> |
852 | + /// Retrieves the count of subkeys of the current key. |
853 | + /// </summary> |
854 | + int SubKeyCount { get; } |
855 | + |
856 | + /// <summary> |
857 | + /// Retrieves the count of values in the key. |
858 | + /// </summary> |
859 | + int ValueCount { get; } |
860 | + |
861 | + #endregion |
862 | + |
863 | + #region Methods |
864 | + |
865 | + /// <summary> |
866 | + /// Closes the key and flushes it to disk if its contents have been modified. |
867 | + /// </summary> |
868 | + void Close(); |
869 | + |
870 | + /// <summary> |
871 | + /// Creates a new subkey or opens an existing subkey for write access. |
872 | + /// The string subkey is not case-sensitive. |
873 | + /// </summary> |
874 | + /// <param name="name">The name or path of the subkey to create or open. </param> |
875 | + /// <returns>A sub key to work with.</returns> |
876 | + IRegistryKey CreateSubKey(string name); |
877 | + |
878 | + /// <summary> |
879 | + /// Creates a new subkey or opens an existing subkey for write access, using the specified |
880 | + /// permission check option. The string subkey is not case-sensitive. |
881 | + /// </summary> |
882 | + /// <param name="subkey">The name or path of the subkey to create or open.</param> |
883 | + /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values that |
884 | + /// specifies whether the key is opened for read or read/write access.</param> |
885 | + /// <returns>A subkey to work with.</returns> |
886 | + IRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck); |
887 | + |
888 | + /// <summary> |
889 | + /// Deletes the specified subkey. The string subkey is not case-sensitive. |
890 | + /// </summary> |
891 | + /// <param name="subkey">The name of the subkey to delete. </param> |
892 | + void DeleteSubKey(string subkey); |
893 | + |
894 | + /// <summary> |
895 | + /// Deletes the specified value from this key. |
896 | + /// </summary> |
897 | + /// <param name="name">The name of the value to delete.</param> |
898 | + void DeleteValue(string name); |
899 | + |
900 | + /// <summary> |
901 | + /// Writes all the attributes of the specified open registry |
902 | + /// key into the registry. |
903 | + /// </summary> |
904 | + void Flush(); |
905 | + |
906 | + /// <summary> |
907 | + /// Retrieves an array of strings that contains all the subkey names. |
908 | + /// </summary> |
909 | + /// <returns>An array of strings that contains the names of the |
910 | + /// subkeys for the current key.</returns> |
911 | + string[] GetSubKeyNames(); |
912 | + |
913 | + /// <summary> |
914 | + /// Retrieves the value associated with the specified name. |
915 | + /// Returns null if the name/value pair does not exist in the registry. |
916 | + /// </summary> |
917 | + /// <param name="name">The name of the value to retrieve. </param> |
918 | + /// <returns>The value associated with name, or null if name is not found.</returns> |
919 | + object GetValue(string name); |
920 | + |
921 | + /// <summary> |
922 | + /// Retrieves the value associated with the specified name. |
923 | + /// If the name is not found, returns the default value that you provide. |
924 | + /// </summary> |
925 | + /// <param name="name">The name of the value to retrieve.</param> |
926 | + /// <param name="defaultValue">The value to return if name does not exist.</param> |
927 | + /// <returns>The value associated with name, with any embedded |
928 | + /// environment variables left unexpanded, or defaultValue if name is not found.</returns> |
929 | + object GetValue(string name, object defaultValue); |
930 | + |
931 | + /// <summary> |
932 | + /// Retrieves the registry data type of the value associated with the specified name. |
933 | + /// </summary> |
934 | + /// <param name="name">The name of the value whose registry data type is to be retrieved. </param> |
935 | + /// <returns>A RegistryValueKind value representing the registry |
936 | + /// data type of the value associated with name.</returns> |
937 | + RegistryValueKind GetValueKind(string name); |
938 | + |
939 | + /// <summary> |
940 | + /// Retrieves an array of strings that contains all the |
941 | + /// value names associated with this key. |
942 | + /// </summary> |
943 | + /// <returns>An array of strings that contains |
944 | + /// the value names for the current key.</returns> |
945 | + string[] GetValueNames(); |
946 | + |
947 | + /// <summary> |
948 | + /// Retrieves a subkey as read-only. |
949 | + /// </summary> |
950 | + /// <param name="name">The name or path of the subkey to open read-only. </param> |
951 | + /// <returns>The subkey requested, or null if the operation failed.</returns> |
952 | + IRegistryKey OpenSubKey(string name); |
953 | + |
954 | + /// <summary> |
955 | + /// Retrieves the specified subkey for read or read/write access. |
956 | + /// </summary> |
957 | + /// <param name="name">The name or path of the subkey to create or open.</param> |
958 | + /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values |
959 | + /// that specifies whether the key is opened for read or read/write access.</param> |
960 | + /// <returns></returns> |
961 | + IRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck); |
962 | + |
963 | + /// <summary> |
964 | + /// Sets the specified name/value pair. |
965 | + /// </summary> |
966 | + /// <param name="name">The name of the value to store. </param> |
967 | + /// <param name="value">The data to be stored.</param> |
968 | + void SetValue(string name, Object value); |
969 | + |
970 | + /// <summary> |
971 | + /// Sets the value of a name/value pair in the registry key, using the specified registry data type. |
972 | + /// </summary> |
973 | + /// <param name="name">The name of the value to be stored. </param> |
974 | + /// <param name="value">The data to be stored. </param> |
975 | + /// <param name="valueKind">The registry data type to use when storing the data</param> |
976 | + void SetValue(string name, Object value, RegistryValueKind valueKind); |
977 | + |
978 | + #endregion |
979 | + |
980 | + |
981 | + |
982 | + } |
983 | +} |
984 | |
985 | === added file 'src/Canonical.Ubuntu.SSO/Keyring.cs' |
986 | --- src/Canonical.Ubuntu.SSO/Keyring.cs 1970-01-01 00:00:00 +0000 |
987 | +++ src/Canonical.Ubuntu.SSO/Keyring.cs 2010-09-17 16:23:44 +0000 |
988 | @@ -0,0 +1,282 @@ |
989 | +/* |
990 | + * Copyright 2010 Canonical Ltd. |
991 | + * |
992 | + * This file is part of UbuntuOne on Windows. |
993 | + * |
994 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
995 | + * it under the terms of the GNU Lesser General Public License version |
996 | + * as published by the Free Software Foundation. |
997 | + * |
998 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
999 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1000 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1001 | + * GNU Lesser General Public License for more details. |
1002 | + * |
1003 | + * You should have received a copy of the GNU Lesser General Public License |
1004 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
1005 | + * |
1006 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
1007 | + */ |
1008 | +using System.Collections.Generic; |
1009 | +using System.Linq; |
1010 | +using System.Security.Cryptography; |
1011 | +using System.Text; |
1012 | +using Canonical.UbuntuOne.Common.Validation; |
1013 | +using log4net; |
1014 | + |
1015 | +namespace Canonical.Ubuntu.SSO |
1016 | +{ |
1017 | + /// <summary> |
1018 | + /// Implementation of the IKeyring interface that will store encripted secrets in the users current keyring. |
1019 | + /// </summary> |
1020 | + public class Keyring : IKeyring |
1021 | + { |
1022 | + #region Variables |
1023 | + |
1024 | + internal const string RootPath = "Canonical\\Keyrings"; |
1025 | + internal const string Entropy = "bdc97980-bbfa-11df-851a-0800200c9a66"; |
1026 | + private const int KeyringMaxNameLength = 255; |
1027 | + private ILog _logger; |
1028 | + private readonly object _loggerLock = new object(); |
1029 | + private bool _keyringsRootExists = false; |
1030 | + |
1031 | + #endregion |
1032 | + |
1033 | + #region DI properties |
1034 | + |
1035 | + /// <summary> |
1036 | + /// Gets and sets the users registry key. |
1037 | + /// </summary> |
1038 | + public IRegistryKey UserRegistry { get; set; } |
1039 | + |
1040 | + /// <summary> |
1041 | + /// Gets and sets the data protector to secure the data in the registry. |
1042 | + /// </summary> |
1043 | + public IDataProtector DataProtector { get; set; } |
1044 | + |
1045 | + #endregion |
1046 | + |
1047 | + #region Properties |
1048 | + |
1049 | + /// <summary> |
1050 | + /// Gets and sets the logger that will be used to log the operation of the |
1051 | + /// class. |
1052 | + /// </summary> |
1053 | + public ILog Logger |
1054 | + { |
1055 | + get |
1056 | + { |
1057 | + if (_logger == null) |
1058 | + { |
1059 | + lock (_loggerLock) |
1060 | + { |
1061 | + _logger = LogManager.GetLogger(typeof(Keyring)); |
1062 | + } |
1063 | + } |
1064 | + return _logger; |
1065 | + } |
1066 | + set |
1067 | + { |
1068 | + _logger = value; |
1069 | + } |
1070 | + } |
1071 | + |
1072 | + #endregion |
1073 | + |
1074 | + #region Constructors |
1075 | + |
1076 | + /// <summary> |
1077 | + /// Creates a new instance of the class that will be using the users registry to store the data. |
1078 | + /// </summary> |
1079 | + public Keyring() |
1080 | + : this(new RegistryKeyWrapper()) |
1081 | + { |
1082 | + |
1083 | + } |
1084 | + |
1085 | + /// <summary> |
1086 | + /// Creates a new instance of the class that will be storing the keyring in the provided registry key. |
1087 | + /// </summary> |
1088 | + /// <param name="key"></param> |
1089 | + public Keyring(IRegistryKey key) |
1090 | + { |
1091 | + UserRegistry = key; |
1092 | + } |
1093 | + |
1094 | + #endregion |
1095 | + |
1096 | + #region Helpers |
1097 | + |
1098 | + private bool KeyringsRootExists() |
1099 | + { |
1100 | + if (!_keyringsRootExists) |
1101 | + { |
1102 | + var rootKey = from key in UserRegistry.GetSubKeyNames() |
1103 | + where key == RootPath |
1104 | + select key; |
1105 | + _keyringsRootExists = rootKey.Count() == 1; |
1106 | + } |
1107 | + return _keyringsRootExists; |
1108 | + } |
1109 | + |
1110 | + private bool KeyringExist(string keyring) |
1111 | + { |
1112 | + // open the root keyring and then the subkeyring to ensure that the |
1113 | + // length of the string is not over 255 chars |
1114 | + if (!KeyringsRootExists()) |
1115 | + return false; |
1116 | + |
1117 | + using (var rootKeyring = UserRegistry.OpenSubKey(RootPath)) |
1118 | + { |
1119 | + var presentKeyrings = from key in rootKeyring.GetSubKeyNames() |
1120 | + where key == keyring |
1121 | + select key; |
1122 | + return presentKeyrings.Count() == 1; |
1123 | + } |
1124 | + } |
1125 | + |
1126 | + private IRegistryKey CreateKeyringRootPath() |
1127 | + { |
1128 | + // create a key with the root path to be used |
1129 | + return UserRegistry.CreateSubKey(RootPath); |
1130 | + } |
1131 | + |
1132 | + private void CreateKeyring(string keyring) |
1133 | + { |
1134 | + using(var rootKey = (KeyringsRootExists())? |
1135 | + UserRegistry.OpenSubKey(RootPath) : CreateKeyringRootPath()) |
1136 | + { |
1137 | + var subkey = rootKey.CreateSubKey(keyring); |
1138 | + subkey.Dispose(); |
1139 | + } |
1140 | + } |
1141 | + |
1142 | + private IRegistryKey OpenKeyring(string keyring) |
1143 | + { |
1144 | + using(var rootKey = UserRegistry.OpenSubKey(RootPath)) |
1145 | + { |
1146 | + return rootKey.OpenSubKey(keyring); |
1147 | + } |
1148 | + } |
1149 | + |
1150 | + private void SaveValue(string keyringName, string applicationName, string secret) |
1151 | + { |
1152 | + using(var keyring = OpenKeyring(keyringName)) |
1153 | + { |
1154 | + var encryptedSecret = DataProtector.Protect(secret, Encoding.UTF8.GetBytes(Entropy), |
1155 | + DataProtectionScope.CurrentUser); |
1156 | + keyring.SetValue(applicationName, encryptedSecret); |
1157 | + } |
1158 | + } |
1159 | + |
1160 | + private string GetValue(string keyringName, string applicationName) |
1161 | + { |
1162 | + using (var keyring = OpenKeyring(keyringName)) |
1163 | + { |
1164 | + var secret = keyring.GetValue(applicationName) as string; |
1165 | + return DataProtector.Unprotect(secret, Encoding.UTF8.GetBytes(Entropy), DataProtectionScope.CurrentUser); |
1166 | + } |
1167 | + } |
1168 | + |
1169 | + |
1170 | + #endregion |
1171 | + |
1172 | + #region Implementation of IKeyring |
1173 | + |
1174 | + /// <summary> |
1175 | + /// Creates a new secret in the the keyring with the given name for a given applciation. |
1176 | + /// </summary> |
1177 | + /// <param name="keyringName">The name of the keyring where the secret will be stored.</param> |
1178 | + /// <param name="applicationName">The name of the application whose secret will be stored.</param> |
1179 | + /// <param name="secret">The secret to store in the keyring.</param> |
1180 | + public void CreateSecret(string keyringName, string applicationName, string secret) |
1181 | + { |
1182 | + ValidateArgs.Begin() |
1183 | + .IsNotNullOrEmpty(keyringName, "keyringName") |
1184 | + .IsShorterThan(keyringName, KeyringMaxNameLength, "keyringName") |
1185 | + .IsNotNullOrEmpty(applicationName, "applicationName") |
1186 | + .IsNotNullOrEmpty(secret, "secret") |
1187 | + .Check(); |
1188 | + |
1189 | + if (!KeyringExist(keyringName)) |
1190 | + { |
1191 | + CreateKeyring(keyringName); |
1192 | + Logger.InfoFormat("Creating keyring with name {0}", keyringName); |
1193 | + } |
1194 | + SaveValue(keyringName, applicationName, secret); |
1195 | + } |
1196 | + |
1197 | + /// <summary> |
1198 | + /// Gets the secret froma keyring using the name of the application that stored it. |
1199 | + /// </summary> |
1200 | + /// <param name="keyringName">The name of the keyring where the secret was stored.</param> |
1201 | + /// <param name="applicationName">the name of the application that stored the secret.</param> |
1202 | + /// <returns>An empty string if the secret does not exist, the secret otherwhise.</returns> |
1203 | + public string GetSecretByName(string keyringName, string applicationName) |
1204 | + { |
1205 | + ValidateArgs.Begin() |
1206 | + .IsNotNullOrEmpty(keyringName, "keyringName") |
1207 | + .IsShorterThan(keyringName, KeyringMaxNameLength, "keyringName") |
1208 | + .IsNotNullOrEmpty(applicationName, "applicationName") |
1209 | + .Check(); |
1210 | + |
1211 | + return KeyringExist(keyringName) ? GetValue(keyringName, applicationName) : string.Empty; |
1212 | + } |
1213 | + |
1214 | + /// <summary> |
1215 | + /// Gets a lists with all the names of the available keyrings. |
1216 | + /// </summary> |
1217 | + /// <returns>An enumerable with all the names of the different keyrings.</returns> |
1218 | + public IEnumerable<string> GetKeyrings() |
1219 | + { |
1220 | + if(KeyringsRootExists()) |
1221 | + { |
1222 | + using(var keyringRoot = UserRegistry.OpenSubKey(RootPath)) |
1223 | + { |
1224 | + return keyringRoot.GetSubKeyNames(); |
1225 | + } |
1226 | + } |
1227 | + return new string[0]; |
1228 | + } |
1229 | + |
1230 | + /// <summary> |
1231 | + /// Gets a list with all the applications in a keyring. |
1232 | + /// </summary> |
1233 | + /// <param name="keyringName">The name of the keyring that is queried.</param> |
1234 | + /// <returns>An enumerable with all the applications in the keyring.</returns> |
1235 | + public IEnumerable<string> GetApplications(string keyringName) |
1236 | + { |
1237 | + ValidateArgs.Begin() |
1238 | + .IsNotNullOrEmpty(keyringName, "keyring") |
1239 | + .IsShorterThan(keyringName, KeyringMaxNameLength, "keyring") |
1240 | + .Check(); |
1241 | + if(KeyringExist(keyringName)) |
1242 | + { |
1243 | + using(var keyringRoot = UserRegistry.OpenSubKey(RootPath)) |
1244 | + { |
1245 | + using(var keyring = keyringRoot.OpenSubKey(keyringName)) |
1246 | + { |
1247 | + return keyring.GetSubKeyNames(); |
1248 | + } |
1249 | + } |
1250 | + } |
1251 | + return new string[0]; |
1252 | + } |
1253 | + |
1254 | + #endregion |
1255 | + |
1256 | + #region Implementation of IDisposable |
1257 | + |
1258 | + /// <summary> |
1259 | + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. |
1260 | + /// </summary> |
1261 | + /// <filterpriority>2</filterpriority> |
1262 | + public void Dispose() |
1263 | + { |
1264 | + if (UserRegistry != null) |
1265 | + UserRegistry.Dispose(); |
1266 | + } |
1267 | + |
1268 | + #endregion |
1269 | + } |
1270 | +} |
1271 | |
1272 | === modified file 'src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs' |
1273 | --- src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs 2010-09-08 11:23:58 +0000 |
1274 | +++ src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs 2010-09-17 16:23:44 +0000 |
1275 | @@ -32,5 +32,4 @@ |
1276 | // You can specify all the values or you can default the Build and Revision Numbers |
1277 | // by using the '*' as shown below: |
1278 | // [assembly: AssemblyVersion("1.0.*")] |
1279 | -[assembly: AssemblyVersion("1.0.0.0")] |
1280 | -[assembly: AssemblyFileVersion("1.0.0.0")] |
1281 | +[assembly: InternalsVisibleTo("Canonical.Ubuntu.SSO.Tests")] |
1282 | |
1283 | === added file 'src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs' |
1284 | --- src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs 1970-01-01 00:00:00 +0000 |
1285 | +++ src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs 2010-09-17 16:23:44 +0000 |
1286 | @@ -0,0 +1,261 @@ |
1287 | +/* |
1288 | + * Copyright 2010 Canonical Ltd. |
1289 | + * |
1290 | + * This file is part of UbuntuOne on Windows. |
1291 | + * |
1292 | + * UbuntuOne on Windows is free software: you can redistribute it and/or modify |
1293 | + * it under the terms of the GNU Lesser General Public License version |
1294 | + * as published by the Free Software Foundation. |
1295 | + * |
1296 | + * Ubuntu One on Windows is distributed in the hope that it will be useful, |
1297 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1298 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1299 | + * GNU Lesser General Public License for more details. |
1300 | + * |
1301 | + * You should have received a copy of the GNU Lesser General Public License |
1302 | + * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>. |
1303 | + * |
1304 | + * Authors: Manuel de la Peña <manuel.delapena@canonical.com> |
1305 | + */ |
1306 | + |
1307 | +using System; |
1308 | +using Microsoft.Win32; |
1309 | + |
1310 | +namespace Canonical.Ubuntu.SSO |
1311 | +{ |
1312 | + /// <summary> |
1313 | + /// Simple wrapper around the registry class that allows the class to be mocked for testing |
1314 | + /// purposes |
1315 | + /// </summary> |
1316 | + public class RegistryKeyWrapper : IRegistryKey |
1317 | + { |
1318 | + #region Variables |
1319 | + |
1320 | + private readonly RegistryKey _key; |
1321 | + |
1322 | + #endregion |
1323 | + |
1324 | + #region Constructors |
1325 | + |
1326 | + /// <summary> |
1327 | + /// Creates a new registry key that contains information about the default user configuration. |
1328 | + /// </summary> |
1329 | + public RegistryKeyWrapper() |
1330 | + : this(Registry.Users) |
1331 | + { |
1332 | + |
1333 | + } |
1334 | + |
1335 | + /// <summary> |
1336 | + /// Creates a new registry key wrapper with the given key. |
1337 | + /// </summary> |
1338 | + /// <param name="key">The key to be wrapped.</param> |
1339 | + public RegistryKeyWrapper(RegistryKey key) |
1340 | + { |
1341 | + _key = key; |
1342 | + } |
1343 | + |
1344 | + #endregion |
1345 | + |
1346 | + #region Implementation of IDisposable |
1347 | + |
1348 | + /// <summary> |
1349 | + /// Performs application-defined tasks associated with freeing, releasing, |
1350 | + /// or resetting unmanaged resources. |
1351 | + /// </summary> |
1352 | + /// <filterpriority>2</filterpriority> |
1353 | + public void Dispose() |
1354 | + { |
1355 | + var disposable = (IDisposable)_key; |
1356 | + disposable.Dispose(); |
1357 | + } |
1358 | + |
1359 | + #endregion |
1360 | + |
1361 | + #region Implementation of IRegistryKey |
1362 | + |
1363 | + /// <summary> |
1364 | + /// Retrieves the name of the key. |
1365 | + /// </summary> |
1366 | + public string Name |
1367 | + { |
1368 | + get { return _key.Name; } |
1369 | + } |
1370 | + |
1371 | + /// <summary> |
1372 | + /// Retrieves the count of subkeys of the current key. |
1373 | + /// </summary> |
1374 | + public int SubKeyCount |
1375 | + { |
1376 | + get { return _key.SubKeyCount; } |
1377 | + } |
1378 | + |
1379 | + /// <summary> |
1380 | + /// Retrieves the count of values in the key. |
1381 | + /// </summary> |
1382 | + public int ValueCount |
1383 | + { |
1384 | + get { return _key.ValueCount; } |
1385 | + } |
1386 | + |
1387 | + /// <summary> |
1388 | + /// Closes the key and flushes it to disk if its contents have been modified. |
1389 | + /// </summary> |
1390 | + public void Close() |
1391 | + { |
1392 | + _key.Close(); |
1393 | + } |
1394 | + |
1395 | + /// <summary> |
1396 | + /// Creates a new subkey or opens an existing subkey for write access. |
1397 | + /// The string subkey is not case-sensitive. |
1398 | + /// </summary> |
1399 | + /// <param name="name">The name or path of the subkey to create or open. </param> |
1400 | + /// <returns>A sub key to work with.</returns> |
1401 | + public IRegistryKey CreateSubKey(string name) |
1402 | + { |
1403 | + return new RegistryKeyWrapper(_key.CreateSubKey(name)); |
1404 | + } |
1405 | + |
1406 | + /// <summary> |
1407 | + /// Creates a new subkey or opens an existing subkey for write access, using the specified |
1408 | + /// permission check option. The string subkey is not case-sensitive. |
1409 | + /// </summary> |
1410 | + /// <param name="subkey">The name or path of the subkey to create or open.</param> |
1411 | + /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values that |
1412 | + /// specifies whether the key is opened for read or read/write access.</param> |
1413 | + /// <returns>A subkey to work with.</returns> |
1414 | + public IRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck) |
1415 | + { |
1416 | + return new RegistryKeyWrapper(_key.CreateSubKey(subkey, permissionCheck)); |
1417 | + } |
1418 | + |
1419 | + /// <summary> |
1420 | + /// Deletes the specified subkey. The string subkey is not case-sensitive. |
1421 | + /// </summary> |
1422 | + /// <param name="subkey">The name of the subkey to delete. </param> |
1423 | + public void DeleteSubKey(string subkey) |
1424 | + { |
1425 | + _key.DeleteSubKey(subkey); |
1426 | + } |
1427 | + |
1428 | + /// <summary> |
1429 | + /// Deletes the specified value from this key. |
1430 | + /// </summary> |
1431 | + /// <param name="name">The name of the value to delete.</param> |
1432 | + public void DeleteValue(string name) |
1433 | + { |
1434 | + _key.DeleteValue(name); |
1435 | + } |
1436 | + |
1437 | + /// <summary> |
1438 | + /// Writes all the attributes of the specified open registry |
1439 | + /// key into the registry. |
1440 | + /// </summary> |
1441 | + public void Flush() |
1442 | + { |
1443 | + _key.Flush(); |
1444 | + } |
1445 | + |
1446 | + /// <summary> |
1447 | + /// Retrieves an array of strings that contains all the subkey names. |
1448 | + /// </summary> |
1449 | + /// <returns>An array of strings that contains the names of the |
1450 | + /// subkeys for the current key.</returns> |
1451 | + public string[] GetSubKeyNames() |
1452 | + { |
1453 | + return _key.GetSubKeyNames(); |
1454 | + } |
1455 | + |
1456 | + /// <summary> |
1457 | + /// Retrieves the value associated with the specified name. |
1458 | + /// Returns null if the name/value pair does not exist in the registry. |
1459 | + /// </summary> |
1460 | + /// <param name="name">The name of the value to retrieve. </param> |
1461 | + /// <returns>The value associated with name, or null if name is not found.</returns> |
1462 | + public object GetValue(string name) |
1463 | + { |
1464 | + return _key.GetValue(name); |
1465 | + } |
1466 | + |
1467 | + /// <summary> |
1468 | + /// Retrieves the value associated with the specified name. |
1469 | + /// If the name is not found, returns the default value that you provide. |
1470 | + /// </summary> |
1471 | + /// <param name="name">The name of the value to retrieve.</param> |
1472 | + /// <param name="defaultValue">The value to return if name does not exist.</param> |
1473 | + /// <returns>The value associated with name, with any embedded |
1474 | + /// environment variables left unexpanded, or defaultValue if name is not found.</returns> |
1475 | + public object GetValue(string name, object defaultValue) |
1476 | + { |
1477 | + return _key.GetValue(name, defaultValue); |
1478 | + } |
1479 | + |
1480 | + /// <summary> |
1481 | + /// Retrieves the registry data type of the value associated with the specified name. |
1482 | + /// </summary> |
1483 | + /// <param name="name">The name of the value whose registry data type is to be retrieved. </param> |
1484 | + /// <returns>A RegistryValueKind value representing the registry |
1485 | + /// data type of the value associated with name.</returns> |
1486 | + public RegistryValueKind GetValueKind(string name) |
1487 | + { |
1488 | + return _key.GetValueKind(name); |
1489 | + } |
1490 | + |
1491 | + /// <summary> |
1492 | + /// Retrieves an array of strings that contains all the |
1493 | + /// value names associated with this key. |
1494 | + /// </summary> |
1495 | + /// <returns>An array of strings that contains |
1496 | + /// the value names for the current key.</returns> |
1497 | + public string[] GetValueNames() |
1498 | + { |
1499 | + return _key.GetValueNames(); |
1500 | + } |
1501 | + |
1502 | + /// <summary> |
1503 | + /// Retrieves a subkey as read-only. |
1504 | + /// </summary> |
1505 | + /// <param name="name">The name or path of the subkey to open read-only. </param> |
1506 | + /// <returns>The subkey requested, or null if the operation failed.</returns> |
1507 | + public IRegistryKey OpenSubKey(string name) |
1508 | + { |
1509 | + return new RegistryKeyWrapper(_key.OpenSubKey(name)); |
1510 | + } |
1511 | + |
1512 | + /// <summary> |
1513 | + /// Retrieves the specified subkey for read or read/write access. |
1514 | + /// </summary> |
1515 | + /// <param name="name">The name or path of the subkey to create or open.</param> |
1516 | + /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values |
1517 | + /// that specifies whether the key is opened for read or read/write access.</param> |
1518 | + /// <returns></returns> |
1519 | + public IRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck) |
1520 | + { |
1521 | + return new RegistryKeyWrapper(_key.OpenSubKey(name, permissionCheck)); |
1522 | + } |
1523 | + |
1524 | + /// <summary> |
1525 | + /// Sets the specified name/value pair. |
1526 | + /// </summary> |
1527 | + /// <param name="name">The name of the value to store. </param> |
1528 | + /// <param name="value">The data to be stored.</param> |
1529 | + public void SetValue(string name, object value) |
1530 | + { |
1531 | + _key.SetValue(name, value); |
1532 | + } |
1533 | + |
1534 | + /// <summary> |
1535 | + /// Sets the value of a name/value pair in the registry key, using the specified registry data type. |
1536 | + /// </summary> |
1537 | + /// <param name="name">The name of the value to be stored. </param> |
1538 | + /// <param name="value">The data to be stored. </param> |
1539 | + /// <param name="valueKind">The registry data type to use when storing the data</param> |
1540 | + public void SetValue(string name, object value, RegistryValueKind valueKind) |
1541 | + { |
1542 | + _key.SetValue(name, value, valueKind); |
1543 | + } |
1544 | + |
1545 | + #endregion |
1546 | + } |
1547 | +} |
1548 | |
1549 | === modified file 'src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs' |
1550 | --- src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs 2010-07-23 15:50:15 +0000 |
1551 | +++ src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs 2010-09-17 16:23:44 +0000 |
1552 | @@ -236,6 +236,44 @@ |
1553 | .Check(); |
1554 | } |
1555 | |
1556 | + [TestCase("Robert", 255)] |
1557 | + [TestCase("true", 5)] |
1558 | + public void IsShorterThanTest(string value, int length) |
1559 | + { |
1560 | + ValidateArgs.Begin() |
1561 | + .IsShorterThan(value, length, "") |
1562 | + .Check(); |
1563 | + } |
1564 | + |
1565 | + |
1566 | + [TestCase("Robert", 2)] |
1567 | + [TestCase("true", 1)] |
1568 | + [ExpectedException(typeof(ValidationException))] |
1569 | + public void IsShorterThanFailTest(string value, int length) |
1570 | + { |
1571 | + ValidateArgs.Begin() |
1572 | + .IsShorterThan(value, length, "") |
1573 | + .Check(); |
1574 | + } |
1575 | + |
1576 | + [TestCase("true", 4)] |
1577 | + [TestCase("Robert", 255)] |
1578 | + public void IsShorterOrEqualToTest(string value, int length) |
1579 | + { |
1580 | + ValidateArgs.Begin() |
1581 | + .IsShorterOrEqualTo(value, length, "") |
1582 | + .Check(); |
1583 | + } |
1584 | + |
1585 | + [TestCase("Robert", 2)] |
1586 | + [TestCase("true", 1)] |
1587 | + [ExpectedException(typeof(ValidationException))] |
1588 | + public void IsShorterOrEqualToFailTest(string value, int length) |
1589 | + { |
1590 | + ValidateArgs.Begin() |
1591 | + .IsShorterOrEqualTo(value, length, "") |
1592 | + .Check(); |
1593 | + } |
1594 | #endregion |
1595 | |
1596 | } |
1597 | |
1598 | === modified file 'src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs' |
1599 | --- src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs 2010-08-11 08:05:19 +0000 |
1600 | +++ src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs 2010-09-17 16:23:44 +0000 |
1601 | @@ -242,5 +242,55 @@ |
1602 | (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException( |
1603 | string.Format("'{0}' cannot be null or empty.", parameterName))); |
1604 | } |
1605 | + |
1606 | + /// <summary> |
1607 | + /// Ensures that the string that was passed as argument is not too long. |
1608 | + /// </summary> |
1609 | + /// <param name="argumentValidation"> |
1610 | + /// A <see cref="ArgumentValidation"/> with the current result of the validations. |
1611 | + /// </param> |
1612 | + /// <param name="value"> |
1613 | + /// A <see cref="System.String"/> with the argument to validate. |
1614 | + /// </param> |
1615 | + /// <param name="length"> |
1616 | + /// An int with the length not to be excided by the string. |
1617 | + /// </param> |
1618 | + /// <param name="parameterName">The name of the parameter under test.</param> |
1619 | + /// <returns> |
1620 | + /// A <see cref="ArgumentValidation"/> the result of the validation. |
1621 | + /// </returns> |
1622 | + public static ArgumentValidation IsShorterThan(this ArgumentValidation argumentValidation, string value, |
1623 | + int length, string parameterName) |
1624 | + { |
1625 | + return (value.Length < length) |
1626 | + ? argumentValidation : |
1627 | + (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException( |
1628 | + string.Format("'{0}' has to be smaller than {1} chars.",parameterName, length))); |
1629 | + } |
1630 | + |
1631 | + /// <summary> |
1632 | + /// Ensures that the string that was passed as argument is not too long. |
1633 | + /// </summary> |
1634 | + /// <param name="argumentValidation"> |
1635 | + /// A <see cref="ArgumentValidation"/> with the current result of the validations. |
1636 | + /// </param> |
1637 | + /// <param name="value"> |
1638 | + /// A <see cref="System.String"/> with the argument to validate. |
1639 | + /// </param> |
1640 | + /// <param name="length"> |
1641 | + /// An int with the length not to be excided by the string. |
1642 | + /// </param> |
1643 | + /// <param name="parameterName">The name of the parameter under test.</param> |
1644 | + /// <returns> |
1645 | + /// A <see cref="ArgumentValidation"/> the result of the validation. |
1646 | + /// </returns> |
1647 | + public static ArgumentValidation IsShorterOrEqualTo(this ArgumentValidation argumentValidation, string value, |
1648 | + int length, string parameterName) |
1649 | + { |
1650 | + return (value.Length <= length) |
1651 | + ? argumentValidation : |
1652 | + (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException( |
1653 | + string.Format("'{0}' has to be smaller or equalt to {1} chars.", parameterName, length))); |
1654 | + } |
1655 | } |
1656 | } |
1657 | |
1658 | === modified file 'src/UbuntuOne.sln' |
1659 | --- src/UbuntuOne.sln 2010-09-08 11:23:58 +0000 |
1660 | +++ src/UbuntuOne.sln 2010-09-17 16:23:44 +0000 |
1661 | @@ -25,6 +25,8 @@ |
1662 | EndProject |
1663 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canonical.Ubuntu.SSO", "Canonical.Ubuntu.SSO\Canonical.Ubuntu.SSO.csproj", "{9460A771-2589-45DA-9618-9FE8BB7D16E8}" |
1664 | EndProject |
1665 | +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canonical.Ubuntu.SSO.Tests", "Canonical.Ubuntu.SSO.Tests\Canonical.Ubuntu.SSO.Tests.csproj", "{17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}" |
1666 | +EndProject |
1667 | Global |
1668 | GlobalSection(SolutionConfigurationPlatforms) = preSolution |
1669 | Debug|Any CPU = Debug|Any CPU |
1670 | @@ -155,6 +157,16 @@ |
1671 | {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU |
1672 | {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU |
1673 | {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|x86.ActiveCfg = Release|Any CPU |
1674 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
1675 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Any CPU.Build.0 = Debug|Any CPU |
1676 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU |
1677 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU |
1678 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|x86.ActiveCfg = Debug|Any CPU |
1679 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Any CPU.ActiveCfg = Release|Any CPU |
1680 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Any CPU.Build.0 = Release|Any CPU |
1681 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU |
1682 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Mixed Platforms.Build.0 = Release|Any CPU |
1683 | + {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|x86.ActiveCfg = Release|Any CPU |
1684 | EndGlobalSection |
1685 | GlobalSection(SolutionProperties) = preSolution |
1686 | HideSolutionNode = FALSE |
I get a whole lot of errors (pasting what I have from my terminal buffer) and the build fails during NAnt.exe tests:
[msbuild] Copying file from "obj\Debug\ ServiceTestApp. pdb" to "bin\Debug\Ser ubuntuone- windows- installer\ revi src\ServiceTest App\ServiceTest App.csproj" (default targets). ubuntuone- windows- installer\ review. aussk\src\ U ubuntuone- windows- installer\ review. a UbuntuOneClient \UbuntuOneClien t.csproj" (13) on node 0 (default targets Resources. resx" into "obj\Deb ent.Properties. Resources. resources" . dCopyLocal: lib\WPFContrib\ AvalonLibrary. dll" to "bin AvalonLibrary. dll". ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Client\ bin\Debug\ Canonical. UbuntuOne. Client. dll" Canonical. UbuntuOne. Client. dll". ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ Canonical. UbuntuOne. Common. dll" Canonical. UbuntuOne. Common. dll". lib\Spring. Net\Common. Logging. Log4Net. dll Common. Logging. Log4Net. dll". lib\log4net\ log4net. dll" to "bin\Debug\lo ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ Spring. Aop.dll" to "bin\Debug\Sp lib\Spring. Net\Common. Logging. dll" to "bi Common. Logging. dll". ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ DotUpdater. dll" to "bin\Debug\Do ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ Spring. Core.dll" to "bin\Debug\S ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ Spring. Aop.xml" to "bin\Debug\Sp ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ DotUpdater. pdb" to "bin\Debug\Do ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Common\ bin\Debug\ Spring. Core.xml" to "bin\Debug\S ubuntuone- windows- installer\ review src\Canonical. UbuntuOne. Client\ bin\Debug\ Canonical. UbuntuOne. Client. pdb" Canonical. UbuntuOne. Client. pdb". ubuntuo. ..
viceTestApp.pdb".
[msbuild] Done Building Project "C:\canonical\
ew.aussk\
[msbuild] Project "C:\canonical\
buntuOne.sln" (1) is building "C:\canonical\
ussk\src\
).
[msbuild] Processing 0 EDMX files.
[msbuild] Finished processing 0 EDMX files.
[msbuild] PrepareForBuild:
[msbuild] Creating directory "bin\Debug\".
[msbuild] Creating directory "obj\Debug\".
[msbuild] CoreResGen:
[msbuild] Processing resource file "Properties\
ug\UbuntuOneCli
[msbuild] _CopyFilesMarke
[msbuild] Copying file from "..\..\
\Debug\
[msbuild] Copying file from "C:\canonical\
.aussk\
to "bin\Debug\
[msbuild] Copying file from "C:\canonical\
.aussk\
to "bin\Debug\
[msbuild] Copying file from "..\..\
" to "bin\Debug\
[msbuild] Copying file from "..\..\
g4net.dll".
[msbuild] Copying file from "C:\canonical\
.aussk\
ring.Aop.dll".
[msbuild] Copying file from "..\..\
n\Debug\
[msbuild] Copying file from "C:\canonical\
.aussk\
tUpdater.dll".
[msbuild] Copying file from "C:\canonical\
.aussk\
pring.Core.dll".
[msbuild] Copying file from "C:\canonical\
.aussk\
ring.Aop.xml".
[msbuild] Copying file from "C:\canonical\
.aussk\
tUpdater.pdb".
[msbuild] Copying file from "C:\canonical\
.aussk\
pring.Core.xml".
[msbuild] Copying file from "C:\canonical\
.aussk\
to "bin\Debug\
[msbuild] Copying file from "C:\canonical\