Cyotek Development Bloghttps://devblog.cyotek.com/tag/https/atom.xml2018-03-30T15:55:08ZUsing the MantisBT REST API when hosted on IISurn:uuid:49741060-f6cc-4982-b2cb-bf12fbb9e6682018-03-30T15:55:08Z2018-03-30T15:55:08Z<p>I'm currently in the process of moving our hosting services from
one provider to another; although some parts of cyotek.com
infrastructure runs on Microsoft Azure, a fair chunk uses more
traditional hosting. Our <a href="https://mantisbt.org/" rel="external nofollow noopener">MantisBT</a> instance is one such
service that I recently migrated.</p>
<p>Previously the instance was hosted on Linux, now it's on
Windows. The initial migration seemed to have gone well and so
I'd moved onto the next sub-domain on the list.</p>
<p>This morning however I noticed the error logs were listing that
cyotek.com wasn't able to display product road maps. On testing,
I was getting <code>404</code> responses for any calls to the REST API on
the migrated MantisBT instance.</p>
<h2 id="apache-redirects">Apache Redirects</h2>
<p>The REST API in MantisBT makes use of Apache's <strong>mod_rewrite</strong>
module to rewrite any URI to <code>/api/rest/</code> to
<code>/api/rest/index.php</code> using the following rules in <code>.htaccess</code></p>
<figure class="lang-bat highlight"><figcaption><span>bat</span></figcaption><pre class="code">
# Based <span class="keyword">on</span> Slim Framework recommendation @ http://docs.slimframework.com/routing/rewrite/
RewriteEngine <span class="keyword">On</span>
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
</pre>
</figure>
<p>Of course, IIS doesn't support <code>.htaccess</code> files and so these
rewrites never occur, hence the <code>404</code>.</p>
<h2 id="redirecting-in-iis">Redirecting in IIS</h2>
<p>IIS has its own version of <strong>mod_rewrite</strong>, the <strong>URL Rewrite</strong>
module, although it isn't installed by default. You can find how
to install this module in a <a href="/post/installing-the-url-rewrite-module-into-internet-information-services">previous post</a>.</p>
<p>Once installed, you can add rewrite rules to <code>web.config</code> either
via the IIS Manager GUI, or by directly editing the
configuration - this post will cover both approaches.</p>
<h2 id="importing.htaccess-rules">Importing .htaccess rules</h2>
<p>I briefly spoke about manually modifying <code>web.config</code> to add
rewrite rules in our post on <a href="/post/redirecting-to-https-when-using-iis-behind-a-load-balancer">Redirecting to HTTPS when using
IIS behind a load balancer</a>. This time I'm going to describe
how to import the rewrite rules of a <code>.htaccess</code> file directly
into IIS.</p>
<ul>
<li><p>Firstly, open IIS manager and then navigate to the
<strong>api/rest</strong> folder of your MantisBT installation</p>
</li>
<li><p>Next open the <strong>URL Rewrite</strong> section.</p>
</li>
<li><p>Click the <strong>Import Rules...</strong> option in the Actions sidebar.</p>
</li>
<li><p>In the <strong>Configuration file</strong> field, select the <code>.htaccess</code>
file located in the local <code>api/rest</code> folder and then click
<strong>Import</strong>.</p>
</li>
<li><p>Verify that the <strong>Rewrite rules</strong> field displays the
appropriate redirect and that <strong>Converted Rules</strong> indicates
that the rule was successfully imported.</p>
<figure class="screenshot" ><a href="https://images.cyotek.com/image/devblog/mantisbt-iis-rewrite-1c.png" class="gallery" title="Importing .htaccess rules into IIS" ><img src="https://images.cyotek.com/image/thumbnail/devblog/mantisbt-iis-rewrite-1c.png" alt="Importing .htaccess rules into IIS" decoding="async" loading="lazy" /></a><figcaption>Importing .htaccess rules into IIS</figcaption></figure></li>
<li><p>In the Actions sidebar, click <strong>Apply</strong> to save the changes,
then click <strong>Back to Rules</strong> to return to to the main <strong>URL
Rewrite</strong> section listing the imported rule.</p>
<figure class="screenshot" ><a href="https://images.cyotek.com/image/devblog/mantisbt-iis-rewrite-1d.png" class="gallery" title="The imported configuration" ><img src="https://images.cyotek.com/image/thumbnail/devblog/mantisbt-iis-rewrite-1d.png" alt="The imported configuration" decoding="async" loading="lazy" /></a><figcaption>The imported configuration</figcaption></figure></li>
</ul>
<p>That should be all that is required; the REST API calls should
now rewrite and succeed. To quickly test that all is well, open
up <code>http://yourinstantURL/api/rest/projects/</code> in your browser -
if you get a 401 error, then the redirect is working correctly.</p>
<h2 id="manually-updating-the-configuration">Manually updating the configuration</h2>
<p>If your instance is hosted remotely you might not have direct
access to IIS Manager or be able to remotely connect to it.
Below is the complete <code>web.config</code> file used to enable
redirects, simply copy it to the <code>/api/rest</code> folder of your
MantisBT instance.</p>
<figure class="lang-xml highlight"><figcaption><span>xml</span></figcaption><pre class="code">
<span class="symbol">&lt;?</span><span class="name">xml</span> <span class="name">version</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">1.0</span><span class="symbol">&quot;</span> <span class="name">encoding</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">UTF-8</span><span class="symbol">&quot;</span><span class="symbol">?&gt;</span>
<span class="symbol">&lt;</span><span class="name">configuration</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">system.webServer</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">rewrite</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">rules</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">rule</span> <span class="name">name</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">API Redirect</span><span class="symbol">&quot;</span> <span class="name">stopProcessing</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">match</span> <span class="name">url</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">^</span><span class="symbol">&quot;</span> <span class="name">ignoreCase</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">false</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
 <span class="symbol">&lt;</span><span class="name">conditions</span> <span class="name">logicalGrouping</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">MatchAll</span><span class="symbol">&quot;</span><span class="symbol">&gt;</span>
 <span class="comment">&lt;!--# Based on Slim Framework recommendation @ http://docs.slimframework.com/routing/rewrite/--&gt;</span>
 <span class="symbol">&lt;</span><span class="name">add</span> <span class="name">input</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">{REQUEST_FILENAME}</span><span class="symbol">&quot;</span> <span class="name">matchType</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">IsFile</span><span class="symbol">&quot;</span> <span class="name">ignoreCase</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">false</span><span class="symbol">&quot;</span> <span class="name">negate</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">conditions</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">action</span> <span class="name">type</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">Rewrite</span><span class="symbol">&quot;</span> <span class="name">url</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">index.php</span><span class="symbol">&quot;</span> <span class="name">appendQueryString</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span> <span class="name">logRewrittenUrl</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">rule</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">rules</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">rewrite</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">system.webServer</span><span class="symbol">&gt;</span>
<span class="symbol">&lt;/</span><span class="name">configuration</span><span class="symbol">&gt;</span>
</pre>
</figure>
<h2 id="update-history">Update History</h2>
<ul>
<li>2018-03-30 - First published</li>
<li>2020-11-22 - Updated formatting</li>
</ul>

<p><small>
All content <a href="https://devblog.cyotek.com/copyright-and-trademarks">Copyright (c) by Cyotek Ltd</a> or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.<br />Original URL of this content is https://devblog.cyotek.com/post/using-the-mantisbt-rest-api-when-hosted-on-iis .
</small></p>Richard Mosshttps://www.cyotek.com/richard.moss@cyotek.comRedirecting to HTTPS when using IIS behind a load balancerurn:uuid:8ceab7e1-834d-4f00-bc82-c78c6bcbaa6a2017-11-19T17:12:25Z2017-11-19T13:25:52Z<p>Cyotek has a number of different websites powering various bits
of our software and services. Some are Windows based using IIS,
and some are Linux based using Apache. Internal servers are are
directly accessed but external servers are behind load
balancers. Almost all are using HTTPS now and have redirects in
place to force the use of HTTPS over HTTP.</p>
<p>There are plenty of articles on the internet dealing how to use
<code>.htaccess</code> files to perform redirects using Apache, and various
articles on different methods of redirecting IIS or ASP.NET
applications. However, there seems to be a slight gap when it
comes to load balancers or reverse proxies. Depending on how the
load balancer / reverse proxy (referred to as just load balancer
for the rest of the article) operates, the secure connection may
terminate at the load balancer, and so the web server always
receives &quot;insecure&quot; traffic.</p>
<p>If the secure connection is terminated at the balancer, then
this can be a problem for the most common method of redirecting
traffic, which is to check if the current request's scheme is
HTTP and perform a redirect if it is. But if the web server
<em>always</em> gets HTTP traffic, then this approach will simply
result in an infinite redirect loop, something I've managed to
do inadvertently more than once.</p>
<p>Fortunately however, when a load balancer forwards traffic to
the final server, it generally includes some extra headers such
as <code>X-Forwarded-For</code> and <code>X-Forwarded-Proto</code>. These headers
provide details such as the original scheme/protocol being used
and the origin IP address.</p>
<blockquote>
<p>When researching the final details for writing this article, I
found that the non-standard <code>X-Forwarded-*</code> headers have been
replaced under <a href="https://tools.ietf.org/html/rfc7239" rel="external nofollow noopener">RFC 7239</a> by a new <code>Forwarded</code> header. It's
possible therefore that the <code>X-Forwarded-For</code> header may start
dropping out of use and you'd be expected to work with
<code>Forwarded</code> instead.</p>
</blockquote>
<p>The header I'm interested in in this case is <code>X-Forwarded-Proto</code>
which simply details the scheme of the original request. If the
value is <code>http</code>, then clearly the original request wasn't secure
and so I can issue a redirect. If it's <code>https</code>, then the
original request - up to hitting the load balancer - was secure,
and we shouldn't try and redirect, or we're back into infinite
loop territory.</p>
<blockquote>
<p>Remember that these are request headers, e.g. headers you
can't control and which could be forged or manipulated.</p>
</blockquote>
<p>When using IIS, I've mostly used code based redirects although
the very oldest bits use an ancient configuration based
re-writer named <code>Intelligencia.UrlRewriter</code>. However, for some
time IIS now has had an optional URL rewriter of its own, which
is what I'm going to use in this article.</p>
<blockquote>
<p>By default the URL rewrite module isn't installed, although
it's easy enough to add using the Web Platform Installer. I've
detailed the steps in a <a href="/post/installing-the-url-rewrite-module-into-internet-information-services">prior
post</a>.</p>
</blockquote>
<h2 id="adding-a-rule-to-force-https">Adding a rule to force HTTPS</h2>
<p>Although you can configure rules from within IIS Managers GUI
interface, I'm just going to detail how to directly modify the
<code>web.config</code> of an application.</p>
<p>In your <code>web.config</code>, find the <code>system.webServer</code> element (or
add it as a child of <code>configuration</code> if it is not already
present), and add a <code>rewrite</code> element containing the following
content.</p>
<figure class="lang-xml highlight"><figcaption><span>xml</span></figcaption><pre class="code">
<span class="symbol">&lt;</span><span class="name">rewrite</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;</span><span class="name">rules</span><span class="symbol">&gt;</span>
 <span class="comment">&lt;!-- Specify a rule element. The stopProcessing attribute means no other
 rules will be processed if this rule is a match. You can also add a boolean
 attribute named enabled which you can use to temporarily disable a rule
 without deleting it from the file --&gt;</span>
 <span class="symbol">&lt;</span><span class="name">rule</span> <span class="name">name</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">HTTPS Redirect</span><span class="symbol">&quot;</span> <span class="name">stopProcessing</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span><span class="symbol">&gt;</span>
 <span class="comment">&lt;!-- Specifies a regular expression used to match the incoming URL. As I
 want all URL&#39;s to be considered, I tell it to match any character. By wrapping 
 the expression in brackets I create a capturing group I can use elsewhere. --&gt;</span>
 <span class="symbol">&lt;</span><span class="name">match</span> <span class="name">url</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">(.*)</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
 <span class="comment">&lt;!-- Each rule can have one or more conditions --&gt;</span>
 <span class="symbol">&lt;</span><span class="name">conditions</span><span class="symbol">&gt;</span>
 <span class="comment">&lt;!-- Here I&#39;ve added a condition which looks at the X-Forwarded-Proto
 header to see if it&#39;s any value other than &quot;https&quot;. (The attribute
 negate=&quot;true&quot; means &quot;does not match&quot;) --&gt;</span>
 <span class="symbol">&lt;</span><span class="name">add</span> <span class="name">input</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">{HTTP_X_FORWARDED_PROTO}</span><span class="symbol">&quot;</span> <span class="name">pattern</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">https</span><span class="symbol">&quot;</span> <span class="name">negate</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">conditions</span><span class="symbol">&gt;</span>
 <span class="comment">&lt;!-- The action element states what should happen if all the rule
 conditions are met. This action instructs IIS to perform a 301 redirect
 to the original host (via the HTTP_HOST variable) with the original request
 path (as captured in the match element above) via R:1 --&gt;</span>
 <span class="symbol">&lt;</span><span class="name">action</span> <span class="name">type</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">Redirect</span><span class="symbol">&quot;</span> <span class="name">url</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">https://{HTTP_HOST}/{R:1}</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">rule</span><span class="symbol">&gt;</span>
 <span class="symbol">&lt;/</span><span class="name">rules</span><span class="symbol">&gt;</span>
<span class="symbol">&lt;/</span><span class="name">rewrite</span><span class="symbol">&gt;</span>
</pre>
</figure>
<p>Rather than trying to add a description outside the code block,
I've added a bunch of comments inside the XML.</p>
<p>Happily, these are the only changes you need to make to
web.config files - you don't need to define new
<code>configSections</code>, <code>httpHandlers</code>, or other elements. I assume
these have been pre-defined at a higher level, but haven't
confirmed this.</p>
<h2 id="a-note-on-using-letsencrypt-renewal-challenges">A note on using LetsEncrypt renewal challenges</h2>
<p>If you are renewing LetsEncrypt certificates via a HTTP
challenge (where a file is placed on your server to confirm
validity), then this rule will cause the challenge to fail due
to the redirect. If your processes are set to only renew the
certificates at the last minute then SSL can stop working on
your website, causing web browsers to display unwelcome danger
messages when visitors attempt to access your site. Somethign
<em>else</em> that has happened more than once to me, and the main
reason why cyotek.com is now running off a 3 year traditional
certificate after lasts months mishap.</p>
<p>As the file is always in a static location
(<code>.well-known/acme-challenge</code>) we can expand our original rule
to add a new condition which prevents the redirect from
triggering if that path is present.</p>
<p>Using the example rule above, I added a new child of the
<code>conditions</code> element as follows.</p>
<figure class="lang-xml highlight"><figcaption><span>xml</span></figcaption><pre class="code">
<span class="symbol">&lt;</span><span class="name">add</span> <span class="name">input</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">{PATH_INFO}</span><span class="symbol">&quot;</span> <span class="name">pattern</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">^/\.well-known/acme-challenge/.*</span><span class="symbol">&quot;</span> <span class="name">negate</span><span class="symbol">=</span><span class="symbol">&quot;</span><span class="attribute">true</span><span class="symbol">&quot;</span> <span class="symbol">/&gt;</span>
</pre>
</figure>
<p>When testing a HTML located in this path, the request was not
forcibly redirected to HTTPS and was displayed via unsecure
HTTP, which should allow LetsEncrypt challenges to succeed. Of
course, the certificates on the domains where I've implemented
these rules aren't due to expire for another two months so time
will tell if this is sufficient.</p>
<h2 id="closing-notes">Closing notes</h2>
<p>Forcing a redirect from HTTP to HTTPS is only one part - you
should also consider using a Content Security Policy (CSP) that
instructs browsers to automatically use HTTPS and setting up
HTTP Strict Transport Security (HSTS). You should also ensure
the redirects you put in place are 301 to guide search engines
to update references (the example above uses a 301 redirect).
Lots of things to try and remember! <a href="https://www.troyhunt.com/" rel="external nofollow noopener">Troy Hunt</a> has a helpful
post on <a href="https://www.troyhunt.com/the-6-step-happy-path-to-https/" rel="external nofollow noopener">getting started with HTTPS</a>.</p>
<p>There is also lots more you can do using rewrite rules - you can
view the <a href="https://www.iis.net/learn/extensions/url-rewrite-module/url-rewrite-module-configuration-reference?amp;clcid=0x409" rel="external nofollow noopener">documentation</a> for more information and examples.
And, although in this article I only covered modifying
<code>web.config</code> directly, you can use the GUI tools in IIS Manager
to explore all the supported function and experiment with rule
creation.</p>
<h2 id="update-history">Update History</h2>
<ul>
<li>2017-11-19 - First published</li>
<li>2020-11-22 - Updated formatting</li>
</ul>

<p><small>
All content <a href="https://devblog.cyotek.com/copyright-and-trademarks">Copyright (c) by Cyotek Ltd</a> or its respective writers. Permission to reproduce news and web log entries and other RSS feed content in unmodified form without notice is granted provided they are not used to endorse or promote any products or opinions (other than what was expressed by the author) and without taking them out of context. Written permission from the copyright owner must be obtained for everything else.<br />Original URL of this content is https://devblog.cyotek.com/post/redirecting-to-https-when-using-iis-behind-a-load-balancer .
</small></p>Richard Mosshttps://www.cyotek.com/richard.moss@cyotek.com