aspnetcore/samples/OpenIdConnectSample/Startup.cs

203 lines
8.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
namespace OpenIdConnectSample
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
Environment = env;
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath);
if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets<Startup>();
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
public IHostingEnvironment Environment { get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(o =>
{
o.ClientId = Configuration["oidc:clientid"];
o.ClientSecret = Configuration["oidc:clientsecret"]; // for code flow
o.Authority = Configuration["oidc:authority"];
o.ResponseType = OpenIdConnectResponseType.CodeIdToken;
o.GetClaimsFromUserInfoEndpoint = true;
o.Events = new OpenIdConnectEvents()
{
OnAuthenticationFailed = c =>
{
c.HandleResponse();
c.Response.StatusCode = 500;
c.Response.ContentType = "text/plain";
if (Environment.IsDevelopment())
{
// Debug only, in production do not share exceptions with the remote host.
return c.Response.WriteAsync(c.Exception.ToString());
}
return c.Response.WriteAsync("An error occurred processing your authentication.");
}
};
});
}
public void Configure(IApplicationBuilder app)
{
app.UseDeveloperExceptionPage();
app.UseAuthentication();
app.Run(async context =>
{
if (context.Request.Path.Equals("/signedout"))
{
await WriteHtmlAsync(context.Response, async res =>
{
await res.WriteAsync($"<h1>You have been signed out.</h1>");
await res.WriteAsync("<a class=\"btn btn-link\" href=\"/\">Sign In</a>");
});
return;
}
if (context.Request.Path.Equals("/signout"))
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await WriteHtmlAsync(context.Response, async res =>
{
await context.Response.WriteAsync($"<h1>Signed out {HtmlEncode(context.User.Identity.Name)}</h1>");
await context.Response.WriteAsync("<a class=\"btn btn-link\" href=\"/\">Sign In</a>");
});
return;
}
if (context.Request.Path.Equals("/signout-remote"))
{
// Redirects
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await context.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties()
{
RedirectUri = "/signedout"
});
return;
}
if (context.Request.Path.Equals("/Account/AccessDenied"))
{
await context.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
await WriteHtmlAsync(context.Response, async res =>
{
await context.Response.WriteAsync($"<h1>Access Denied for user {HtmlEncode(context.User.Identity.Name)} to resource '{HtmlEncode(context.Request.Query["ReturnUrl"])}'</h1>");
await context.Response.WriteAsync("<a class=\"btn btn-link\" href=\"/signout\">Sign Out</a>");
});
return;
}
// DefaultAuthenticateScheme causes User to be set
var user = context.User;
// This is what [Authorize] calls
// var user = await context.AuthenticateAsync();
// This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
// var user = await context.AuthenticateAsync(OpenIdConnectDefaults.AuthenticationScheme);
// Not authenticated
if (user == null || !user.Identities.Any(identity => identity.IsAuthenticated))
{
// This is what [Authorize] calls
await context.ChallengeAsync();
// This is what [Authorize(ActiveAuthenticationSchemes = OpenIdConnectDefaults.AuthenticationScheme)] calls
// await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
return;
}
// Authenticated, but not authorized
if (context.Request.Path.Equals("/restricted") && !user.Identities.Any(identity => identity.HasClaim("special", "true")))
{
await context.ChallengeAsync();
return;
}
await WriteHtmlAsync(context.Response, async response =>
{
await response.WriteAsync($"<h1>Hello Authenticated User {HtmlEncode(user.Identity.Name)}</h1>");
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/restricted\">Restricted</a>");
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout\">Sign Out</a>");
await response.WriteAsync("<a class=\"btn btn-default\" href=\"/signout-remote\">Sign Out Remote</a>");
await response.WriteAsync("<h2>Claims:</h2>");
await WriteTableHeader(response, new string[] { "Claim Type", "Value" }, context.User.Claims.Select(c => new string[] { c.Type, c.Value }));
});
});
}
private static async Task WriteHtmlAsync(HttpResponse response, Func<HttpResponse, Task> writeContent)
{
var bootstrap = "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css\" integrity=\"sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u\" crossorigin=\"anonymous\">";
response.ContentType = "text/html";
await response.WriteAsync($"<html><head>{bootstrap}</head><body><div class=\"container\">");
await writeContent(response);
await response.WriteAsync("</div></body></html>");
}
private static async Task WriteTableHeader(HttpResponse response, IEnumerable<string> columns, IEnumerable<IEnumerable<string>> data)
{
await response.WriteAsync("<table class=\"table table-condensed\">");
await response.WriteAsync("<tr>");
foreach (var column in columns)
{
await response.WriteAsync($"<th>{HtmlEncode(column)}</th>");
}
await response.WriteAsync("</tr>");
foreach (var row in data)
{
await response.WriteAsync("<tr>");
foreach (var column in row)
{
await response.WriteAsync($"<td>{HtmlEncode(column)}</td>");
}
await response.WriteAsync("</tr>");
}
await response.WriteAsync("</table>");
}
private static string HtmlEncode(string content) =>
string.IsNullOrEmpty(content) ? string.Empty : HtmlEncoder.Default.Encode(content);
}
}