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

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.

Related

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!

Authentication in webAPI

I want to set Individual authentication for the web API application i have created in Visual studio 2013 using Asp.net . please tell me how can i do that .
VS 2013 by default provide several types of authentication while designing . i choose individual Authentication . But don't know how it works .
Create authentication token on server-side and store it in your database or even in cache. Then send this token with requests from your win forms application. WebApi should check this token all the time. It's good enough and you have full control over your auth process.
Basically it's similar to Darin's answer.
Let me share, how it works for me:
Object with Auth details:
public class TokenIdentity
{
public int UserID { get; set; }
public string AuthToken { get; set; }
public ISocialUser SocialUser { get; set; }
}
Web API Auth Controller:
public class AuthController : ApiController
{
public TokenIdentity Post(
SocialNetwork socialNetwork,
string socialUserID,
[FromUri]string socialAuthToken,
[FromUri]string deviceRegistrationID = null,
[FromUri]DeviceType? deviceType = null)
{
var socialManager = new SocialManager();
var user = socialManager.GetSocialUser(socialNetwork, socialUserID, socialAuthToken);
var tokenIdentity = new AuthCacheManager()
.Authenticate(
user,
deviceType,
deviceRegistrationID);
return tokenIdentity;
}
}
Auth Cache Manager:
public class AuthCacheManager : AuthManager
{
public override TokenIdentity CurrentUser
{
get
{
var authToken = HttpContext.Current.Request.Headers["AuthToken"];
if (authToken == null) return null;
if (HttpRuntime.Cache[authToken] != null)
{
return (TokenIdentity) HttpRuntime.Cache.Get(authToken);
}
return base.CurrentUser;
}
}
public int? CurrentUserID
{
get
{
if (CurrentUser != null)
{
return CurrentUser.UserID;
}
return null;
}
}
public override TokenIdentity Authenticate(
ISocialUser socialUser,
DeviceType? deviceType = null,
string deviceRegistrationID = null)
{
if (socialUser == null) throw new ArgumentNullException("socialUser");
var identity = base.Authenticate(socialUser, deviceType, deviceRegistrationID);
HttpRuntime.Cache.Add(
identity.AuthToken,
identity,
null,
DateTime.Now.AddDays(7),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null);
return identity;
}
}
Auth Manager:
public abstract class AuthManager
{
public virtual TokenIdentity CurrentUser
{
get
{
var authToken = HttpContext.Current.Request.Headers["AuthToken"];
if (authToken == null) return null;
using (var usersRepo = new UsersRepository())
{
var user = usersRepo.GetUserByToken(authToken);
if (user == null) return null;
return new TokenIdentity
{
AuthToken = user.AuthToken,
SocialUser = user,
UserID = user.ID
};
}
}
}
public virtual TokenIdentity Authenticate(
ISocialUser socialUser,
DeviceType? deviceType = null,
string deviceRegistrationID = null)
{
using (var usersRepo = new UsersRepository())
{
var user = usersRepo.GetUserBySocialID(socialUser.SocialUserID, socialUser.SocialNetwork);
user = (user ?? new User()).CopyFrom(socialUser);
user.AuthToken = System.Guid.NewGuid().ToString();
if (user.ID == default(int))
{
usersRepo.Add(user);
}
usersRepo.SaveChanges();
return new TokenIdentity
{
AuthToken = user.AuthToken,
SocialUser = user,
UserID = user.ID
};
}
}
}
Global Action Filter:
public class TokenAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.AbsolutePath.Contains("api/auth"))
{
return;
}
var authManager = new AuthCacheManager();
var user = authManager.CurrentUser;
if (user == null)
{
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
//Updates the authentication
authManager.Authenticate(user.SocialUser);
}
}
Global.asax registration:
GlobalConfiguration.Configuration.Filters.Add(new AuthFilterAttribute());
The idea is that AuthCacheManager extends AuthManager and decorates it's methods and properties. If there is nothing inside cache then go check database.
It is a little complicated! By default it is a Token-Based authenctication. Check these links for more details :
Individual Accounts in ASP.NET Web API: http://www.asp.net/vnext/overview/authentication/individual-accounts-in-aspnet-web-api
Understanding OWIN Forms authentication options : http://blogs.msdn.com/b/webdev/archive/2013/07/03/understanding-owin-forms-authentication-in-mvc-5.aspx#_Understanding_OWIN_Forms
also these links will help :
10 Things You Should Know about Tokens: http://blog.auth0.com/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies
Cookies vs Tokens. : http://blog.auth0.com/2014/01/07/angularjs-authentication-with-cookies-vs-token/

What is the correct way of find out if user is logged in in MVC WEB API?

I am very confused about this problem. Restfull service make it up to you to decide which way to implement this functionallity.
Ive read multiple articles about this problem, but every article says something different.
For example some people propopse sessions, but if you do that Web api is losing its "rest fullness". Other people suggest cockies.
I dont know if what i am done is actually done right:
On login of user i create a cockie which contains UserID(Guid) and on every request which needs user to be logged in i check if this id exsists in the DB.
Is it secure enough? Or how should i make it more secure? Or do i have to choose completly different way?
Just create authentication token on server-side and store it in your database or even in cache. Then send this token with requests from your client application. WebApi should check this token all the time. It's good enough and you have full control over your auth process.
Let me share, how it works for me:
Object with Auth details:
public class TokenIdentity
{
public int UserID { get; set; }
public string AuthToken { get; set; }
public ISocialUser SocialUser { get; set; }
}
Web API Auth Controller:
public class AuthController : ApiController
{
public TokenIdentity Post(
SocialNetwork socialNetwork,
string socialUserID,
[FromUri]string socialAuthToken,
[FromUri]string deviceRegistrationID = null,
[FromUri]DeviceType? deviceType = null)
{
var socialManager = new SocialManager();
var user = socialManager.GetSocialUser(socialNetwork, socialUserID, socialAuthToken);
var tokenIdentity = new AuthCacheManager()
.Authenticate(
user,
deviceType,
deviceRegistrationID);
return tokenIdentity;
}
}
Auth Cache Manager:
public class AuthCacheManager : AuthManager
{
public override TokenIdentity CurrentUser
{
get
{
var authToken = HttpContext.Current.Request.Headers["AuthToken"];
if (authToken == null) return null;
if (HttpRuntime.Cache[authToken] != null)
{
return (TokenIdentity) HttpRuntime.Cache.Get(authToken);
}
return base.CurrentUser;
}
}
public int? CurrentUserID
{
get
{
if (CurrentUser != null)
{
return CurrentUser.UserID;
}
return null;
}
}
public override TokenIdentity Authenticate(
ISocialUser socialUser,
DeviceType? deviceType = null,
string deviceRegistrationID = null)
{
if (socialUser == null) throw new ArgumentNullException("socialUser");
var identity = base.Authenticate(socialUser, deviceType, deviceRegistrationID);
HttpRuntime.Cache.Add(
identity.AuthToken,
identity,
null,
DateTime.Now.AddDays(7),
Cache.NoSlidingExpiration,
CacheItemPriority.Default,
null);
return identity;
}
}
Auth Manager:
public abstract class AuthManager
{
public virtual TokenIdentity CurrentUser
{
get
{
var authToken = HttpContext.Current.Request.Headers["AuthToken"];
if (authToken == null) return null;
using (var usersRepo = new UsersRepository())
{
var user = usersRepo.GetUserByToken(authToken);
if (user == null) return null;
return new TokenIdentity
{
AuthToken = user.AuthToken,
SocialUser = user,
UserID = user.ID
};
}
}
}
public virtual TokenIdentity Authenticate(
ISocialUser socialUser,
DeviceType? deviceType = null,
string deviceRegistrationID = null)
{
using (var usersRepo = new UsersRepository())
{
var user = usersRepo.GetUserBySocialID(socialUser.SocialUserID, socialUser.SocialNetwork);
user = (user ?? new User()).CopyFrom(socialUser);
user.AuthToken = System.Guid.NewGuid().ToString();
if (user.ID == default(int))
{
usersRepo.Add(user);
}
usersRepo.SaveChanges();
return new TokenIdentity
{
AuthToken = user.AuthToken,
SocialUser = user,
UserID = user.ID
};
}
}
}
Global Action Filter:
public class TokenAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.RequestUri.AbsolutePath.Contains("api/auth"))
{
return;
}
var authManager = new AuthCacheManager();
var user = authManager.CurrentUser;
if (user == null)
{
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
//Updates the authentication
authManager.Authenticate(user.SocialUser);
}
}
Global.asax registration:
GlobalConfiguration.Configuration.Filters.Add(new AuthFilterAttribute());
The idea is that AuthCacheManager extends AuthManager and decorates it's methods and properties. If there is nothing inside cache then go check database.
It's an example from real app, but I hope the idea is clear :)

Return error to angular ajax request from MVC web API

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;
}

Resources