This commit is contained in:
Paul Schneider 2021-04-11 22:22:37 +01:00
commit ec5bd7ca1f
13 changed files with 173 additions and 46 deletions

2
.vscode/tasks.json vendored
View file

@ -23,7 +23,7 @@
"${workspaceFolder}/nuget-host.csproj", "${workspaceFolder}/nuget-host.csproj",
"/property:GenerateFullPaths=true", "/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary", "/consoleloggerparameters:NoSummary",
"/restore" "--ignore-failed-sources"
], ],
"problemMatcher": "$msCompile" "problemMatcher": "$msCompile"
}, },

View file

@ -0,0 +1,9 @@
using IdentityServer4.Models;
namespace nuget_host.Models
{
public class RepositoryIdentityResource : IdentityResource
{
}
}

View file

@ -128,7 +128,8 @@ namespace IdentityServerHost.Quickstart.UI
// check if external login is in the context of an OIDC request // check if external login is in the context of an OIDC request
var context = await _interaction.GetAuthorizationContextAsync(returnUrl); var context = await _interaction.GetAuthorizationContextAsync(returnUrl);
await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username, true, context?.Client.ClientId)); await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.SubjectId, user.Username, true,
context?.ClientId));
if (context != null) if (context != null)
{ {

View file

@ -14,7 +14,7 @@ using System.Threading.Tasks;
using IdentityServer4.Validation; using IdentityServer4.Validation;
using System.Collections.Generic; using System.Collections.Generic;
using System; using System;
using IdentityServer4.Models;
namespace IdentityServerHost.Quickstart.UI namespace IdentityServerHost.Quickstart.UI
{ {
/// <summary> /// <summary>
@ -149,7 +149,7 @@ namespace IdentityServerHost.Quickstart.UI
// indicate that's it ok to redirect back to authorization endpoint // indicate that's it ok to redirect back to authorization endpoint
result.RedirectUri = model.ReturnUrl; result.RedirectUri = model.ReturnUrl;
result.Client = request.Client; result.Client = model.Client;
} }
else else
{ {
@ -186,26 +186,25 @@ namespace IdentityServerHost.Quickstart.UI
Description = model?.Description, Description = model?.Description,
ReturnUrl = returnUrl, ReturnUrl = returnUrl,
ClientName = model.ClientName,
ClientName = request.Client.ClientName ?? request.Client.ClientId, ClientUrl = model.ClientUri,
ClientUrl = request.Client.ClientUri, ClientLogoUrl = model.LogoUri,
ClientLogoUrl = request.Client.LogoUri, AllowRememberConsent = model.AllowRememberConsent
AllowRememberConsent = request.Client.AllowRememberConsent
}; };
vm.IdentityScopes = request.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray(); vm.IdentityScopes = model.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray();
var apiScopes = new List<ScopeViewModel>(); var apiScopes = new List<ScopeViewModel>();
foreach(var parsedScope in request.ValidatedResources.ParsedScopes) foreach(var parsedScope in model.ValidatedResources.ParsedScopes.Scopes)
{ {
var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName); var apiScope = model.ValidatedResources.Resources.FindApiScope(parsedScope);
if (apiScope != null) if (apiScope != null)
{ {
var scopeVm = CreateScopeViewModel(parsedScope, apiScope, vm.ScopesConsented.Contains(parsedScope.RawValue) || model == null); var scopeVm = CreateScopeViewModel(model.ValidatedResources.ParsedScopes, apiScope, vm.ScopesConsented.Contains(model.ValidatedResources.ParsedScopes.RawValue) || model == null);
apiScopes.Add(scopeVm); apiScopes.Add(scopeVm);
} }
} }
if (ConsentOptions.EnableOfflineAccess && request.ValidatedResources.Resources.OfflineAccess) if (ConsentOptions.EnableOfflineAccess && model.ValidatedResources.Resources.OfflineAccess)
{ {
apiScopes.Add(GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess) || model == null)); apiScopes.Add(GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess) || model == null));
} }
@ -227,17 +226,17 @@ namespace IdentityServerHost.Quickstart.UI
}; };
} }
public ScopeViewModel CreateScopeViewModel(ParsedScopeValue parsedScopeValue, ApiScope apiScope, bool check) public ScopeViewModel CreateScopeViewModel(ParsedScopes parsedScope, Scope apiScope, bool check)
{ {
var displayName = apiScope.DisplayName ?? apiScope.Name; var displayName = apiScope.DisplayName;
if (!String.IsNullOrWhiteSpace(parsedScopeValue.ParsedParameter)) if (!String.IsNullOrWhiteSpace(parsedScope.RawValue))
{ {
displayName += ":" + parsedScopeValue.ParsedParameter; displayName += ":" + parsedScope.RawValue;
} }
return new ScopeViewModel return new ScopeViewModel
{ {
Value = parsedScopeValue.RawValue, Value = parsedScope.RawValue,
DisplayName = displayName, DisplayName = displayName,
Description = apiScope.Description, Description = apiScope.Description,
Emphasize = apiScope.Emphasize, Emphasize = apiScope.Emphasize,

View file

@ -3,6 +3,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using IdentityServer4.Models;
namespace IdentityServerHost.Quickstart.UI namespace IdentityServerHost.Quickstart.UI
{ {
@ -13,5 +14,11 @@ namespace IdentityServerHost.Quickstart.UI
public bool RememberConsent { get; set; } public bool RememberConsent { get; set; }
public string ReturnUrl { get; set; } public string ReturnUrl { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string ClientName { get; internal set; }
public string ClientUri { get; internal set; }
public string LogoUri { get; internal set; }
public bool AllowRememberConsent { get; internal set; }
public ValidatedResources ValidatedResources { get; internal set; }
public Client Client { get; internal set; }
} }
} }

View file

@ -8,12 +8,13 @@ namespace IdentityServerHost.Quickstart.UI
{ {
public class ConsentViewModel : ConsentInputModel public class ConsentViewModel : ConsentInputModel
{ {
public string ClientName { get; set; }
public string ClientUrl { get; set; }
public string ClientLogoUrl { get; set; } public string ClientLogoUrl { get; set; }
public bool AllowRememberConsent { get; set; } public string ClientUrl { get; set; }
public IEnumerable<ScopeViewModel> ApiScopes { get; set; }
public IEnumerable<ScopeViewModel> IdentityScopes { get; set; } public IEnumerable<ScopeViewModel> IdentityScopes { get; set; }
public IEnumerable<ScopeViewModel> ApiScopes { get; set; }
} }
} }

View file

@ -0,0 +1,29 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using System.Collections.Generic;
using IdentityServer4.Models;
namespace IdentityServerHost.Quickstart.UI
{
public class ParsedScopes
{
public ParsedScopes(ParsedSecret secret)
{
RawValue = secret.Properties.ContainsKey(KEY_SCOPES) ? null : secret.Properties[KEY_SCOPES];
Emphasize = secret.Properties.ContainsKey(KEY_OL);
if (secret.Properties.ContainsKey(KEY_SCOPES)) Scopes = secret.Properties[KEY_SCOPES].Split(',');
}
public const string KEY_SCOPES = "scopes";
public const string KEY_OL = "ol";
public string RawValue {
get ;
}
public string[] Scopes { get ; protected set; }
public bool Emphasize { get; }
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using IdentityServer4.Models;
using IdentityServer4.Validation;
using NuGet.Packaging;
namespace nuget_host.OAuth
{
internal class NHAuthorizationRequest : AuthorizationRequest
{
internal NHAuthorizationRequest(ValidatedAuthorizeRequest request) : base()
{
ClientId = request.ClientId;
RedirectUri = request.RedirectUri;
DisplayMode = request.DisplayMode;
UiLocales = request.UiLocales;
IdP = request.GetIdP();
Tenant = request.GetTenant();
LoginHint = request.LoginHint;
PromptMode = request.PromptMode;
AcrValues = request.GetAcrValues();
ScopesRequested = request.RequestedScopes;
Parameters.Add(request.Raw);
RequestObjectValues.AddRange(request.RequestObjectValues);
}
}
}

View file

@ -0,0 +1,17 @@
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
using IdentityServer4.Models;
using System.Collections.Generic;
namespace IdentityServerHost.Quickstart.UI
{
public class ValidatedResources
{
public Resources Resources { get; set; }
public ParsedScopes ParsedScopes { get; internal set; }
public bool OfflineAccess { get; internal set; }
}
}

View file

@ -4,8 +4,10 @@
namespace IdentityServerHost.Quickstart.UI namespace IdentityServerHost.Quickstart.UI
{ {
public class DeviceAuthorizationInputModel : ConsentInputModel public class DeviceAuthorizationInputModel : ConsentInputModel
{ {
public string UserCode { get; set; } public string UserCode { get; set; }
} }
} }

View file

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using IdentityModel.Client;
using IdentityServer4.Configuration; using IdentityServer4.Configuration;
using IdentityServer4.Events; using IdentityServer4.Events;
using IdentityServer4.Extensions; using IdentityServer4.Extensions;
@ -16,6 +17,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using nuget_host.OAuth;
namespace IdentityServerHost.Quickstart.UI namespace IdentityServerHost.Quickstart.UI
{ {
@ -131,7 +133,7 @@ namespace IdentityServerHost.Quickstart.UI
// indicate that's it ok to redirect back to authorization endpoint // indicate that's it ok to redirect back to authorization endpoint
result.RedirectUri = model.ReturnUrl; result.RedirectUri = model.ReturnUrl;
result.Client = request.Client; result.Client = model.Client;
} }
else else
{ {
@ -153,7 +155,9 @@ namespace IdentityServerHost.Quickstart.UI
return null; return null;
} }
private DeviceAuthorizationViewModel CreateConsentViewModel(string userCode, DeviceAuthorizationInputModel model, DeviceFlowAuthorizationRequest request) private DeviceAuthorizationViewModel CreateConsentViewModel(
string userCode, DeviceAuthorizationInputModel model,
DeviceFlowAuthorizationRequest request)
{ {
var vm = new DeviceAuthorizationViewModel var vm = new DeviceAuthorizationViewModel
{ {
@ -163,25 +167,27 @@ namespace IdentityServerHost.Quickstart.UI
RememberConsent = model?.RememberConsent ?? true, RememberConsent = model?.RememberConsent ?? true,
ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>(), ScopesConsented = model?.ScopesConsented ?? Enumerable.Empty<string>(),
ClientName = request.Client.ClientName ?? request.Client.ClientId, ClientName = model?.ClientName,
ClientUrl = request.Client.ClientUri, ClientUrl = model?.ClientUri,
ClientLogoUrl = request.Client.LogoUri, ClientLogoUrl = model?.LogoUri,
AllowRememberConsent = request.Client.AllowRememberConsent AllowRememberConsent = model != null && model.AllowRememberConsent
}; };
vm.IdentityScopes = request.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray(); vm.IdentityScopes = model.ValidatedResources.Resources.IdentityResources.Select(x => CreateScopeViewModel(x, vm.ScopesConsented.Contains(x.Name) || model == null)).ToArray();
var apiScopes = new List<ScopeViewModel>(); var apiScopes = new List<ScopeViewModel>();
foreach (var parsedScope in request.ValidatedResources.ParsedScopes) foreach (var parsedScope in model.ValidatedResources.ParsedScopes.Scopes)
{ {
var apiScope = request.ValidatedResources.Resources.FindApiScope(parsedScope.ParsedName); var apiScope = model.ValidatedResources.Resources.FindApiScope(parsedScope);
if (apiScope != null) if (apiScope != null)
{ {
var scopeVm = CreateScopeViewModel(parsedScope, apiScope, vm.ScopesConsented.Contains(parsedScope.RawValue) || model == null); var vreq = CreateValidatedRequest(request, apiScope);
var scopeVm = CreateScopeViewModel(apiScope,vreq);
apiScopes.Add(scopeVm); apiScopes.Add(scopeVm);
} }
} }
if (ConsentOptions.EnableOfflineAccess && request.ValidatedResources.Resources.OfflineAccess) if (ConsentOptions.EnableOfflineAccess && model.ValidatedResources.Resources.OfflineAccess)
{ {
apiScopes.Add(GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess) || model == null)); apiScopes.Add(GetOfflineAccessScope(vm.ScopesConsented.Contains(IdentityServer4.IdentityServerConstants.StandardScopes.OfflineAccess) || model == null));
} }
@ -190,6 +196,24 @@ namespace IdentityServerHost.Quickstart.UI
return vm; return vm;
} }
private ValidatedAuthorizeRequest CreateValidatedRequest(DeviceFlowAuthorizationRequest request, Scope apiScope)
{
throw new NotImplementedException();
}
private ScopeViewModel CreateScopeViewModel(Scope scope, ValidatedAuthorizeRequest req)
{
return new ScopeViewModel
{
Value = scope.Name,
DisplayName = scope.DisplayName ?? scope.Name,
Description = scope.Description,
Emphasize = scope.Emphasize,
Required = scope.Required,
Checked = req.Client != null
};
}
private ScopeViewModel CreateScopeViewModel(IdentityResource identity, bool check) private ScopeViewModel CreateScopeViewModel(IdentityResource identity, bool check)
{ {
return new ScopeViewModel return new ScopeViewModel
@ -203,15 +227,15 @@ namespace IdentityServerHost.Quickstart.UI
}; };
} }
public ScopeViewModel CreateScopeViewModel(ParsedScopeValue parsedScopeValue, ApiScope apiScope, bool check) public ScopeViewModel CreateScopeViewModel(ParsedScopes parsedScopeValue, Scope apiScope, bool check)
{ {
return new ScopeViewModel return new ScopeViewModel
{ {
Value = parsedScopeValue.RawValue, Value = parsedScopeValue.RawValue,
// todo: use the parsed scope value in the display? // todo: use the parsed scope value in the display?
DisplayName = apiScope.DisplayName ?? apiScope.Name, DisplayName = apiScope.DisplayName,
Description = apiScope.Description, Description = apiScope.Description,
Emphasize = apiScope.Emphasize, Emphasize = parsedScopeValue.Emphasize,
Required = apiScope.Required, Required = apiScope.Required,
Checked = check || apiScope.Required Checked = check || apiScope.Required
}; };

View file

@ -7,22 +7,22 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="2.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Common" Version="1.0.0-alpha2-final" /> <PackageReference Include="Microsoft.AspNetCore.SignalR.Common" Version="1.0.0" />
<PackageReference Include="NuGet.Packaging.Core" Version="5.9.0" /> <PackageReference Include="NuGet.Packaging.Core" Version="5.9.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="2.2.0" />
<PackageReference Include="IdentityServer4" Version="2.5.4" /> <PackageReference Include="IdentityServer4" Version="2.5.4" />
<PackageReference Include="MailKit" Version="2.11.1" /> <PackageReference Include="MailKit" Version="2.11.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.0.5" /> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.5" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.0.5" /> <PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="2.1.0" />
</ItemGroup> </ItemGroup>

8
omnisharp.json Normal file
View file

@ -0,0 +1,8 @@
{
"msbuild": {
"useBundledOnly": false,
"Configuration": "Debug",
"CscToolPath": "/usr/bin",
"CscToolExe": "csc"
}
}