Combine server-side and client-side authentication with WebAPI - c#

I have a legacy ASP.NET webforms application in which users login via a form that is processed server-side. If the entered username + password match to credentials in the database, I set some values in the sessions (e.g., the current user ID) and perform a Response.Redirect afterwards. I'm also creating a HttpCookie for a "automatically relog me next time I visit" functionality.
Currently, I'm also adding WebApi support into that web application. I've managed to implement token authentication which allows me to login on the client side.
How can I combine both authentication approaches? I want to the user to enter his credentials once, get authenticated on the server side and on the client side an redirect the users to another page after authenticating.

The following code will create a cookie to keep user logged in.
// login etc
if (chkRemember.Checked)
{
// calculate the total number of minutes in 20 days to use as the time out.
int timeout = (int)TimeSpan.FromDays(30).TotalMinutes;
// create an authentication ticket
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(txtUserName.Text, true, timeout);
// Encrypt the ticket
string encrptedTicked = FormsAuthentication.Encrypt(ticket);
// create the cookie for the ticket, and put the ticket inside
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrptedTicked);
// give cookie and ticket same expiration
cookie.Expires = ticket.Expiration;
// Attach cookie to current response. it will now to the client and then back to the webserver with every request
HttpContext.Current.Response.Cookies.Set(cookie);
// send the user to the originally requested page.
string requestedPage = FormsAuthentication.GetRedirectUrl(txtUserName.Text, false);
Response.Redirect(requestedPage, true);
}
else
{
// login without saving cookie to client
FormsAuthentication.RedirectFromLoginPage(txtUserName.Text, false);
}

You can use token based authentication in webapi using Angular JS. Visit following link
http://www.dotnetcurry.com/aspnet/1223/secure-aspnet-web-api-using-tokens-owin-angularjs

Related

Prevent login with one user in different browser .NET Core

I want to create a login page that contain user and password with ASP.NET Core 5.
How can I prevent login with one user in different browser?
I would suggest at login you create a unique token that is stored on the server and passed back to the client as either an encrypted cookie value or if you are using Claims authentication as a claim. You then write a filter to test that the sent token matches the server side stored value on Authentication. You may want to store and update a datetime on the token - similar to a sliding cache item - so that you can expire the token.
When another browser or login occurs and the token is within a certain date then you can either suppress the login attempt or generate a new token which would logout the first browser user.
An example filter is shown below.
public class SignOnCheckerFilter : IAuthorizationFilter
{
public SignOnCheckerFilter (){}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool checkOk = false;
if (context.HttpContext.User.Identity.IsAuthenticated)
{
//read cookie or claims
//check match
//if match success
checkOk = true;
}
//return if checkOk
if(checkOk) return;
//return forbidden result if invalid match (you could redirect the user to a logout page?)
context.Result = new ForbidResult();
}
}

How to Invalidate AspNetCore.Identity.Application Cookie after user log out

I am having trouble invalidating .AspNetCore.Identity.Application cookie in ASP.NET Core Identity once the user log out.
Once user clicks on log out below code will execute.
public async Task<IActionResult> Logout(LogoutInputModel model)
{
// build a model so the logged out page knows what to display
LoggedOutViewModel loggedOutViewModel = await BuildLoggedOutViewModelAsync(model.LogoutId);
_logger.LogInformation($"loggedOutViewModel : {JsonConvert.SerializeObject(loggedOutViewModel)}");
if (User?.Identity.IsAuthenticated == true)
{
// delete local authentication cookie
await _norskTakstSignInManager.SignOutAsync();
//clear cookies
var appCookies = Request.Cookies.Keys;
foreach (var cookie in appCookies)
{
Response.Cookies.Delete(cookie);
}
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
// check if we need to trigger sign-out at an upstream identity provider
if (loggedOutViewModel.TriggerExternalSignout)
{
// build a return URL so the upstream provider will redirect back
// to us after the user has logged out. this allows us to then
// complete our single sign-out processing.
string url = Url.Action("Logout", new { logoutId = loggedOutViewModel.LogoutId });
// this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url }, loggedOutViewModel.ExternalAuthenticationScheme);
}
return View("LoggedOut", loggedOutViewModel);
}
This successfully clears all the cookies in the browser, however, if I grab the value of the cookie named ".AspNetCore.Identity.Application" prior to signing out, then add it back in on to the browser, then i can log in to the application without entering user credentials.
I tested few flows setting up cookie expiration time in different ways but non of them seem to work correctly.
I want to know way to invalidate the cookie without just clearing to resolve this issue.Then user should not be able to enter cookie manually and log in to the system. Any help is hugly appreciated. Thank you.
That's by design... one thing you can do is try updating the user's security stamp after logout, using UserManager.UpdateSecurityStampAsync.
This way the cookie's security stamp won't match the one in the database and the cookie will no longer be valid (however, no other cookie issued to that user will, even if they haven't "signed out"... so if a user has several sessions opened, all of those cookies will stop being valid, not just the one you signed out).
Identity doesn't track specific user sessions (it just validates the cookie against the user, and if it matches, it matches). If you want to be able to selectively remove sessions, you'll have to track them yourself
For me the best security practice is save every login and logout in one record with an unique random ID as GUID, then save this "id session" into the claims, and check this everytime the user access, if the ID in the claim is correct to that session.

SSRS Forms Authentication - How To Pass Cookie Credentials To Report Server

I am currently attempting to render the SSRS report in my web application using forms authentication.
My SSRS Report Version is 2016.
Initially I was under the impression that NetworkCredentials would work, and after encountering errors, I found that we are required to use FormsAuthentication, with passing the cookie as a means of authenticating the user.
I have done the necessary settings on the config files in the Reporting Server by following the guide from the link below:-
https://github.com/Microsoft/Reporting-Services/tree/master/CustomSecuritySample2016
The reporting services works as intended on the localhost/ReportServer and on
the SSRS Portal, localhost/Reports. I am also able to access said server
remotely.
Below is the code I used to obtain the authenticated cookie.
MyReportingService rsClient = new MyReportingService();
rsClient.Url = "http://xxx.xxx.xxx.xxx/reportserver/ReportService2010.asmx";
try
{
rsClient.LogonUser("user", "password", "");
Cookie myAuthCookie = rsClient.AuthCookie;
HttpCookie cookie = new HttpCookie(myAuthCookie.Name, myAuthCookie.Value);
Response.Cookies.Add(cookie);
}
Which supposedly would then be used to authenticate the user.
Cookie authCookie = new Cookie(cookie2.Name, cookie2.Value);
authCookie.Domain = "DomainName";
rvSiteMapping.ServerReport.ReportServerCredentials = new MyReportServerCredentials(authCookie);
rvSiteMapping.ServerReport.Cookies.Add(authCookie);
And in my forms authentication within the IReportsServerCredentials Class:-
public bool GetFormsCredentials(out Cookie authCookie,
out string user, out string password, out string authority)
{
authCookie = m_authCookie;
user = password = authority = null;
return true; // Use forms credentials to authenticate.
}
The issue I am experiencing is when the application is passing the credentials to the report server. I believe I must be doing this part incorrectly because while my application does get the cookie, when it authenticates the credentials provided by the cookie, I receive the text/html error:-
Object moved to <a href="/ReportServer/logon.aspx?ReturnUrl=%2fReportserver%2fReportExecution2005.asmx" />
This error is in response to setting a default generic Identity in the event that
the HttpContext.Current.User = null.
if (HttpContext.Current != null
&& HttpContext.Current.User != null)
{
userIdentity = HttpContext.Current.User.Identity;
}
else
{
userIdentity = new GenericIdentity("AnonymousUser");
}
I have tried googling the answer but most of the results are for
windows authentication and the few that are related to forms authentication
are very similar to the code I referred to.
The underlying cause of the issue was under my nose the whole time.
The domain name should refer to the web domain and not the active directory domain.
authCookie.Domain = "DomainName";
The cookie is now able to authenticate the user as intended.
Hopefully this helps anyone who happens to make the same mistake.

Store Id after authentication ASP net web forms

I would like to save the user ID after the forms authentication is made through email and password. I am currently using a session to do so;
However the session and the form authentication have different timeouts and because the session is a server type of variable when one user is logged in if I login with a different username on another machine the session simple changes its value and that is a major issue.
Besides Caching is there any other way to accomplish it?
You can store user ID in expanded authentication cookie. On authorization routine compose custom cookie and add it to response:
var ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(60), false, userId.ToString()));
HttpContext.Current.Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket)) { HttpOnly = true });
You can decrypt that cookie for authenticated request and find out what was user ID:
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);
int iserId = int.Parse(authTicket.UserData);

AuthorizeAttribute not recognizing AuthCookie in ASP.NET

Upon successful Login I have this line
FormsAuthentication.SetAuthCookie(a.username, true);
Then I have several pages which require login to be accessed, so I added the [Authorize] attribute to them like so
[Authorize]
public ActionResult Upload()
{
return View();
}
However, after logging in, such functions still return a 401 - Unauthorized error page just as if the user had not logged in. The error page states:
Logon Method Anonymous
Logon User Anonymous
Furthermore, in my project Anonymous Authentication is enabled and Windows Authentication is disabled.
I am looking for a solution where funcitons like Upload() are always available to any logged in user.
What you can do and what I've done is to write your own cookie this way:
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version number of ticket
userName, // UserName
DateTime.Now, //cookie creation time
DateTime.Now.AddHours(24), //Expiration time . cookie valid for 1 day
true, //Persistent
userData); // other data to store in ticket
// set Cookie
Response.SetCookie(
new HttpCookie(
FormsAuthentication.FormsCookieName,
FormsAuthentication.Encrypt(authTicket)) //// encrypt ticket
{
Expires = DateTime.Now.AddHours(24),
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL
});
"Forms authentication needs to be enabled, look in your web.config if you have in system.web" – glacasa

Categories