Merge lp:~mandel/ubuntuone-windows-installer/add_ubuntu_sso_service_keyring into lp:ubuntuone-windows-installer/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
Reviewer Review Type Date Requested Status
Vincenzo Di Somma (community) Approve
Rick McBride (community) Approve
Review via email: mp+35276@code.launchpad.net

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 :
Download full text (16.7 KiB)

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
viceTestApp.pdb".
  [msbuild] Done Building Project "C:\canonical\ubuntuone-windows-installer\revi
ew.aussk\src\ServiceTestApp\ServiceTestApp.csproj" (default targets).
  [msbuild] Project "C:\canonical\ubuntuone-windows-installer\review.aussk\src\U
buntuOne.sln" (1) is building "C:\canonical\ubuntuone-windows-installer\review.a
ussk\src\UbuntuOneClient\UbuntuOneClient.csproj" (13) on node 0 (default targets
).
  [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\Resources.resx" into "obj\Deb
ug\UbuntuOneClient.Properties.Resources.resources".
  [msbuild] _CopyFilesMarkedCopyLocal:
  [msbuild] Copying file from "..\..\lib\WPFContrib\AvalonLibrary.dll" to "bin
\Debug\AvalonLibrary.dll".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Client\bin\Debug\Canonical.UbuntuOne.Client.dll"
to "bin\Debug\Canonical.UbuntuOne.Client.dll".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\Canonical.UbuntuOne.Common.dll"
to "bin\Debug\Canonical.UbuntuOne.Common.dll".
  [msbuild] Copying file from "..\..\lib\Spring.Net\Common.Logging.Log4Net.dll
" to "bin\Debug\Common.Logging.Log4Net.dll".
  [msbuild] Copying file from "..\..\lib\log4net\log4net.dll" to "bin\Debug\lo
g4net.dll".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\Spring.Aop.dll" to "bin\Debug\Sp
ring.Aop.dll".
  [msbuild] Copying file from "..\..\lib\Spring.Net\Common.Logging.dll" to "bi
n\Debug\Common.Logging.dll".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\DotUpdater.dll" to "bin\Debug\Do
tUpdater.dll".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\Spring.Core.dll" to "bin\Debug\S
pring.Core.dll".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\Spring.Aop.xml" to "bin\Debug\Sp
ring.Aop.xml".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\DotUpdater.pdb" to "bin\Debug\Do
tUpdater.pdb".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Common\bin\Debug\Spring.Core.xml" to "bin\Debug\S
pring.Core.xml".
  [msbuild] Copying file from "C:\canonical\ubuntuone-windows-installer\review
.aussk\src\Canonical.UbuntuOne.Client\bin\Debug\Canonical.UbuntuOne.Client.pdb"
to "bin\Debug\Canonical.UbuntuOne.Client.pdb".
  [msbuild] Copying file from "C:\canonical\ubuntuo...

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.

Revision history for this message
Rick McBride (rmcbride) wrote :

+1

review: Approve
Revision history for this message
Vincenzo Di Somma (vds) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file '.bzrignore'
--- .bzrignore 2010-09-08 11:23:58 +0000
+++ .bzrignore 2010-09-17 16:23:44 +0000
@@ -8,6 +8,8 @@
8src/_ReSharper.UbuntuOne8src/_ReSharper.UbuntuOne
9src/Canonical.Ubuntu.SSO/bin9src/Canonical.Ubuntu.SSO/bin
10src/Canonical.Ubuntu.SSO/obj10src/Canonical.Ubuntu.SSO/obj
11src/Canonical.Ubuntu.SSO.Tests/bin
12src/Canonical.Ubuntu.SSO.Tests/obj
11src/Canonical.UbuntuOne.Client/bin13src/Canonical.UbuntuOne.Client/bin
12src/Canonical.UbuntuOne.Client/obj14src/Canonical.UbuntuOne.Client/obj
13src/Canonical.UbuntuOne.Client.Test/obj15src/Canonical.UbuntuOne.Client.Test/obj
1416
=== modified file 'main.build'
--- main.build 2010-09-02 10:27:49 +0000
+++ main.build 2010-09-17 16:23:44 +0000
@@ -156,7 +156,7 @@
156 program="nunit-console.exe"156 program="nunit-console.exe"
157 commandline="Canonical.UbuntuOne.ProcessDispatcher.Tests.dll /xml=../../../../test-results/Canonical.UbuntuOne.ProcessDispatcher.Tests-Result.xml" />157 commandline="Canonical.UbuntuOne.ProcessDispatcher.Tests.dll /xml=../../../../test-results/Canonical.UbuntuOne.ProcessDispatcher.Tests-Result.xml" />
158158
159 <echo>Canonical.UbuntuOne.Client.Test</echo>159 <echo>Executing Canonical.UbuntuOne.Client.Test</echo>
160 <exec basedir="tools/NUnit"160 <exec basedir="tools/NUnit"
161 managed="true"161 managed="true"
162 workingdir="src/Canonical.UbuntuOne.Client.Test/bin/${enviroment}"162 workingdir="src/Canonical.UbuntuOne.Client.Test/bin/${enviroment}"
@@ -169,12 +169,20 @@
169 <copy file="src/Canonical.UbuntuOne.Client.Views/bin/${enviroment}/AvalonLibrary.dll"169 <copy file="src/Canonical.UbuntuOne.Client.Views/bin/${enviroment}/AvalonLibrary.dll"
170 tofile="src/UbuntuOneClient.Tests/bin/${enviroment}/AvalonLibrary.dll" /> 170 tofile="src/UbuntuOneClient.Tests/bin/${enviroment}/AvalonLibrary.dll" />
171 171
172 <echo>UbuntuOneClient.Tests</echo>172 <echo>Executing UbuntuOneClient.Tests</echo>
173 <exec basedir="tools/NUnit"173 <exec basedir="tools/NUnit"
174 managed="true"174 managed="true"
175 workingdir="src/UbuntuOneClient.Tests/bin/${enviroment}"175 workingdir="src/UbuntuOneClient.Tests/bin/${enviroment}"
176 program="nunit-console.exe"176 program="nunit-console.exe"
177 commandline="UbuntuOneClient.Tests.dll /xml=../../../../test-results/UbuntuOneClient.Tests-Result.xml" />177 commandline="UbuntuOneClient.Tests.dll /xml=../../../../test-results/UbuntuOneClient.Tests-Result.xml" />
178
179 <echo>Executing Canonical.Ubuntu.SSO.Tests</echo>
180 <exec basedir="tools/NUnit"
181 managed="true"
182 workingdir="src/Canonical.Ubuntu.SSO.Tests/bin/${enviroment}"
183 program="nunit-console.exe"
184 commandline="Canonical.Ubuntu.SSO.Tests.dll /xml=../../../../test-results/Canonical.Ubuntu.SSO.Tests-Result.xml" />
185
178 </target>186 </target>
179 <target name="package_python"187 <target name="package_python"
180 description="Creates the exe binary that embeds the python libs that will be used to perform the sync operation in the windows platform">188 description="Creates the exe binary that embeds the python libs that will be used to perform the sync operation in the windows platform">
181189
=== added directory 'src/Canonical.Ubuntu.SSO.Tests'
=== added file 'src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj'
--- src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO.Tests/Canonical.Ubuntu.SSO.Tests.csproj 2010-09-17 16:23:44 +0000
@@ -0,0 +1,74 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup>
4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 <ProductVersion>9.0.21022</ProductVersion>
7 <SchemaVersion>2.0</SchemaVersion>
8 <ProjectGuid>{17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}</ProjectGuid>
9 <OutputType>Library</OutputType>
10 <AppDesignerFolder>Properties</AppDesignerFolder>
11 <RootNamespace>Canonical.Ubuntu.SSO.Tests</RootNamespace>
12 <AssemblyName>Canonical.Ubuntu.SSO.Tests</AssemblyName>
13 <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
14 <FileAlignment>512</FileAlignment>
15 </PropertyGroup>
16 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17 <DebugSymbols>true</DebugSymbols>
18 <DebugType>full</DebugType>
19 <Optimize>false</Optimize>
20 <OutputPath>bin\Debug\</OutputPath>
21 <DefineConstants>DEBUG;TRACE</DefineConstants>
22 <ErrorReport>prompt</ErrorReport>
23 <WarningLevel>4</WarningLevel>
24 </PropertyGroup>
25 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
26 <DebugType>pdbonly</DebugType>
27 <Optimize>true</Optimize>
28 <OutputPath>bin\Release\</OutputPath>
29 <DefineConstants>TRACE</DefineConstants>
30 <ErrorReport>prompt</ErrorReport>
31 <WarningLevel>4</WarningLevel>
32 </PropertyGroup>
33 <ItemGroup>
34 <Reference Include="nunit.framework, Version=2.5.5.10112, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
35 <SpecificVersion>False</SpecificVersion>
36 <HintPath>..\..\lib\Nunit\nunit.framework.dll</HintPath>
37 </Reference>
38 <Reference Include="Rhino.Mocks, Version=3.6.0.0, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL">
39 <SpecificVersion>False</SpecificVersion>
40 <HintPath>..\..\lib\RhinoMocks\Rhino.Mocks.dll</HintPath>
41 </Reference>
42 <Reference Include="System" />
43 <Reference Include="System.Core">
44 <RequiredTargetFramework>3.5</RequiredTargetFramework>
45 </Reference>
46 <Reference Include="System.Security" />
47 <Reference Include="System.Xml.Linq">
48 <RequiredTargetFramework>3.5</RequiredTargetFramework>
49 </Reference>
50 <Reference Include="System.Data.DataSetExtensions">
51 <RequiredTargetFramework>3.5</RequiredTargetFramework>
52 </Reference>
53 <Reference Include="System.Data" />
54 <Reference Include="System.Xml" />
55 </ItemGroup>
56 <ItemGroup>
57 <Compile Include="KeyringFixture.cs" />
58 <Compile Include="Properties\AssemblyInfo.cs" />
59 </ItemGroup>
60 <ItemGroup>
61 <ProjectReference Include="..\Canonical.Ubuntu.SSO\Canonical.Ubuntu.SSO.csproj">
62 <Project>{9460A771-2589-45DA-9618-9FE8BB7D16E8}</Project>
63 <Name>Canonical.Ubuntu.SSO</Name>
64 </ProjectReference>
65 </ItemGroup>
66 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
67 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
68 Other similar extension points exist, see Microsoft.Common.targets.
69 <Target Name="BeforeBuild">
70 </Target>
71 <Target Name="AfterBuild">
72 </Target>
73 -->
74</Project>
0\ No newline at end of file75\ No newline at end of file
176
=== added file 'src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs'
--- src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO.Tests/KeyringFixture.cs 2010-09-17 16:23:44 +0000
@@ -0,0 +1,409 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System.Linq;
21using System.Security.Cryptography;
22using System.Text;
23using NUnit.Framework;
24using Rhino.Mocks;
25
26namespace Canonical.Ubuntu.SSO.Tests
27{
28 [TestFixture]
29 public class KeyringFixture
30 {
31 #region Variables
32
33 private MockRepository _mocks;
34 private IRegistryKey _userRegistry;
35 private IRegistryKey _keyringsRoot;
36 private IRegistryKey _keyringKey;
37 private IDataProtector _dataProtector;
38 private Keyring _keyring;
39
40 #endregion
41
42 #region Setup & TearDown
43
44 [SetUp]
45 public void Setup()
46 {
47 _mocks = new MockRepository();
48 _userRegistry = _mocks.StrictMock<IRegistryKey>();
49 _keyringsRoot = _mocks.StrictMock<IRegistryKey>();
50 _keyringKey = _mocks.StrictMock<IRegistryKey>();
51 _dataProtector = _mocks.StrictMock<IDataProtector>();
52 _keyring = new Keyring(_userRegistry) { DataProtector = _dataProtector };
53 }
54
55 #endregion
56
57 #region Tests
58
59 [Test]
60 public void DisposeTest()
61 {
62 using (_mocks.Record())
63 {
64 Expect.Call(() => _userRegistry.Dispose())
65 .Repeat.Once();
66 }
67 using (_mocks.Playback())
68 {
69 // we ensure that we always dispose the registry key to ensure no
70 // memory leaks.
71 _keyring.Dispose();
72 }
73 }
74
75 [TestCase("Default", "UbuntuOne", "myPassword")]
76 [TestCase("Default", "Mandel", "Secret")]
77 [TestCase("Test", "Leo", "MySecret")]
78 public void CreateSecretNoRootPathPresentTest(string keyringName, string applicationName, string secret)
79 {
80 using (_mocks.Record())
81 {
82 using (_mocks.Ordered())
83 {
84 Expect.Call(_userRegistry.GetSubKeyNames())
85 .Return(new[] {"Blah", "BlahBlah"})
86 .Repeat.Twice();
87
88 Expect.Call(_userRegistry.CreateSubKey(Keyring.RootPath))
89 .Return(_keyringsRoot)
90 .Repeat.Once();
91
92 Expect.Call(_keyringsRoot.CreateSubKey(keyringName))
93 .Return(_keyringKey)
94 .Repeat.Once();
95
96 Expect.Call(() => _keyringKey.Dispose())
97 .Repeat.Any();
98
99 Expect.Call(() => _keyringsRoot.Dispose())
100 .Repeat.Any();
101
102 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
103 .Return(_keyringsRoot)
104 .Repeat.Once();
105
106 Expect.Call(_keyringsRoot.OpenSubKey(keyringName))
107 .Return(_keyringKey)
108 .Repeat.Once();
109
110 Expect.Call(_dataProtector.Protect(secret,
111 Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser))
112 .Return(secret)
113 .Repeat.Once();
114
115 Expect.Call(() => _keyringKey.SetValue(applicationName, secret))
116 .Repeat.Once();
117
118 }
119
120 }
121 using (_mocks.Playback())
122 {
123 _keyring.CreateSecret(keyringName, applicationName, secret);
124 }
125 }
126
127 [TestCase("Default", "UbuntuOne", "myPassword")]
128 [TestCase("Default", "Mandel", "Secret")]
129 [TestCase("Test", "Leo", "MySecret")]
130 public void CreateSecretNoKeyringPresentTest(string keyringName, string applicationName, string secret)
131 {
132 using (_mocks.Record())
133 {
134 using(_mocks.Ordered())
135 {
136 Expect.Call(_userRegistry.GetSubKeyNames())
137 .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath})
138 .Repeat.Once();
139
140 Expect.Call(() => _keyringsRoot.Dispose())
141 .Repeat.Any();
142
143 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
144 .Return(_keyringsRoot)
145 .Repeat.Once();
146
147 Expect.Call(_keyringsRoot.GetSubKeyNames())
148 .Return(new string[] { })
149 .Repeat.Once();
150
151 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
152 .Return(_keyringsRoot)
153 .Repeat.Once();
154
155 Expect.Call(_keyringsRoot.CreateSubKey(keyringName))
156 .Return(_keyringKey)
157 .Repeat.Once();
158
159 Expect.Call(() => _keyringKey.Dispose())
160 .Repeat.Any();
161
162 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
163 .Return(_keyringsRoot)
164 .Repeat.Once();
165
166 Expect.Call(_keyringsRoot.OpenSubKey(keyringName))
167 .Return(_keyringKey)
168 .Repeat.Once();
169
170 Expect.Call(_dataProtector.Protect(secret,
171 Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser))
172 .Return(secret)
173 .Repeat.Once();
174
175 Expect.Call(() => _keyringKey.SetValue(applicationName, secret))
176 .Repeat.Once();
177
178 }
179 }
180 using (_mocks.Playback())
181 {
182 _keyring.CreateSecret(keyringName, applicationName, secret);
183 }
184 }
185
186 [TestCase("Default", "UbuntuOne", "myPassword")]
187 [TestCase("Default", "Mandel", "Secret")]
188 [TestCase("Test", "Leo", "MySecret")]
189 public void CreateSecretPresentKeyringTest(string keyringName, string applicationName, string secret)
190 {
191 using(_mocks.Record())
192 {
193 using(_mocks.Ordered())
194 {
195 Expect.Call(_userRegistry.GetSubKeyNames())
196 .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath })
197 .Repeat.Once();
198
199 Expect.Call(() => _keyringsRoot.Dispose())
200 .Repeat.Any();
201
202 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
203 .Return(_keyringsRoot)
204 .Repeat.Once();
205
206 Expect.Call(_keyringsRoot.GetSubKeyNames())
207 .Return(new[] { keyringName})
208 .Repeat.Once();
209
210 Expect.Call(() => _keyringKey.Dispose())
211 .Repeat.Any();
212
213 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
214 .Return(_keyringsRoot)
215 .Repeat.Once();
216
217 Expect.Call(_keyringsRoot.OpenSubKey(keyringName))
218 .Return(_keyringKey)
219 .Repeat.Once();
220
221 Expect.Call(_dataProtector.Protect(secret,
222 Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser))
223 .Return(secret)
224 .Repeat.Once();
225
226 Expect.Call(() => _keyringKey.SetValue(applicationName, secret))
227 .Repeat.Once();
228 }
229 }
230 using(_mocks.Playback())
231 {
232 _keyring.CreateSecret(keyringName, applicationName, secret);
233 }
234 }
235
236 [TestCase("Default", "UbuntuOne")]
237 [TestCase("Keyring", "AppNAme")]
238 public void GetSecretByNameNotKeyringTest(string keyringName, string applicationName)
239 {
240 using(_mocks.Record())
241 {
242 Expect.Call(_userRegistry.GetSubKeyNames())
243 .Return(new[] { "Blah", "BlahBlah" })
244 .Repeat.Once();
245 }
246 using(_mocks.Playback())
247 {
248 var secret = _keyring.GetSecretByName(keyringName, applicationName);
249 Assert.IsEmpty(secret);
250 }
251 }
252
253 [TestCase("Default", "UbuntuOne")]
254 [TestCase("Keyring", "AppNAme")]
255 public void GetSecretByNameKeyringExistsTest(string keyringName, string applicationName)
256 {
257 using (_mocks.Record())
258 {
259 using (_mocks.Ordered())
260 {
261 Expect.Call(_userRegistry.GetSubKeyNames())
262 .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath })
263 .Repeat.Once();
264
265 Expect.Call(() => _keyringsRoot.Dispose())
266 .Repeat.Any();
267
268 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
269 .Return(_keyringsRoot)
270 .Repeat.Once();
271
272 Expect.Call(_keyringsRoot.GetSubKeyNames())
273 .Return(new[] { keyringName })
274 .Repeat.Once();
275
276 Expect.Call(() => _keyringKey.Dispose())
277 .Repeat.Any();
278
279 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
280 .Return(_keyringsRoot)
281 .Repeat.Once();
282
283 Expect.Call(_keyringsRoot.OpenSubKey(keyringName))
284 .Return(_keyringKey)
285 .Repeat.Once();
286
287 Expect.Call(_keyringKey.GetValue(applicationName))
288 .Return(applicationName)
289 .Repeat.Once();
290
291 Expect.Call(_dataProtector.Unprotect("",
292 Encoding.UTF8.GetBytes(Keyring.Entropy), DataProtectionScope.CurrentUser))
293 .IgnoreArguments()
294 .Return(applicationName)
295 .Repeat.Once();
296
297 }
298 }
299 using (_mocks.Playback())
300 {
301 var secret = _keyring.GetSecretByName(keyringName, applicationName);
302 Assert.AreEqual(applicationName, secret);
303 }
304 }
305
306 [Test]
307 public void GetKeyringsTest()
308 {
309 var keyrings = new[] {"Default", "Test", "Test1"};
310
311 using(_mocks.Record())
312 {
313 // make it such that the root is present
314 Expect.Call(_userRegistry.GetSubKeyNames())
315 .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath })
316 .Repeat.Once();
317
318 Expect.Call(() => _keyringsRoot.Dispose())
319 .Repeat.Any();
320
321 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
322 .Return(_keyringsRoot)
323 .Repeat.Once();
324
325 Expect.Call(_keyringsRoot.GetSubKeyNames())
326 .Return(keyrings)
327 .Repeat.Once();
328
329 }
330 using(_mocks.Playback())
331 {
332 Assert.AreSame(_keyring.GetKeyrings(), keyrings);
333 }
334 }
335
336 [Test]
337 public void GetKeyringsNotRootTest()
338 {
339 using (_mocks.Record())
340 {
341 // make it such that the root is present
342 Expect.Call(_userRegistry.GetSubKeyNames())
343 .Return(new[] { "Blah", "BlahBlah"})
344 .Repeat.Once();
345 }
346 using (_mocks.Playback())
347 {
348 Assert.AreEqual(0, _keyring.GetKeyrings().Count());
349 }
350 }
351
352 [TestCase("Default")]
353 [TestCase("Test")]
354 public void GetApplicationsTest(string keyringName)
355 {
356 var applications = new[] {"Ubuntu One", "Test", "Default"};
357 using(_mocks.Record())
358 {
359 Expect.Call(_userRegistry.GetSubKeyNames())
360 .Return(new[] { "Blah", "BlahBlah", Keyring.RootPath })
361 .Repeat.Once();
362
363 Expect.Call(() => _keyringsRoot.Dispose())
364 .Repeat.Any();
365
366 Expect.Call(_userRegistry.OpenSubKey(Keyring.RootPath))
367 .Return(_keyringsRoot)
368 .Repeat.Twice();
369
370 Expect.Call(_keyringsRoot.GetSubKeyNames())
371 .Return(new[] { keyringName })
372 .Repeat.Once();
373
374 Expect.Call(_keyringsRoot.OpenSubKey(keyringName))
375 .Return(_keyringKey)
376 .Repeat.Once();
377
378 Expect.Call(_keyringKey.GetSubKeyNames())
379 .Return(applications)
380 .Repeat.Once();
381
382 Expect.Call(() => _keyringKey.Dispose())
383 .Repeat.Any();
384 }
385 using(_mocks.Playback())
386 {
387 Assert.AreSame(applications, _keyring.GetApplications(keyringName));
388 }
389 }
390
391 [Test]
392 public void GetApplicationNotKeyringTest()
393 {
394 using (_mocks.Record())
395 {
396 // make it such that the root is present
397 Expect.Call(_userRegistry.GetSubKeyNames())
398 .Return(new[] { "Blah", "BlahBlah" })
399 .Repeat.Once();
400 }
401 using(_mocks.Playback())
402 {
403 Assert.AreEqual(0, _keyring.GetApplications("Test").Count());
404 }
405 }
406
407 #endregion
408 }
409}
0410
=== added directory 'src/Canonical.Ubuntu.SSO.Tests/Properties'
=== added file 'src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs'
--- src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO.Tests/Properties/AssemblyInfo.cs 2010-09-17 16:23:44 +0000
@@ -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("Canonical.Ubuntu.SSO.Tests")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("")]
12[assembly: AssemblyProduct("Canonical.Ubuntu.SSO.Tests")]
13[assembly: AssemblyCopyright("Copyright © 2010")]
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("055a2726-2682-4018-8c48-e1795da59ab2")]
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")]
037
=== modified file 'src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj'
--- src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj 2010-09-08 11:23:58 +0000
+++ src/Canonical.Ubuntu.SSO/Canonical.Ubuntu.SSO.csproj 2010-09-17 16:23:44 +0000
@@ -31,10 +31,15 @@
31 <WarningLevel>4</WarningLevel>31 <WarningLevel>4</WarningLevel>
32 </PropertyGroup>32 </PropertyGroup>
33 <ItemGroup>33 <ItemGroup>
34 <Reference Include="log4net, Version=1.2.10.0, Culture=neutral, PublicKeyToken=1b44e1d426115821, processorArchitecture=MSIL">
35 <SpecificVersion>False</SpecificVersion>
36 <HintPath>..\..\lib\log4net\log4net.dll</HintPath>
37 </Reference>
34 <Reference Include="System" />38 <Reference Include="System" />
35 <Reference Include="System.Core">39 <Reference Include="System.Core">
36 <RequiredTargetFramework>3.5</RequiredTargetFramework>40 <RequiredTargetFramework>3.5</RequiredTargetFramework>
37 </Reference>41 </Reference>
42 <Reference Include="System.Security" />
38 <Reference Include="System.Xml.Linq">43 <Reference Include="System.Xml.Linq">
39 <RequiredTargetFramework>3.5</RequiredTargetFramework>44 <RequiredTargetFramework>3.5</RequiredTargetFramework>
40 </Reference>45 </Reference>
@@ -45,17 +50,31 @@
45 <Reference Include="System.Xml" />50 <Reference Include="System.Xml" />
46 </ItemGroup>51 </ItemGroup>
47 <ItemGroup>52 <ItemGroup>
53 <Compile Include="..\Version.cs">
54 <Link>Properties\Version.cs</Link>
55 </Compile>
48 <Compile Include="CredentialsDeniedEventArgs.cs" />56 <Compile Include="CredentialsDeniedEventArgs.cs" />
49 <Compile Include="CredentialsErrorEventArgs.cs" />57 <Compile Include="CredentialsErrorEventArgs.cs" />
50 <Compile Include="CredentialsFoundEventArgs.cs" />58 <Compile Include="CredentialsFoundEventArgs.cs" />
59 <Compile Include="DPAPIDataProtector.cs" />
60 <Compile Include="IDataProtector.cs" />
51 <Compile Include="ILoginOrRegisterView.cs" />61 <Compile Include="ILoginOrRegisterView.cs" />
52 <Compile Include="ILoginView.cs" />62 <Compile Include="ILoginView.cs" />
63 <Compile Include="IRegistryKey.cs" />
64 <Compile Include="Keyring.cs" />
53 <Compile Include="LoginCredentialsEventArgs.cs" />65 <Compile Include="LoginCredentialsEventArgs.cs" />
66 <Compile Include="RegistryKeyWrapper.cs" />
54 <Compile Include="SSOCredentialsProvider.cs" />67 <Compile Include="SSOCredentialsProvider.cs" />
55 <Compile Include="IKeyring.cs" />68 <Compile Include="IKeyring.cs" />
56 <Compile Include="ISSOCredentialsProvider.cs" />69 <Compile Include="ISSOCredentialsProvider.cs" />
57 <Compile Include="Properties\AssemblyInfo.cs" />70 <Compile Include="Properties\AssemblyInfo.cs" />
58 </ItemGroup>71 </ItemGroup>
72 <ItemGroup>
73 <ProjectReference Include="..\Canonical.UbuntuOne.Common\Canonical.UbuntuOne.Common.csproj">
74 <Project>{11353FF8-8E5A-488E-9CB1-873DADD232B9}</Project>
75 <Name>Canonical.UbuntuOne.Common</Name>
76 </ProjectReference>
77 </ItemGroup>
59 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />78 <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
60 <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 79 <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
61 Other similar extension points exist, see Microsoft.Common.targets.80 Other similar extension points exist, see Microsoft.Common.targets.
6281
=== added file 'src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs'
--- src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO/DPAPIDataProtector.cs 2010-09-17 16:23:44 +0000
@@ -0,0 +1,65 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20
21using System.Security.Cryptography;
22using System.Text;
23
24namespace Canonical.Ubuntu.SSO
25{
26 /// <summary>
27 /// Implementation of the IDataProtector that uses the DAPI api to perform the protection.
28 /// </summary>
29 public class DPAPIDataProtector : IDataProtector
30 {
31 #region Implementation of IDataProtector
32
33 /// <summary>
34 /// Protects the userData parameter and returns a string.
35 /// </summary>
36 /// <param name="userData">A string containing data to protect. </param>
37 /// <param name="optionalEntropy">An additional byte array used to encrypt the data. </param>
38 /// <param name="scope">One of the DataProtectionScope values.</param>
39 /// <returns>A string representing the encrypted data.</returns>
40 public string Protect(string userData, byte[] optionalEntropy, DataProtectionScope scope)
41 {
42 var userDataBytes = Encoding.UTF8.GetBytes(userData);
43 var encryptedBytes = ProtectedData.Protect(userDataBytes, optionalEntropy, scope);
44 var enc = new UTF8Encoding(false);
45 return enc.GetString(encryptedBytes);
46 }
47
48 /// <summary>
49 /// Unprotects the encryptedData parameter and returns a string.
50 /// </summary>
51 /// <param name="encryptedData">A string containing data encrypted using the Protect method.</param>
52 /// <param name="optionalEntropy">An additional byte array used to encrypt the data.</param>
53 /// <param name="scope">One of the DataProtectionScope values. </param>
54 /// <returns>A string representing the unprotected data.</returns>
55 public string Unprotect(string encryptedData, byte[] optionalEntropy, DataProtectionScope scope)
56 {
57 var encryptedDataBytes = Encoding.UTF8.GetBytes(encryptedData);
58 var userDataBytes = ProtectedData.Unprotect(encryptedDataBytes, optionalEntropy, scope);
59 var enc = new UTF8Encoding(false);
60 return enc.GetString(userDataBytes);
61 }
62
63 #endregion
64 }
65}
066
=== added file 'src/Canonical.Ubuntu.SSO/IDataProtector.cs'
--- src/Canonical.Ubuntu.SSO/IDataProtector.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO/IDataProtector.cs 2010-09-17 16:23:44 +0000
@@ -0,0 +1,48 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System.Security.Cryptography;
21
22namespace Canonical.Ubuntu.SSO
23{
24 /// <summary>
25 /// Interface to be implemented by those objects that are able to encryp and decrypt users
26 /// data to protect it.
27 /// </summary>
28 public interface IDataProtector
29 {
30 /// <summary>
31 /// Protects the userData parameter and returns a string.
32 /// </summary>
33 /// <param name="userData">A string containing data to protect. </param>
34 /// <param name="optionalEntropy">An additional byte array used to encrypt the data. </param>
35 /// <param name="scope">One of the DataProtectionScope values.</param>
36 /// <returns>A string representing the encrypted data.</returns>
37 string Protect(string userData, byte[] optionalEntropy, DataProtectionScope scope);
38
39 /// <summary>
40 /// Unprotects the encryptedData parameter and returns a string.
41 /// </summary>
42 /// <param name="encryptedData">A string containing data encrypted using the Protect method.</param>
43 /// <param name="optionalEntropy">An additional byte array used to encrypt the data.</param>
44 /// <param name="scope">One of the DataProtectionScope values. </param>
45 /// <returns>A string representing the unprotected data.</returns>
46 string Unprotect(string encryptedData, byte[] optionalEntropy, DataProtectionScope scope);
47 }
48}
049
=== modified file 'src/Canonical.Ubuntu.SSO/IKeyring.cs'
--- src/Canonical.Ubuntu.SSO/IKeyring.cs 2010-09-09 09:11:07 +0000
+++ src/Canonical.Ubuntu.SSO/IKeyring.cs 2010-09-17 16:23:44 +0000
@@ -17,6 +17,7 @@
17 * 17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */19 */
20using System;
20using System.Collections.Generic;21using System.Collections.Generic;
2122
22namespace Canonical.Ubuntu.SSO23namespace Canonical.Ubuntu.SSO
@@ -25,7 +26,7 @@
25 /// Interface to be implemented by a class that allows to store data in the registry of the 26 /// Interface to be implemented by a class that allows to store data in the registry of the
26 /// current user and makes the class behave like a keyring.27 /// current user and makes the class behave like a keyring.
27 /// </summary>28 /// </summary>
28 public interface IKeyring29 public interface IKeyring : IDisposable
29 {30 {
30 /// <summary>31 /// <summary>
31 /// Creates a new secret in the the keyring with the given name for a given applciation.32 /// Creates a new secret in the the keyring with the given name for a given applciation.
@@ -36,11 +37,11 @@
36 void CreateSecret(string keyringName, string applicationName, string secret);37 void CreateSecret(string keyringName, string applicationName, string secret);
3738
38 /// <summary>39 /// <summary>
39 /// 40 /// Gets the secret froma keyring using the name of the application that stored it.
40 /// </summary>41 /// </summary>
41 /// <param name="keyringName"></param>42 /// <param name="keyringName">The name of the keyring where the secret was stored.</param>
42 /// <param name="applicationName"></param>43 /// <param name="applicationName">the name of the application that stored the secret.</param>
43 /// <returns></returns>44 /// <returns>An empty string if the secret does not exist, the secret otherwhise.</returns>
44 string GetSecretByName(string keyringName, string applicationName);45 string GetSecretByName(string keyringName, string applicationName);
4546
46 /// <summary>47 /// <summary>
@@ -52,8 +53,8 @@
52 /// <summary>53 /// <summary>
53 /// Gets a list with all the applications in a keyring.54 /// Gets a list with all the applications in a keyring.
54 /// </summary>55 /// </summary>
55 /// <param name="keyring">The name of the keyring that is queried.</param>56 /// <param name="keyringName">The name of the keyring that is queried.</param>
56 /// <returns>An enumerable with all the applications in the keyring.</returns>57 /// <returns>An enumerable with all the applications in the keyring.</returns>
57 IEnumerable<string> GetApplications(string keyring);58 IEnumerable<string> GetApplications(string keyringName);
58 }59 }
59}60}
6061
=== added file 'src/Canonical.Ubuntu.SSO/IRegistryKey.cs'
--- src/Canonical.Ubuntu.SSO/IRegistryKey.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO/IRegistryKey.cs 2010-09-17 16:23:44 +0000
@@ -0,0 +1,171 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20
21using System;
22using Microsoft.Win32;
23
24namespace Canonical.Ubuntu.SSO
25{
26 /// <summary>
27 /// Interface that represents a class that allows to perform the access to
28 /// the registry keys of the machine.
29 /// </summary>
30 public interface IRegistryKey : IDisposable
31 {
32 #region Properties
33
34 /// <summary>
35 /// Retrieves the name of the key.
36 /// </summary>
37 string Name { get; }
38
39 /// <summary>
40 /// Retrieves the count of subkeys of the current key.
41 /// </summary>
42 int SubKeyCount { get; }
43
44 /// <summary>
45 /// Retrieves the count of values in the key.
46 /// </summary>
47 int ValueCount { get; }
48
49 #endregion
50
51 #region Methods
52
53 /// <summary>
54 /// Closes the key and flushes it to disk if its contents have been modified.
55 /// </summary>
56 void Close();
57
58 /// <summary>
59 /// Creates a new subkey or opens an existing subkey for write access.
60 /// The string subkey is not case-sensitive.
61 /// </summary>
62 /// <param name="name">The name or path of the subkey to create or open. </param>
63 /// <returns>A sub key to work with.</returns>
64 IRegistryKey CreateSubKey(string name);
65
66 /// <summary>
67 /// Creates a new subkey or opens an existing subkey for write access, using the specified
68 /// permission check option. The string subkey is not case-sensitive.
69 /// </summary>
70 /// <param name="subkey">The name or path of the subkey to create or open.</param>
71 /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values that
72 /// specifies whether the key is opened for read or read/write access.</param>
73 /// <returns>A subkey to work with.</returns>
74 IRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck);
75
76 /// <summary>
77 /// Deletes the specified subkey. The string subkey is not case-sensitive.
78 /// </summary>
79 /// <param name="subkey">The name of the subkey to delete. </param>
80 void DeleteSubKey(string subkey);
81
82 /// <summary>
83 /// Deletes the specified value from this key.
84 /// </summary>
85 /// <param name="name">The name of the value to delete.</param>
86 void DeleteValue(string name);
87
88 /// <summary>
89 /// Writes all the attributes of the specified open registry
90 /// key into the registry.
91 /// </summary>
92 void Flush();
93
94 /// <summary>
95 /// Retrieves an array of strings that contains all the subkey names.
96 /// </summary>
97 /// <returns>An array of strings that contains the names of the
98 /// subkeys for the current key.</returns>
99 string[] GetSubKeyNames();
100
101 /// <summary>
102 /// Retrieves the value associated with the specified name.
103 /// Returns null if the name/value pair does not exist in the registry.
104 /// </summary>
105 /// <param name="name">The name of the value to retrieve. </param>
106 /// <returns>The value associated with name, or null if name is not found.</returns>
107 object GetValue(string name);
108
109 /// <summary>
110 /// Retrieves the value associated with the specified name.
111 /// If the name is not found, returns the default value that you provide.
112 /// </summary>
113 /// <param name="name">The name of the value to retrieve.</param>
114 /// <param name="defaultValue">The value to return if name does not exist.</param>
115 /// <returns>The value associated with name, with any embedded
116 /// environment variables left unexpanded, or defaultValue if name is not found.</returns>
117 object GetValue(string name, object defaultValue);
118
119 /// <summary>
120 /// Retrieves the registry data type of the value associated with the specified name.
121 /// </summary>
122 /// <param name="name">The name of the value whose registry data type is to be retrieved. </param>
123 /// <returns>A RegistryValueKind value representing the registry
124 /// data type of the value associated with name.</returns>
125 RegistryValueKind GetValueKind(string name);
126
127 /// <summary>
128 /// Retrieves an array of strings that contains all the
129 /// value names associated with this key.
130 /// </summary>
131 /// <returns>An array of strings that contains
132 /// the value names for the current key.</returns>
133 string[] GetValueNames();
134
135 /// <summary>
136 /// Retrieves a subkey as read-only.
137 /// </summary>
138 /// <param name="name">The name or path of the subkey to open read-only. </param>
139 /// <returns>The subkey requested, or null if the operation failed.</returns>
140 IRegistryKey OpenSubKey(string name);
141
142 /// <summary>
143 /// Retrieves the specified subkey for read or read/write access.
144 /// </summary>
145 /// <param name="name">The name or path of the subkey to create or open.</param>
146 /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values
147 /// that specifies whether the key is opened for read or read/write access.</param>
148 /// <returns></returns>
149 IRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck);
150
151 /// <summary>
152 /// Sets the specified name/value pair.
153 /// </summary>
154 /// <param name="name">The name of the value to store. </param>
155 /// <param name="value">The data to be stored.</param>
156 void SetValue(string name, Object value);
157
158 /// <summary>
159 /// Sets the value of a name/value pair in the registry key, using the specified registry data type.
160 /// </summary>
161 /// <param name="name">The name of the value to be stored. </param>
162 /// <param name="value">The data to be stored. </param>
163 /// <param name="valueKind">The registry data type to use when storing the data</param>
164 void SetValue(string name, Object value, RegistryValueKind valueKind);
165
166 #endregion
167
168
169
170 }
171}
0172
=== added file 'src/Canonical.Ubuntu.SSO/Keyring.cs'
--- src/Canonical.Ubuntu.SSO/Keyring.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO/Keyring.cs 2010-09-17 16:23:44 +0000
@@ -0,0 +1,282 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20using System.Collections.Generic;
21using System.Linq;
22using System.Security.Cryptography;
23using System.Text;
24using Canonical.UbuntuOne.Common.Validation;
25using log4net;
26
27namespace Canonical.Ubuntu.SSO
28{
29 /// <summary>
30 /// Implementation of the IKeyring interface that will store encripted secrets in the users current keyring.
31 /// </summary>
32 public class Keyring : IKeyring
33 {
34 #region Variables
35
36 internal const string RootPath = "Canonical\\Keyrings";
37 internal const string Entropy = "bdc97980-bbfa-11df-851a-0800200c9a66";
38 private const int KeyringMaxNameLength = 255;
39 private ILog _logger;
40 private readonly object _loggerLock = new object();
41 private bool _keyringsRootExists = false;
42
43 #endregion
44
45 #region DI properties
46
47 /// <summary>
48 /// Gets and sets the users registry key.
49 /// </summary>
50 public IRegistryKey UserRegistry { get; set; }
51
52 /// <summary>
53 /// Gets and sets the data protector to secure the data in the registry.
54 /// </summary>
55 public IDataProtector DataProtector { get; set; }
56
57 #endregion
58
59 #region Properties
60
61 /// <summary>
62 /// Gets and sets the logger that will be used to log the operation of the
63 /// class.
64 /// </summary>
65 public ILog Logger
66 {
67 get
68 {
69 if (_logger == null)
70 {
71 lock (_loggerLock)
72 {
73 _logger = LogManager.GetLogger(typeof(Keyring));
74 }
75 }
76 return _logger;
77 }
78 set
79 {
80 _logger = value;
81 }
82 }
83
84 #endregion
85
86 #region Constructors
87
88 /// <summary>
89 /// Creates a new instance of the class that will be using the users registry to store the data.
90 /// </summary>
91 public Keyring()
92 : this(new RegistryKeyWrapper())
93 {
94
95 }
96
97 /// <summary>
98 /// Creates a new instance of the class that will be storing the keyring in the provided registry key.
99 /// </summary>
100 /// <param name="key"></param>
101 public Keyring(IRegistryKey key)
102 {
103 UserRegistry = key;
104 }
105
106 #endregion
107
108 #region Helpers
109
110 private bool KeyringsRootExists()
111 {
112 if (!_keyringsRootExists)
113 {
114 var rootKey = from key in UserRegistry.GetSubKeyNames()
115 where key == RootPath
116 select key;
117 _keyringsRootExists = rootKey.Count() == 1;
118 }
119 return _keyringsRootExists;
120 }
121
122 private bool KeyringExist(string keyring)
123 {
124 // open the root keyring and then the subkeyring to ensure that the
125 // length of the string is not over 255 chars
126 if (!KeyringsRootExists())
127 return false;
128
129 using (var rootKeyring = UserRegistry.OpenSubKey(RootPath))
130 {
131 var presentKeyrings = from key in rootKeyring.GetSubKeyNames()
132 where key == keyring
133 select key;
134 return presentKeyrings.Count() == 1;
135 }
136 }
137
138 private IRegistryKey CreateKeyringRootPath()
139 {
140 // create a key with the root path to be used
141 return UserRegistry.CreateSubKey(RootPath);
142 }
143
144 private void CreateKeyring(string keyring)
145 {
146 using(var rootKey = (KeyringsRootExists())?
147 UserRegistry.OpenSubKey(RootPath) : CreateKeyringRootPath())
148 {
149 var subkey = rootKey.CreateSubKey(keyring);
150 subkey.Dispose();
151 }
152 }
153
154 private IRegistryKey OpenKeyring(string keyring)
155 {
156 using(var rootKey = UserRegistry.OpenSubKey(RootPath))
157 {
158 return rootKey.OpenSubKey(keyring);
159 }
160 }
161
162 private void SaveValue(string keyringName, string applicationName, string secret)
163 {
164 using(var keyring = OpenKeyring(keyringName))
165 {
166 var encryptedSecret = DataProtector.Protect(secret, Encoding.UTF8.GetBytes(Entropy),
167 DataProtectionScope.CurrentUser);
168 keyring.SetValue(applicationName, encryptedSecret);
169 }
170 }
171
172 private string GetValue(string keyringName, string applicationName)
173 {
174 using (var keyring = OpenKeyring(keyringName))
175 {
176 var secret = keyring.GetValue(applicationName) as string;
177 return DataProtector.Unprotect(secret, Encoding.UTF8.GetBytes(Entropy), DataProtectionScope.CurrentUser);
178 }
179 }
180
181
182 #endregion
183
184 #region Implementation of IKeyring
185
186 /// <summary>
187 /// Creates a new secret in the the keyring with the given name for a given applciation.
188 /// </summary>
189 /// <param name="keyringName">The name of the keyring where the secret will be stored.</param>
190 /// <param name="applicationName">The name of the application whose secret will be stored.</param>
191 /// <param name="secret">The secret to store in the keyring.</param>
192 public void CreateSecret(string keyringName, string applicationName, string secret)
193 {
194 ValidateArgs.Begin()
195 .IsNotNullOrEmpty(keyringName, "keyringName")
196 .IsShorterThan(keyringName, KeyringMaxNameLength, "keyringName")
197 .IsNotNullOrEmpty(applicationName, "applicationName")
198 .IsNotNullOrEmpty(secret, "secret")
199 .Check();
200
201 if (!KeyringExist(keyringName))
202 {
203 CreateKeyring(keyringName);
204 Logger.InfoFormat("Creating keyring with name {0}", keyringName);
205 }
206 SaveValue(keyringName, applicationName, secret);
207 }
208
209 /// <summary>
210 /// Gets the secret froma keyring using the name of the application that stored it.
211 /// </summary>
212 /// <param name="keyringName">The name of the keyring where the secret was stored.</param>
213 /// <param name="applicationName">the name of the application that stored the secret.</param>
214 /// <returns>An empty string if the secret does not exist, the secret otherwhise.</returns>
215 public string GetSecretByName(string keyringName, string applicationName)
216 {
217 ValidateArgs.Begin()
218 .IsNotNullOrEmpty(keyringName, "keyringName")
219 .IsShorterThan(keyringName, KeyringMaxNameLength, "keyringName")
220 .IsNotNullOrEmpty(applicationName, "applicationName")
221 .Check();
222
223 return KeyringExist(keyringName) ? GetValue(keyringName, applicationName) : string.Empty;
224 }
225
226 /// <summary>
227 /// Gets a lists with all the names of the available keyrings.
228 /// </summary>
229 /// <returns>An enumerable with all the names of the different keyrings.</returns>
230 public IEnumerable<string> GetKeyrings()
231 {
232 if(KeyringsRootExists())
233 {
234 using(var keyringRoot = UserRegistry.OpenSubKey(RootPath))
235 {
236 return keyringRoot.GetSubKeyNames();
237 }
238 }
239 return new string[0];
240 }
241
242 /// <summary>
243 /// Gets a list with all the applications in a keyring.
244 /// </summary>
245 /// <param name="keyringName">The name of the keyring that is queried.</param>
246 /// <returns>An enumerable with all the applications in the keyring.</returns>
247 public IEnumerable<string> GetApplications(string keyringName)
248 {
249 ValidateArgs.Begin()
250 .IsNotNullOrEmpty(keyringName, "keyring")
251 .IsShorterThan(keyringName, KeyringMaxNameLength, "keyring")
252 .Check();
253 if(KeyringExist(keyringName))
254 {
255 using(var keyringRoot = UserRegistry.OpenSubKey(RootPath))
256 {
257 using(var keyring = keyringRoot.OpenSubKey(keyringName))
258 {
259 return keyring.GetSubKeyNames();
260 }
261 }
262 }
263 return new string[0];
264 }
265
266 #endregion
267
268 #region Implementation of IDisposable
269
270 /// <summary>
271 /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
272 /// </summary>
273 /// <filterpriority>2</filterpriority>
274 public void Dispose()
275 {
276 if (UserRegistry != null)
277 UserRegistry.Dispose();
278 }
279
280 #endregion
281 }
282}
0283
=== modified file 'src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs'
--- src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs 2010-09-08 11:23:58 +0000
+++ src/Canonical.Ubuntu.SSO/Properties/AssemblyInfo.cs 2010-09-17 16:23:44 +0000
@@ -32,5 +32,4 @@
32// You can specify all the values or you can default the Build and Revision Numbers 32// You can specify all the values or you can default the Build and Revision Numbers
33// by using the '*' as shown below:33// by using the '*' as shown below:
34// [assembly: AssemblyVersion("1.0.*")]34// [assembly: AssemblyVersion("1.0.*")]
35[assembly: AssemblyVersion("1.0.0.0")]35[assembly: InternalsVisibleTo("Canonical.Ubuntu.SSO.Tests")]
36[assembly: AssemblyFileVersion("1.0.0.0")]
3736
=== added file 'src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs'
--- src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs 1970-01-01 00:00:00 +0000
+++ src/Canonical.Ubuntu.SSO/RegistryKeyWrapper.cs 2010-09-17 16:23:44 +0000
@@ -0,0 +1,261 @@
1/*
2 * Copyright 2010 Canonical Ltd.
3 *
4 * This file is part of UbuntuOne on Windows.
5 *
6 * UbuntuOne on Windows is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version
8 * as published by the Free Software Foundation.
9 *
10 * Ubuntu One on Windows is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with UbuntuOne for Windows. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Authors: Manuel de la Peña <manuel.delapena@canonical.com>
19 */
20
21using System;
22using Microsoft.Win32;
23
24namespace Canonical.Ubuntu.SSO
25{
26 /// <summary>
27 /// Simple wrapper around the registry class that allows the class to be mocked for testing
28 /// purposes
29 /// </summary>
30 public class RegistryKeyWrapper : IRegistryKey
31 {
32 #region Variables
33
34 private readonly RegistryKey _key;
35
36 #endregion
37
38 #region Constructors
39
40 /// <summary>
41 /// Creates a new registry key that contains information about the default user configuration.
42 /// </summary>
43 public RegistryKeyWrapper()
44 : this(Registry.Users)
45 {
46
47 }
48
49 /// <summary>
50 /// Creates a new registry key wrapper with the given key.
51 /// </summary>
52 /// <param name="key">The key to be wrapped.</param>
53 public RegistryKeyWrapper(RegistryKey key)
54 {
55 _key = key;
56 }
57
58 #endregion
59
60 #region Implementation of IDisposable
61
62 /// <summary>
63 /// Performs application-defined tasks associated with freeing, releasing,
64 /// or resetting unmanaged resources.
65 /// </summary>
66 /// <filterpriority>2</filterpriority>
67 public void Dispose()
68 {
69 var disposable = (IDisposable)_key;
70 disposable.Dispose();
71 }
72
73 #endregion
74
75 #region Implementation of IRegistryKey
76
77 /// <summary>
78 /// Retrieves the name of the key.
79 /// </summary>
80 public string Name
81 {
82 get { return _key.Name; }
83 }
84
85 /// <summary>
86 /// Retrieves the count of subkeys of the current key.
87 /// </summary>
88 public int SubKeyCount
89 {
90 get { return _key.SubKeyCount; }
91 }
92
93 /// <summary>
94 /// Retrieves the count of values in the key.
95 /// </summary>
96 public int ValueCount
97 {
98 get { return _key.ValueCount; }
99 }
100
101 /// <summary>
102 /// Closes the key and flushes it to disk if its contents have been modified.
103 /// </summary>
104 public void Close()
105 {
106 _key.Close();
107 }
108
109 /// <summary>
110 /// Creates a new subkey or opens an existing subkey for write access.
111 /// The string subkey is not case-sensitive.
112 /// </summary>
113 /// <param name="name">The name or path of the subkey to create or open. </param>
114 /// <returns>A sub key to work with.</returns>
115 public IRegistryKey CreateSubKey(string name)
116 {
117 return new RegistryKeyWrapper(_key.CreateSubKey(name));
118 }
119
120 /// <summary>
121 /// Creates a new subkey or opens an existing subkey for write access, using the specified
122 /// permission check option. The string subkey is not case-sensitive.
123 /// </summary>
124 /// <param name="subkey">The name or path of the subkey to create or open.</param>
125 /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values that
126 /// specifies whether the key is opened for read or read/write access.</param>
127 /// <returns>A subkey to work with.</returns>
128 public IRegistryKey CreateSubKey(string subkey, RegistryKeyPermissionCheck permissionCheck)
129 {
130 return new RegistryKeyWrapper(_key.CreateSubKey(subkey, permissionCheck));
131 }
132
133 /// <summary>
134 /// Deletes the specified subkey. The string subkey is not case-sensitive.
135 /// </summary>
136 /// <param name="subkey">The name of the subkey to delete. </param>
137 public void DeleteSubKey(string subkey)
138 {
139 _key.DeleteSubKey(subkey);
140 }
141
142 /// <summary>
143 /// Deletes the specified value from this key.
144 /// </summary>
145 /// <param name="name">The name of the value to delete.</param>
146 public void DeleteValue(string name)
147 {
148 _key.DeleteValue(name);
149 }
150
151 /// <summary>
152 /// Writes all the attributes of the specified open registry
153 /// key into the registry.
154 /// </summary>
155 public void Flush()
156 {
157 _key.Flush();
158 }
159
160 /// <summary>
161 /// Retrieves an array of strings that contains all the subkey names.
162 /// </summary>
163 /// <returns>An array of strings that contains the names of the
164 /// subkeys for the current key.</returns>
165 public string[] GetSubKeyNames()
166 {
167 return _key.GetSubKeyNames();
168 }
169
170 /// <summary>
171 /// Retrieves the value associated with the specified name.
172 /// Returns null if the name/value pair does not exist in the registry.
173 /// </summary>
174 /// <param name="name">The name of the value to retrieve. </param>
175 /// <returns>The value associated with name, or null if name is not found.</returns>
176 public object GetValue(string name)
177 {
178 return _key.GetValue(name);
179 }
180
181 /// <summary>
182 /// Retrieves the value associated with the specified name.
183 /// If the name is not found, returns the default value that you provide.
184 /// </summary>
185 /// <param name="name">The name of the value to retrieve.</param>
186 /// <param name="defaultValue">The value to return if name does not exist.</param>
187 /// <returns>The value associated with name, with any embedded
188 /// environment variables left unexpanded, or defaultValue if name is not found.</returns>
189 public object GetValue(string name, object defaultValue)
190 {
191 return _key.GetValue(name, defaultValue);
192 }
193
194 /// <summary>
195 /// Retrieves the registry data type of the value associated with the specified name.
196 /// </summary>
197 /// <param name="name">The name of the value whose registry data type is to be retrieved. </param>
198 /// <returns>A RegistryValueKind value representing the registry
199 /// data type of the value associated with name.</returns>
200 public RegistryValueKind GetValueKind(string name)
201 {
202 return _key.GetValueKind(name);
203 }
204
205 /// <summary>
206 /// Retrieves an array of strings that contains all the
207 /// value names associated with this key.
208 /// </summary>
209 /// <returns>An array of strings that contains
210 /// the value names for the current key.</returns>
211 public string[] GetValueNames()
212 {
213 return _key.GetValueNames();
214 }
215
216 /// <summary>
217 /// Retrieves a subkey as read-only.
218 /// </summary>
219 /// <param name="name">The name or path of the subkey to open read-only. </param>
220 /// <returns>The subkey requested, or null if the operation failed.</returns>
221 public IRegistryKey OpenSubKey(string name)
222 {
223 return new RegistryKeyWrapper(_key.OpenSubKey(name));
224 }
225
226 /// <summary>
227 /// Retrieves the specified subkey for read or read/write access.
228 /// </summary>
229 /// <param name="name">The name or path of the subkey to create or open.</param>
230 /// <param name="permissionCheck">One of the RegistryKeyPermissionCheck values
231 /// that specifies whether the key is opened for read or read/write access.</param>
232 /// <returns></returns>
233 public IRegistryKey OpenSubKey(string name, RegistryKeyPermissionCheck permissionCheck)
234 {
235 return new RegistryKeyWrapper(_key.OpenSubKey(name, permissionCheck));
236 }
237
238 /// <summary>
239 /// Sets the specified name/value pair.
240 /// </summary>
241 /// <param name="name">The name of the value to store. </param>
242 /// <param name="value">The data to be stored.</param>
243 public void SetValue(string name, object value)
244 {
245 _key.SetValue(name, value);
246 }
247
248 /// <summary>
249 /// Sets the value of a name/value pair in the registry key, using the specified registry data type.
250 /// </summary>
251 /// <param name="name">The name of the value to be stored. </param>
252 /// <param name="value">The data to be stored. </param>
253 /// <param name="valueKind">The registry data type to use when storing the data</param>
254 public void SetValue(string name, object value, RegistryValueKind valueKind)
255 {
256 _key.SetValue(name, value, valueKind);
257 }
258
259 #endregion
260 }
261}
0262
=== modified file 'src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs'
--- src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs 2010-07-23 15:50:15 +0000
+++ src/Canonical.UbuntuOne.Common.Tests/Validation/EqualityExtensionsValidation.cs 2010-09-17 16:23:44 +0000
@@ -236,6 +236,44 @@
236 .Check();236 .Check();
237 }237 }
238238
239 [TestCase("Robert", 255)]
240 [TestCase("true", 5)]
241 public void IsShorterThanTest(string value, int length)
242 {
243 ValidateArgs.Begin()
244 .IsShorterThan(value, length, "")
245 .Check();
246 }
247
248
249 [TestCase("Robert", 2)]
250 [TestCase("true", 1)]
251 [ExpectedException(typeof(ValidationException))]
252 public void IsShorterThanFailTest(string value, int length)
253 {
254 ValidateArgs.Begin()
255 .IsShorterThan(value, length, "")
256 .Check();
257 }
258
259 [TestCase("true", 4)]
260 [TestCase("Robert", 255)]
261 public void IsShorterOrEqualToTest(string value, int length)
262 {
263 ValidateArgs.Begin()
264 .IsShorterOrEqualTo(value, length, "")
265 .Check();
266 }
267
268 [TestCase("Robert", 2)]
269 [TestCase("true", 1)]
270 [ExpectedException(typeof(ValidationException))]
271 public void IsShorterOrEqualToFailTest(string value, int length)
272 {
273 ValidateArgs.Begin()
274 .IsShorterOrEqualTo(value, length, "")
275 .Check();
276 }
239 #endregion277 #endregion
240278
241 }279 }
242280
=== modified file 'src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs'
--- src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs 2010-08-11 08:05:19 +0000
+++ src/Canonical.UbuntuOne.Common/Validation/EqualityValidationExtensions.cs 2010-09-17 16:23:44 +0000
@@ -242,5 +242,55 @@
242 (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException(242 (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException(
243 string.Format("'{0}' cannot be null or empty.", parameterName)));243 string.Format("'{0}' cannot be null or empty.", parameterName)));
244 }244 }
245
246 /// <summary>
247 /// Ensures that the string that was passed as argument is not too long.
248 /// </summary>
249 /// <param name="argumentValidation">
250 /// A <see cref="ArgumentValidation"/> with the current result of the validations.
251 /// </param>
252 /// <param name="value">
253 /// A <see cref="System.String"/> with the argument to validate.
254 /// </param>
255 /// <param name="length">
256 /// An int with the length not to be excided by the string.
257 /// </param>
258 /// <param name="parameterName">The name of the parameter under test.</param>
259 /// <returns>
260 /// A <see cref="ArgumentValidation"/> the result of the validation.
261 /// </returns>
262 public static ArgumentValidation IsShorterThan(this ArgumentValidation argumentValidation, string value,
263 int length, string parameterName)
264 {
265 return (value.Length < length)
266 ? argumentValidation :
267 (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException(
268 string.Format("'{0}' has to be smaller than {1} chars.",parameterName, length)));
269 }
270
271 /// <summary>
272 /// Ensures that the string that was passed as argument is not too long.
273 /// </summary>
274 /// <param name="argumentValidation">
275 /// A <see cref="ArgumentValidation"/> with the current result of the validations.
276 /// </param>
277 /// <param name="value">
278 /// A <see cref="System.String"/> with the argument to validate.
279 /// </param>
280 /// <param name="length">
281 /// An int with the length not to be excided by the string.
282 /// </param>
283 /// <param name="parameterName">The name of the parameter under test.</param>
284 /// <returns>
285 /// A <see cref="ArgumentValidation"/> the result of the validation.
286 /// </returns>
287 public static ArgumentValidation IsShorterOrEqualTo(this ArgumentValidation argumentValidation, string value,
288 int length, string parameterName)
289 {
290 return (value.Length <= length)
291 ? argumentValidation :
292 (argumentValidation ?? new ArgumentValidation()).AddException(new ArgumentException(
293 string.Format("'{0}' has to be smaller or equalt to {1} chars.", parameterName, length)));
294 }
245 }295 }
246}296}
247297
=== modified file 'src/UbuntuOne.sln'
--- src/UbuntuOne.sln 2010-09-08 11:23:58 +0000
+++ src/UbuntuOne.sln 2010-09-17 16:23:44 +0000
@@ -25,6 +25,8 @@
25EndProject25EndProject
26Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canonical.Ubuntu.SSO", "Canonical.Ubuntu.SSO\Canonical.Ubuntu.SSO.csproj", "{9460A771-2589-45DA-9618-9FE8BB7D16E8}"26Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canonical.Ubuntu.SSO", "Canonical.Ubuntu.SSO\Canonical.Ubuntu.SSO.csproj", "{9460A771-2589-45DA-9618-9FE8BB7D16E8}"
27EndProject27EndProject
28Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Canonical.Ubuntu.SSO.Tests", "Canonical.Ubuntu.SSO.Tests\Canonical.Ubuntu.SSO.Tests.csproj", "{17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}"
29EndProject
28Global30Global
29 GlobalSection(SolutionConfigurationPlatforms) = preSolution31 GlobalSection(SolutionConfigurationPlatforms) = preSolution
30 Debug|Any CPU = Debug|Any CPU32 Debug|Any CPU = Debug|Any CPU
@@ -155,6 +157,16 @@
155 {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU157 {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
156 {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU158 {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
157 {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|x86.ActiveCfg = Release|Any CPU159 {9460A771-2589-45DA-9618-9FE8BB7D16E8}.Release|x86.ActiveCfg = Release|Any CPU
160 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
161 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
162 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
163 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
164 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Debug|x86.ActiveCfg = Debug|Any CPU
165 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
166 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Any CPU.Build.0 = Release|Any CPU
167 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
168 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
169 {17BBBEC2-0F4F-48CE-A585-07AA33B6B2B3}.Release|x86.ActiveCfg = Release|Any CPU
158 EndGlobalSection170 EndGlobalSection
159 GlobalSection(SolutionProperties) = preSolution171 GlobalSection(SolutionProperties) = preSolution
160 HideSolutionNode = FALSE172 HideSolutionNode = FALSE

Subscribers

People subscribed via source and target branches

to all changes: