ADFS Authentication with multiple account - asp.net-mvc

I am authenticating user based on ADFS. I am adding claim provider trust to my adfs server so that I could use multiple accounts to login.
I am able to authenticate user for my adfs server whereas If I use other claim provider trust adfs to authenticate I am not able to return token
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
//Authority = authority,
MetadataAddress = metadataAddress,
RedirectUri = postLogoutRedirectUri,
PostLogoutRedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
},
AuthorizationCodeReceived = context =>
{
string authorizationCode = context.Code;
// (tricky) the authorizationCode is available here to use, but...
return Task.FromResult(0);
}
});
When I enter user credentials and hit login I get back to initial screen

Related

Microsoft login with subdomains

Using this guide: https://learn.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-asp-webapp i have added Microsoft Login to two projects.
The projects are placed as subdomains on the same domain and i would like for them to share login.
On the CookieAuthenticationOptions i have tried setting CookieDomain. This is what i have in my Startup.cs
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
CookieAuthenticationOptions options = new CookieAuthenticationOptions {
CookieName = "mytestcookie",
CookieDomain = ".azurewebsites.net",
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie
};
app.UseCookieAuthentication(options);
var ss1 = app.GetDefaultSignInAsAuthenticationType();
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions {
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
Scope = OpenIdConnectScope.OpenIdProfile + " email",
SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
ResponseType = OpenIdConnectResponseType.CodeIdToken,
Notifications = new OpenIdConnectAuthenticationNotifications {
AuthenticationFailed = OnAuthenticationFailed,
RedirectToIdentityProvider = notification => {
if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.Authentication) {
if ((IsAjaxRequest(notification.Request) || IsApiRequest(notification.Request)) && notification.Response.StatusCode == (int)HttpStatusCode.Unauthorized) {
notification.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
notification.HandleResponse();
return Task.FromResult(0);
}
}
return Task.FromResult(0);
},
},
UseTokenLifetime = false
});
However this breaks something, resulting microsoft login redirecting me back and forth a couple of times.
According to: ASP.NET Core Sharing Identity Cookie across azure web apps on default domain (*.azurewebsites.net)
.azurewebsites.net is blacklisted.
Using my own domain fixed the issue.

Mixing cookie external login using Azure AD and individual account in MVC5

I am getting problems with application cookie and external cookie that are integrated login with Azure AD to my web app using MVC5. Currently, my local account work correctly but external account (Google and Azure AD) cannot map external cookie to local cookie. My code get userId return incorrect user Id.
IIdentity ident = HttpContext.Current.GetOwinContext().Request.User.Identity;
ident.GetUserId()
Below is my startup.cs
public partial class Startup
{
// The Client ID is used by the application to uniquely identify itself to Azure AD.
string clientId = System.Configuration.ConfigurationManager.AppSettings["ClientId"];
// RedirectUri is the URL where the user will be redirected to after they sign in.
string redirectUri = System.Configuration.ConfigurationManager.AppSettings["RedirectUri"];
string postLogoutRedirectUri = System.Configuration.ConfigurationManager.AppSettings["PostLogoutRedirectUri"];
// Tenant is the tenant ID (e.g. contoso.onmicrosoft.com, or 'common' for multi-tenant)
static string tenant = System.Configuration.ConfigurationManager.AppSettings["Tenant"];
// Authority is the URL for authority, composed by Microsoft identity platform endpoint and the tenant name (e.g. https://login.microsoftonline.com/contoso.onmicrosoft.com/v2.0)
string authority = String.Format(System.Globalization.CultureInfo.InvariantCulture, System.Configuration.ConfigurationManager.AppSettings["Authority"], tenant);
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(AppIdentityDbContext.Create);
app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);
app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
AuthenticationMode = AuthenticationMode.Active,
LoginPath = new PathString("/"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<AppUserManager, AppUser>(
validateInterval: TimeSpan.FromHours(1),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
ExpireTimeSpan = TimeSpan.FromHours(1),
//Samesite secure
CookieSameSite = SameSiteMode.Lax,
CookieHttpOnly = true,
CookieSecure = CookieSecureOption.Always,
CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
//Open Id Connect
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ExternalCookie,
CookieManager = new SameSiteCookieManager(new SystemWebCookieManager())
});
app.UseOpenIdConnectAuthentication(CreateOpenIdOptions());
// GOOGLE
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = ConfigurationManager.AppSettings["GoogleClientID"].ToString(),
ClientSecret = ConfigurationManager.AppSettings["GoogleClientSecret"].ToString()
});
}
private OpenIdConnectAuthenticationOptions CreateOpenIdOptions()
{
var options = new OpenIdConnectAuthenticationOptions
{
Authority = authority,
ClientId = clientId,
RedirectUri = redirectUri,
AuthenticationMode = AuthenticationMode.Passive,
// PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
PostLogoutRedirectUri = postLogoutRedirectUri,
Scope = OpenIdConnectScope.OpenIdProfile, // a basic set of permissions for user sign in & profile access
// ResponseType is set to request the id_token - which contains basic information about the signed-in user
ResponseType = OpenIdConnectResponseType.IdToken,
TokenValidationParameters = new TokenValidationParameters
{
// In a real application you would use ValidateIssuer = true for additional checks and security.
ValidateIssuer = false,
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = OnAuthenticationFailed,
},
// Handling SameSite cookie according to https://learn.microsoft.com/en-us/aspnet/samesite/owin-samesite
CookieManager = new SameSiteCookieManager(
new SystemWebCookieManager()),
};
return options;
}
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
// Handle any unexpected errors during sign in
context.OwinContext.Response.Redirect("/Error?message=" + context.Exception.Message);
context.HandleResponse(); // Suppress the exception
return Task.FromResult(0);
}
}
Below is sign out method which is called before sign in
var authenticationTypes = new string[] {
DefaultAuthenticationTypes.ApplicationCookie,
DefaultAuthenticationTypes.ExternalCookie,
};
AuthManager.SignOut(authenticationTypes);
I also already tried apply many fixed posts related to this but it does not work. How can we resolve external cookie map to local cookie?
Finally, I found workaround solutions below:
First if you don want to use Open id connect use the link below
Use Azure AD only for Authentication and not Authorization
I use Kentor.OwinCookieSaver to resolve my problem
https://github.com/Sustainsys/owin-cookie-saver

Azure AD OWIN and OpenID Connect authentication problem IDX21323

My application is just looping redirection between login.microsoft.com and https://localhost:44353/
I have tried multiple workarounds provided like using Kentor and SystemWebChunkingCookieManager
Here is my startup.cs
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieManager = new SystemWebChunkingCookieManager()
});
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// Sets the ClientId, authority, RedirectUri as obtained from web.config
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
// PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
PostLogoutRedirectUri = redirectUri,
Scope = OpenIdConnectScope.OpenIdProfile,
// ResponseType is set to request the id_token - which contains basic information about the signed-in user
ResponseType = OpenIdConnectResponseType.IdToken,
// ValidateIssuer set to false to allow personal and work accounts from any organization to sign in to your application
// To only allow users from a single organizations, set ValidateIssuer to true and 'tenant' setting in web.config to the tenant name
// To allow users from only a list of specific organizations, set ValidateIssuer to true and use ValidIssuers parameter
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false // This is a simplification
},
// OpenIdConnectAuthenticationNotifications configures OWIN to send notification of failed authentications to OnAuthenticationFailed method
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed
}
}
);
}
/// <summary>
/// Handle failed authentication requests by redirecting the user to the home page with an error in the query string
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
context.HandleResponse();
context.Response.Redirect("/?errormessage=" + context.Exception.Message);
return Task.FromResult(0);
}
}

Owin OpenId Callback url

I'm working in implementing OpenId in a .NET MVC application.
I have used: https://learn.microsoft.com/en-us/azure/active-directory/develop/quickstart-v1-aspnet-webapp
as a starting guide. It is working, but i have 1 question regarding RedirectUri and CallbackPath.
If i only use RedirectUri, the callback page in my application gets a 302 redirection.
If i use CallbackPath the callback page is actually hit.
It is not really clear from the example what is going on? This is from MS:
"An optional constrained path on which to process the authentication callback. If not provided and RedirectUri is available, this value will be generated from RedirectUri."
I'm using [Authorize] attribute on my controllers.
Code Startup.cs:
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
var openIdOptions = new OpenIdConnectAuthenticationOptions
{
// Sets the ClientId, authority, RedirectUri as obtained from web.config
ClientId = ApplicationIdentifier,
Authority = FederationGateway,
RedirectUri = RedirectUrl,
ClientSecret = AppToken,
AuthenticationMode = AuthenticationMode.Active,
//CallbackPath = new PathString("/callback/"),
// PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
PostLogoutRedirectUri = "~/home/loggedout/",
//Scope is the requested scope: OpenIdConnectScopes.OpenIdProfileis equivalent to the string 'openid profile': in the consent screen, this will result in 'Sign you in and read your profile'
Scope = OpenIdConnectScope.OpenIdProfile,
// ResponseType is set to request the id_token - which contains basic information about the signed-in user
////ResponseType = OpenIdConnectResponseType.IdToken,
ResponseType = OpenIdConnectResponseType.IdTokenToken,
// ValidateIssuer set to false to allow work accounts from any organization to sign in to your application
// To only allow users from a single organizations, set ValidateIssuer to true and 'tenant' setting in web.config to the tenant name or Id (example: contoso.onmicrosoft.com)
// To allow users from only a list of specific organizations, set ValidateIssuer to true and use ValidIssuers parameter
TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false
},
// OpenIdConnectAuthenticationNotifications configures OWIN to send notification of failed authentications to OnAuthenticationFailed method
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed,
SecurityTokenValidated = OnSecurityTokenValidated
}
};
app.UseOpenIdConnectAuthentication(openIdOptions);
AntiForgeryConfig.UniqueClaimTypeIdentifier = IdentityNameIdentifier;
}

Redirect other then Home/Index using OpenIdConnectAuthentication and Identity server after login

I'm trying to Redirect user to Dashboard but it always redirect it to Home/Index that is because I've set RedirectUri to http://localhost:35641/ in Identity Server Options. But that is true in case of application landing page after login it needs to redirect o dashboard. I can write custom logic in Index's Action Result but I want to avoid it.
MVC web Startup method
public void Configuration(IAppBuilder app)
{
// Implicit mvc owin
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ApplicationConstants.ClientIdNucleusMvcApp,
Authority = ApplicationConstants.UrlBaseAuth,
RedirectUri = ApplicationConstants.UrlBaseWeb,
PostLogoutRedirectUri = ApplicationConstants.UrlBaseWeb,
ResponseType = "id_token token",
Scope = string.Format("openid email {0}", ApplicationScopes.MvcApp),
SignInAsAuthenticationType = "Cookies",
// sample how to access token on form (when adding the token response type)
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
// Adding access token in claims
var accessToken = n.ProtocolMessage.AccessToken;
if (!string.IsNullOrEmpty(accessToken))
{
n.AuthenticationTicket.Identity.AddClaim(new Claim("access_token", accessToken));
}
// Adding identity token in claims
var identityToken = n.ProtocolMessage.IdToken;
if (!string.IsNullOrEmpty(identityToken))
{
n.AuthenticationTicket.Identity.AddClaim(new Claim("identity_token", identityToken));
}
},
RedirectToIdentityProvider = async n =>
{
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idToken = n.OwinContext.Authentication.User.FindFirst("identity_token");
n.ProtocolMessage.IdTokenHint = idToken == null ? null : idToken.Value;
n.ProtocolMessage.PostLogoutRedirectUri = ApplicationConstants.UrlBaseWeb;
}
}
}
});
}
Here is my Client on Identity Server
new Client
{
Enabled = true,
ClientName = ApplicationConstants.ClientNameNucleusMvcApp,
ClientId = ApplicationConstants.ClientIdNucleusMvcApp,
ClientSecrets = new List<ClientSecret>
{
new ClientSecret(ApplicationConstants.ClientSecretNucleusMvcApp.Sha256())
},
Flow = Flows.Implicit,
RequireConsent = false,
AccessTokenType = AccessTokenType.Reference,
IdentityTokenLifetime = 1800,
AccessTokenLifetime = 1800,
RedirectUris = new List<string>
{
// MVC form post sample
ApplicationConstants.UrlBaseWeb,
ApplicationConstants.UrlBaseWeb + "Dashboard/Index"
},
PostLogoutRedirectUris = new List<string>
{
ApplicationConstants.UrlBaseWeb
}
}
Help will be appreciated. Thanks
The RedirectUri you use for talking with your authority should not make a difference, that's just used for dispatching the token back to your application. After that there is an internal (==local to the app) redirect that is used for setting the session cookie and can go anywhere you want within the site. How do you trigger authentication? If you started from a protected action via [authorize], you should always land back in there in the end. If you are using explicit sign in code like if
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/" }, OpenIdConnectAuthenticationDefaults.AuthenticationType);
you can always specify whatever desired landing route you want in RedirectUri. I know, it is fantastically confusing that the property driving this internal redirect has the exact same name as the protocol counterpart - the only excuse we have is that the AuthenticationProperties class already existed when the new claims based middleware was introduced, and calling the actual OAuth/OIDC redirect_uri with the underscore didn't fly with the .NET community. HTH

Resources