tomcat or apache automatically encodes redirect url - apache

I have a simple redirect in my Spring controller as follow:
if (url != null) {
String username = request.getParameter("j_username");
if(username != null) {
username = URLEncoder.encode(username, "UTF-8");
}
url = url + (url.contains("?")? "&":"?") + "j_username=" + username;
getRedirectStrategy().sendRedirect(request, response, url);
}
The username should be prepopulated in the next form. This works fine in my local jetty and dev(Tomcat) environment (username shows up as "abc#mysite.com" correctly). But when it gets to QA which is on apache/tomcat, the username gets double encoded, it shows "j_username=abc%2540mysite.com" on the browser address bar and it shows as "abc%40mysite.com" on the form. Never seen this problem before. Any pointers? thanks.

Try using org.springframework.web.util.UriUtils.encodeQueryParam(String, String) for encoding query parameter, URLEncoder is just too generic and does not know the context you're in.

Related

Get Sitefinitys Generated Password Reset URL

I am trying to get the URL from the password reset which I receive via email of the sitefinity frontend login.
I need to send the URL with the username which is enterd in the form to a server to send the email.
I already tried to override the SendResetPasswordEmail of the LoginFormModel but that only gives me the URL where the reset is located at. (localhost/login/resetpassword)
It looks like the URL is generated in the method SendRecoveryPasswordMail of the Telerik.Sitefinity.Security.UserManager which is not overridable.
Is there a way to get the generated recovery URL to use it in a custom method?
Thanks in advance
Since you already have the URL of the reset password page, I guess your issue is getting the proper query string to pass to that page.
Looking at the source code with JustDecompile, the query string is made up of this:
?vk=userValidationKeyEncoded&cp=pr
The cp=pr seems to be hardcoded, so we leave it as is, the question is how the userValidationKeyEncoded is made.
Again, looking in the code, it is this line:
string userValidationKeyEncoded = UserManager.GetUserValidationKeyEncoded(userByEmail);
And finally:
private static string GetUserValidationKeyEncoded(User user)
{
object[] providerName = new object[] { user.ProviderName, ',', user.Id, ',', DateTime.UtcNow };
string str = string.Format("{0}{1}{2}{3}{4}", providerName);
return SecurityManager.EncryptData(str).UrlEncode();
}
You can use the above code to manually generate the validationKey.

Google authentication Redirect_uri_missmatch error

I have checked all possible solution by other people and applied in my setting of app or in code but nothing is working for me.
Here is the parameter that I had passed to the baseUrl https://accounts.google.com/o/oauth2/auth
scope:https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile
client_id:xxxxxxxx.apps.googleusercontent.com
redirect_uri:http://localhost:8228/Auth/ExternalLoginCallback?__provider__=Google&__sid__=xxxxxxxxxxxxxxxxxxxx
state:xxxxxxxxxxxxxxxxxxxx
response_type:code
access_type:online
What i am missing? Please anyone suggest me something.
I got following error every time:
This is my App information:
Update 1:
Here is my code for RequestAuthentication method class for google:
public GoogleScopedClient(string cleintId, string clientSecretId)
{
this.cleintId = cleintId;
this.clientSecretId = clientSecretId;
}
public string ProviderName
{
get { return "Google"; }
}
public void RequestAuthentication(System.Web.HttpContextBase context, Uri returnUrl)
{
string state = Regex.Match(returnUrl.AbsoluteUri, "(?<=__sid__=).*?($|&)", RegexOptions.IgnoreCase).Value;
string url = baseUrl + HttpUtility.UrlEncode(SCOPE.ToString()) +
"&client_id=" + cleintId + "&redirect_uri=" +HttpUtility.UrlEncode(returnUrl.ToString())
+"&response_type=code&access_type=online";
context.Response.Redirect(url);
}
Your redirect URI doesn't match. Specifically, what you've specified in Google Developer Console is http://localhost:8228/Auth/ExternalLoginCallback/, but what's being sent is http://localhost:8228/Auth/ExternalLoginCallback (without the trailing slash). Those are actually two entirely different URLs, even though, they usually go to the same place.

ETrade API unattended authentication

Background
The ETrade authentication system has me creating a RequestToken, then executing an Authorization URL, which opens an ETrade page.
The user logs in to authorize the activity on their account.
They receive a pin, which they enter in my app.
I call ExchangeRequestTokenForAccessToken with the RequestToken and the Pin.
Then we are off and running.
Question
The problem is I'm creating a service that runs continuously in the background. There won't be any user to log in. Conversely, I won't be making any trades. Just crunching numbers, looking for stocks that meet certain criteria.
I can't figure how to get this to work unattended.
Thanks, Brad.
Previously, I have used a series of WebRequests and manually added headers to simulate the authorization pages. This worked until about a year ago when ETrade complicated their headers with something that appears to be tracking information. I now use http://watin.org/ to log in, and to strip the Auth Code.
Sloppy code looks like this:
using WatiN.Core; // IE Automation
...
// verify current thread in STA.
Settings.Instance.MakeNewIeInstanceVisible = false;
var ieStaticInstanceHelper = new IEStaticInstanceHelper();
Settings.AutoStartDialogWatcher = false;
using (ieStaticInstanceHelper.IE = new IE())
{
string authCode = "";
ieStaticInstanceHelper.IE.GoTo(GetAuthorizationLink());
if (ieStaticInstanceHelper.IE.ContainsText("Scheduled System Maintenance"))
{
throw new ApplicationException("eTrade down for maintenance.");
}
TextField user = ieStaticInstanceHelper.IE.TextField(Find.ByName("USER"));
TextField pass = ieStaticInstanceHelper.IE.TextField(Find.ById("txtPassword"));
TextField pass2 = ieStaticInstanceHelper.IE.TextField(Find.ByName("PASSWORD"));
Button btn = ieStaticInstanceHelper.IE.Button(Find.ByClass("log-on-btn"));
Button btnAccept = ieStaticInstanceHelper.IE.Button(Find.ByValue("Accept"));
TextField authCodeBox = ieStaticInstanceHelper.IE.TextField(Find.First());
if (user != null && pass != null && btn != null &&
user.Exists && pass2.Exists && btn.Exists)
{
user.Value = username;
pass2.Value = password;
btn.Click();
}
btnAccept.WaitUntilExists(30);
btnAccept.Click();
authCodeBox.WaitUntilExists(30);
authCode = authCodeBox.Value;
SavePin(authCode);
}
Current version of Brad Melton's code.
WatiN has changed and no longer contains the IE.AttachToIE function.
So, IEStaticInstanceHelper is now called StaticBrowserInstanceHelper, but that code is hard to find, so I've included it here.
class StaticBrowserInstanceHelper<T> where T : Browser {
private Browser _browser;
private int _browserThread;
private string _browserHwnd;
public Browser Browser {
get {
int currentThreadId = GetCurrentThreadId();
if (currentThreadId != _browserThread) {
_browser = Browser.AttachTo<T>(Find.By("hwnd", _browserHwnd));
_browserThread = currentThreadId;
}
return _browser;
}
set {
_browser = value;
_browserHwnd = _browser.hWnd.ToString();
_browserThread = GetCurrentThreadId();
}
}
private int GetCurrentThreadId() {
return Thread.CurrentThread.GetHashCode();
}
}
ETrade's login pages have changed as well. They have several. All the login pages I checked consistently had a USER field and a PASSWORD field, but the login buttons had various names that look fragile. So if this doesn't work, that's the first thing I'd check.
Second, if I go directly to the auth page, it prompts to log in, but then it frequently doesn't take you to the auth page.
I got more consistent results by going to the home page to log in, then going to the auth page.
static public string GetPin(string username, string password, string logonLink, string authLink) {
// Settings.Instance.MakeNewIeInstanceVisible = false;
var StaticInstanceHelper = new StaticBrowserInstanceHelper<IE>();
Settings.AutoStartDialogWatcher = false;
// This code doesn't always handle it well when IE is already running, but it won't be in my case. You may need to attach to existing, depending on your context.
using (StaticInstanceHelper.Browser = new IE(logonLink)) {
string authCode = "";
// Browser reference was failing because IE hadn't started up yet.
// I'm in the background, so I don't care how long it takes.
// You may want to do a WaitFor to make it snappier.
Thread.Sleep(5000);
if (StaticInstanceHelper.Browser.ContainsText("Scheduled System Maintenance")) {
throw new ApplicationException("eTrade down for maintenance.");
}
TextField user = StaticInstanceHelper.Browser.TextField(Find.ByName("USER"));
TextField pass2 = StaticInstanceHelper.Browser.TextField(Find.ByName("PASSWORD"));
// Class names of the Logon and Logoff buttons vary by page, so I find by text. Seems likely to be more stable.
Button btnLogOn = StaticInstanceHelper.Browser.Button(Find.ByText("Log On"));
Element btnLogOff = StaticInstanceHelper.Browser.Element(Find.ByText("Log Off"));
Button btnAccept = StaticInstanceHelper.Browser.Button(Find.ByValue("Accept"));
TextField authCodeBox = StaticInstanceHelper.Browser.TextField(Find.First());
if (user != null && btnLogOn != null &&
user.Exists && pass2.Exists && btnLogOn.Exists) {
user.Value = username;
pass2.Value = password;
btnLogOn.Click();
}
Thread.Sleep(1000);
if (StaticInstanceHelper.Browser.ContainsText("Scheduled System Maintenance")) {
Element btnContinue = StaticInstanceHelper.Browser.Element(Find.ByName("continueButton"));
if (btnContinue.Exists)
btnContinue.Click();
}
btnLogOff.WaitUntilExists(30);
// Here we go, finally.
StaticInstanceHelper.Browser.GoTo(authLink);
btnAccept.WaitUntilExists(30);
btnAccept.Click();
authCodeBox.WaitUntilExists(30);
authCode = authCodeBox.Value;
StaticInstanceHelper.Browser.Close();
return authCode;
}
}
Being able to automate it like this means that I no longer care about how long the token is valid. Thanks BradM!
This was amazingly helpful. I used your code plus what was posted here to automate this (because tokens expire daily): E*Trade API frequently returns HTTP 401 Unauthorized when fetching an access token but not always
I made two edits:
Changed the authorize URL to what was posted here: https://seansoper.com/blog/connecting_etrade.html
For the log on button, changed it to search by ID: Button btnLogOn = StaticInstanceHelper.Browser.Button(Find.ById("logon_button"));
I ran into issues with Watin and setting up the Apartmentstate. So did this:
static void Main(string[] args)
{
System.Threading.Thread th = new Thread(new ThreadStart(TestAuth));
th.SetApartmentState(ApartmentState.STA);
th.Start();
th.Join();
}
Then put the code in the TestAuth method.

Redirect to previous URL after login using Revel

I have a golang web application made with revel framework. I am facing issue in redirecting to the previous page after login. I have few pages where users should login to view the content. I have successfully redirected to login page if the users is not logged in. Here is my code snippet below:
func checkUser(c *revel.Controller) revel.Result {
if _, ok := c.Session["user"]; ok {
return nil
}
var cont = c.Request.RequestURI
fmt.Printf("Requesting URL : ", cont)
return c.Redirect(LoginApp.Login, cont)
}
func init() {
revel.InterceptFunc(checkUser, revel.BEFORE, &App{})
}
And here is my app.go
type App struct {
*revel.Controller
}
func (c App) Application() revel.Result {
var app = make(map[string]string)
app["appTitle"] = "Hourglass"
app["ngApp"] = "app"
app["theme"] = "dark"
app["ngController"] = "ApplicationController"
return c.Render(app)
}
func (c App) Test() revel.Result {
var app = make(map[string]string)
app["appTitle"] = "Hourglass"
app["ngApp"] = "app"
app["theme"] = "dark"
app["ngController"] = "ApplicationController"
return c.Render(app)
}
Now I have a login.go file which contains a ServiceLogin method
func (c LoginApp) ServiceLogin(user models.User) revel.Result {
username := user.UserName
password := user.Password
fmt.Printf("", username)
fmt.Printf("", password)
sess := service.GetSession()
usercoll := sess.DB("hourglass_dev").C("user")
var result models.User
var err = usercoll.Find(bson.M{"UserName": username, "Password": password}).One(&result)
fmt.Printf("", result)
fmt.Printf("", c.Request.RequestURI)
if err != nil {
fmt.Printf("", err)
}
//var app := make(map[string]string)
//return c.Render(app)
c.Session["user"] = username
return c.Redirect(App.Application)
}
Now in the last line of the method I have to hard coded the App.Application instead of which I want the requesting URL to be used so that when the user logged in successfully it automatically redirects to the page they are requesting for.
There are a few things you can do:
You could use the referer field of the header in the request and redirect back there. I don't know how reliable the referer field is so I don't think I would use this technique myself, but it's easy, so depending on your use-case, it might be good enough. In revel, you would access the referer with something like this:
c.Request.Header["referer"].Get()
You could store the original link you want to redirect to in the database, and associate that link with the session id you are already using. Revel does not come with a database, but it does come with an in-memory cache that might work.
You could store the link in a cookie on the client. I never do this, so I'm not really sure what you need to think about with this, but I believe it would work.
You could communicate the link to each URL in the process via request parameters. There's a few things to keep in mind with this technique including security, url escaping and so on, but this technique has some advantages, such as not requiring database access. Your URLs would look something like this:
http://www.example.com/loginurl?redirecturl=[someurl]

Using ViewData to send requested URL to View for hyperlink, URL truncates parameter

I'm using a filter that checks the user's browser/version upon arrival to the site. If they use an unsupported browser, I save the URL they intended to reach into a ViewData called "RequestedURL" and redirect to a view telling them their browser is old. This view gives the user the ability to proceed by clicking a link. The URL of this link is being populated by the ViewData attribute of "RequestedUrl" that was set in the filter.
Filter:
/// <summary>
/// If the user has a browser we don't support, this will present them with a page that tells them they have an old browser. This check is done only when they first visit the site. A cookie also prevents unnecessary future checks, so this won't slow the app down.
/// </summary>
public class WarnAboutUnsupportedBrowserAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext.Request;
//this will be true when it's their first visit to the site (will happen again if they clear cookies)
if (request.UrlReferrer == null && request.Cookies["browserChecked"] == null)
{
//give old IE users a warning the first time
if ((request.Browser.Browser.Trim().ToUpperInvariant().Equals("IE") && request.Browser.MajorVersion <= 7) ||
(request.Browser.Browser.Trim().ToUpperInvariant().Equals("Chrome") && request.Browser.MajorVersion <= 22) ||
(request.Browser.Browser.Trim().ToUpperInvariant().Equals("Mozilla") && request.Browser.MajorVersion <= 16) ||
(request.Browser.Browser.Trim().ToUpperInvariant().Equals("Safari") && request.Browser.MajorVersion <= 4))
{
filterContext.Controller.ViewData["RequestedUrl"] = request.Url.ToString();
filterContext.Result = new ViewResult { ViewName = "UnsupportedBrowserWarning" };
}
filterContext.HttpContext.Response.AppendCookie(new HttpCookie("browserChecked", "true"));
}
}
}
View reference to the ViewData:
Thanks for letting me know.
Most Urls work fine. The problem comes when the user enters a URL that has a parameter in it. For example:
[WarnAboutUnsupportedBrowser]
public ActionResult Index(string providerkey)
If the Url the user entered is "../Controller/Foo/providerkey", the Url that populates in the view is "Controller/Foo" with the missing parameter that is required to access the page.
How can I make sure that the URL in the view is the entire URL the user originally entered?