Error HTTP 404.11 passing account activation Token by querystring - asp.net

I'm trying to implement password reset funcionallity. I use the ASP.NET Identity.
I am using the UserManager.GetConfirmationToken that returns a token like this:
UW/cj4xUj08kiGCntnWs7z1eUcWlyfNczH5IZfvf0ScTi4L1jgdkkus/Zb5ROJOWb%2b1XAVRSiBUvVGnESfEyauDDa4u%2bPDUH6D/CIpwPcFYRvLi%2b%2bq6f%2bRIhKHRTsGMV0y8lXpSZ5VqySWGSSaW9kofGage/IjW4HrvONeEtA4Szov3u7HgmqEUf0yzgivJ0
Then, I compose my URL and I send it by Email to the registered user. The url to activate the account is like this:
http://localhost:4322/Account/Confirm/UW/cj4xUj08kiGCntnWs7z1eUcWlyfNczH5IZfvf0ScTi4L1jgdkkus/Zb5ROJOWb%2b1XAVRSiBUvVGnESfEyauDDa4u%2bPDUH6D/CIpwPcFYRvLi%2b%2bq6f%2bRIhKHRTsGMV0y8lXpSZ5VqySWGSSaW9kofGage/IjW4HrvONeEtA4Szov3u7HgmqEUf0yzgivJ0
When I click, this error occurs:
Error HTTP 404.11 - Double escape sequence issue

The underlying problem here is trying to add confirmation code to the path. Whereas it should be sent via querystring.
So it should be like this
http://localhost:4322/Account/Confirm?code=UW/cj4xUj08kiGCntnWs7z1eUcWlyfNczH5IZfvf0ScTi4L1jgdkkus/Zb5ROJOWb%2b1XAVRSiBUvVGnESfEyauDDa4u%2bPDUH6D/CIpwPcFYRvLi%2b%2bq6f%2bRIhKHRTsGMV0y8lXpSZ5VqySWGSSaW9kofGage/IjW4HrvONeEtA4Szov3u7HgmqEUf0yzgivJ0
This will save day whose tries to solve this problem.
I found the answer at this comment : http://blogs.msdn.com/b/webdev/archive/2014/03/20/test-announcing-rtm-of-asp-net-identity-2-0-0.aspx?PageIndex=1#comments Thanks to pranav rostgi

You may need to encode URL using httputility.urlencode

Your token contains / symbols wich are being parsed as a path to some server page. You can either encode it somehow (maybe base64) and use as query string parameter like ...?token=.... Or change token generations so it will contain only good symbols

Make sure you aren't double encoding the token, so you can do something like this to send the email:
string code = await UserManager.GetConfirmationToken(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking this link: link");

Related

Unity-Firebase urls to signin or signup give error with restClient

Im learning Firebase with Unity and using the RestClient and while it worked well with just reading and writing to the database, in the authentication part Im stuck, I have only tested the signup part so far but it gives me error http unknown, I got the url from the reference docs in firebase site, here is the function that throws the error in case it helps but I assume I got the url wrong or something, Im open to any solution you give, thanks =) :
void signUpUser(string nombreusuario,string email, string password)
{
string datosusuario="{\"email\":\""+email+"\",\"password\":\""+password+"\",\"returnSecureToken\":true}";
RestClient.Post<signresponse>("https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=" + AuthKey, datosusuario).Then( ResponseHelper=>
{
localId = ResponseHelper.localId;
idToken = ResponseHelper.idToken;
nombre = nombreusuario;
enviaBaseDatos(true);
}).Catch(error=>
{
Debug.Log(error);
});
}
So I've been digging and I think that documentation is partially wrong as it says that the endpoint is
https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=[API_KEY]
But It also says
You can create a new email and password user by issuing an
HTTP POST request to the Auth signupNewUser endpoint.
So the real endpoint is signUpNewUser instead of simply signUp!
https://identitytoolkit.googleapis.com/v1/accounts: signUpNewUser?key=[API_KEY]
If this new endpoint does not work, try the version 3 of the endpoint:
https://www.googleapis.com/identitytoolkit/v3/relyingparty/signUpNewUser?key=[API_KEY]

ASP.Net Identity reset password with website and web api

We have 2 separate ways for people to perform a forgot password:
1. Via the website - mywebsite.com/account/forgotpassword
2. Via our App - Clicking the "Forgot Password" passes the users email address to our asp.net web api which in turn creates the code and sends the email.
Clicking the link in the email brings up the correct page where we can enter the email and new password. When resetting the password using option 1, it works fine. Using option 2 gives an invalid token error. Both the website and web api are on the same server.
Here's the Web api code:
var user = await UserManager.FindByEmailAsync(email);
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = $"/Account/ResetPassword?userId={user.Id}&code={code}";
var path = System.Web.Hosting.HostingEnvironment.MapPath("~/Content/emails/ResetPassword.html");
var body = GenerateEmailBody(user);
await UserManager.SendEmailAsync(user.Id, "Reset Password", body);
Here's the website code
var user = await UserManager.FindByEmailAsync(model.Email);
if (user == null)// || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
var body = GenerateEmailBody(user);
await UserManager.SendEmailAsync(user.Id, "Reset Password", body);
I verified that the UserTokenProvider is the same in both as well.
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("IdentityStuff"));
I read that MachineKey can cause this issue except we're only using a single server.
An additional piece of info that is worth mentioning is when the website was created, it didn't have identity added to it. This was an after thought. The web api started off with identity.
For clarity purposes I thought I would answer my question.
Instead of have the reset logic in both the website and api, I have both the website and our app call the api to reset the password.
I did, however run into an additional problem when using a load balancer. Since one server may create the code for the reset and another may respond to the link, we run into the same issue.
To fix this problem, I have a DNS entry that always points to a single server which is used to create the code as well as actually reset the password. This eliminates the issue of getting an invalid token.
HTH.

Mailgun - POST body is not interpreted as url-encoded

I'm trying to send emails through mailgun email service. I'm using angular 2. This is what my service looks like:
sendEmail(fromName, fromEmail, message) {
var headers = new Headers();
var recieverMail = "abc#123.se";//service#csc.kth.se"
var subject = "error report submitted by interactive screen"
headers.append("Authorization", "Basic "+btoa("MY_API_KEY"));
headers.append("content-type", "application/x-www-form-urlencoded");
var url = "https://api.mailgun.net/v3/mymailgun.mailgun.org/messages";
var data = "from="+fromName+"&to=" +recieverMail+"&subject="+subject+"&text="+message;
return this.http.post(url,data, {headers: headers});
}
I got two different programs that is using this service and they both passes the service strings but the service only fails for one of them.
Applcation 1 recieves an error message saying that the "from" parameter is missing and it is because the mail data is not interpreted as url-encoded for some reason. It is just interpreted as plain text!
Application 2 successfully sends messages with the same service and input. As you can see, this time the mail data is interpreted as url-encoded and the mailgun API recognizes the mail parameters.
Any suggestions on what might be causing this problem for application 1?
(I know that the data is not 100% identical from the screenshot but the problem that i want to illustrate is that they interpret the mail data differently)

What is the parameter name for basic authentication in meteor's http.post API?

I'm using HTTP.post in meteor and I need to send basic authentication with only a username to an external service. Where does this go and what would that look like?
I am only using it on the server side so I know it should look like the below code, but I'm not sure where to put the username and what to call it.
I've tried this.
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"processor_uri": "/customers/customerURI"},
authentication: {"MYKEYHERE":""}
});
And this.
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"authentication": "MYKEYHERE",
"processor_uri": "/customers/customerURI"}
});
And this.
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"processor_uri": "/customers/customerURI"
},
headers: {'Authorization': 'MYKEYHERE'}
});
I get this error each time.
Error: failed [403] 403 Forbidden Access was denied to this resource.
Unauthorized: CustomerIndexView failed permission check
The plain auth : 'username:password' should do (from docs):
var resultSet = HTTP.post("https://billy.balancedpayments.com/v1/customers", {
params: {"processor_uri": "/customers/customerURI"},
auth: 'yourkey:'
});
As per the balanced payments documentation:
To authenticate with Balanced, you will need the API key secret provided from the dashboard. You have to use http basic access authentication. Your key has to be set as the username. A password is not required for simplicity.
So this means you leave the password blank, so its just your key followed by the colon :
Also you might want to consider using the balanced package for Meteor which does all the boilerplate for you.

ASP.Net Web API - Authorization header blank

I am having to re-write an existing REST API using .NET (originally written with Ruby). From the client's perspective, it has to work exactly the same way as the old API - i.e. the client code mustn't need to change. The current API requires Basic Authentication. So to call the old API, the following works perfectly:-
var wc = new System.Net.WebClient();
var myCache = new CredentialCache();
myCache.Add(new Uri(url), "Basic", new NetworkCredential("XXX", "XXX"));
wc.Credentials = myCache;
var returnBytes = wc.DownloadData("http://xxxx");
(I have had to ommit the real URL / username / password etc for security reasons).
Now I am writing the new API using ASP.Net Web API with MVC4. I have a weird problem and cannot find anybody else with exactly the same problem. In order to support Basic Authentication, I have followed the guidelines here:
http://sixgun.wordpress.com/2012/02/29/asp-net-web-api-basic-authentication/
One thing, I put the code to "hook in the handler" in the Global.asax.cs file in the Application_Start() event (that wasn't explained so I guessed).
Anyway, if I call my API (which I have deployed in IIS) using the above code, the Authorization header is always null, and the above fails with 401 Unauthorized. However, if I manually set the header using this code, it works fine - i.e. the Authorization header now exists and I am able to Authenticate the user.
private void SetBasicAuthHeader(WebClient request, String userName, String userPassword)
{
string authInfo = userName + ":" + userPassword;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
}
.......
var wc = new System.Net.WebClient();
SetBasicAuthHeader(request, "XXXX", "XXXX");
var returnBytes = wc.DownloadData("http://xxxx");
Although that works, it's no good to me because existing users of the existing API are not going to be manually setting the header.
Reading up on how Basic Authentication works, the initial request is meant to be anonymous, then the client is returned 401, then the client is meant to try again. However if I put a break point in my code, it will never hit the code again in Antony's example. I was expecting my breakpoint to be hit twice.
Any ideas how I can get this to work?
You're expecting the right behavior. System.Net.WebClient does not automatically include the Authorization headers upon initial request. It only sends them when properly challenged by a response, which to my knowledge is a 401 status code and a proper WWW-Authenticate header. See here and here for further info.
I'm assuming your basic authentication handler is not returning the WWW-Authenticate header and as such WebClient never even attempts to send the credentials on a second request. You should be able to watch this in Fiddler or a similar tool.
If your handler did something like this, you should witness the WebClient approach working:
//if is not authenticated or Authorization header is null
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
response.StatusCode = HttpStatusCode.Unauthorized;
response.Headers.Add("WWW-Authenticate", "Basic realm=\"www.whatever.com\"");
return response;
});
//else (is authenticated)
return base.SendAsync(request, cancellationToken);
As you noticed, if you include the Authorization headers on every request (like you did in your alternative approach) then your handler already works as is. So it may be sufficient - it just isn't for WebClient and other clients that operate in the same way.

Resources