Browse Source

Introduce OpenIddictManager and IOpenIddictStore to decouple the core project from Entity Framework

pull/8/head
Kévin Chalet 10 years ago
parent
commit
e666759161
  1. 14
      OpenIddict.sln
  2. 5
      samples/Mvc.Server/Startup.cs
  3. 14
      src/OpenIddict.Core/IOpenIddictStore.cs
  4. 20
      src/OpenIddict.Core/OpenIddict.Core.xproj
  5. 36
      src/OpenIddict.Core/OpenIddictBuilder.cs
  6. 8
      src/OpenIddict.Core/OpenIddictConstants.cs
  7. 52
      src/OpenIddict.Core/OpenIddictController.cs
  8. 0
      src/OpenIddict.Core/OpenIddictDefaults.cs
  9. 201
      src/OpenIddict.Core/OpenIddictExtensions.cs
  10. 78
      src/OpenIddict.Core/OpenIddictManager.cs
  11. 0
      src/OpenIddict.Core/OpenIddictOptions.cs
  12. 61
      src/OpenIddict.Core/OpenIddictProvider.cs
  13. 23
      src/OpenIddict.Core/Properties/AssemblyInfo.cs
  14. 7
      src/OpenIddict.Core/Views/Shared/Authorize.cshtml
  15. 0
      src/OpenIddict.Core/Views/Shared/Error.cshtml
  16. 0
      src/OpenIddict.Core/Views/Shared/Logout.cshtml
  17. 0
      src/OpenIddict.Core/Views/Shared/SignIn.cshtml
  18. 0
      src/OpenIddict.Core/Views/Shared/_Layout.cshtml
  19. 0
      src/OpenIddict.Core/Views/_ViewStart.cshtml
  20. 41
      src/OpenIddict.Core/project.json
  21. 20
      src/OpenIddict.EF/OpenIddict.EF.xproj
  22. 9
      src/OpenIddict.EF/OpenIddictContext.cs
  23. 74
      src/OpenIddict.EF/OpenIddictExtensions.cs
  24. 67
      src/OpenIddict.EF/OpenIddictStore.cs
  25. 20
      src/OpenIddict.EF/project.json
  26. 226
      src/OpenIddict/OpenIddictExtensions.cs
  27. 33
      src/OpenIddict/project.json

14
OpenIddict.sln

@ -17,6 +17,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "OpenIddict.Assets", "src\Op
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "OpenIddict.Models", "src\OpenIddict.Models\OpenIddict.Models.xproj", "{79AE02C3-2AB4-4495-BEDD-685A714EA51C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "OpenIddict.EF", "src\OpenIddict.EF\OpenIddict.EF.xproj", "{D2450929-ED0E-420D-B475-327924F9701C}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "OpenIddict.Core", "src\OpenIddict.Core\OpenIddict.Core.xproj", "{E60CF8CA-6313-4359-BE43-AFCBB927EA30}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -43,6 +47,14 @@ Global
{79AE02C3-2AB4-4495-BEDD-685A714EA51C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{79AE02C3-2AB4-4495-BEDD-685A714EA51C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79AE02C3-2AB4-4495-BEDD-685A714EA51C}.Release|Any CPU.Build.0 = Release|Any CPU
{D2450929-ED0E-420D-B475-327924F9701C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2450929-ED0E-420D-B475-327924F9701C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2450929-ED0E-420D-B475-327924F9701C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2450929-ED0E-420D-B475-327924F9701C}.Release|Any CPU.Build.0 = Release|Any CPU
{E60CF8CA-6313-4359-BE43-AFCBB927EA30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E60CF8CA-6313-4359-BE43-AFCBB927EA30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E60CF8CA-6313-4359-BE43-AFCBB927EA30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E60CF8CA-6313-4359-BE43-AFCBB927EA30}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -53,5 +65,7 @@ Global
{7CBEAFD2-E3D0-4424-9B78-E87AB52327A6} = {F47D1283-0EE9-4728-8026-58405C29B786}
{86293E11-DD31-4D54-BCAD-8788B5C9972F} = {D544447C-D701-46BB-9A5B-C76C612A596B}
{79AE02C3-2AB4-4495-BEDD-685A714EA51C} = {D544447C-D701-46BB-9A5B-C76C612A596B}
{D2450929-ED0E-420D-B475-327924F9701C} = {D544447C-D701-46BB-9A5B-C76C612A596B}
{E60CF8CA-6313-4359-BE43-AFCBB927EA30} = {D544447C-D701-46BB-9A5B-C76C612A596B}
EndGlobalSection
EndGlobal

5
samples/Mvc.Server/Startup.cs

@ -34,7 +34,8 @@ namespace Mvc.Server {
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
.AddDefaultTokenProviders()
.AddOpenIddict();
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
@ -75,7 +76,7 @@ namespace Mvc.Server {
// Note: OpenIddict must be added after
// ASP.NET Identity and the external providers.
app.UseOpenIddict<ApplicationDbContext, ApplicationUser>(options => {
app.UseOpenIddict(options => {
options.AllowInsecureHttp = true;
});

14
src/OpenIddict.Core/IOpenIddictStore.cs

@ -0,0 +1,14 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
namespace OpenIddict {
public interface IOpenIddictStore<TUser, TApplication> : IUserStore<TUser> where TUser : class where TApplication : class {
Task<TApplication> FindApplicationByIdAsync(string identifier, CancellationToken cancellationToken);
Task<TApplication> FindApplicationByLogoutRedirectUri(string url, CancellationToken cancellationToken);
Task<string> GetApplicationTypeAsync(TApplication application, CancellationToken cancellationToken);
Task<string> GetDisplayNameAsync(TApplication application, CancellationToken cancellationToken);
Task<string> GetRedirectUriAsync(TApplication application, CancellationToken cancellationToken);
Task<bool> ValidateSecretAsync(TApplication application, string secret, CancellationToken cancellationToken);
}
}

20
src/OpenIddict.Core/OpenIddict.Core.xproj

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>e60cf8ca-6313-4359-be43-afcbb927ea30</ProjectGuid>
<RootNamespace>OpenIddict.Core</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

36
src/OpenIddict.Core/OpenIddictBuilder.cs

@ -0,0 +1,36 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using Microsoft.Extensions.DependencyInjection;
namespace OpenIddict {
public class OpenIddictBuilder {
internal OpenIddictBuilder(IServiceCollection services) {
Services = services;
}
/// <summary>
/// Gets or sets the type corresponding to the Application entity.
/// </summary>
public Type ApplicationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Role entity.
/// </summary>
public Type RoleType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the User entity.
/// </summary>
public Type UserType { get; set; }
/// <summary>
/// Gets the services used by OpenIddict.
/// </summary>
public IServiceCollection Services { get; }
}
}

8
src/OpenIddict.Core/OpenIddictConstants.cs

@ -0,0 +1,8 @@
namespace OpenIddict {
public static class OpenIddictConstants {
public static class ApplicationTypes {
public const string Confidential = "confidential";
public const string Public = "public";
}
}
}

52
src/OpenIddict/OpenIddictController.cs → src/OpenIddict.Core/OpenIddictController.cs

@ -13,30 +13,21 @@ using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNet.Authorization;
using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Mvc;
using Microsoft.Data.Entity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace OpenIddict {
// Note: this controller is generic and doesn't need to
// be marked as internal to prevent MVC from discovering it.
public class OpenIddictController<TContext, TUser, TRole, TKey> : Controller
where TContext : OpenIddictContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey> {
public OpenIddictController([NotNull] TContext context) {
Context = context;
// Note: this controller is generic and doesn't need to be marked as internal to prevent MVC from discovering it.
public class OpenIddictController<TUser, TApplication> : Controller where TUser : class where TApplication : class {
public OpenIddictController([NotNull] OpenIddictManager<TUser, TApplication> manager) {
Manager = manager;
}
/// <summary>
/// Gets the OpenIddict context.
/// Gets the OpenIddict manager used by the controller.
/// </summary>
protected TContext Context { get; }
protected virtual OpenIddictManager<TUser, TApplication> Manager { get; }
/// <summary>
/// Gets the OpenIddict options used by the server.
@ -83,9 +74,7 @@ namespace OpenIddict {
// Note: AspNet.Security.OpenIdConnect.Server automatically ensures an application
// corresponds to the client_id specified in the authorization request using
// IOpenIdConnectServerProvider.ValidateClientRedirectUri (see OpenIddictProvider.cs).
var application = await (from entity in Context.Applications
where entity.ApplicationID == request.ClientId
select entity).SingleOrDefaultAsync(HttpContext.RequestAborted);
var application = await Manager.FindApplicationByIdAsync(request.ClientId);
// In theory, this null check is thus not strictly necessary. That said, a race condition
// and a null reference exception could appear here if you manually removed the application
@ -97,11 +86,10 @@ namespace OpenIddict {
});
}
return View("Authorize", Tuple.Create(request, application));
return View("Authorize", Tuple.Create(request, await Manager.GetDisplayNameAsync(application)));
}
[Authorize]
[HttpPost, ValidateAntiForgeryToken]
[Authorize, HttpPost, ValidateAntiForgeryToken]
public async Task<IActionResult> Accept() {
// Extract the authorization request from the cache,
// the query string or the request form.
@ -113,11 +101,8 @@ namespace OpenIddict {
});
}
// Resolve the user manager from the services provider.
var manager = HttpContext.RequestServices.GetRequiredService<UserManager<TUser>>();
// Retrieve the user data using the unique identifier.
var user = await manager.FindByIdAsync(User.GetUserId());
var user = await Manager.FindByIdAsync(User.GetUserId());
if (user == null) {
return View("Error", new OpenIdConnectMessage {
Error = OpenIdConnectConstants.Errors.ServerError,
@ -128,24 +113,22 @@ namespace OpenIddict {
// Create a new ClaimsIdentity containing the claims that
// will be used to create an id_token, a token or a code.
var identity = new ClaimsIdentity(Options.AuthenticationScheme);
identity.AddClaim(ClaimTypes.NameIdentifier, user.Id.ToString());
identity.AddClaim(ClaimTypes.NameIdentifier, await Manager.GetUserIdAsync(user));
// Only add the name claim if the "profile" scope was present in the token request.
if (request.GetScopes().Contains("profile", StringComparer.OrdinalIgnoreCase)) {
identity.AddClaim(ClaimTypes.Name, user.UserName, destination: "id_token token");
identity.AddClaim(ClaimTypes.Name, await Manager.GetUserNameAsync(user), destination: "id_token token");
}
// Only add the email address if the "email" scope was present in the token request.
if (request.GetScopes().Contains("email", StringComparer.OrdinalIgnoreCase)) {
identity.AddClaim(ClaimTypes.Email, user.Email, destination: "id_token token");
identity.AddClaim(ClaimTypes.Email, await Manager.GetEmailAsync(user), destination: "id_token token");
}
// Note: AspNet.Security.OpenIdConnect.Server automatically ensures an application
// corresponds to the client_id specified in the authorization request using
// IOpenIdConnectServerProvider.ValidateClientRedirectUri (see OpenIddictProvider.cs).
var application = await (from entity in Context.Applications
where entity.ApplicationID == request.ClientId
select entity).SingleOrDefaultAsync(HttpContext.RequestAborted);
var application = await Manager.FindApplicationByIdAsync(request.ClientId);
// In theory, this null check is thus not strictly necessary. That said, a race condition
// and a null reference exception could appear here if you manually removed the application
@ -161,8 +144,8 @@ namespace OpenIddict {
// Note: setting identity.Actor is not mandatory but can be useful to access
// the whole delegation chain from the resource server (see ResourceController.cs).
identity.Actor = new ClaimsIdentity(Options.AuthenticationScheme);
identity.Actor.AddClaim(ClaimTypes.NameIdentifier, application.ApplicationID);
identity.Actor.AddClaim(ClaimTypes.Name, application.DisplayName, destination: "id_token token");
identity.Actor.AddClaim(ClaimTypes.NameIdentifier, request.ClientId);
identity.Actor.AddClaim(ClaimTypes.Name, await Manager.GetDisplayNameAsync(application), destination: "id_token token");
// This call will instruct AspNet.Security.OpenIdConnect.Server to serialize
// the specified identity to build appropriate tokens (id_token and token).
@ -174,8 +157,7 @@ namespace OpenIddict {
return new EmptyResult();
}
[Authorize]
[HttpPost, ValidateAntiForgeryToken]
[Authorize, HttpPost, ValidateAntiForgeryToken]
public IActionResult Deny() {
// Extract the authorization request from the cache,
// the query string or the request form.

0
src/OpenIddict/OpenIddictDefaults.cs → src/OpenIddict.Core/OpenIddictDefaults.cs

201
src/OpenIddict.Core/OpenIddictExtensions.cs

@ -0,0 +1,201 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.Diagnostics;
using System.Reflection;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using OpenIddict;
#if DNX451
using NWebsec.Owin;
#endif
namespace Microsoft.AspNet.Builder {
public static class OpenIddictExtensions {
public static OpenIddictBuilder AddOpenIddictCore<TApplication>(
[NotNull] this IdentityBuilder builder) where TApplication : class {
builder.Services.AddSingleton(
typeof(OpenIdConnectServerProvider),
typeof(OpenIddictProvider<,>).MakeGenericType(
builder.UserType, typeof(TApplication)));
builder.Services.AddScoped(
typeof(OpenIddictManager<,>).MakeGenericType(
builder.UserType, typeof(TApplication)));
var services = new OpenIddictBuilder(builder.Services) {
ApplicationType = typeof(TApplication),
RoleType = builder.RoleType,
UserType = builder.UserType
};
builder.Services.AddInstance(services);
return services;
}
public static IApplicationBuilder UseOpenIddict(
[NotNull] this IApplicationBuilder app,
[NotNull] Action<OpenIddictOptions> configuration) {
var instance = new OpenIddictOptions();
// Turn ApplicationCanDisplayErrors on to ensure ASP.NET MVC 6
// handles errored requests and returns an appropriate error page.
instance.ApplicationCanDisplayErrors = true;
// Call the configuration delegate defined by the user.
configuration(instance);
var types = app.ApplicationServices.GetRequiredService<OpenIddictBuilder>();
// Run OpenIddict in an isolated environment.
return app.Isolate(builder => {
// Add the options to the ASP.NET context
// before executing the rest of the pipeline.
builder.Use(next => context => {
context.Items[typeof(OpenIddictOptions)] = instance;
return next(context);
});
#if DNX451
builder.UseKatana(owin => {
// Insert a new middleware responsible of setting the Content-Security-Policy header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20Content%20Security%20Policy&referringTitle=NWebsec
owin.UseCsp(options => options.DefaultSources(directive => directive.Self())
.ImageSources(directive => directive.Self().CustomSources("*"))
.ScriptSources(directive => directive.UnsafeInline())
.StyleSources(directive => directive.Self().UnsafeInline()));
// Insert a new middleware responsible of setting the X-Content-Type-Options header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20security%20headers&referringTitle=NWebsec
owin.UseXContentTypeOptions();
// Insert a new middleware responsible of setting the X-Frame-Options header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20security%20headers&referringTitle=NWebsec
owin.UseXfo(options => options.Deny());
// Insert a new middleware responsible of setting the X-Xss-Protection header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20security%20headers&referringTitle=NWebsec
owin.UseXXssProtection(options => options.EnabledWithBlockMode());
});
#endif
if (!instance.UseCustomViews) {
builder.UseStaticFiles(new StaticFileOptions {
FileProvider = new EmbeddedFileProvider(
assembly: Assembly.Load(new AssemblyName("OpenIddict.Assets")),
baseNamespace: "OpenIddict.Assets")
});
}
builder.UseCors(options => {
options.AllowAnyHeader();
options.AllowAnyMethod();
options.AllowAnyOrigin();
options.AllowCredentials();
});
// Add OpenIdConnectServerMiddleware to the ASP.NET 5 pipeline.
builder.UseOpenIdConnectServer(options => {
// Resolve the OpenIddict provider from the global services container.
options.Provider = app.ApplicationServices.GetRequiredService<OpenIdConnectServerProvider>();
// Copy the OpenIddict options to the ASOS configuration.
options.Options.AuthenticationScheme = instance.AuthenticationScheme;
options.Options.Issuer = instance.Issuer;
options.Options.AuthorizationEndpointPath = instance.AuthorizationEndpointPath;
options.Options.LogoutEndpointPath = instance.LogoutEndpointPath;
options.Options.AccessTokenLifetime = instance.AccessTokenLifetime;
options.Options.AuthorizationCodeLifetime = instance.AuthorizationCodeLifetime;
options.Options.IdentityTokenLifetime = instance.IdentityTokenLifetime;
options.Options.RefreshTokenLifetime = instance.RefreshTokenLifetime;
options.Options.ApplicationCanDisplayErrors = instance.ApplicationCanDisplayErrors;
options.Options.AllowInsecureHttp = instance.AllowInsecureHttp;
});
// Register ASP.NET MVC 6 and the actions
// associated to the OpenIddict controller.
builder.UseMvc(routes => {
// Register the actions corresponding to the authorization endpoint.
if (instance.AuthorizationEndpointPath.HasValue) {
routes.MapRoute("{D97891B4}", instance.AuthorizationEndpointPath.Value.Substring(1), new {
controller = typeof(OpenIddictController<,>).Name,
action = nameof(OpenIddictController<dynamic, dynamic>.Authorize)
});
routes.MapRoute("{7148DB83}", instance.AuthorizationEndpointPath.Value.Substring(1) + "/accept", new {
controller = typeof(OpenIddictController<,>).Name,
action = nameof(OpenIddictController<dynamic, dynamic>.Accept)
});
routes.MapRoute("{23438BCC}", instance.AuthorizationEndpointPath.Value.Substring(1) + "/deny", new {
controller = typeof(OpenIddictController<,>).Name,
action = nameof(OpenIddictController<dynamic, dynamic>.Deny)
});
}
// Register the action corresponding to the logout endpoint.
if (instance.LogoutEndpointPath.HasValue) {
routes.MapRoute("{C7DB102A}", instance.LogoutEndpointPath.Value.Substring(1), new {
controller = typeof(OpenIddictController<,>).Name,
action = nameof(OpenIddictController<dynamic, dynamic>.Logout)
});
}
});
}, services => {
services.AddAuthentication();
services.AddCaching();
services.AddMvc()
// Register the OpenIddict controller.
.AddControllersAsServices(new[] {
typeof(OpenIddictController<,>).MakeGenericType(types.UserType, types.ApplicationType)
})
// Update the Razor options to use an embedded provider
// extracting its views from the current assembly.
.AddRazorOptions(options => {
if (!instance.UseCustomViews) {
options.FileProvider = new EmbeddedFileProvider(
assembly: typeof(OpenIddictOptions).GetTypeInfo().Assembly,
baseNamespace: "OpenIddict.Core");
}
});
// Register the sign-in manager in the isolated container.
services.AddScoped(typeof(SignInManager<>).MakeGenericType(types.UserType), provider => {
var accessor = provider.GetRequiredService<IHttpContextAccessor>();
var container = (IServiceProvider) accessor.HttpContext.Items[typeof(IServiceProvider)];
Debug.Assert(container != null);
// Resolve the sign-in manager from the parent container.
return container.GetRequiredService(typeof(SignInManager<>).MakeGenericType(types.UserType));
});
// Register the user manager in the isolated container.
services.AddScoped(typeof(OpenIddictManager<,>).MakeGenericType(types.UserType, types.ApplicationType), provider => {
var accessor = provider.GetRequiredService<IHttpContextAccessor>();
var container = (IServiceProvider) accessor.HttpContext.Items[typeof(IServiceProvider)];
Debug.Assert(container != null);
// Resolve the user manager from the parent container.
return container.GetRequiredService(typeof(OpenIddictManager<,>).MakeGenericType(types.UserType, types.ApplicationType));
});
});
}
}
}

78
src/OpenIddict.Core/OpenIddictManager.cs

@ -0,0 +1,78 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.OptionsModel;
namespace OpenIddict {
public class OpenIddictManager<TUser, TApplication> : UserManager<TUser> where TUser : class where TApplication : class {
public OpenIddictManager([NotNull] IServiceProvider services)
: base(services: services,
store: services.GetService<IOpenIddictStore<TUser, TApplication>>(),
optionsAccessor: services.GetService<IOptions<IdentityOptions>>(),
passwordHasher: services.GetService<IPasswordHasher<TUser>>(),
userValidators: services.GetServices<IUserValidator<TUser>>(),
passwordValidators: services.GetServices<IPasswordValidator<TUser>>(),
keyNormalizer: services.GetService<ILookupNormalizer>(),
errors: services.GetService<IdentityErrorDescriber>(),
logger: services.GetService<ILogger<UserManager<TUser>>>(),
contextAccessor: services.GetService<IHttpContextAccessor>()) {
Context = services.GetRequiredService<IHttpContextAccessor>().HttpContext;
}
/// <summary>
/// Gets the HTTP context associated with the current manager.
/// </summary>
public virtual HttpContext Context { get; }
/// <summary>
/// Gets the store associated with the current manager.
/// </summary>
public virtual new IOpenIddictStore<TUser, TApplication> Store {
get { return base.Store as IOpenIddictStore<TUser, TApplication>; }
}
public virtual Task<TApplication> FindApplicationByIdAsync(string identifier) {
return Store.FindApplicationByIdAsync(identifier, Context.RequestAborted);
}
public virtual Task<TApplication> FindApplicationByLogoutRedirectUri(string url) {
return Store.FindApplicationByLogoutRedirectUri(url, Context.RequestAborted);
}
public virtual Task<string> GetApplicationTypeAsync(TApplication application) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Store.GetApplicationTypeAsync(application, Context.RequestAborted);
}
public virtual Task<string> GetDisplayNameAsync(TApplication application) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Store.GetDisplayNameAsync(application, Context.RequestAborted);
}
public virtual Task<string> GetRedirectUriAsync(TApplication application) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Store.GetRedirectUriAsync(application, Context.RequestAborted);
}
public virtual Task<bool> ValidateSecretAsync(TApplication application, string secret) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Store.ValidateSecretAsync(application, secret, Context.RequestAborted);
}
}
}

0
src/OpenIddict/OpenIddictOptions.cs → src/OpenIddict.Core/OpenIddictOptions.cs

61
src/OpenIddict/OpenIddictProvider.cs → src/OpenIddict.Core/OpenIddictProvider.cs

@ -12,19 +12,11 @@ using System.Security.Claims;
using System.Threading.Tasks;
using AspNet.Security.OpenIdConnect.Extensions;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Data.Entity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using OpenIddict.Models;
namespace OpenIddict {
public class OpenIddictProvider<TContext, TUser, TRole, TKey> : OpenIdConnectServerProvider
where TContext : OpenIddictContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey> {
public class OpenIddictProvider<TUser, TApplication> : OpenIdConnectServerProvider where TUser : class where TApplication : class {
public override Task MatchEndpoint([NotNull] MatchEndpointContext context) {
// Note: by default, OpenIdConnectServerHandler only handles authorization requests made to AuthorizationEndpointPath.
// This context handler uses a more relaxed policy that allows extracting authorization requests received at
@ -48,13 +40,10 @@ namespace OpenIddict {
return;
}
var database = context.HttpContext.RequestServices.GetRequiredService<TContext>();
// Retrieve the application details corresponding to the requested client_id.
var application = await (from entity in database.Applications
where entity.ApplicationID == context.ClientId
select entity).SingleOrDefaultAsync(context.HttpContext.RequestAborted);
var manager = context.HttpContext.RequestServices.GetRequiredService<OpenIddictManager<TUser, TApplication>>();
var application = await manager.FindApplicationByIdAsync(context.ClientId);
if (application == null) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -63,7 +52,7 @@ namespace OpenIddict {
return;
}
if (!string.Equals(context.RedirectUri, application.RedirectUri, StringComparison.Ordinal)) {
if (!string.Equals(context.RedirectUri, await manager.GetRedirectUriAsync(application), StringComparison.Ordinal)) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Invalid redirect_uri");
@ -75,9 +64,10 @@ namespace OpenIddict {
}
public override async Task ValidateClientLogoutRedirectUri([NotNull] ValidateClientLogoutRedirectUriContext context) {
var database = context.HttpContext.RequestServices.GetRequiredService<TContext>();
var manager = context.HttpContext.RequestServices.GetRequiredService<OpenIddictManager<TUser, TApplication>>();
if (!await database.Applications.AnyAsync(application => application.LogoutRedirectUri == context.PostLogoutRedirectUri)) {
var application = await manager.FindApplicationByLogoutRedirectUri(context.PostLogoutRedirectUri);
if (application == null) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Invalid post_logout_redirect_uri");
@ -111,13 +101,10 @@ namespace OpenIddict {
return;
}
var database = context.HttpContext.RequestServices.GetRequiredService<TContext>();
// Retrieve the application details corresponding to the requested client_id.
var application = await (from entity in database.Applications
where entity.ApplicationID == context.ClientId
select entity).SingleOrDefaultAsync(context.HttpContext.RequestAborted);
var manager = context.HttpContext.RequestServices.GetRequiredService<OpenIddictManager<TUser, TApplication>>();
var application = await manager.FindApplicationByIdAsync(context.ClientId);
if (application == null) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -126,8 +113,10 @@ namespace OpenIddict {
return;
}
// Reject tokens requests containing a client_secret if the client application is not confidential.
if (application.Type == ApplicationType.Public && !string.IsNullOrEmpty(context.ClientSecret)) {
// Reject tokens requests containing a client_secret
// if the client application is not confidential.
var type = await manager.GetApplicationTypeAsync(application);
if (type == OpenIddictConstants.ApplicationTypes.Public && !string.IsNullOrEmpty(context.ClientSecret)) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidRequest,
description: "Public clients are not allowed to send a client_secret");
@ -136,8 +125,8 @@ namespace OpenIddict {
}
// Confidential applications MUST authenticate.
else if (application.Type == ApplicationType.Confidential &&
!string.Equals(context.ClientSecret, application.Secret, StringComparison.Ordinal)) {
else if (type == OpenIddictConstants.ApplicationTypes.Confidential &&
!await manager.ValidateSecretAsync(application, context.ClientSecret)) {
context.Rejected(
error: OpenIdConnectConstants.Errors.InvalidClient,
description: "Invalid credentials: ensure that you specified a correct client_secret");
@ -173,7 +162,7 @@ namespace OpenIddict {
return;
}
var manager = context.HttpContext.RequestServices.GetRequiredService<UserManager<TUser>>();
var manager = context.HttpContext.RequestServices.GetRequiredService<OpenIddictManager<TUser, TApplication>>();
// Ensure the user still exists.
var user = await manager.FindByIdAsync(principal.GetUserId());
@ -208,7 +197,7 @@ namespace OpenIddict {
return;
}
var manager = context.HttpContext.RequestServices.GetRequiredService<UserManager<TUser>>();
var manager = context.HttpContext.RequestServices.GetRequiredService<OpenIddictManager<TUser, TApplication>>();
// Note: principal is guaranteed to be non-null since ValidateAuthorizationRequest
// rejects prompt=none requests missing or having an invalid id_token_hint.
@ -225,16 +214,16 @@ namespace OpenIddict {
}
var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
identity.AddClaim(ClaimTypes.NameIdentifier, user.Id.ToString());
identity.AddClaim(ClaimTypes.NameIdentifier, await manager.GetUserIdAsync(user));
// Only add the name claim if the "profile" scope was present in the token request.
if (context.Request.GetScopes().Contains("profile", StringComparer.OrdinalIgnoreCase)) {
identity.AddClaim(ClaimTypes.Name, user.UserName, destination: "id_token token");
identity.AddClaim(ClaimTypes.Name, await manager.GetUserNameAsync(user), destination: "id_token token");
}
// Only add the email address if the "email" scope was present in the token request.
if (context.Request.GetScopes().Contains("email", StringComparer.OrdinalIgnoreCase)) {
identity.AddClaim(ClaimTypes.Email, user.Email, destination: "id_token token");
identity.AddClaim(ClaimTypes.Email, await manager.GetEmailAsync(user), destination: "id_token token");
}
// Call SignInAsync to create and return a new OpenID Connect response containing the serialized code/tokens.
@ -246,7 +235,7 @@ namespace OpenIddict {
}
public override async Task GrantResourceOwnerCredentials([NotNull] GrantResourceOwnerCredentialsContext context) {
var manager = context.HttpContext.RequestServices.GetRequiredService<UserManager<TUser>>();
var manager = context.HttpContext.RequestServices.GetRequiredService<OpenIddictManager<TUser, TApplication>>();
var user = await manager.FindByNameAsync(context.UserName);
if (user == null) {
@ -291,18 +280,18 @@ namespace OpenIddict {
}
var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
identity.AddClaim(ClaimTypes.NameIdentifier, user.Id.ToString());
identity.AddClaim(ClaimTypes.NameIdentifier, await manager.GetUserIdAsync(user));
// Only add the name claim if the "profile" scope was present in the token request.
if (context.Request.GetScopes().Contains("profile", StringComparer.OrdinalIgnoreCase)) {
identity.AddClaim(ClaimTypes.Name, user.UserName, destination: "id_token token");
identity.AddClaim(ClaimTypes.Name, await manager.GetUserNameAsync(user), destination: "id_token token");
}
// Only add the email address if the "email" scope was present in the token request.
if (context.Request.GetScopes().Contains("email", StringComparer.OrdinalIgnoreCase)) {
identity.AddClaim(ClaimTypes.Email, user.Email, destination: "id_token token");
identity.AddClaim(ClaimTypes.Email, await manager.GetEmailAsync(user), destination: "id_token token");
}
context.Validated(new ClaimsPrincipal(identity));
}
}

23
src/OpenIddict.Core/Properties/AssemblyInfo.cs

@ -0,0 +1,23 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenIddict.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("OpenIddict.Core")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("e60cf8ca-6313-4359-be43-afcbb927ea30")]

7
src/OpenIddict/Views/Shared/Authorize.cshtml → src/OpenIddict.Core/Views/Shared/Authorize.cshtml

@ -1,14 +1,13 @@
@using AspNet.Security.OpenIdConnect.Extensions
@using Microsoft.IdentityModel.Protocols.OpenIdConnect
@using OpenIddict.Models
@model Tuple<OpenIdConnectMessage, Application>
@model Tuple<OpenIdConnectMessage, string>
<div class="jumbotron">
<h1>Authorization</h1>
<p class="lead text-left">Do you wanna grant <strong>@Model.Item2.DisplayName</strong> an access to your resources? (scopes requested: @Model.Item1.Scope)</p>
<p class="lead text-left"><strong>@Model.Item2.DisplayName</strong> will be able to access the following endpoints: @string.Join(" ; ", Model.Item1.GetResources())</p>
<p class="lead text-left">Do you wanna grant <strong>@Model.Item2</strong> an access to your resources? (scopes requested: @Model.Item1.Scope)</p>
<p class="lead text-left"><strong>@Model.Item2</strong> will be able to access the following endpoints: @string.Join(" ; ", Model.Item1.GetResources())</p>
<form enctype="application/x-www-form-urlencoded" method="post">
@Html.AntiForgeryToken()

0
src/OpenIddict/Views/Shared/Error.cshtml → src/OpenIddict.Core/Views/Shared/Error.cshtml

0
src/OpenIddict/Views/Shared/Logout.cshtml → src/OpenIddict.Core/Views/Shared/Logout.cshtml

0
src/OpenIddict/Views/Shared/SignIn.cshtml → src/OpenIddict.Core/Views/Shared/SignIn.cshtml

0
src/OpenIddict/Views/Shared/_Layout.cshtml → src/OpenIddict.Core/Views/Shared/_Layout.cshtml

0
src/OpenIddict/Views/_ViewStart.cshtml → src/OpenIddict.Core/Views/_ViewStart.cshtml

41
src/OpenIddict.Core/project.json

@ -0,0 +1,41 @@
{
"version": "1.0.0-alpha1-*",
"resource": "Views/**",
"dependencies": {
"Microsoft.AspNet.Cors": "6.0.0-*",
"Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*",
"Microsoft.AspNet.Identity": "3.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*",
"Microsoft.Extensions.Configuration.Json": "1.0.0-*",
"Microsoft.Extensions.NotNullAttribute.Sources": {
"type": "build",
"version": "1.0.0-*"
},
"AspNet.Hosting.Extensions": "1.0.0-*",
"AspNet.Security.OpenIdConnect.Server": "1.0.0-*",
"OpenIddict.Assets": "1.0.0-*"
},
"frameworks": {
"dnx451": {
"dependencies": {
"AspNet.Hosting.Katana.Extensions": "1.0.0-*",
"NWebsec.Owin": "1.0.0"
}
},
"dnxcore50": {
"dependencies": {
"System.Linq": "4.0.1-*",
"System.Runtime.Serialization.Primitives": "4.0.11-*"
}
}
}
}

20
src/OpenIddict.EF/OpenIddict.EF.xproj

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>d2450929-ed0e-420d-b475-327924f9701c</ProjectGuid>
<RootNamespace>OpenIddict.EF</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

9
src/OpenIddict/OpenIddictContext.cs → src/OpenIddict.EF/OpenIddictContext.cs

@ -10,12 +10,15 @@ using Microsoft.Data.Entity;
using OpenIddict.Models;
namespace OpenIddict {
public class OpenIddictContext<TUser, TRole, TKey> : IdentityDbContext<TUser, TRole, TKey>
public class OpenIddictContext<TUser, TApplication, TRole, TKey> : IdentityDbContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TApplication : Application
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey> {
public DbSet<Application> Applications { get; set; }
public DbSet<TApplication> Applications { get; set; }
}
public class OpenIddictContext<TUser> : OpenIddictContext<TUser, IdentityRole, string> where TUser : IdentityUser { }
public class OpenIddictContext<TUser> : OpenIddictContext<TUser, Application, IdentityRole, string> where TUser : IdentityUser { }
public class OpenIddictContext : OpenIddictContext<IdentityUser> { }
}

74
src/OpenIddict.EF/OpenIddictExtensions.cs

@ -0,0 +1,74 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using OpenIddict;
namespace Microsoft.AspNet.Builder {
public static class OpenIddictExtensions {
public static OpenIddictBuilder AddEntityFrameworkStore([NotNull] this OpenIddictBuilder builder) {
// Resolve the key type from the user type definition.
var keyType = ResolveKeyType(builder);
builder.Services.AddScoped(
typeof(IOpenIddictStore<,>).MakeGenericType(builder.UserType, builder.ApplicationType),
typeof(OpenIddictStore<,,,>).MakeGenericType(builder.UserType, builder.ApplicationType, builder.RoleType, keyType));
var type = typeof(OpenIddictContext<,,,>).MakeGenericType(new[] {
/* TUser: */ builder.UserType,
/* TApplication: */ builder.ApplicationType,
/* TRole: */ builder.RoleType,
/* TKey: */ keyType
});
builder.Services.AddScoped(type, provider => {
// Resolve the user store from the parent container and extract the associated context.
dynamic store = provider.GetRequiredService(typeof(IUserStore<>).MakeGenericType(builder.UserType));
dynamic context = store?.Context;
if (!type.GetTypeInfo().IsAssignableFrom(context?.GetType())) {
throw new InvalidOperationException(
"Only EntityFramework contexts derived from " +
"OpenIddictContext can be used with OpenIddict.");
}
return context;
});
return builder;
}
private static Type ResolveKeyType([NotNull] OpenIddictBuilder builder) {
TypeInfo type;
for (type = builder.UserType.GetTypeInfo(); type != null; type = type.BaseType?.GetTypeInfo()) {
if (!type.IsGenericType) {
continue;
}
var definition = type.GetGenericTypeDefinition();
if (definition == null) {
continue;
}
if (definition != typeof(IdentityUser<>)) {
continue;
}
return type.AsType().GetGenericArguments().Single();
}
throw new InvalidOperationException(
"The type of the key identifier used by the user " +
$"entity '{builder.UserType}' cannot be automatically inferred.");
}
}
}

67
src/OpenIddict.EF/OpenIddictStore.cs

@ -0,0 +1,67 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Data.Entity;
using OpenIddict.Models;
namespace OpenIddict {
public class OpenIddictStore<TUser, TApplication, TRole, TKey> : UserStore<TUser, TRole, OpenIddictContext<TUser, TApplication, TRole, TKey>, TKey>, IOpenIddictStore<TUser, TApplication>
where TUser : IdentityUser<TKey>
where TApplication : Application
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey> {
public OpenIddictStore(OpenIddictContext<TUser, TApplication, TRole, TKey> context)
: base(context) {
}
public virtual Task<TApplication> FindApplicationByIdAsync(string identifier, CancellationToken cancellationToken) {
return Context.Applications.SingleOrDefaultAsync(application => application.ApplicationID == identifier, cancellationToken);
}
public virtual Task<TApplication> FindApplicationByLogoutRedirectUri(string url, CancellationToken cancellationToken) {
return Context.Applications.SingleOrDefaultAsync(application => application.LogoutRedirectUri == url, cancellationToken);
}
public virtual Task<string> GetApplicationTypeAsync(TApplication application, CancellationToken cancellationToken) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
switch (application.Type) {
case ApplicationType.Confidential:
return Task.FromResult(OpenIddictConstants.ApplicationTypes.Confidential);
case ApplicationType.Public:
return Task.FromResult(OpenIddictConstants.ApplicationTypes.Public);
default:
throw new InvalidOperationException($"Unsupported application type ('{application.Type.ToString()}').");
}
}
public virtual Task<string> GetDisplayNameAsync(TApplication application, CancellationToken cancellationToken) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Task.FromResult(application.DisplayName);
}
public virtual Task<string> GetRedirectUriAsync(TApplication application, CancellationToken cancellationToken) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Task.FromResult(application.RedirectUri);
}
public virtual Task<bool> ValidateSecretAsync(TApplication application, string secret, CancellationToken cancellationToken) {
if (application == null) {
throw new ArgumentNullException(nameof(application));
}
return Task.FromResult(string.Equals(application.Secret, secret, StringComparison.Ordinal));
}
}
}

20
src/OpenIddict.EF/project.json

@ -0,0 +1,20 @@
{
"version": "1.0.0-alpha1-*",
"dependencies": {
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-*",
"Microsoft.Extensions.NotNullAttribute.Sources": {
"type": "build",
"version": "1.0.0-*"
},
"OpenIddict.Core": "1.0.0-*",
"OpenIddict.Models": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
}
}

226
src/OpenIddict/OpenIddictExtensions.cs

@ -4,232 +4,22 @@
* the license and the contributors participating to this project.
*/
using System;
using System.Diagnostics;
using System.Reflection;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNet.FileProviders;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal;
using OpenIddict;
#if DNX451
using NWebsec.Owin;
#endif
using OpenIddict.Models;
namespace Microsoft.AspNet.Builder {
public static class OpenIddictExtensions {
public static IApplicationBuilder UseOpenIddict<TContext>([NotNull] this IApplicationBuilder app)
where TContext : OpenIddictContext<IdentityUser, IdentityRole, string> {
return app.UseOpenIddict<TContext>(configuration => { });
}
public static IApplicationBuilder UseOpenIddict<TContext>(
[NotNull] this IApplicationBuilder app,
[NotNull] Action<OpenIddictOptions> configuration)
where TContext : OpenIddictContext<IdentityUser, IdentityRole, string> {
return app.UseOpenIddict<TContext, IdentityUser>(configuration);
}
public static IApplicationBuilder UseOpenIddict<TContext, TUser>([NotNull] this IApplicationBuilder app)
where TContext : OpenIddictContext<TUser, IdentityRole, string>
where TUser : IdentityUser<string> {
return app.UseOpenIddict<TContext, TUser>(configuration => { });
public static OpenIddictBuilder AddOpenIddict([NotNull] this IdentityBuilder builder) {
return builder.AddOpenIddictCore<Application>()
.AddEntityFrameworkStore();
}
public static IApplicationBuilder UseOpenIddict<TContext, TUser>(
[NotNull] this IApplicationBuilder app,
[NotNull] Action<OpenIddictOptions> configuration)
where TContext : OpenIddictContext<TUser, IdentityRole, string>
where TUser : IdentityUser<string> {
return app.UseOpenIddict<TContext, TUser, IdentityRole>(configuration);
}
public static IApplicationBuilder UseOpenIddict<TContext, TUser, TRole>([NotNull] this IApplicationBuilder app)
where TContext : OpenIddictContext<TUser, TRole, string>
where TRole : IdentityRole<string>
where TUser : IdentityUser<string> {
return app.UseOpenIddict<TContext, TUser, TRole>(configuration => { });
}
public static IApplicationBuilder UseOpenIddict<TContext, TUser, TRole>(
[NotNull] this IApplicationBuilder app,
[NotNull] Action<OpenIddictOptions> configuration)
where TContext : OpenIddictContext<TUser, TRole, string>
where TRole : IdentityRole<string>
where TUser : IdentityUser<string> {
return app.UseOpenIddict<TContext, TUser, TRole, string>(configuration);
}
public static IApplicationBuilder UseOpenIddict<TContext, TUser, TRole, TKey>(
[NotNull] this IApplicationBuilder app,
[NotNull] Action<OpenIddictOptions> configuration)
where TContext : OpenIddictContext<TUser, TRole, TKey>
where TUser : IdentityUser<TKey>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey> {
var instance = new OpenIddictOptions();
// Turn ApplicationCanDisplayErrors on to ensure ASP.NET MVC 6
// handles errored requests and returns an appropriate error page.
instance.ApplicationCanDisplayErrors = true;
// Call the configuration delegate defined by the user.
configuration(instance);
// Run OpenIddict in an isolated environment.
return app.Isolate(builder => {
// Add the options to the ASP.NET context
// before executing the rest of the pipeline.
builder.Use(next => context => {
context.Items[typeof(OpenIddictOptions)] = instance;
return next(context);
});
#if DNX451
builder.UseKatana(owin => {
// Insert a new middleware responsible of setting the Content-Security-Policy header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20Content%20Security%20Policy&referringTitle=NWebsec
owin.UseCsp(options => options.DefaultSources(directive => directive.Self())
.ImageSources(directive => directive.Self().CustomSources("*"))
.ScriptSources(directive => directive.UnsafeInline())
.StyleSources(directive => directive.Self().UnsafeInline()));
// Insert a new middleware responsible of setting the X-Content-Type-Options header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20security%20headers&referringTitle=NWebsec
owin.UseXContentTypeOptions();
// Insert a new middleware responsible of setting the X-Frame-Options header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20security%20headers&referringTitle=NWebsec
owin.UseXfo(options => options.Deny());
// Insert a new middleware responsible of setting the X-Xss-Protection header.
// See https://nwebsec.codeplex.com/wikipage?title=Configuring%20security%20headers&referringTitle=NWebsec
owin.UseXXssProtection(options => options.EnabledWithBlockMode());
});
#endif
if (!instance.UseCustomViews) {
builder.UseStaticFiles(new StaticFileOptions {
FileProvider = new EmbeddedFileProvider(
assembly: Assembly.Load(new AssemblyName("OpenIddict.Assets")),
baseNamespace: "OpenIddict.Assets")
});
}
builder.UseCors(options => {
options.AllowAnyHeader();
options.AllowAnyMethod();
options.AllowAnyOrigin();
options.AllowCredentials();
});
// Add OpenIdConnectServerMiddleware to the ASP.NET 5 pipeline.
builder.UseOpenIdConnectServer(options => {
options.Provider = new OpenIddictProvider<TContext, TUser, TRole, TKey>();
// Copy the OpenIddict options to the ASOS configuration.
options.Options.AuthenticationScheme = instance.AuthenticationScheme;
options.Options.Issuer = instance.Issuer;
options.Options.AuthorizationEndpointPath = instance.AuthorizationEndpointPath;
options.Options.LogoutEndpointPath = instance.LogoutEndpointPath;
options.Options.AccessTokenLifetime = instance.AccessTokenLifetime;
options.Options.AuthorizationCodeLifetime = instance.AuthorizationCodeLifetime;
options.Options.IdentityTokenLifetime = instance.IdentityTokenLifetime;
options.Options.RefreshTokenLifetime = instance.RefreshTokenLifetime;
options.Options.ApplicationCanDisplayErrors = instance.ApplicationCanDisplayErrors;
options.Options.AllowInsecureHttp = instance.AllowInsecureHttp;
});
// Register ASP.NET MVC 6 and the actions
// associated to the OpenIddict controller.
builder.UseMvc(routes => {
// Register the actions corresponding to the authorization endpoint.
if (instance.AuthorizationEndpointPath.HasValue) {
routes.MapRoute("{D97891B4}", instance.AuthorizationEndpointPath.Value.Substring(1), new {
controller = typeof(OpenIddictController<TContext, TUser, TRole, TKey>).Name,
action = nameof(OpenIddictController<TContext, TUser, TRole, TKey>.Authorize)
});
routes.MapRoute("{7148DB83}", instance.AuthorizationEndpointPath.Value.Substring(1) + "/accept", new {
controller = typeof(OpenIddictController<TContext, TUser, TRole, TKey>).Name,
action = nameof(OpenIddictController<TContext, TUser, TRole, TKey>.Accept)
});
routes.MapRoute("{23438BCC}", instance.AuthorizationEndpointPath.Value.Substring(1) + "/deny", new {
controller = typeof(OpenIddictController<TContext, TUser, TRole, TKey>).Name,
action = nameof(OpenIddictController<TContext, TUser, TRole, TKey>.Deny)
});
}
// Register the action corresponding to the logout endpoint.
if (instance.LogoutEndpointPath.HasValue) {
routes.MapRoute("{C7DB102A}", instance.LogoutEndpointPath.Value.Substring(1), new {
controller = typeof(OpenIddictController<TContext, TUser, TRole, TKey>).Name,
action = nameof(OpenIddictController<TContext, TUser, TRole, TKey>.Logout)
});
}
});
}, services => {
services.AddAuthentication();
services.AddCaching();
services.AddCors();
services.AddOptions();
services.AddMvc()
// Register the OpenIddict controller.
.AddControllersAsServices(new[] {
typeof(OpenIddictController<TContext, TUser, TRole, TKey>)
})
// Update the Razor options to use an embedded provider
// extracting its views from the current assembly.
.AddRazorOptions(options => {
if (!instance.UseCustomViews) {
options.FileProvider = new EmbeddedFileProvider(
assembly: typeof(OpenIddictOptions).GetTypeInfo().Assembly,
baseNamespace: typeof(OpenIddictOptions).Namespace);
}
});
// Register the sign-in manager in the isolated container.
services.AddScoped(provider => {
var accessor = provider.GetRequiredService<IHttpContextAccessor>();
var container = (IServiceProvider) accessor.HttpContext.Items[typeof(IServiceProvider)];
Debug.Assert(container != null);
// Resolve the sign-in manager from the parent container.
return container.GetRequiredService<SignInManager<TUser>>();
});
// Register the user manager in the isolated container.
services.AddScoped(provider => {
var accessor = provider.GetRequiredService<IHttpContextAccessor>();
var container = (IServiceProvider) accessor.HttpContext.Items[typeof(IServiceProvider)];
Debug.Assert(container != null);
// Resolve the user manager from the parent container.
return container.GetRequiredService<UserManager<TUser>>();
});
// Register the OpenIddict context in the isolated container.
services.AddScoped(provider => {
var accessor = provider.GetRequiredService<IHttpContextAccessor>();
var container = (IServiceProvider) accessor.HttpContext.Items[typeof(IServiceProvider)];
Debug.Assert(container != null);
// Resolve the EntityFramework context from the parent container.
return container.GetRequiredService<TContext>();
});
});
public static OpenIddictBuilder AddOpenIddict<TApplication>([NotNull] this IdentityBuilder builder)
where TApplication : Application {
return builder.AddOpenIddictCore<TApplication>()
.AddEntityFrameworkStore();
}
}
}

33
src/OpenIddict/project.json

@ -1,42 +1,17 @@
{
"version": "1.0.0-alpha1-*",
"resource": "Views/**",
"dependencies": {
"Microsoft.AspNet.Cors": "6.0.0-*",
"Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*",
"Microsoft.AspNet.Identity.EntityFramework": "3.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*",
"Microsoft.Extensions.Configuration.Json": "1.0.0-*",
"OpenIddict.EF": "1.0.0-*",
"Microsoft.Extensions.NotNullAttribute.Sources": {
"type": "build",
"version": "1.0.0-*"
},
"AspNet.Hosting.Extensions": "1.0.0-*",
"AspNet.Security.OpenIdConnect.Server": "1.0.0-*",
"OpenIddict.Assets": "1.0.0-*",
"OpenIddict.Models": "1.0.0-*"
}
},
"frameworks": {
"dnx451": {
"dependencies": {
"AspNet.Hosting.Katana.Extensions": "1.0.0-*",
"NWebsec.Owin": "1.0.0"
}
},
"dnxcore50": {
"dependencies": {
"System.Linq": "4.0.1-*",
"System.Runtime.Serialization.Primitives": "4.0.11-*"
}
}
"dnx451": { },
"dnxcore50": { }
}
}
Loading…
Cancel
Save