1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
var db = new ApplicationDbContext();
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieSecure = CookieSecureOption.SameAsRequest,
ExpireTimeSpan = TimeSpan.FromMinutes(15)
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = AuthenticationConfiguration.ClientId,
Authority = AuthenticationConfiguration.Authority,
TokenValidationParameters = new TokenValidationParameters
{
// Instead of using the default validation (validating against a single issuer value, as we do in line of business apps),
// we inject our own multitenant validation logic.
ValidateIssuer = false,
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async context =>
{
var code = context.Code;
var credential = new ClientCredential(AuthenticationConfiguration.ClientId, AuthenticationConfiguration.ClientSecret);
var tenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
var signedInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
var authContext = new AuthenticationContext($"https://login.microsoftonline.com/{tenantId}", new EFADALTokenCache(signedInUserId));
var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, GraphConfiguration.GraphUrl);
},
RedirectToIdentityProvider = context =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
// this allows you to deploy your app (to Azure Web Sites, for example) without having to change settings.
// Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
var appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
return Task.FromResult(0);
},
// We use this notification for injecting our custom logic.
SecurityTokenValidated = context =>
{
// Retrieve caller data from the incoming principal.
var issuer = context.AuthenticationTicket.Identity.FindFirst("iss").Value;
var upn = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value;
var tenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
// If we go into this bloc, we must stop the authentication flow.
if ((db.Tenants.FirstOrDefault(a => ((a.IssValue == issuer) && (a.AdminConsented))) == null) && // The caller comes from an admin-consented, recorded issuer.
(db.Users.FirstOrDefault(b => ((b.Upn == upn) && (b.TenantId == tenantId))) == null)) // The caller is recorded in the db of users who went through the individual onboardoing.
{
// The caller was neither from a trusted issuer or a registered user - throw to block the authentication flow.
throw new SecurityTokenValidationException();
}
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
Logger.Error("StartupAuth Exception: " + context.Exception?.Message + " - Inner: " + context.Exception?.InnerException?.Message);
// As the authentication failed, we force a sign out to ensure there is no remaining token/cookie.
context.OwinContext.Authentication.SignOut(OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType);
//TODO: Redirect to / but for development purposes it is more helpful to redirect there.
context.OwinContext.Response.Redirect("/Home/Error");
context.HandleResponse(); // Suppress the exception
return Task.FromResult(0);
}
}
});
}
} |
Partager