Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit b929d55

Browse files
committed
Merge branch 'fixes/1332-validate-scopes' into feature/sso
Conflicts: src/DesignTimeStyleHelper/App.config src/GitHub.Api/ApiClientConfiguration.cs src/GitHub.Api/LoginManager.cs src/GitHub.StartPage/app.config src/GitHub.VisualStudio/app.config test/UnitTests/GitHub.Api/LoginManagerTests.cs
2 parents 032cc0f + 6a8f551 commit b929d55

File tree

75 files changed

+1237
-819
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1237
-819
lines changed

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: '2.3.5.{build}'
1+
version: '2.3.6.{build}'
22
skip_tags: true
33
install:
44
- ps: |

nuget.config

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@
77
<activePackageSource>
88
<add key="All" value="(Aggregate source)" />
99
</activePackageSource>
10-
</configuration>
10+
<bindingRedirects>
11+
<add key="skip" value="True" />
12+
</bindingRedirects>
13+
</configuration>

src/DesignTimeStyleHelper/App.config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@
4949
<assemblyIdentity name="Microsoft.VisualStudio.ComponentModelHost" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
5050
<bindingRedirect oldVersion="0.0.0.0-14.0.0.0" newVersion="14.0.0.0" />
5151
</dependentAssembly>
52+
<dependentAssembly>
53+
<assemblyIdentity name="Microsoft.VisualStudio.Validation" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
54+
<bindingRedirect oldVersion="0.0.0.0-14.0.0.0" newVersion="14.0.0.0" />
55+
</dependentAssembly>
5256
</assemblyBinding>
5357
</runtime>
5458
</configuration>

src/GitHub.Api/ApiClientConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ static ApiClientConfiguration()
3535
/// <summary>
3636
/// Gets the scopes required by the application.
3737
/// </summary>
38-
public static IReadOnlyList<string> Scopes { get; } = new[] { "user", "repo", "gist", "write:public_key" };
38+
public static IReadOnlyList<string> RequiredScopes { get; } = new[] { "user", "repo", "gist", "write:public_key" };
3939

4040
/// <summary>
4141
/// Gets a note that will be stored with the OAUTH token.

src/GitHub.Api/GitHub.Api.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
</PropertyGroup>
4747
<Import Project="$(SolutionDir)\src\common\signing.props" />
4848
<ItemGroup>
49+
<Reference Include="Serilog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=24c2f752a8e58a10, processorArchitecture=MSIL">
50+
<HintPath>..\..\packages\Serilog.2.5.0\lib\net46\Serilog.dll</HintPath>
51+
<Private>True</Private>
52+
</Reference>
4953
<Reference Include="System" />
5054
<Reference Include="System.ComponentModel.Composition" />
5155
<Reference Include="System.Core" />
@@ -65,6 +69,7 @@
6569
<Compile Include="IKeychain.cs" />
6670
<Compile Include="ILoginManager.cs" />
6771
<Compile Include="IOAuthCallbackListener.cs" />
72+
<Compile Include="IncorrectScopesException.cs" />
6873
<Compile Include="ITwoFactorChallengeHandler.cs" />
6974
<Compile Include="LoginManager.cs" />
7075
<Compile Include="KeychainCredentialStore.cs" />
@@ -100,6 +105,9 @@
100105
<Name>GitHub.Logging</Name>
101106
</ProjectReference>
102107
</ItemGroup>
108+
<ItemGroup>
109+
<None Include="packages.config" />
110+
</ItemGroup>
103111
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
104112
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
105113
Other similar extension points exist, see Microsoft.Common.targets.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Runtime.Serialization;
3+
4+
namespace GitHub.Api
5+
{
6+
/// <summary>
7+
/// Thrown when the login for a user does not have the required scopes.
8+
/// </summary>
9+
[Serializable]
10+
public class IncorrectScopesException : Exception
11+
{
12+
public IncorrectScopesException()
13+
: this("You need to sign out and back in.")
14+
{
15+
}
16+
17+
public IncorrectScopesException(string message)
18+
: base(message)
19+
{
20+
}
21+
22+
public IncorrectScopesException(string message, Exception innerException)
23+
: base(message, innerException)
24+
{
25+
}
26+
27+
protected IncorrectScopesException(SerializationInfo info, StreamingContext context)
28+
: base(info, context)
29+
{
30+
}
31+
}
32+
}

src/GitHub.Api/LoginManager.cs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using System.Net;
35
using System.Threading;
46
using System.Threading.Tasks;
57
using GitHub.Extensions;
8+
using GitHub.Logging;
69
using GitHub.Primitives;
710
using Octokit;
11+
using Serilog;
812

913
namespace GitHub.Api
1014
{
@@ -13,10 +17,14 @@ namespace GitHub.Api
1317
/// </summary>
1418
public class LoginManager : ILoginManager
1519
{
20+
const string ScopesHeader = "X-OAuth-Scopes";
21+
static readonly ILogger log = LogManager.ForContext<LoginManager>();
22+
static readonly Uri UserEndpoint = new Uri("user", UriKind.Relative);
1623
readonly IKeychain keychain;
1724
readonly ITwoFactorChallengeHandler twoFactorChallengeHandler;
1825
readonly string clientId;
1926
readonly string clientSecret;
27+
readonly IReadOnlyList<string> scopes;
2028
readonly string authorizationNote;
2129
readonly string fingerprint;
2230
IOAuthCallbackListener oauthListener;
@@ -36,6 +44,7 @@ public LoginManager(
3644
IOAuthCallbackListener oauthListener,
3745
string clientId,
3846
string clientSecret,
47+
IReadOnlyList<string> scopes,
3948
string authorizationNote = null,
4049
string fingerprint = null)
4150
{
@@ -49,6 +58,7 @@ public LoginManager(
4958
this.oauthListener = oauthListener;
5059
this.clientId = clientId;
5160
this.clientSecret = clientSecret;
61+
this.scopes = scopes;
5262
this.authorizationNote = authorizationNote;
5363
this.fingerprint = fingerprint;
5464
}
@@ -71,7 +81,7 @@ public async Task<User> Login(
7181

7282
var newAuth = new NewAuthorization
7383
{
74-
Scopes = ApiClientConfiguration.Scopes,
84+
Scopes = scopes,
7585
Note = authorizationNote,
7686
Fingerprint = fingerprint,
7787
};
@@ -147,7 +157,7 @@ public Task<User> LoginFromCache(HostAddress hostAddress, IGitHubClient client)
147157
Guard.ArgumentNotNull(hostAddress, nameof(hostAddress));
148158
Guard.ArgumentNotNull(client, nameof(client));
149159

150-
return client.User.Current();
160+
return ReadUserWithRetry(client);
151161
}
152162

153163
/// <inheritdoc/>
@@ -282,7 +292,7 @@ async Task<User> ReadUserWithRetry(IGitHubClient client)
282292
{
283293
try
284294
{
285-
return await client.User.Current().ConfigureAwait(false);
295+
return await GetUserAndCheckScopes(client).ConfigureAwait(false);
286296
}
287297
catch (AuthorizationException)
288298
{
@@ -295,13 +305,42 @@ async Task<User> ReadUserWithRetry(IGitHubClient client)
295305
}
296306
}
297307

298-
static Uri GetLoginUrl(IOauthClient client, string state)
308+
async Task<User> GetUserAndCheckScopes(IGitHubClient client)
309+
{
310+
var response = await client.Connection.Get<User>(
311+
UserEndpoint, null, null).ConfigureAwait(false);
312+
313+
if (response.HttpResponse.Headers.ContainsKey(ScopesHeader))
314+
{
315+
var returnedScopes = response.HttpResponse.Headers[ScopesHeader]
316+
.Split(',')
317+
.Select(x => x.Trim())
318+
.ToArray();
319+
320+
if (scopes.Except(returnedScopes).Count() == 0)
321+
{
322+
return response.Body;
323+
}
324+
else
325+
{
326+
log.Error("Incorrect API scopes: require {RequiredScopes} but got {Scopes}", scopes, returnedScopes);
327+
}
328+
}
329+
else
330+
{
331+
log.Error("Error reading scopes: /user succeeded but scopes header was not present");
332+
}
333+
334+
throw new IncorrectScopesException();
335+
}
336+
337+
Uri GetLoginUrl(IOauthClient client, string state)
299338
{
300339
var request = new OauthLoginRequest(ApiClientConfiguration.ClientId);
301340

302341
request.State = state;
303342

304-
foreach (var scope in ApiClientConfiguration.Scopes)
343+
foreach (var scope in scopes)
305344
{
306345
request.Scopes.Add(scope);
307346
}

src/GitHub.Api/packages.config

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<packages>
3+
<package id="Serilog" version="2.5.0" targetFramework="net461" />
4+
</packages>

src/GitHub.App/GitHub.App.csproj

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3-
<Import Project="..\..\packages\LibGit2Sharp.NativeBinaries.1.0.185\build\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\..\packages\LibGit2Sharp.NativeBinaries.1.0.185\build\LibGit2Sharp.NativeBinaries.props')" />
3+
<Import Project="..\..\packages\LibGit2Sharp.NativeBinaries.1.0.164\build\LibGit2Sharp.NativeBinaries.props" Condition="Exists('..\..\packages\LibGit2Sharp.NativeBinaries.1.0.164\build\LibGit2Sharp.NativeBinaries.props')" />
44
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
55
<PropertyGroup>
66
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -16,6 +16,8 @@
1616
<CodeAnalysisRuleSet>..\common\GitHubVS.ruleset</CodeAnalysisRuleSet>
1717
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
1818
<CodeAnalysisIgnoreGeneratedCode>true</CodeAnalysisIgnoreGeneratedCode>
19+
<NuGetPackageImportStamp>
20+
</NuGetPackageImportStamp>
1921
</PropertyGroup>
2022
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
2123
<DebugSymbols>true</DebugSymbols>
@@ -48,8 +50,8 @@
4850
</PropertyGroup>
4951
<Import Project="$(SolutionDir)\src\common\signing.props" />
5052
<ItemGroup>
51-
<Reference Include="LibGit2Sharp, Version=0.24.0.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
52-
<HintPath>..\..\packages\LibGit2Sharp.0.24.0\lib\net40\LibGit2Sharp.dll</HintPath>
53+
<Reference Include="LibGit2Sharp, Version=0.23.1.0, Culture=neutral, PublicKeyToken=7cbde695407f0333, processorArchitecture=MSIL">
54+
<HintPath>..\..\packages\LibGit2Sharp.0.23.1\lib\net40\LibGit2Sharp.dll</HintPath>
5355
<Private>True</Private>
5456
</Reference>
5557
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@@ -229,9 +231,6 @@
229231
<Resource Include="Images\default_user_avatar.png" />
230232
</ItemGroup>
231233
<ItemGroup>
232-
<None Include="app.config">
233-
<SubType>Designer</SubType>
234-
</None>
235234
<None Include="packages.config">
236235
<SubType>Designer</SubType>
237236
</None>
@@ -316,7 +315,7 @@
316315
<ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
317316
</PropertyGroup>
318317
<Error Condition="!Exists('..\..\packages\SQLitePCL.raw_basic.0.7.3.0-vs2012\build\net45\SQLitePCL.raw_basic.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\SQLitePCL.raw_basic.0.7.3.0-vs2012\build\net45\SQLitePCL.raw_basic.targets'))" />
319-
<Error Condition="!Exists('..\..\packages\LibGit2Sharp.NativeBinaries.1.0.185\build\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\LibGit2Sharp.NativeBinaries.1.0.185\build\LibGit2Sharp.NativeBinaries.props'))" />
318+
<Error Condition="!Exists('..\..\packages\LibGit2Sharp.NativeBinaries.1.0.164\build\LibGit2Sharp.NativeBinaries.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\LibGit2Sharp.NativeBinaries.1.0.164\build\LibGit2Sharp.NativeBinaries.props'))" />
320319
</Target>
321320
<Import Project="..\..\packages\SQLitePCL.raw_basic.0.7.3.0-vs2012\build\net45\SQLitePCL.raw_basic.targets" Condition="Exists('..\..\packages\SQLitePCL.raw_basic.0.7.3.0-vs2012\build\net45\SQLitePCL.raw_basic.targets')" />
322321
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

src/GitHub.App/SampleData/PullRequestListViewModelDesigner.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public PullRequestListViewModelDesigner()
5353
Authors = new ObservableCollection<IAccount>(prs.Select(x => x.Author));
5454
SelectedAssignee = Assignees.ElementAt(1);
5555
SelectedAuthor = Authors.ElementAt(1);
56+
57+
IsLoaded = true;
5658
}
5759

5860
public IReadOnlyList<IRemoteRepositoryModel> Repositories { get; }
@@ -68,6 +70,8 @@ public PullRequestListViewModelDesigner()
6870
public IAccount SelectedAuthor { get; set; }
6971
public bool RepositoryIsFork { get; set; } = true;
7072
public bool ShowPullRequestsForFork { get; set; }
73+
public string SearchQuery { get; set; }
74+
public bool IsLoaded { get; }
7175

7276
public ObservableCollection<IAccount> Assignees { get; set; }
7377
public IAccount SelectedAssignee { get; set; }

0 commit comments

Comments
 (0)