How do I acquire the right token for a Web API from within an Azure Function App or Javascript? - asp.net-web-api2

We have a web service which requires authentication before use. When you type in the URL of the Web Service directly in the browser, everything works fine. However, if you were to try and call this very same service from Javascript, it doesn't work because authentication has yet to happen.
I've tried calling getAccessTokenAsync (this is part of the OfficeJS libray) but ended up getting one of those 1300x errors. Also, since this call is still in Preview I would like to avoid it.
The code below gets invoked when you enter the URL to the webservice directly in the browser windows. You're authenticated and everything works fine.
I just don't know how to do the equivalent authentication from within an Azure Function App, or Javascript (from a Web-Add-In)
public partial class AuthStartup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
// This part is for web sso so web pages can consume the API without obtaining a token
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
// http://www.cloudidentity.com/blog/2014/11/17/skipping-the-home-realm-discovery-page-in-azure-ad/
Notifications = new WsFederationAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage.Whr = "ourcompany.com";// similar effect to domain_hint from client so users never see the "choose account" prompt
return Task.FromResult(0);
}
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
Wtrealm = ConfigurationManager.AppSettings["ida:Audience"],
// this part is needed so that cookie and token auth can coexist
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new string[] { $"spn:{ConfigurationManager.AppSettings["ida:Audience"]}" }
}
});
// This part is for bearer token authentication
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
});
}
}

Related

How to reach signup page of openiddict authorization server?

I have built opeiddict as separate web application as authorization server. I am stuck with small problem, that is how I can go to user registration page directly though a link from the client web application. Right now I can go to login page, as your sample example:
public ActionResult SignIn() {
// Instruct the OIDC client middleware to redirect the user agent to the identity provider.
// Note: the authenticationType parameter must match the value configured in Startup.cs
return new ChallengeResult(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties {
RedirectUri = "/"
});
}
Is there a way to go to authentication server Account/Register from client app?
It looks like you can set the url in the redirect. See the following snippet:
[AllowAnonymous]
public IActionResult SignIn()
{
return new ChallengeResult(
OpenIdConnectDefaults.AuthenticationScheme,
new AuthenticationProperties
{
IsPersistent = true,
RedirectUri = Url.Action("SignInCallback", "Account")
});
}
See the docs here: Initiating the authentication flow

How to convert Azure OpenIdConnect OWIN Middleware Cookie Auth to JavaScript JWT for SPA application?

My ASP.NET MVC Core application uses OWIN Middleware along with the following modules to perform OpenIdConnect authentication against Azure AD:
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Azure.ActiveDirectory.GraphClient;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Azure.ActiveDirectory.GraphClient.Extensions;
The OWIN Middleware performs a bunch of tasks including
Fetching Azure AD Groups and Roles via Azure Graph API
Fetching User Profile Data from Database
Creating Claims from steps 1 & 2
Issuing cookie
The Middleware automatically handles Refresh tokens
The Middleware caches the token in the database and able to retrieve via a mechanism AcquireTokenSilentAsync for Graph client.
The MVC application serves a single Razor view and from that point onward, I am using Aurelia JavasScript framework (could easily be Angular, Knockout, React, not important) which only performs API requests to my Api Controller via AJAX.
So my question is how to convert all these authentication and authorization steps handled on the server to JWT based authentication on the client against Azure AD?
Admittedly, my question is fairly naive as there is substantial work being performed by OWIN Middleware components in the code below. So I am looking for a starting point, helper libraries and feasibility. I don't feel confident removing all the middleware code and server side authentication until I am confident this flow can be replicated using AJAX and JWT authentication.
I have done some research and the answer may involve the following
adal.js
JWT middleware in ASP.NET Core
HTML Web Storage
Azure AD Graph REST API (instead of C# Graph Client)
Here is the current OWIN Middleware code performing OpenIdConnect authentication against Azure AD on the server:
app.UseCookieAuthentication();
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["Authentication:AzureAd:ClientId"],
ClientSecret = Configuration["Authentication:AzureAd:ClientSecret"],
Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"],
ResponseType = OpenIdConnectResponseType.CodeIdToken,
Events = new OpenIdConnectEvents()
{
OnAuthorizationCodeReceived = async (context) =>
{
var code = context.TokenEndpointRequest.Code;
var identity = context.Ticket.Principal.Identity as ClaimsIdentity;
userObjectID = identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
signedInUserID = identity.FindFirst(ClaimTypes.NameIdentifier).Value;
ClientCredential credential =
new ClientCredential(
Configuration["Authentication:AzureAd:ClientId"],
Configuration["Authentication:AzureAd:ClientSecret"]);
var authority = Configuration["Authentication:AzureAd:AADInstance"]
+ Configuration["Authentication:AzureAd:TenantId"];
AuthenticationContext authContext =
new AuthenticationContext(authority, new ADALTokenCacheService(signedInUserID, Configuration));
await authContext.AcquireTokenByAuthorizationCodeAsync(
context.TokenEndpointRequest.Code,
new Uri(context.TokenEndpointRequest.RedirectUri, UriKind.RelativeOrAbsolute),
credential,
Configuration["Authentication:AzureAd:GraphResource"]);
context.HandleCodeRedemption();
ActiveDirectoryClient activeDirectoryClient = GetActiveDirectoryClient();
// Get currently logged in User from Graph
IPagedCollection<IUser> users = await activeDirectoryClient.Users.Where(u => u.ObjectId.Equals(userObjectID)).ExecuteAsync();
IUser user = users.CurrentPage.ToList().First();
// Get User's AD Groups
IEnumerable<string> userGroupIds = await user.GetMemberGroupsAsync(false);
List<string> userGroupIdList = userGroupIds.ToList();
// Transform User's AD Groups into Claims
foreach (var groupObjectId in userGroupIdList)
{
var group = await activeDirectoryClient.Groups.GetByObjectId(groupObjectId).ExecuteAsync();
Claim newClaim = new Claim(
CustomClaimValueTypes.ADGroup,
group.DisplayName,
ClaimValueTypes.String,
"AAD GRAPH");
((ClaimsIdentity)(context.Ticket.Principal.Identity)).AddClaim(newClaim);
}
// Get User's Application permissions from Database
upn = identity.FindFirst(ClaimTypes.Upn).Value;
DbContext db =
new DbContext(Configuration["ConnectionStrings:DefaultConnection"]);
if (db.PortalUsers.FirstOrDefault(b => (b.UPN == upn)) == null)
{
throw new System.IdentityModel.Tokens.SecurityTokenValidationException("You are not registered to use this application.");
}
var applications = from permissions in db.PortalPermissions
where permissions.PortalUser.UPN == upn
//orderby permissions.Application.SortOrder ascending
select permissions.PortalApplication;
// Transform User's Application permissions into Claims
foreach (var application in applications)
{
Claim newClaim = new Claim(
CustomClaimValueTypes.Application,
application.Name,
ClaimValueTypes.String,
"DATABASE");
((ClaimsIdentity)(context.Ticket.Principal.Identity)).AddClaim(newClaim);
}
},
OnRemoteFailure = (context) =>
{
if (context.Failure.Message == "You are not registered to use this application.")
{
context.Response.Redirect("/AuthenticationError");
}
else
{
context.Response.Redirect("/Error");
}
context.HandleResponse();
return Task.FromResult(0);
}
}
});
app.UseFileServer(new FileServerOptions
{
EnableDefaultFiles = true,
EnableDirectoryBrowsing = false
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Start}/{id?}");
});
}
private ActiveDirectoryClient GetActiveDirectoryClient()
{
Uri servicePointUri = new Uri(Configuration["Authentication:AzureAd:GraphResource"]);
Uri serviceRoot = new Uri(servicePointUri, Configuration["Authentication:AzureAd:TenantId"]);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(
serviceRoot, async () => await GetTokenForApplicationAsync());
return activeDirectoryClient;
}
private async Task<string> GetTokenForApplicationAsync()
{
ClientCredential clientCredential =
new ClientCredential(
Configuration["Authentication:AzureAd:ClientId"],
Configuration["Authentication:AzureAd:ClientSecret"]);
AuthenticationContext authenticationContext =
new AuthenticationContext(
Configuration["Authentication:AzureAd:AADInstance"] +
Configuration["Authentication:AzureAd:TenantId"],
new ADALTokenCacheService(signedInUserID, Configuration));
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(
Configuration["Authentication:AzureAd:GraphResource"],
clientCredential,
new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
return authenticationResult.AccessToken;
}
The MVC application serves a single Razor view and from that point onward, I am using Aurelia JavasScript framework (could easily be Angular, Knockout, React, not important) which only performs API requests to my Api Controller via AJAX.
Did you mean that the ASP.NET MVC Core application will protect the the API controller by both cookies and bearer token? And the Aurelia JavasScript framework will perform the AJAX request to the API control using the bearer token?
If I understood correctly, you need to register another native app on the Azure portal for authentication for the app which using Aurelia JavaScript framework(as same as the SPA call web API which protected by Azure AD here).
And for the existing ASP.NET MVC Core application to support the token authentication, we need to add the JWT token middler ware.
And if the web API which publish for your SPA application want to call other resource, we also need to check authentciation methoed.
For example, if we call the web API with token(the audince of token should be the app id uri of you ASP.Net MVC core application), and the web API need to exhcange this token for the target resource using the flow described Delegated User Identity with OAuth 2.0 On-Behalf-Of Draft Specification to call the another web API.
Update
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = ClientId,
Authority = Authority,
PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
ResponseType = OpenIdConnectResponseType.CodeIdToken,
GetClaimsFromUserInfoEndpoint = false,
Events = new OpenIdConnectEvents
{
OnRemoteFailure = OnAuthenticationFailed,
OnAuthorizationCodeReceived = OnAuthorizationCodeReceived,
OnTokenValidated= context => {
(context.Ticket.Principal.Identity as ClaimsIdentity).AddClaim(new Claim("AddByMyWebApp", "ClaimValue"));
return Task.FromResult(0);
}
}
});

Azure mobile apps Custom + Facebook authentication with Xamarin.Forms

I'm working on a Xamarin Forms mobile app with .NET backend. I followed this guide and successfully set up custom authentications with one change in Startup.cs:
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
SigningKey = Environment.GetEnvironmentVariable("WEBSITE_AUTH_SIGNING_KEY"),
ValidAudiences = new[] { Identifiers.Environment.ApiUrl },
ValidIssuers = new[] { Identifiers.Environment.ApiUrl },
TokenHandler = config.GetAppServiceTokenHandler()
});
Without "if (string.IsNullOrEmpty(settings.HostName))". Otherwise I am always getting unauthorized for all requests after login.
Server project:
Auth controller
public class ClubrAuthController : ApiController
{
private readonly ClubrContext dbContext;
private readonly ILoggerService loggerService;
public ClubrAuthController(ILoggerService loggerService)
{
this.loggerService = loggerService;
dbContext = new ClubrContext();
}
public async Task<IHttpActionResult> Post(LoginRequest loginRequest)
{
var user = await dbContext.Users.FirstOrDefaultAsync(x => x.Email == loginRequest.username);
if (user == null)
{
user = await CreateUser(loginRequest);
}
var token = GetAuthenticationTokenForUser(user.Email);
return Ok(new
{
authenticationToken = token.RawData,
user = new { userId = loginRequest.username }
});
}
private JwtSecurityToken GetAuthenticationTokenForUser(string userEmail)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userEmail)
};
var secretKey = Environment.GetEnvironmentVariable("WEBSITE_AUTH_SIGNING_KEY");
var audience = Identifiers.Environment.ApiUrl;
var issuer = Identifiers.Environment.ApiUrl;
var token = AppServiceLoginHandler.CreateToken(
claims,
secretKey,
audience,
issuer,
TimeSpan.FromHours(24)
);
return token;
}
}
Startup.cs
ConfigureMobileAppAuth(app, config, container);
app.UseWebApi(config);
}
private void ConfigureMobileAppAuth(IAppBuilder app, HttpConfiguration config, IContainer container)
{
config.Routes.MapHttpRoute("ClubrAuth", ".auth/login/ClubrAuth", new { controller = "ClubrAuth" });
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
SigningKey = Environment.GetEnvironmentVariable("WEBSITE_AUTH_SIGNING_KEY"),
ValidAudiences = new[] { Identifiers.Environment.ApiUrl },
ValidIssuers = new[] { Identifiers.Environment.ApiUrl },
TokenHandler = config.GetAppServiceTokenHandler()
});
}
Client project:
MobileServiceUser user = await MobileClient.LoginAsync(loginProvider, jtoken);
Additionally I configured Facebook provider in azure portal like described here.
But it works only when I comment out app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions(){...}); in Startup.cs.
What I am missing to make both types of authentication works at the same time?
Since you have App Service Authentication/Authorization enabled, that will already validate the token. It assumes things about your token structure, such as having the audience and issuer be the same as your app URL (as a default).
app.UseAppServiceAuthentication() will also validate the token, as it is meant for local development. So in your example, the token will be validated twice. Aside from the potential performance impact, this is generally fine. However, that means the tokens must pass validation on both layers, and I suspect that this is not the case, hence the error.
One way to check this is to inspect the tokens themselves. Set a breakpoint in your client app and grab the token you get from LoginAsync(), which will be part of that user object. Then head to a service like http://jwt.io to see what the token contents look like. I suspect that the Facebook token will have a different aud and iss claim than the Identifiers.Environment.ApiUrl you are configuring for app.UseAppServiceAuthentication(), while the custom token probably would match it since you're using that value in your first code snippet.
If that holds true, than you should be in a state where both tokens are failing. The Facebook token would pass the hosted validation but fail on the local middleware, while the custom token would fail the hosted validation but pass the local middleware.
The simplest solution here is to remove app.UseAppServiceAuthentication() when hosting in the cloud. You will also need to make sure that your call to CreateToken() uses the cloud-based URL as the audience and issuer.
For other folks that find this issue
The documentation for custom authentication can be found here.
A general overview of App Service Authentication / Authorization can be found here.
The code you reference is only for local deployments. For Azure deployments, you need to turn on App Service Authentication / Authorization - even if you don't configure an auth provider (which you wouldn't in the case of custom auth).
Check out Chapter 2 of my book - http://aka.ms/zumobook

Authorize via JWT Token

ASP.NET Core 5 with ASP.NET Identity 3.0, I'm using both web pages and apis. I am using OpenIddict to issue a JWT token and to authenticate. My code looks as such:
X509Certificate2 c = new X509Certificate2(#"tokensign.p12", "MyCertificatePassword");
services.AddOpenIddict<WebUser, IdentityRole<int>, WebDbContext, int>()
.EnableTokenEndpoint("/api/customauth/login")
.AllowPasswordFlow()
.UseJsonWebTokens()
.AddSigningCertificate(c);
If I disable UseJsonWebTokens(), I can generate a token and authorise successfully. However, I am not sure that my certificate is validating the returned tokens.
And when enable UseJsonWebTokens, I am able to issue a JWT token at this end point. However, I can't authenticate any request!
I am using the following code in the app configuration:
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
RequireHttpsMetadata = false,
Authority = "http://localhost:60000/",
Audience = "http://localhost:60000/",
});
app.UseOAuthValidation();
app.UseIdentity();
app.UseOpenIddict();
app.UseMvcWithDefaultRoute();
How can I enforce the request to be validated with my certificate to make sure the JWT token is not tampered with.
What are the correct settings that will allow validation and authorisation of my JWT token, given that if I am not using JWT, I am getting authorised successfully.
If I disable UseJsonWebTokens(), I can generate a token and authorise successfully. However, I am not sure that my certificate is validating the returned tokens.
In ASOS (the OpenID Connect server framework behind OpenIddict), there are 2 different built-in serialization mechanisms to create and protect tokens:
One that uses IdentityModel (a library developed by Microsoft) and produces standard tokens verifiable by third parties:
Identity tokens (JWT by definition) are always created using this process and you can call UseJsonWebTokens() to force OpenIddict to issue access tokens that use the same serialization process.
The certificate you specify when calling AddSigningCertificate() is always used to sign these tokens.
One that uses the ASP.NET Core Data Protection stack (also developed by Microsoft):
This stack exclusively produces "proprietary" tokens that are not meant to be read or verified by a third-party, as the token format is not standard and necessarily relies on symmetric signing and encryption.
It's the mechanism we use for authorization codes and refresh tokens, that are only meant to be consumed by OpenIddict itself. It's also used for access tokens when you use the default token format.
In this case, the certificate you specify when calling AddSigningCertificate() is not used.
Instead, these tokens are always encrypted by the Data Protection stack using an Authenticated Encryption algorithm (by default, AES-256-CBC with HMACSHA256), that provides authenticity, integrity and confidentiality. For that, 2 keys (one for encryption, one for validation) are derived by the Data Protection stack from one of the master keys stored in the key ring.
How can I enforce the request to be validated with my certificate to make sure the JWT token is not tampered with.
What are the correct settings that will allow validation and authorisation of my JWT token, given that if I am not using JWT, I am getting authorised successfully.
To answer these questions, it would help if you enabled logging and shared your traces.
Creating JWT Token based authentication in ASP.NET Core is very very simple. Please follow below link you will get more idea.
How to Create JWT Token in Asp NET Core
Sample Code
public static class AuthenticationConfig
{
public static string GenerateJSONWebToken(string user)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[] {
new Claim("UserName", user),
new Claim("Role", "1"),
};
var token = new JwtSecurityToken("http://localhost:30972",
"http://localhost:30972",
claims,
DateTime.UtcNow,
expires: DateTime.Now.AddMinutes(10),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
//ConfigureJwtAuthentication
internal static TokenValidationParameters tokenValidationParams;
public static void ConfigureJwtAuthentication(this IServiceCollection services)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("730F046B1ADF1555FF0C80149B47B38CD7C0A146AAFA34870E863CAA25B585C3"));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
tokenValidationParams = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
ValidIssuer = "http://localhost:30972",
ValidateLifetime = true,
ValidAudience = "http://localhost:30972",
ValidateAudience = true,
RequireSignedTokens = true,
// Use our signing credentials key here
// optionally we can inject an RSA key as
//IssuerSigningKey = new RsaSecurityKey(rsaParams),
IssuerSigningKey = credentials.Key,
ClockSkew = TimeSpan.FromMinutes(10)
};
services.AddAuthentication(options =>
{
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = tokenValidationParams;
#if PROD || UAT
options.IncludeErrorDetails = false;
#elif DEBUG
options.RequireHttpsMetadata = false;
#endif
});
}
}
Add this line in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.ConfigureJwtAuthentication();
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
Add these lines in Authentication Controller
[Route("api/[controller]")]
public class AuthenticationController : Controller
{
// GET: api/<controller>
[HttpGet]
public string Get(string user, string pass)
{
if (user == "admin")
{
return AuthenticationConfig.GenerateJSONWebToken(user);
}
else
{
return "";
}
}
// POST api/<controller>
[Authorize]
[HttpPost]
public string Post()
{
var identity = HttpContext.User.Identity as ClaimsIdentity;
IEnumerable<Claim> claim = identity.Claims;
var UserName = claim.Where(c => c.Type == "UserName").Select(c => c.Value).SingleOrDefault();
return "Welcome to " + UserName + "!";
}
}

Owin authentication cookie not visible subsequent to the first request

MVC 5 app with Microsoft Owin v3 authenticating users via Windows Azure Active Directory. I have a login process that I don't fully understand. I expect to see a cookie on every request by I only see one on the landing page after sign-in. After navigating to another controller the cookie disappears yet the session appears to be authenticated correctly. Does anyone know how this is working? Here is my sign on logic...I don't see any cookie with the expiry time set in any browser. I see .AspNet.Cookies, __RequestVerificationToken and 2 cookies associated with a support utility. Removing any of these using Firebug has no effect on the user session and I remain logged in.
HttpContext.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = "/", IsPersistent = true, AllowRefresh = true, ExpiresUtc = DateTime.UtcNow.AddMinutes(20) },
OpenIdConnectAuthenticationDefaults.AuthenticationType
);
And here is the startup logic taken from an online example...
public void ConfigureAuth(IAppBuilder app)
{
//TODO: Use the Ioc container to get this but need to check if the kernel has been created before this runs
string applicationClientId = ConfigurationManager.AppSettings.Get(ConfigurationConstants.AppSettings.AzureApplicationClientId);
//fixed address for multitenant apps in the public cloud
string authority = "https://login.windows.net/common/";
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions { CookieDomain = "example.com" });
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = applicationClientId,
Authority = authority,
TokenValidationParameters = new System.IdentityModel.Tokens.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()
{
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.
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl;
//This will need changing to the web site home page once it is live
context.ProtocolMessage.PostLogoutRedirectUri = "http://www.example.com";
return Task.FromResult(0);
},
// we use this notification for injecting our custom logic
SecurityTokenValidated = (context) =>
{
// retriever caller data from the incoming principal
string issuer = context.AuthenticationTicket.Identity.FindFirst("iss").Value;
string UPN = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.Name).Value;
string tenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
//Todo - fetch the tenant info
//if ((db.Tenants.FirstOrDefault(a => ((a.IdentityProvider == issuer) && (a.ActiveDirectoryTenantId == tenantId))) == null))
// // the caller wasn't from a trusted issuer throw to block the authentication flow
// throw new SecurityTokenValidationException();
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
context.OwinContext.Response.Redirect("/Home/Error");
context.HandleResponse(); // Suppress the exception
return Task.FromResult(0);
}
}
});
}