MVC 5 openid connect on-premises ADFS 4.0 logout issue - asp.net-mvc

I am trying to setup a new MVC 5 project and a new 2016 server with ADFS. I can authenticate with Oauth 2 and OpenID Connect. The issue I have is when I try to logout of the application. The sign out link points to the default /Account/SignOut action. When that action is called I get redirected to the post logout redirect uri which is https://website.com. This redirect loops until the browser errors out with "website redirected you too many times".
This is my signout method.
public void SignOut()
{
string callbackUrl = Url.Action("SignOutCallback", "Account", routeValues: null, protocol: Request.Url.Scheme);
// Send an OpenID Connect sign-out request.
HttpContext.GetOwinContext().Authentication.SignOut(
new AuthenticationProperties { RedirectUri = callbackUrl },
OpenIdConnectAuthenticationDefaults.AuthenticationType, CookieAuthenticationDefaults.AuthenticationType
);
}
If I just call
HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType)
the logout fails but at least the constant redirects don't happen.
Is there an overload of the Authentication.Signout() method which logs me out and then redirects to the post logout redirect uri?

I worked with MS support and determined that Sign Out is not currently supported for OID Connect with ADFS 2016. It may be part of a future release, but as of now there is no set release date for support.

ADFS 4.0 (on Windows Server 2016) supports "Single log-out". If you use Microsoft.AspNetCore.Authentication.OpenIDConnect package (this is the newer one, for ASP.NET Core) it works seamlessly.
If you query the well known endpoint for OpenID Connect configuration, which is https://your-server/adfs/.well-known/openid-configuration, you will find a key end_session_endpoint which contains the logout URL you should use.
Also, you can check the documentation: https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/development/ad-fs-logout-openid-connect
For instance, in order to invoke it from your controller, you would would use an action method like this one:
[HttpGet]
public IActionResult SignOut()
{
var callbackUrl = Url.Action(nameof(SignedOut), "Account", values: null, protocol: Request.Scheme);
return SignOut(
new AuthenticationProperties { RedirectUri = callbackUrl },
CookieAuthenticationDefaults.AuthenticationScheme,
OpenIdConnectDefaults.AuthenticationScheme);
}
You might find this sample useful (even though it is for Azure ADFS, it works for local installs as well): https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore

Related

Cannot Signout the External Identity provider in IdentityServer

I've an MVC Application which uses IdentityServer4. In IdentityServer4, I registered SAML2 (SustainSys.SAML2) as the external Login provider. and Login works fine.
When user log out of the MVC application, it logs out from the MVC application but the log out for External Login Provider isn't triggering. I checked the LogOut method of my identity Server which does the redirect to External Authentication Scheme. but the redirect doesnt happen.
this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url },
vm.ExternalAuthenticationScheme);
And here is the code where in i registered External Identity Provider for SAML. I've used Nuget package from SustainSys SAML.
.AddSaml2(options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SPOptions = CreateSPOptions();
var idp = new IdentityProvider(new EntityId(_strIDPEntityId), options.SPOptions)
{
AllowUnsolicitedAuthnResponse = true,
Binding = Saml2BindingType.HttpRedirect,
SingleSignOnServiceUrl = new Uri(_strSingleSignOnURL),
SingleLogoutServiceBinding = Saml2BindingType.HttpRedirect,
SingleLogoutServiceUrl = new Uri("https://devit-dev.onelogin.com/trust/saml2/http-redirect/slo/1111")
};
idp.SigningKeys.AddConfiguredKey(
new X509Certificate2(
AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "../../../App_Data/OneLogin.cer"));
options.IdentityProviders.Add(idp);
});
Not sure what am i missing here. Appreciate any help.
Check your logs, it should show you the decision process that ends up in a local logout. There are A LOT of things that need to be in place for a federated logout to work. You need a service certificate and you need some special claims. The latter will be simplified in a future compatibility release with Sustainsys.Saml2/IdSrv4

LinkedIn Authentication via Oauth2 returns null result (error=access_denied)

I moved my ASP.NET MVC web application from membership to Identity authentication and since that I cannot authenticate on LinkedIn anymore.
The Facebook authentication is still working fine but the LinkedIn is always returning a null loginInfo after the GetExternalLoginInfo call.
For the LinkedIn I'm using the Owin LinkedIn provider: LinkedIn APIs for .NET. I also unsuccessful tried to follow this post from Jerrie Pelser.
The Application calls the ExternalLogin Action that executes the ExecuteResult method and calls back the ExternalLoginCallback (after I allow access to the application). As I stated before, the method AuthenticationManager.GetExternalLoginInfoAsync() always returns a null loginInfo.
I checked the application settings in the LinkedIn and everything seems to be OK.
Ops! I almost forgot to say that the LinkedIn is returning back the URL with a generic error message: "GET /Account/ExternalLoginCallback?error=access_denied HTTP/1.1"
I can Authenticate using the DotNetOpenAuth.Clients (hosted github) but I'd like to just use the Identity.
Startup.Auth.cs
var linkedInOptions = new LinkedInAuthenticationOptions();
linkedInOptions.ClientId = "Xxxxx";
linkedInOptions.ClientSecret = "Yyyyyyy";
linkedInOptions.Scope.Add("r_fullprofile");
linkedInOptions.Provider = new LinkedInAuthenticationProvider()
{
OnAuthenticated = async context =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("LinkedIn_AccessToken", context.AccessToken));
}
};
linkedInOptions.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseLinkedInAuthentication(linkedInOptions);
ExternalLogin
public ActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
CallBack Action
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
LinkedIn CallBack URI
http://localhost:3279/signin-linkedin
After some researches and a visit the NuGet package repository I found a prerelease version of Owin.Security.Providers that worked like a charm. I just had to install it from package manager console and the issue with the null return from the LinkedIn External Login has gone.
Install-Package Owin.Security.Providers -Pre
Caution: Please be aware that the use of pre release packages may cause unexpected problems.

asp.net identity 2.1 google authentication

I'm using trying to use Google authentication in an ASP.NET MVC application.
For testing purposes I'm using the template app generated by VS2013 Update 4
In Google settings the return URLs are properly set and Google+ API is turned on. The app works fine when I publish it to an azure website. I can login using Google accounts without any problems.
However I'd like to deploy it on premises but here we have a reverse proxy setup which works like this:
the server sees itself as server01.mysite.com but this is an
internal name
outside world sees it as www.mysite.com (certain paths are
reverese proxied to the server01.mysite.com
Essentially www.mysite.com/myapp is reverse proxied to server01.mysite.com/myapp
With this setup I can't seem to use Google authentication. GetExternalLoginInfoAsync returns null and the app redirects itself to the login page.
By default the system generates a redirectUri using the private hostname. I tried changing it to the public address but this does not solve the problem.
Below is what I did at startup.auth.cs
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "...",
ClientSecret = "...",
Provider = new GoogleOAuth2AuthenticationProvider
{
OnApplyRedirect = context =>
{
var redirectUri = context.RedirectUri.Replace("server01", "www");
context.Response.Redirect(redirectUri);
},
}
});
Is there anyway I can make Google authentication work in a setup like this?
Thanks
To achieve this one has to tell the app to use the outside URL earlier so that the relevant hashes are built taking that into account. So instead of changing the redirect URI at the OnApplyRedirect call this before UseGoogleAuthentication:
app.Use((context, next) =>
{
context.Request.Host = new HostString(
context.Request.Host.Value.Replace("server01", "www"));
return next();
}
);
and remove the Provider=... from UseGoogleAuthentication
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "...",
ClientSecret = "..."
});

Azure Active Directory Sign out Error

I've created a generic website from visual studio 2013 and successfully wired it up to an existing Azure Active Directory instance for authentication. I can login as any user in the Azure AD with the appropriate credentials. Unfortunately I can not sign out without receiving this error:
AADSTS50068: Signout failed. The initiating application is not a
participant in the current session.
I've googled the error number, but apparently I'm the first person to ever encounter this....:) I'm pretty sure I'm not, but I'm now at a loss to explain why sign in works, but sign out does not.
Here is the sign out code, pretty much exactly as it was generated:
public ActionResult SignOut()
{
WsFederationConfiguration config = FederatedAuthentication.FederationConfiguration.WsFederationConfiguration;
// Redirect to SignOutCallback after signing out.
string callbackUrl = Url.Action("SignOutCallback", "Account", routeValues: null, protocol: Request.Url.Scheme);
SignOutRequestMessage signoutMessage = new SignOutRequestMessage(new Uri(config.Issuer), callbackUrl);
signoutMessage.SetParameter("wtrealm", IdentityConfig.Realm ?? config.Realm);
string signoutMsg = signoutMessage.WriteQueryString();
FederatedAuthentication.SessionAuthenticationModule.SignOut();
return new RedirectResult(signoutMsg);
}
After deleting the website in Azure and the associated live.com registration for Microsoft OAuth (https://account.live.com/developers/applications/) I recreated the example and logout worked as expected. I'm pretty confident I had incorrectly registered the application with an invalid "Redirect Url" (http vs https).

Google Authentication using OWIN Oauth in MVC5 not hitting ExternalLoginCallback function

I am currently upgrading my login process for Google to use OAuth before they depricate their OpenID login method.
The steps I have Identified so far is that I have upgraded the package Microsoft.Owin.Security.Google to version 2.1.0 as this version includes the ability to include options in the UseGoogleAuthentication method.
I have tried to use Alex Wheat's Solution in the link:
Get ExtraData from MVC5 framework OAuth/OWin identity provider with external auth provider
The code in Startup.Auth.cs (which also includes Facebook authentication) goes from this:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "MYAPPID",
AppSecret = "MYSECRET"
};
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
app.UseGoogleAuthentication();
To this:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "MYAPPID",
AppSecret = "MYSECRET"
};
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "MYCLIENTID",
ClientSecret = "MYSECRET",
CallbackPath = new PathString("/en/Account/ExternalLoginCallback"),
Provider = new GoogleOAuth2AuthenticationProvider()
{
}
};
app.UseGoogleAuthentication(googleOAuth2AuthenticationOptions);
After I add options to the Google Authentication, my app does not allow the ExternalLoginCallback action to be called for either google or facebook (no changes to facebook code but the issue still affects it).
On the front end, after clicking the external login buttons, the page redirects me to the link below and returns an empty white screen
https....../en/Account/ExternalLoginCallback#__=_ (There is actually only a single underscore before the = sign, SO syntax removes it if I have it as it appears on my address bar).
for facebook and
https....../en/Account/ExternalLoginCallback
for google. It does not hit the controller method below as it normally does (I have tried to place debug breakpoints within this function and it never gets stopped when there are google authentication options.
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
If I remove the authentication options from Google Authentication, it just reverts back to the old OpenID login and works fine again.
Am I missing something simple here? or is there something bad happening inside the Owin.Security.Google Library that is causing the problem?
I'm using the default ASP.NET MVC 5 template with Identity Authentication for simplicity, but hopefully this can be modified for different use cases.
StartupAuth.cs
Do not customize the redirect path. It gets replaced by /signin-google anyways and my attempts at getting around that caused "silent" (not in the debugger) Internal Server 500 errors.
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "whatevs.apps.googleusercontent.com",
ClientSecret = "whatevs_secrut",
Provider = new GoogleOAuth2AuthenticationProvider()
});
Make sure to add http://whatever.com/signin-google to https://console.developers.google.com/ in your APIs & auth > Credentials > Redirect URIs section.
RouteConfig.cs
Add a route to a permanent redirect controller action to your routes. Permanent redirects are the only thing that will suffice here. It is not enough to simply direct directly to the Callback URL.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Google API Sign-in",
url: "signin-google",
defaults: new { controller = "Account", action = "ExternalLoginCallbackRedirect" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
AccountController.cs
Permanent redirect to the built-in callback method and you should be fine.
[AllowAnonymous]
public ActionResult ExternalLoginCallbackRedirect(string returnUrl)
{
return RedirectPermanent("/Account/ExternalLoginCallback");
}
A template project has been posted on GitHub for reference: https://github.com/Pritchard/Test-AspNetGoogleOAuth2Authentication
Try only this
var googleOAuth2AuthenticationOptions = new GoogleOAuth2AuthenticationOptions
{
ClientId = "MYCLIENTID",
ClientSecret = "MYSECRET",
};
app.UseGoogleAuthentication(googleOAuth2AuthenticationOptions);
This worked for me
Make sure you have also enabled the Google+ API in your developer console. It is an additional step after you have your client and secret
As #Ronen said in the comments, this link should solve the issues with Google OAuth in MVC5:
http://blogs.msdn.com/b/webdev/archive/2014/07/02/changes-to-google-oauth-2-0-and-updates-in-google-middleware-for-3-0-0-rc-release.aspx
Also update the OWIN packages from NuGet. This is how my code looks and is working great:
var googleOptions = new GoogleOAuth2AuthenticationOptions ()
{
ClientId = "xxxxxxxxxx",
ClientSecret = "xxxxxxxxxx",
CallbackPath = new PathString("/signin-google")
};
googleOptions.Scope.Add("email");
app.UseGoogleAuthentication(googleOptions);

Resources