Return error to angular ajax request from MVC web API - asp.net-mvc

Ive used couple of days trying to figugure out how to return an error to angular ajax request to web api.
in my js AccountController i have a login method:
$scope.Login = function () {
AccountService.Login($scope.UserData.LoginName, $scope.UserData.Password).success(function (account) {
$scope.UserData = account;
}).error(function () {
console.log("failed");
});
};
and in web api i have folowing:
public Account Login(string loginName, string password)
{
var emptyAccount = new Account();
password = Encrypt(password);
var account = db.Accounts.FirstOrDefault(c=>c.Password == password && c.LoginName == loginName);
if (account == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
acount.Password = "";
return account;
}
The problem is that i throw a new HttpResponseException which fire off and dont return anything back to ajax. How do i fix this?

Normally, in this case it is the error handler that will get triggered.
.error(function () {
alert("login failed");
}
This is where you could handle the error.
Also you probably want to return 401 Unauthorized in this case instead of 404. Also in general it is considered bad practice to throw exceptions in cases where you can handle it gracefully:
public HttpResponseMessage Login(string loginName, string password)
{
var emptyAccount = new Account();
password = Encrypt(password);
var account = db.Accounts.FirstOrDefault(c => c.Password == password && c.LoginName == loginName);
if (account == null)
{
return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "unauthorized");
}
acount.Password = "";
return Request.CreateResponse(HttpStatusCode.OK, account);
}

When you sending the data, and it's hit the servers, it will return header 200 OK because it's already hit your controller, even when your controller code is throw error (in later process).
so, if you want to know what error that thrown, I will create AccountResponse Dto into that, and introduce new Error field in that like so:
public class AccountResponse()
{
public Account account { get; set;}
public string ErrorMessage { get; set; }
}
and then on the controller:
public AccountResponse Login(string loginName, string password)
{
var emptyAccount = new Account();
password = Encrypt(password);
var account = db.Accounts.FirstOrDefault(c=>c.Password == password && c.LoginName == loginName);
if (account == null)
{
return new AccountResponse(){ ErrorMessage = Response.ResponseCodes.something;
}
AccountResponse.account = account;
AccountResponse.account.Password = "";
return AccountResponse;
}

Related

ASP.Net MVC - Cookie Remember Me

Hi Trying to create a simple username cookie.
seems to add but when I refresh the page the cookie has gone, any ideas?
[HttpGet]
public ActionResult Login()
{
var model = new ViewModels.UserCredentials();
ViewBag.Title = "Login";
model.UserName = CheckLoginCookie();
model.RememberMe = !string.IsNullOrEmpty(model.UserName);
return View("Login",model);
}
private string CheckLoginCookie()
{
if (Response.Cookies.Get("username") != null)
{
return Response.Cookies["username"].Value;
}
return string.Empty;
}
[HttpPost]
public ActionResult Login(ViewModels.UserCredentials credentials)
{
//do lots of stuff
//Create username remember cookie
if (credentials.RememberMe)
{
HttpCookie ckUserName = new HttpCookie("username");
ckUserName.Expires = DateTime.Now.AddSeconds(500)
//yeap i know its only 500;
ckUserName.Value = credentials.UserName;
Response.Cookies.Add(ckUserName);
}
}
To check the cookies cming from the client you need to look in to Request not the Response.
private string CheckLoginCookie()
{
if (Request.Cookies.Get("username") != null)
{
return Request.Cookies["username"].Value;
}
return string.Empty;
}

when I try to make google authorization get Error: invalid_request Error when site is published. Oauth 1.0

I have already finished MVC site which use Oauth 1.0
When I try to make authorize with google account from localhost (from debug mode) I fluently make authorization without any problem, But when I publish my site on server I have some problem, when I click button "google LogIn" I get error. please see screen below.
Developers please help me to fix this problem. tank you
P.S. 192.168.77.155 -it's my internal server IP, But I can't imagine why to show it.
return Information Hare:
internal class ExternalLoginResult : ActionResult
{
public ExternalLoginResult(string provider, string returnUrl)
{
Provider = provider;
ReturnUrl = returnUrl;
}
public string Provider { get; private set; }
public string ReturnUrl { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
}
}
public ActionResult ExternalLoginCallback(string returnUrl)
{
GooglePlusClient.RewriteRequest();
var result = OAuthWebSecurity.VerifyAuthentication();
if (result.IsSuccessful)
{
ProfilePicture helper = new ProfilePicture();
// name of the provider we just used
OauthProvider provider = helper.GetProvider(result.Provider);
if ((int)provider == 0)
{
Logger.Fatal("Unknown Oauth Provider try to SignIn. Check Providers Name (maybe it changeed)");
return null; //todo MessageBox for Unkown Provider, or something wrong
}
// provider's unique ID for the user
var uniqueUserID = result.ProviderUserId;
// since we might use multiple identity providers, then
// our app uniquely identifies the user by combination of
// provider name and provider user id
var uniqueID = provider + "/" + uniqueUserID;
// we then log the user into our application
// we could have done a database lookup for a
// more user-friendly username for our app
FormsAuthentication.SetAuthCookie(uniqueID, false);
string userName;
string nameAndLsatName = string.Empty;
var userDataFromProvider = result.ExtraData;
if (provider.Equals(OauthProvider.Twitter))
{
userName = result.UserName;
}
else
{
userName = userDataFromProvider["username"];
nameAndLsatName = userDataFromProvider["name"];
}
//Check if user already is in Db with Provider
var chekUserName = Uow.Users.Data.Where(x => x.UserName == userName && x.UserGroup.Id == (int)provider).FirstOrDefault();
if (chekUserName == null)
{
MM.Data.Model.User user = new MM.Data.Model.User();
user.UserName = userName;
if (!provider.Equals(OauthProvider.Twitter))
{
user.FirstName = nameAndLsatName.Split(' ')[0];
user.LastName = nameAndLsatName.Split(' ')[1];
}
user.Email = userName; //it'a Email
if (provider.Equals(OauthProvider.Twitter))
{
user.ShowNameAndLastName = false;
}
else
{
user.ShowNameAndLastName = true;
}
user.GroupId = (int)provider;
if (provider.Equals(OauthProvider.Twitter))
{
user.ProfilePicture = helper.GetImageInBytesByProvider(provider, userName);
}
else
{
user.ProfilePicture = helper.GetImageInBytesByProvider(provider, uniqueUserID);
}
Uow.Users.Add(user);
Uow.SaveChanges();
}
//Valid Login
//todo need improvement
var userModel = Uow.Users.GetSingle(x => x.UserName == userName && x.UserGroup.Id == (int)provider);
Session["User"] = new LoggedUserModel
{
Id = userModel.Id,
UserName = userName,
ProfilePicture = userModel.ProfilePicture
};
Session["UserId"] = userModel.Id;
//FormsAuthentication.SetAuthCookie(useruserNamename, false);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
// return View("", result);
}
return null; //need change
}
in the screenshot that you attached, I see that redirect_uri is your 192.168.77.155 ip. If you correct it, google will redirect back to the correct ip address.

Explicit password and email validation in Microsoft.AspNet.Identity, why needed?

I am big fan of Adam Freeman's books. At his Pro Asp.net mvc 5 platform, in chapter 13, page 325, the following code confused me. Does anyone have the explanation why he used the email and password validation explicitly?
The call this.UserManager.UpdateAsync(user) should return a result with same errors generated by this.UserManager.UserValidator.ValidateAsync(user) and this.UserManager.PasswordValidator.ValidateAsync(password). Is he not doing the same thing twice? Or there is a special purpose?
[HttpPost]
public async Task<ActionResult> Edit(string id, string email, string password)
{
AppUser user = await this.UserManager.FindByIdAsync(id);
if (user != null)
{
user.Email = email;
IdentityResult validEmail = await this.UserManager.UserValidator.ValidateAsync(user);
if (!validEmail.Succeeded)
{
this.AddErrorsFromResult(validEmail);
}
IdentityResult validPass = null;
if (password != string.Empty)
{
validPass = await this.UserManager.PasswordValidator.ValidateAsync(password);
if (validPass.Succeeded)
{
user.PasswordHash = this.UserManager.PasswordHasher.HashPassword(password);
}
else
{
this.AddErrorsFromResult(validPass);
}
}
if ((validEmail.Succeeded && validPass == null)
|| (validEmail.Succeeded && password != string.Empty && validPass.Succeeded))
{
IdentityResult result = await this.UserManager.UpdateAsync(user);
if (result.Succeeded)
{
return this.RedirectToAction("Index");
}
this.AddErrorsFromResult(result);
}
}
else
{
ModelState.AddModelError(string.Empty, "User not found");
}
return this.View(user);
}
private AppUserManager UserManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
private void AddErrorsFromResult(IdentityResult result)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError(string.Empty, error);
}
}
in source code of identity UserManager class UpdateAsync method is like this:
public virtual async Task<IdentityResult> UpdateAsync(TUser user)
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException("user");
}
var result = await UserValidator.ValidateAsync(user).ConfigureAwait(false);
if (!result.Succeeded)
{
return result;
}
await Store.UpdateAsync(user).ConfigureAwait(false);
return IdentityResult.Success;
}
that calls UserValidator.ValidateAsync(user) method for validating that username is not illegal or user not registered before with a different Owner Id and does not care for validating Email address or password string. if you want to validate passwords and do your custom checks you must create custom validators .
you can find Default UserValidator source code here

Authenticate - provide login email address to lookup user identity

I am using Thinktecture AuthenticationConfiguration to provide an end point for signing tokens on my API:
var authConfig = new AuthenticationConfiguration
{
EnableSessionToken = true,
SendWwwAuthenticateResponseHeaders = true,
RequireSsl = false,
ClaimsAuthenticationManager = new ClaimsTransformation(),
SessionToken = new SessionTokenConfiguration
{
EndpointAddress = "/api/token",
SigningKey = signingKey,
DefaultTokenLifetime = new TimeSpan(1, 0, 0)
}
};
var userCredentialsService = new CredentialsService(credentialStore);
authConfig.AddBasicAuthentication(userCredentialsService.Validate);
And authenticating users with CredentialsService:
public class CredentialsService
{
public bool Validate(string username, string password)
{
return username == password;
}
}
The above works, and no its certainly not used in production, but on returning true i will get a token in which contains a claim with the username.
In my scenario I have a user id (an integer) which can never change and I would like this to be in my claim. So the user would pass an email address to the service endpoint in the header as basic authentication, and then if valid go ahead and sign with the id as the claim (but not the email address as the claim):
public class CredentialsService
{
public bool Validate(string emailAddress, string password)
{
// map from the provided name, to the user id
var details = MySqlDb.ReadBy(emailAddress);
var id = details.Id; // this is the actual identity of the user
var email = details.EmailAddress;
var hash = details.Hash;
return PasswordHash.ValidatePassword(password,hash);
}
}
I appreciate this will need a second lookup to a sql server database to transform the emailAddress in to a userId, is there a way for me to insert this in to the pipeline flow before CredentialsService is called?
Or am i going about it the wrong way, and just stick with the username that was signed in as, then use a claims transformation based on the username to enrich with the integer identity - but then what if they changed the username?
Ok, I managed to solve this by taking a look at the awesome thinktecture source and overriding BasicAuthenticationSecurityTokenHandler to give a derived class which has a second delegate returning a Claim[] ready to be signed:
public class BasicAuthSecurityTokenHandlerWithClaimsOutput : BasicAuthenticationSecurityTokenHandler
{
public BasicAuthSecurityTokenHandlerWithClaimsOutput(ValidateUserNameCredentialDelegate validateUserNameCredential, GetClaimsForAuthenticatedUser getClaimsForAuthenticatedUser)
: base()
{
if (validateUserNameCredential == null)
{
throw new ArgumentNullException("ValidateUserNameCredential");
}
if (getClaimsForAuthenticatedUser== null)
{
throw new ArgumentNullException("GetClaimsForAuthenticatedUser");
}
base.ValidateUserNameCredential = validateUserNameCredential;
_getClaimsForAuthenticatedUser = getClaimsForAuthenticatedUser;
}
public delegate Claim[] GetClaimsForAuthenticatedUser(string username);
private readonly GetClaimsForAuthenticatedUser _getClaimsForAuthenticatedUser;
public override ReadOnlyCollection<ClaimsIdentity> ValidateToken(SecurityToken token)
{
if (token == null)
{
throw new ArgumentNullException("token");
}
if (base.Configuration == null)
{
throw new InvalidOperationException("No Configuration set");
}
UserNameSecurityToken unToken = token as UserNameSecurityToken;
if (unToken == null)
{
throw new ArgumentException("SecurityToken is not a UserNameSecurityToken");
}
if (!ValidateUserNameCredentialCore(unToken.UserName, unToken.Password))
{
throw new SecurityTokenValidationException(unToken.UserName);
}
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, unToken.UserName),
new Claim(ClaimTypes.AuthenticationMethod, AuthenticationMethods.Password),
AuthenticationInstantClaim.Now
};
var lookedUpClaims = _getClaimsForAuthenticatedUser(unToken.UserName);
claims.AddRange(lookedUpClaims);
if (RetainPassword)
{
claims.Add(new Claim("password", unToken.Password));
}
var identity = new ClaimsIdentity(claims, "Basic");
if (Configuration.SaveBootstrapContext)
{
if (this.RetainPassword)
{
identity.BootstrapContext = new BootstrapContext(unToken, this);
}
else
{
var bootstrapToken = new UserNameSecurityToken(unToken.UserName, null);
identity.BootstrapContext = new BootstrapContext(bootstrapToken, this);
}
}
return new List<ClaimsIdentity> {identity}.AsReadOnly();
}
}
I then added a second helper method to make it easier to wire up:
public static class BasicAuthHandlerExtensionWithClaimsOutput
{
public static void AddBasicAuthenticationWithClaimsOutput(
this AuthenticationConfiguration configuration,
BasicAuthenticationSecurityTokenHandler.ValidateUserNameCredentialDelegate validationDelegate,
BasicAuthSecurityTokenHandlerWithClaimsOutput.GetClaimsForAuthenticatedUser getClaimsForAuthenticatedUserDelegate,
string realm = "localhost", bool retainPassword = false)
{
var handler = new BasicAuthSecurityTokenHandlerWithClaimsOutput(validationDelegate, getClaimsForAuthenticatedUserDelegate);
handler.RetainPassword = retainPassword;
configuration.AddMapping(new AuthenticationOptionMapping
{
TokenHandler = new SecurityTokenHandlerCollection { handler },
Options = AuthenticationOptions.ForAuthorizationHeader(scheme: "Basic"),
Scheme = AuthenticationScheme.SchemeAndRealm("Basic", realm)
});
}
}
Hope this helps others, please let me know if i have done something horrific!

How to create custom iPrincipal in MVC 4, WinAPI

I'm experiencing a situation that I have find nowhere in other articles. I'm designing a RESTful server to be consumed by an mobile app. In this case, username and password are part of header in app call, there is no logon screen.
The following code does the job of validating user info and the controllers has security controlled.
My question is: how can I populate iPrincipal in the ApiController controllers?
I have created a filter addressed at WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Filtro de login
config.Filters.Add(new tbAuthorize());
The code for tbAuthorize is:
public class tbAuthorize : AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (!isUserAuthorized(username, password))
return false;
else
{
//Users = username;
return true;
}
}
else
return false;
}
private bool GetUserNameAndPassword(HttpActionContext actionContext, out string username, out string password)
{
username = "";
password = "";
if (actionContext.Request.Headers.Authorization == null) return false;
// Convert 64 code to separated string[]
string[] s = ParseAuthHeader(actionContext.Request.Headers.Authorization.ToString());
if (s == null)
return false;
username = s[0];
password = s[1];
return true;
}
private string[] ParseAuthHeader(string authHeader)
{
// Check this is a Basic Auth header
if (authHeader == null || authHeader.Length == 0 || !authHeader.StartsWith("Basic")) return null;
// Pull out the Credentials with are seperated by ':' and Base64 encoded
string base64Credentials = authHeader.Substring(6);
string[] credentials = Encoding.ASCII.GetString(Convert.FromBase64String(base64Credentials)).Split(new char[] { ':' });
if (credentials.Length != 2 || string.IsNullOrEmpty(credentials[0]) || string.IsNullOrEmpty(credentials[0])) return null;
// Okay this is the credentials
return credentials;
}
private bool isUserAuthorized(string username, string password)
{
// Valid the user at database
var userId = new UsersController().Login(username, password);
// Membership.GetUser() is null
//Users = Membership.GetUser().Email;
return userId != 0;
}
}
The issue is that I have no access to a cookie in Response and I did not find to way to populate iPrincipal.
I need to has data in this.User.Identity.Name, as this:
[tbAuthorize]
public class UsersController : ApiController
{
public void test()
{
string x = this.User.Identity.Name;
}
Thanks for any help,
Marco Castro
Authentication and Authorization are two differents things. Before authorizing a user you have to authenticate their.
With WebApi you have the concept of pipeline with Delegatinghandler. Message goes from one handler to the next until one send the response. I recommend you to create a DelegatingHandler to authentificate users. Then you can use AuthorizeAttribute to prevent unauthenticated user to access your API.
Here's an example to authenticate user with HTTP Basic
public abstract class BasicAuthMessageHandler : DelegatingHandler
{
private const string BasicAuthResponseHeader = "WWW-Authenticate";
private const string BasicAuthResponseHeaderValue = "Basic Realm=\"{0}\"";
protected BasicAuthMessageHandler()
{
}
protected BasicAuthMessageHandler(HttpConfiguration httpConfiguration)
{
InnerHandler = new HttpControllerDispatcher(httpConfiguration);
}
protected virtual string GetRealm(HttpRequestMessage message)
{
return message.RequestUri.Host;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Process request
AuthenticationHeaderValue authValue = request.Headers.Authorization;
if (authValue != null && !String.IsNullOrWhiteSpace(authValue.Parameter) &&
string.Equals(authValue.Scheme, "basic", StringComparison.OrdinalIgnoreCase))
{
// Try to authenticate user
IPrincipal principal = ValidateHeader(authValue.Parameter);
if (principal != null)
{
request.GetRequestContext().Principal = principal;
}
}
return base.SendAsync(request, cancellationToken) // Send message to the InnerHandler
.ContinueWith(task =>
{
// Process response
var response = task.Result;
if (response.StatusCode == HttpStatusCode.Unauthorized &&
!response.Headers.Contains(BasicAuthResponseHeader))
{
response.Headers.Add(BasicAuthResponseHeader,
string.Format(BasicAuthResponseHeaderValue, GetRealm(request)));
}
return response;
}, cancellationToken);
}
private IPrincipal ValidateHeader(string authHeader)
{
// Decode the authentication header & split it
var fromBase64String = Convert.FromBase64String(authHeader);
var lp = Encoding.Default.GetString(fromBase64String);
if (string.IsNullOrWhiteSpace(lp))
return null;
string login;
string password;
int pos = lp.IndexOf(':');
if (pos < 0)
{
login = lp;
password = string.Empty;
}
else
{
login = lp.Substring(0, pos).Trim();
password = lp.Substring(pos + 1).Trim();
}
return ValidateUser(login, password);
}
protected abstract IPrincipal ValidateUser(string userName, string password);
}
Write you own user validation logic. For example:
public class SampleBasicAuthMessageHandler : BasicAuthMessageHandler
{
protected override IPrincipal ValidateUser(string userName, string password)
{
if (string.Equals(userName, "Meziantou", StringComparison.OrdinalIgnoreCase) && password == "123456")
return new GenericPrincipal(new GenericIdentity(userName, "Basic"), new string[0]);
return null;
}
}
Finally you have to register the Handler
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.MessageHandlers.Add(new SampleBasicAuthMessageHandler());
You'll find a complete example on Github: https://github.com/meziantou/Samples/tree/master/Web%20Api%20-%20Basic%20Authentication

Resources