AspCore Client Global Signout with IdentityServer - asp.net

in a non core asp mvc application I had a controller action for signout the user globaly
it looked like this
public ActionResult Logout()
{
Request.GetOwinContext().Authentication.SignOut();
return Redirect("/");
}
now I have a asp core client and want a logout I tried
public async Task<ActionResult> LogOut()
{
if (User.Identity.IsAuthenticated)
{
await HttpContext.Authentication.SignOutAsync("Cookies");
}
return Redirect("/");
}
Update
Now it seems like I get logout, but I'm redirect to a site which requires auth.
I can see that i'm shortly redirected to identity server back again, which automatically sings me again in.
Summarized:
I get logged out in my asp application but not at the identity server.
How can I globally signout ? So that I need to resign in at the identity server?

If you use OpenIdConnect authentication, you also need to remote signout. Try to change your code something like below:
public async Task<ActionResult> LogOut()
{
if (User.Identity.IsAuthenticated)
{
await HttpContext.Authentication.SignOutAsync("Cookies");
await context.Authentication.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme, new AuthenticationProperties()
{
RedirectUri = "<signed out url>"
});
// if you use different scheme name for openid authentication, use below code
//await context.Authentication.SignOutAsync(<your openid scheme>, new AuthenticationProperties()
//{
// RedirectUri = "/signedout"
//});
}
return Redirect("/");
}
See original sample https://github.com/aspnet/Security/blob/dev/samples/OpenIdConnectSample/Startup.cs

I've came across the same issue and to solve it I had to clear the Response cookies myself in my IdentityServer application.
var cookies = HttpContext.Request.Cookies.Keys;
foreach (var cookie in cookies)
{
HttpContext.Response.Cookies.Delete(cookie, new CookieOptions
{
Domain = "localhost" // Your host name here
});
}
// SignOutAsync depends on IdentityServer4 > Microsoft.AspNetCore.Http.Authentication
await HttpContext.Authentication.SignOutAsync();
What I did was, when I client wants to sign-out, I redirect it to my IdentityServer app which clear the Response Cookies as above.
In this code I'm deleting all the Cookies for localhost, however you can add a filter there and delete only cookies that IdentityServer makes use of to persist the user authentication.
Below you'll find more details on this implementation.
http://benjii.me/2016/04/single-sign-out-logout-identity-server-4/

Here is the official documentation for ASP.NET Identity Server Single Sign-Out:
single sign out documentation
This is a sample tooked from their demo implementation:
public ActionResult Signout()
{
Request.GetOwinContext().Authentication.SignOut();
return Redirect("/");
}
public void SignoutCleanup(string sid)
{
var cp = (ClaimsPrincipal)User;
var sidClaim = cp.FindFirst("sid");
if (sidClaim != null && sidClaim.Value == sid)
{
Request.GetOwinContext().Authentication.SignOut("Cookies");
}
}

Related

How to implement single logout using http-redirect

I am using the library ITfoxtec Identity SAML 2.0 to implement SAML 2.0 with an ASP.Net 4.6 MVC App and a 3rd party IdP that only supports http-redirect single logout. I am able to login, but I can't get the single logout to work. The sample only use http-post to logout. Is there any sample code that is publicly available that shows how to implement a single logout using http-redirect?
Thanking you in advance for your help!
Logout with redirect binding can be supported with small changes by changing the binding class Saml2PostBinding to Saml2RedirectBinding. The following is based on the ITfoxtec Identity SAML 2.0 documentation.
Logout method in the Auth Controller
[HttpPost("Logout")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
if (!User.Identity.IsAuthenticated)
{
return Redirect(Url.Content("~/"));
}
var binding = new Saml2RedirectBinding();
var saml2LogoutRequest = await new Saml2LogoutRequest(config, User).DeleteSession(HttpContext);
return binding.Bind(saml2LogoutRequest).ToActionResult();
}
LoggedOut method in the Auth Controller
After successfully or failing logout the logged out method receive the response.
[Route("LoggedOut")]
public IActionResult LoggedOut()
{
var binding = new Saml2RedirectBinding();
binding.Unbind(Request.ToGenericHttpRequest(), new Saml2LogoutResponse(config));
return Redirect(Url.Content("~/"));
}
SingleLogout method in the Auth Controller
Receives a Single Logout request and send a response.
[Route("SingleLogout")]
public async Task<IActionResult> SingleLogout()
{
Saml2StatusCodes status;
var requestBinding = new Saml2RedirectBinding();
var logoutRequest = new Saml2LogoutRequest(config, User);
try
{
requestBinding.Unbind(Request.ToGenericHttpRequest(), logoutRequest);
status = Saml2StatusCodes.Success;
await logoutRequest.DeleteSession(HttpContext);
}
catch (Exception exc)
{
// log exception
Debug.WriteLine("SingleLogout error: " + exc.ToString());
status = Saml2StatusCodes.RequestDenied;
}
var responsebinding = new Saml2RedirectBinding();
responsebinding.RelayState = requestBinding.RelayState;
var saml2LogoutResponse = new Saml2LogoutResponse(config)
{
InResponseToAsString = logoutRequest.IdAsString,
Status = status,
};
return responsebinding.Bind(saml2LogoutResponse).ToActionResult();
}

Why is my microsoft.owin.security.authenticationmanager Signin method not working?

I working on an ASP MVC login form.
I have pretty simple codes. A Startup class and an action trying to set the cookie. Below is my code :
Startup
which is located in App_Start (there is also a reference to it in <appSetting> with key="owin:AppStartup")
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new PathString("/auth/login"),
});
}
}
The action method that is suppose to authenticate the user is :
[HttpPost]
public ActionResult Login(user model)
{
if(ModelState.IsValid)
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Email, "admin#admin.com"),
new Claim(ClaimTypes.Name, "tom"),
new Claim(ClaimTypes.Role, "admin")
});
var ctx = Request.GetOwinContext();
var authManager = ctx.Authentication;
authManager.SignIn(identity);
return RedirectToAction("Index", "Home");
}
return View(model);
}
But this does not get the identity authenticated as #User.Authenticated is false in my _Layout.cshtml when return RedirectToAction("Index", "Home"); and also the debbuger shows that IsAuthenticated property is false (in the controller Login action and in the _Layout.cshtml.
I have checked that IIS is enabled for Anonymous authentication using my windows administrative tools and also I have checked that Startup is set when the application starts...
I seems that authManager.SignIn(identity) is not doing its job.
How can we solve this ?
debugger screenshot
ps : I do not even see the browser popup asking if I want to save the password (I popped only once during my tests even though the user was still not authenticated)
SignIn persists the user for future requests (via cookies), it does not alter the current request. You can directly set HttpContext.User for the current request if you want.
I also recall that you need to set the ClaimsIdentity AuthenticationType to CookieAuthenticationDefaults.AuthenticationType (or whatever auth type you're using to identify your middleware). Otherwise the cookie auth middleware won't activate.

MVC5 Authentication redirects to Login Page even after login

I am working on MVC5 Project, it works fine on my system but it's behaving strange after deployment on server. I used OWIN for authentication, it works fine for first login, but after few seconds if I refresh the page, it redirects me back to the login page (This on happens on deployed server).
My Code:
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);}
I used [Authorize] on my controller.
[Authorize]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
}
Here's my login code:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginUserModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindAsync(model.userName, model.password);
if (user != null)
{
return RedirectToLocal(returnUrl);
}
}
}
At a glance, its either that the cookie is not being set correctly or at all. Or that the ModelState for some reason is not valid and your redirect is never hit.
Check out the link :-
http://coding.abel.nu/2014/06/understanding-the-owin-external-authentication-pipeline/
It should help with your configuration of OWIN middleware.
I added machineKey and sessionState in my Web.config file and that resolved the issue.
I had a similar issue which was caused by not using SSL. Choose the project in Solution Explorer, hit F4 and change to use SSL. Login requires SSL, a setting you can change but if set wrong it causes this confusing loop.

ASP.net identity - external login - won't log out

In my application, all my authentication happens with Google - ie - all my users are Google Accounts.
I don't need users to need to register in my app, just sign in using a Google account. However, I do want to manage Roles for the users with ASP.net Identity (I think)
With that in mind, on successful external authentication, I create an ASP.net Identity user (if one doesn't exist)
So, I've got my ExternalLoginCallback as follows:
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var authenticationManager = Request.GetOwinContext().Authentication;
var loginInfo = await authenticationManager.GetExternalLoginInfoAsync();
//successfully authenticated with google, so sign them in to our app
var id = new ClaimsIdentity(loginInfo.ExternalIdentity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
authenticationManager.SignIn(id);
//Now we need to see if the user exists in our database
var user = UserManager.FindByName(loginInfo.Email);
if (user == null)
{
//user doesn't exist, so the user needs to be created
user = new ApplicationUser { UserName = loginInfo.Email, Email = loginInfo.Email };
await UserManager.CreateAsync(user);
//add the google login to the newly created user
await UserManager.AddLoginAsync(user.Id, loginInfo.Login);
}
return RedirectToLocal(returnUrl);
}
Idea being, I can now manage users, add roles, check if users are in roles, etc....
Firstly, is this a sensible approach? Or have I over complicated it?
One issue I'm having, however, is with logging out of my application
My Logout action looks like:
public ActionResult LogOut()
{
HttpContext.GetOwinContext().Authentication.SignOut();
return RedirectToAction("Index", "Home");
}
My Index action is decorated with the [Authorize] attribute -
However, when I 'logout' - it redirects to Home.Index - but I still seem to be logged in?
According to this ASPNet Identity Work Item, this is by design, and you need to call directly to Google's API in order to log the user out.
completing the post Logout link with return URL (OAuth)
Here is a solution that work for me :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
return Redirect("https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=https://[url-of-your-site]");
}

How to authenticate an access token using OWIN OAuthBearerAuthentication?

What I want:
A token generator use OAuthAuthorizationServer and token consumer use OAuthBearerAuthentication (authenticate the access token).
Use OWIN pipeline to manage all stuff, token stuff and web api stuff.
What about the code:
public void Configuration(IAppBuilder app)
{
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AuthorizeEndpointPath = "/Authorize",
AllowInsecureHttp = true,
Provider = new OAuthAuthorizationServerProvider
{
OnGrantCustomExtension = GrantCustomExtension,
OnValidateClientRedirectUri = ValidateClientRedirectUri,
OnValidateClientAuthentication = ValidateClientAuthentication,
}
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new OAuthBearerAuthenticationProvider
{
//Handles applying the authentication challenge to the response message.
ApplyChallenge=MyApplyChallenge,
//Handles processing OAuth bearer token.
RequestToken=MyRequestToken,
//Handles validating the identity produced from an OAuth bearer token.
ValidateIdentity = MyValidateIdentity,
}
});
app.UseWebApi(new WebApplication3.Config.MyWebApiConfiguration());
}
What's the question:
The 3 properties of OAuthBearerAuthenticationProvider,
ApplyChallenge, RequestToken and ValidateIdentity. How to
implement the 3 methods?
In the token authetication process, What I thought is to decrypt the access token, validate the token from the client, and if the token is validated, put the identities of the token to the HttpContext.Current.User.
The OAuthBearerAuthenticationProvider's responsibility is to fulfill the
previous steps. Am I right?
As you know, UseOAuthAuthorizationServer has the job of authenticating the user. Then, UseOAuthBearerAuthentication has the job of ensuring that only authenticated users can access your application. Often, these two jobs are assigned to different web application. It looks like your application is doing both.
There are certainly some cases were you need to override the default OAuthBearerAuthenticationProvider. Maybe you do, or maybe you don't In my case, ApplicationCookie didn't quite fit the scenario. So, I'm storing a 3rd party JWT token in a cookie, rather than the header, and using it to indicate that the user is authenticated to a web application. I also needed to redirect to my own login page, rather than provide a 401.
Here's an implementation that does both:
public class CustomOAuthBearerProvider : IOAuthBearerAuthenticationProvider
{
public Task ApplyChallenge(OAuthChallengeContext context)
{
context.Response.Redirect("/Account/Login");
return Task.FromResult<object>(null);
}
public Task RequestToken(OAuthRequestTokenContext context)
{
string token = context.Request.Cookies[SessionKey];
if (!string.IsNullOrEmpty(token))
{
context.Token = token;
}
return Task.FromResult<object>(null);
}
public Task ValidateIdentity(OAuthValidateIdentityContext context)
{
return Task.FromResult<object>(null);
}
}
I didn't need to do anything special in ValidateIdentity, but I needed to satisfy the interface.
To wire this up, tell your app to use JwtBearerAuthentication with your provider:
// controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = audiences.ToArray(),
IssuerSecurityTokenProviders = providers.ToArray(),
Provider = new CookieOAuthBearerProvider()
}
);

Resources