Is it possible write a cookie with the current url using Apache - apache

A third party application I am working with normally allows the user to bookmark pages anywhere on the site. Once logged in the user will be redirected to the original page requested. Unfortunately through a commissioned single sign on customization this functionality gets lost. That is to say if you use a bookmark to access a specific page in the product (or get an email or follow an external link), if you are not already signed in you go to a log in page and then get returned to the main application page instead of the page requested.
If I can set a cookie with the original URL requested I can then use that information through JavaScript to change the location upon landing on the home page.
Let's say the home page is /app/index.jsp - If I could get a cookie to remember any URL but this one - I could restore the functionality that the user goes to the requested page after they log in. Is this possible?

I found the solution to this myself...
Using mod_rewrite I could key on the initial request by looking for the JSESSIONID cookie. The folowing when placed within my servers virtualhost section achieved my goal.
RewriteEngine On
RewriteCond %{REQUEST_URI} !^/app/*$
RewriteCond %{REQUEST_URI} !^/content/.*$
RewriteCond %{REQUEST_URI} !^/app/adm/.*$
RewriteCond %{REQUEST_URI} !^/app/index\.jsp$
RewriteCond %{REQUEST_URI} !^/favicon\.ico$
RewriteCond %{HTTP:Cookie} !^.*JSESSIONID=.*$
RewriteRule . - [co=appURI:%{REQUEST_URI}?%{QUERY_STRING}:.mydomain.com]
Note: I added some filters above for pages I did not want to set the cookie for. I use JavaScript to detect, unset the cookie, and redirect within the application to achieve my goal.
var appURI = getCookie("appURI");
if (typeof(appURI) != "undefined" && appURI != null && appURI != "") {
mydomain.console.log("Found URI from SSO relocating to: " + appURI);
setCookie("appURI", "", -1, "/", "mydomain.com");
document.location.href = appURI;
}
Note that "setCookie" and "mydomain.console.log" above are proprietary but simple functions that do the obvious actions based on their names.

Related

Mod_rewrite rules not working in .htaccess to change the URL

I'm trying to rewrite the below URL but the URLs just don't change, no errors.
Current URL:
https://example.com/test/news/?c=value1&s=value2&id=9876
Expected URL:
https://example.com/test/news/value1/value2
My .htaccess
RewriteEngine On
RewriteRule ^test/news/([^/]*)/([^/]*)$ /test/news/?c=$1&s=$2&id=1 [L]
but I've seen many articles where a url such as example.com/display_article.php?articleId=my-article can be rewritten as example.com/articles/my-article for example with .htaccess
But the important point here (that I think you are missing) is that the URL must already have been changed internally in your application - in all your internal links. It is a common misconception that .htaccess alone can be used to change the format of the URL. Whilst .htaccess is an important part of this, it is only part of it.
Yes, you can implement a redirect in .htaccess to redirect from the old to new URL - and this is essential to preserve SEO (see below), but it is not critical to your application working. If you don't first change the URL in your internal links then:
The "old" URL is still exposed in the HTML source. When a user hovers over or copies the link, they are seeing and copying the "old" URL.
Every time a user clicks one of your internal links they are externally redirected to the "new" URL. This is slow for your users, bad for SEO (you should never link to a URL that is redirected) and bad for your server, as it potentially doubles the number of requests hitting your server (OK, 301s are cached locally).
To quote from #IMSoP's answer to this reference question on the subject:
Rewrite rules don't make ugly URLs pretty, they make pretty URLs ugly
So, once you have changed your internal links to the "new" (expected) format, eg. /test/news/value1/value2 (or should that be /test/news/value1/value2/id or even /test/news/id/value1/value2? See below), then you can do as follows...
RewriteRule ^test/news/([^/]*)/([^/]*)$ /test/news/?c=$1&s=$2&id=1 [L]
This internally rewrites a request from /test/news/<value1>/<value2> to /test/news/?c=<value1>&s=<value2>&id=1. However, there are a couple of issues with this:
/test/news/ is not itself a valid endpoint. This requires further rewriting. Perhaps you are serving a DirectoryIndex document (eg. index.php)? This might appear seamless to you, but this requires an additional internal subrequest and makes the rule dependent on other elements of the config. You should rewrite directly to the file that handles the request. eg. /test/news/index.php?c=<value1>&s=<value2>&id=1 (remember, this is entirely hidden from the user).
You are hardcoding the id=1 parameter? Should every URL have the same id? Or should this be passed in the "new" URL (which is what I would expect)? What does the id represent? If this is critical to the routing of the URL then the id should appear earlier in the URL-path, in case the URL gets accidentally truncated when copy/pasted/shared.
If the id is required then it needs to be passed in the "new" URL. We only have the "new" URL to route the request, so the information can't be hidden.
So, if the "new" URL is now /test/news/<id>/<value1>/<value2> then the rewrite would need to be like this instead:
# Rewrite new URLs to old/actual URL
# "/test/news/<id>/<value1>/<value2>" to "/test/news/?c=<value1>&s=<value2>&id=<id>"
RewriteRule ^test/news/(\d+)/([^/]+)/([^/]+)$ /test/news/?c=$2&s=$3&id=$1 [L]
Then (optionally*1) you can implement an external redirect in order to preserve SEO. This is for search engines that have indexed the "old" URLs or third party inbound links that cannot be updated - these need to be corrected to inform search engines of the change and get the user on the "new" canonical URL having followed an out-of-date inbound link.
(*1 It's not "optional" if you are changing an existing URL, but optional with regards to your application being functional.)
This "redirect" goes before the above rewrite:
# Redirect old URLs to the new "canonical" URL
# "/test/news/?c=<value1>&s=<value2>&id=<id>" to "/test/news/<id>/<value1>/<value2>"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^c=([^&]+)&s=([^&]+)&id=(\d+)
RewriteRule ^test/news/$ /$0%3/%1/%2 [QSD,R=301,L]
The $0 backreference contains the full match from the RewriteRule pattern, ie. test/news/ in this case - this simply saves repetition.
The %1, %2 and %3 backreferences contain the values captured from the preceding condition. ie. the values of the c, s and id URL parameters respectively.
Note that the URL parameters / path segments should not be optional as in your original directive (ie. ([^/]*)). If they are optional and they are omitted, then the resulting URL becomes ambiguous. eg. <value2> becomes <value1> if <value1> is omitted.
Note that the URL parameters must be in the order as stated. If you have a mismatch of "old" URLs with these params in a different order (or even intermixed with other params) then this can be accounted for with additional complexity. (It may be easier to perform this redirect in your server-side script, instead of .htaccess.)
The first condition that checks against the REDIRECT_STATUS environment variable ensures that we only redirect direct requests and not rewritten requests by the later rewrite (which would otherwise result in a redirect loop). An alternative on Apache 2.4 is to use the END flag on the RewriteRule instead.
The QSD flag (Apache 2.4) discards the original query string from the request.
You should test first with a 302 (temporary) redirect to avoid potential caching issues and only change to a 301 (permanent) redirect once you have tested that everything works as intended. 301s are cached persistently by the browser so can make testing problematic.
Summary
Your complete .htaccess file should look something like this:
Options -MultiViews +FollowSymLinks
# If relying on the DirectoryIndex to handle the request
DirectoryIndex index.php
RewriteEngine On
# Redirect old URLs to the new "canonical" URL
# "/test/news/?c=<value1>&s=<value2>&id=<id>" to "/test/news/<id>/<value1>/<value2>"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^c=([^&]+)&s=([^&]+)&id=(\d+)
RewriteRule ^test/news/$ /$0%3/%1/%2 [QSD,R=301,L]
# Rewrite new URLs to old/actual URL
# "/test/news/<id>/<value1>/<value2>" to "/test/news/?c=<value1>&s=<value2>&id=<id>"
RewriteRule ^test/news/(\d+)/([^/]+)/([^/]+)$ /test/news/?c=$2&s=$3&id=$1 [L]

POST information getting lost in .htaccess redirect

So, I have a fully working CRUD. The problem is, because of my file structure, my URLs were looking something like https://localhost/myapp/resources/views/add-product.php but that looked too ugly, so after research and another post here, I was able to use a .htaccess file to make the links look like https://localhost/myapp/add-product (removing .php extension and the directories), and I'm also using it to enforce HTTPS. Now, most of the views are working fine, but my Mass Delete view uses POST information from a form on my index. After restructuring the code now that the redirect works, the Mass Delete view is receiving an empty array. If I remove the redirect and use the "ugly URLs" it works fine. Here's how my .htaccess file is looking like:
Options +FollowSymLinks +MultiViews
RewriteEngine On
RewriteBase /myapp/
RewriteRule ^resources/views/(.+)\.php$ $1 [L,NC,R=301]
RewriteCond %{DOCUMENT_ROOT}/myapp/resources/views/$1.php -f
RewriteRule ^(.+?)/?$ resources/views/$1.php [END]
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
I didn't actually write any of it, it's a mesh between answered questions and research. I did try to change the L flag to a P according to this post: Is it possible to redirect post data?, but that gave me the following error:
Internal Server Error
The server encountered an internal error or misconfiguration and was unable to complete your request.
Please contact the server administrator at admin#example.com to inform them of the time this error occurred, and the actions you performed just before this error.
More information about this error may be available in the server error log.
Apache/2.4.52 (Win64) OpenSSL/1.1.1m PHP/8.1.2 Server at localhost Port 443
POST information getting lost in .htaccess redirect
You shouldn't be redirecting the form submission in the first place. Ideally, you should be linking directly to the "pretty" URL in your form action. If you are unable to change the form action in the HTML then include an exception in your .htaccess redirect to exclude this particular URL from being redirected.
Redirecting the form submission is not really helping anyone here. Users and search engines can still see the "ugly" URL (it's in the HTML source) and you are doubling the form submission that hits your server (and doubling the user's bandwidth).
"Redirects" like this are only for when search engines have already indexed the "ugly" URL and/or is linked to by external third parties that you have no control over. This is in order to preserve SEO, just like when you change any URL structure. All internal "ugly" URLs should have already been converted to the "pretty" version. The "ugly" URLs are then never exposed to users or search engines.
So, using a 307 (temporary) or 308 (permanent) status code to get the browser to preserve the request method across the redirect should not be necessary in the first place. For redirects like this it is common to see an exception for POST requests (because the form submission shouldn't be redirected). Or only target GET requests. For example:
RewriteCond %{REQUEST_METHOD} GET
:
Changing this redirect to a 307/8 is a workaround, not a solution. And if this redirect is for SEO (as it only should be) then this should be a 308 (permanent), not a 307 (temporary).
Aside:
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Your HTTP to HTTPS redirect is in the wrong place. This needs to go as the first rule, or make sure you are redirecting to HTTPS in the current first rule and include this as the second rule, before the rewrite (to ensure you never get a double redirect).
By placing this rule last then any HTTP requests to /resources/views/<something>.php (or /<something>) will not be upgraded to HTTPS.

Is is possible for the user to find out the actual redirected path?

I'm using .htaccess for URL redirection as below:
RewriteEngine On
RewriteRule ^x.php$ /y.php
Can the user know some how (even using some advanced tools) that the page was actually served from y.php instead of x.php?
Thanks

.htaccess point specific domain home to internal page

Okay...i am doing something kinda strange and out of the ordinary. I will try to explain...
I have several domain names pointed to the same root directory on my webserver. I can access the entire website using any of the domain names (I know this is bad for SEO, but there are reasons). Additionally, none of the "pages" really exist...as they are all being built dynamically...so i have some mod rewrite rules set up to point all incoming queries to view.php and passing in variables to generate the page content...anyway...
What i want to do is set ONLY THE HOME PAGE of two of my domains to (invisibly) use content of an existing sub page. Here is an example:
These all are the same page:
www.domain1.com/process/
www.domain2.com/process/
www.domain3.com/process/
which is really doing something like: view.php?page=process/
I want this page to display for www.domain2.com (and still also be accessible at domain2.com/process)
Essentially, there is a sub page of the site that i want to serve as the "HOME" page for domain2.com and domain3.com but if domain1.com should still use the default (index.php) HOME page.
I am sure i will need to post clarifications to this once replies start coming in...but here is what i have at the moment:
# special rules to set other domain names default homepage as specific internal page
RewriteCond %{HTTP_HOST} ^www.domain2.com [NC]
RewriteRule ^(.+)?$ /view.php?page=process/ [NC,L]
Currently this is sending ALL traffic to domain2.com to the "process/" page...so it is blocking out all other pages. I need to know how to have this rule ONLY apply to the base domain without any extra query string or url path. The key is that i DO NOT want to affect other pages within the domain...so i shoudl still be able to browse the whole site using this domain name...i just get started on a different view.
To only match the homepage, i.e. http://domain2com/ you need to match the empty path (as mod_Rewrite removes the leading /.
RewriteCond %{HTTP_HOST} ^www.domain2.com [NC]
RewriteRule ^$ /view.php?page=process/ [NC,L]

How to redirect page with query-string to external webpage using APACHE RewriteRule

I am trying to redirect a login page to an external security service. This service, after validating the credentials, will then return user back to the originating page using the referrer url, as in the following example:
http://{IP NUMBER}/MyWiki/index.php?title=Special:UserLogin&returnto=Main_Page
or any call to a page in the site containing Special:UserLogin in the query_string needs to be redirected to:
https://login.security.server.com/test/UI/Login?service=DSSEC&goto=http://{IP NUMBER}/MyWiki/index.php/Special:UserLogin
I have been testing with RewriteCond and RewriteRule without any luck.
You want something like this?
RewriteEngine On
RewriteCond %{REQUEST_URI} Special:UserLogin [OR]
RewriteCond %{QUERY_STRING} Special:UserLogin
RewriteCond ?#%{QUERY_STRING} ([^#]+)#([^#]+)
RewriteRule ^ https://login.security.server.com/test/UI/Login?service=DSSEC&goto=http://%{SERVER_ADDR}%{REQUEST_URI}%1%2 [L,B,NE]
Ok, this is going to seem a little confusing, but here's what's going on.
Check if Special:UserLogin is in the request URI or the query string.
Create backreference matches for the ? mark, the URI and the query string (this is very important)
Redirect the request to https://login.security.server.com/test/UI/Login, but using the back references from the previous condition to build the goto= param, and using the B flag, which URL encodes the backreferences. This way, the result is an entire URL, along with query string, that's been URL encoded. (The NE flag is there to make sure the % signs themselves don't get double encoded).
With these rules, a request for:
/MyWiki/index.php?title=Special:UserLogin&returnto=Main_Page
Will get redirected to:
https://login.security.server.com/test/UI/Login?service=DSSEC&goto=http://123.45.67.89/MyWiki/index.php%3ftitle%3dSpecial%3aUserLogin%26returnto%3dMain_Page
As you can see, the query string ?title=Special:UserLogin&returnto=Main_Page gets encoded into %3ftitle%3dSpecial%3aUserLogin%26returnto%3dMain_Page, so that the login.security.server.com doesn't mistake it for its own query string. Instead, their login service will see the goto parameter as:
http://123.45.67.89/MyWiki/index.php?title=Special:UserLogin&returnto=Main_Page
entirely intact.