{"id":152,"date":"2020-01-13T13:26:27","date_gmt":"2020-01-13T12:26:27","guid":{"rendered":"https:\/\/www.hallam.ch\/blog\/?p=152"},"modified":"2020-07-25T12:07:04","modified_gmt":"2020-07-25T10:07:04","slug":"apache-and-two-factor-authentication-2fa-using-ldap-accounts","status":"publish","type":"post","link":"https:\/\/www.hallam.ch\/blog\/index.php\/2020\/01\/13\/apache-and-two-factor-authentication-2fa-using-ldap-accounts\/","title":{"rendered":"Apache and Two-factor Authentication (2FA) using LDAP accounts"},"content":{"rendered":"\r\n<h1><strong>Introduction<\/strong><\/h1>\r\n\r\n\r\n\r\n<p>Although I am happy locking down my Apache web server so I can\u00a0 just use web management tools from my local network, I&#8217;m also interested in potentially doing this from the Internet, therefore I decided to try and find a secure way to do this. For several years I just protected my web sites using an LDAP user account and password, which in most cases is most likely good enough. Nevertheless I decided I wanted to add that second layer of security. In this post I will describe how I implemented Two-factored authentication (2FA). If you have no basic Apache web server and\/or no basic LDAP know-how then please familiarise yourself with both of these services before proceeding.<\/p>\r\n\r\n\r\n\r\n<p>Before I start explaining, it&#8217;s worth understanding what you are getting as you don&#8217;t want to spend a lot of time trying to get things to work and then deciding it&#8217;s not what you want. The first authentication is an LDAP authentication using Apache basic authentication, and not a Forms based authentication. What this means is that the LDAP authentication is valid as long as your browser is open, e.g. there is no expiration after so many minutes\/hours of inactivity. So if you want session time expiration then this solution is potentially not for you. One can build in some session time expiration on the 2nd Authentication which I will explain later. The 2nd authentication will be done using Time-Based One-Time Password (TOTP), so typically an App on your smartphone like Google Authenticator or Authy (I use an App called Aegis simply because it&#8217;s Open Source).<\/p>\r\n\r\n\r\n\r\n<p>For the know-how for the 2nd Authentication, credit has to go to the person contributing code and instructions to Github. Besides reading my blog you should also read that persons guide! &#8211; <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a>.<\/p>\r\n\r\n\r\n\r\n<p>If you want to take a look at how things work first, feel free to scroll down to the &#8220;<strong>Let&#8217;s try it out<\/strong>&#8221; section further down.<\/p>\r\n\r\n\r\n\r\n<h1><strong>Preparation<\/strong><\/h1>\r\n\r\n\r\n\r\n<p>As I&#8217;ve mentioned\u00a0 please go through the\u00a0 <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a>, but specifically for my guide you&#8217;ll need to do the following commands mentioned in the <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a>:<\/p>\r\n\r\n\r\n\r\n<p><em>git clone https:\/\/github.com\/itemir\/apache_2fa<\/em><br \/><em>cd apache_2fa<\/em><br \/><em>sudo pip3 install onetimepass<\/em><br \/><em>mkdir state<\/em><br \/><em>sudo chmod 750 state<\/em><br \/><em>sudo chmod 640 tokens.json<\/em><\/p>\r\n\r\n\r\n\r\n<p>Enable mod_rewrite, mod_auth_digest and mod_cgid if not already enabled<\/p>\r\n\r\n\r\n\r\n<p><em>sudo a2enmod rewrite<\/em><br \/><em>sudo a2enmod auth_digest<\/em><br \/><em>sudo a2enmod cgid<\/em><br \/><em>sudo service apache2 restart<\/em><\/p>\r\n\r\n\r\n\r\n<p>If you want to exactly follow my instructions, then you&#8217;ll either have to move the directory <em>apache_2fa<\/em> and it&#8217;s contents to<em> \/usr\/share\/ <\/em>or make a symbolic link called <em> \/usr\/share\/apache_2fa <\/em>to point to wherever you placed <em>apache_2fa<\/em> when you executed the &#8220;git&#8221; command above.<\/p>\r\n<p>Finally do:<\/p>\r\n\r\n\r\n\r\n<p><em>sudo chmod -R www-data:www-data \/usr\/share\/apache_2fa<\/em><\/p>\r\n\r\n\r\n\r\n<h1><strong>Let&#8217;s Get Started<\/strong><\/h1>\r\n\r\n\r\n\r\n<p>My goal is to protect certain parts of my website that I don&#8217;t want the public to have access to. In my example, I want to restrict access to https:\/\/www.hallam.ch\/2fa\/ and everything that lies under this URL.<\/p>\r\n\r\n\r\n\r\n<h3><em>1st Authentication (LDAP)<\/em><\/h3>\r\n\r\n\r\n\r\n<p>As previously written, the assumption is, is that you have some basic understanding on how LDAP and Apache services work. To figure out how to implement LDAP basic authentication for Apache please refer to Apache documentation or to the many websites that will detail how to do this. A search using your preferred search engine for &#8220;Apache LDAP basic authentication&#8221; will help you get going. What I will explain here is how I configured Apache with Basic LDAP authentication to protect my &#8220;2fa&#8221; web pages.<\/p>\r\n\r\n\r\n\r\n<p>To configure Apache to protect https:\/\/www.hallam.ch\/2fa\/\u00a0 I created an Apache configuration file in \/etc\/apache2\/sites-available\/ . I called my configuration file &#8220;2fa_test.conf&#8221; which at the moment is misleading as we are only doing a single LDAP authentication. NOTE: We will be changing the content of &#8220;2fa_test.conf&#8221; when we finalise things with the 2nd Authentication.<\/p>\r\n\r\n\r\n\r\n<p>Make sure the file has the correct ownership and permissions so it can be accessed by Apache. The file will have to be present in \/etc\/apache2\/sites-enabled for the directives to be activated on an Apache server restart, so to ensure that the file is in \/etc\/apache2\/sites-enabled from a CLI prompt, execute the command &#8220;ln -s \/etc\/apache2\/sites-available\/2fa_test.conf \/etc\/apache2\/sites-enabled\/2fa_test.conf&#8221;.<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<p>Don&#8217;t forget to reload or restart your Apache web server after any configuration change with &#8220;service apache2 reload&#8221; (or &#8220;service apache2 restart&#8221;)<\/p>\r\n\r\n\r\n\r\n<p>Here is an example of what the &#8220;2fa_test.conf&#8221; content should look like:<\/p>\r\n\r\n\r\n\r\n<p><em>&lt;Directory &#8220;\/var\/www\/2fa\/&#8221;&gt; <\/em><br \/><em>SSLRequireSSL<\/em><br \/><em> AuthType Basic<\/em><br \/><em> AuthName &#8220;Please provide your credentials&#8221; <\/em><br \/><em> AuthBasicProvider ldap<\/em><br \/><em> AuthLDAPURL ldap:\/\/ldap-server\/dc=acme,dc=com?mail?sub<\/em><br \/><em> require ldap-group cn=group-test2fa,ou=groups,dc=acme,dc=com<\/em><br \/><em>&lt;\/Directory&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<p>and here the explanation<\/p>\r\n\r\n\r\n\r\n<p><em>&lt;Directory &#8220;\/var\/www\/2fa\/&#8221;&gt;\u00a0 (<\/em>The directory you are trying to protect)<br \/><em>SSLRequireSSL<\/em>\u00a0 (Ensure basic authentication is done using HTTPS)<br \/><em> AuthType Basic<\/em><br \/><em> AuthName &#8220;Please provide your credentials&#8221;\u00a0 <\/em>(you can type whatever you want between the quotes)<br \/><em> AuthBasicProvider ldap<\/em>\u00a0 (use LDAP for Authentication)<br \/><em> AuthLDAPURL ldap:\/\/ldap-server\/dc=acme,dc=com?mail?sub <\/em>(explained below)<br \/><em> require ldap-group cn=group-test2fa,ou=groups,dc=acme,dc=com <\/em>(explained below)<br \/><em>&lt;\/Directory&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>AuthLDAPURL ldap:\/\/ldap-server\/dc=acme,dc=com?mail?sub<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>&#8220;ldap-server&#8221;<\/em> is the hostname of where your ldap server is &#8211; e.g. localhost, ldap.acme.com.<br \/><em>&#8220;dc=acme,dc=com&#8221; is <\/em>where to start searching from for the user you want to authenticate<em>.<br \/>&#8220;mail&#8221; <\/em>this is the attribute I have chosen to find the appropriate LDAP entry. I could use. Other attributes that will have a unique value like uid, or for Active Directory UserPrincipalName.<br \/><em>&#8220;sub&#8221; <\/em>a tree search of your LDAP server<\/p>\r\n\r\n\r\n\r\n<p><em>require ldap-group cn=group-test2fa,ou=groups,dc=acme,dc=com <\/em>(easier is <em>require valid-user)<\/em><\/p>\r\n\r\n\r\n\r\n<p>The above statement,\u00a0<em>require ldap-group<\/em>, is an extra step that authorises anyone who is a member of the LDAP group &#8220;group-test2fa&#8221; to access the protected web pages. All others have no access. Maybe at this stage you should just use the less restrictive &#8220;<em>require valid-user<\/em>&#8220;.<\/p>\r\n\r\n\r\n\r\n<p>If the above is all a bit too much, then start by looking at the appropriate Apache and LDAP documentation as mentioned.<\/p>\r\n\r\n\r\n\r\n<p>A lot of you might be happy just with this level of security which would be hard to crack if you use LDAP\/TLS.<\/p>\r\n\r\n\r\n\r\n<p>If things are working fine you should get a dialogue box like this when trying to access https:\/\/your-website\/2fa\/<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image\"><img loading=\"lazy\" class=\"alignnone wp-image-160\" src=\"https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2019\/12\/ldap-auth-300x97.png\" alt=\"\" width=\"500\" height=\"161\" srcset=\"https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2019\/12\/ldap-auth-300x97.png 300w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2019\/12\/ldap-auth-768x248.png 768w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2019\/12\/ldap-auth-1024x330.png 1024w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2019\/12\/ldap-auth.png 1299w\" sizes=\"(max-width: 500px) 100vw, 500px\" \/><\/figure>\r\n<p>NOTE VERY WELL: In my example above, it is configured to use LDAP but not LDAP\/TLS, therefore if your LDAP server is not on the same box as your Apache server then there is a potential security risk. I actually do have it working with LDAP\/TLS so here is an example of what\u00a0 my <em>2fa_test.conf <\/em>would look like (note the extra line &#8220;LDAPTrustedGlobalCert that points to you LDAP certificate, and note the &#8220;TLS&#8221; at the end of the &#8220;AuthLDAPURL line):<\/p>\r\n<p><em>LDAPTrustedGlobalCert CA_DER &#8220;\/certs\/ldap.crt&#8221;<\/em><\/p>\r\n<p><em>&lt;Directory &#8220;\/var\/www\/2fa\/&#8221;&gt; <\/em><br \/><em>SSLRequireSSL<\/em><br \/><em> AuthType Basic<\/em><br \/><em> AuthName &#8220;Please provide your credentials&#8221; <\/em><br \/><em> AuthBasicProvider ldap<\/em><br \/><em> AuthLDAPURL ldap:\/\/ldap-server\/dc=acme,dc=com?mail?sub TLS<\/em><br \/><em> require ldap-group cn=group-test2fa,ou=groups,dc=acme,dc=com<\/em><br \/><em>&lt;\/Directory&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<h3><em>2nd Authentication (TOTP)<\/em><\/h3>\r\n\r\n\r\n\r\n<p>This is the harder part for me as I&#8217;m a novice regarding the Python programming language (maybe I should learn), and I&#8217;ve never really got involved with Apache rewrite rules. Anyhow, I started off by following these instructions, the <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a>. I&#8217;m not going to repeat what&#8217;s written there so note those instructions and I will outline here what I&#8217;ve done differently.<\/p>\r\n\r\n\r\n\r\n<p>I started by trying to implement exactly the <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a>, but I couldn&#8217;t get it to work and I struggled to understand why, maybe because the example given is to achieve something different to what I want to do? As stated right at the beginning, my goal is to restrict access to everything under https:\/\/www.hallam.ch\/2fa\/.<\/p>\r\n\r\n\r\n\r\n<p>In &#8220;<em>1st\u00a0 Authentication (LDAP)<\/em>&#8221; I explained how I setup &#8220;2fa_test.conf&#8221;\u00a0 to configure Apache for LDAP authentication and authorisation. Following is how I&#8217;ve now changed &#8220;2fa_test.conf&#8221;\u00a0 to accommodate the 1st and 2nd level authentication<\/p>\r\n\r\n\r\n\r\n<p><em>&lt;Directory &#8220;\/usr\/share\/apache_2fa\/&#8221;&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>SSLRequireSSL<\/em><br \/><em> AuthType Basic<\/em><br \/><em> AuthName &#8220;2FA First Authentication&#8221;<\/em><br \/><em> AuthBasicProvider ldap<\/em><br \/><em> AuthLDAPURL ldap:\/\/localhost\/dc=local,dc=net?mail?sub<\/em><br \/><em> require ldap-group cn=group-test2fa,ou=groups,dc=local,dc=net<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>&lt;\/Directory&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>ScriptAlias \/auth\/ \/usr\/share\/apache_2fa\/<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>&lt;Directory &#8220;\/var\/www\/2fa\/&#8221;&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>RewriteEngine On<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>RewriteCond %{REQUEST_URI} !^\/auth\/<\/em><br \/><em>RewriteCond %{HTTP_COOKIE} !^.*2FA_Auth=([a-zA-Z0-9]+)<\/em><br \/><em>RewriteRule ^(.*)$ \/auth\/auth?%{REQUEST_URI} [L,R=302]<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>RewriteCond %{REQUEST_URI} !^\/auth\/<\/em><br \/><em>RewriteCond %{HTTP_COOKIE} ^.*2FA_Auth=([a-zA-Z0-9]+)<\/em><br \/><em>RewriteCond \/usr\/share\/apache_2fa\/state\/%1 !-f<\/em><br \/><em>RewriteRule ^(.*)$ \/auth\/auth?%{REQUEST_URI} [L,R=302]<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>SSLRequireSSL<\/em><br \/><em> AuthType Basic<\/em><br \/><em> AuthName &#8220;2FA First Authentication&#8221;<\/em><br \/><em> AuthBasicProvider ldap<\/em><br \/><em> AuthLDAPURL ldap:\/\/localhost\/dc=local,dc=net?mail?sub<\/em><br \/><em> require ldap-group cn=group-test2fa,ou=groups,dc=local,dc=net<\/em><\/p>\r\n\r\n\r\n\r\n<p><em>&lt;\/Directory&gt;<\/em><\/p>\r\n\r\n\r\n\r\n<p>Let&#8217;s go through the configuration.<\/p>\r\n\r\n\r\n\r\n<p><em>&lt;Directory &#8220;\/usr\/share\/apache_2fa\/&#8221;&gt;<br \/><\/em><\/p>\r\n\r\n\r\n\r\n<p>\/usr\/share\/apache_2fa\u00a0 is where I&#8217;ve put the downloaded code (the code downloaded with the command <em>git clone https:\/\/github.com\/itemir\/apache_2fa<\/em>).<\/p>\r\n<p>The directives from &#8220;<em>&lt;Directory &#8220;\/usr\/share\/apache_2fa\/&#8221;&gt;<\/em>&#8221; to &#8220;<em>&lt;\/Directory&gt;<\/em>&#8221; I explained in the <em>1st Authentication (LDAP)<\/em> section.<\/p>\r\n\r\n\r\n\r\n<p><em>ScriptAlias \/auth\/ \/usr\/share\/apache_2fa\/<\/em><\/p>\r\n\r\n\r\n\r\n<p>This forces Apache\u00a0 to get all the HTML code and scripts for https:\/\/www.hallam.ch\/auth\/ from\u00a0 \/usr\/share\/apache_2fa\/ . Please note that the web server does not have have a directory called &#8220;auth&#8221; (e.g. you won&#8217;t find a directory &#8220;&lt;<em>DocumentRoot&gt;<\/em>\/auth&#8221;, in my case &#8220;\/var\/www\/auth&#8221;). When you read the next part on the rewrite rules it will hopefully become clear what is happening.<\/p>\r\n\r\n\r\n\r\n<p><em>&lt;Directory &#8220;\/var\/www\/2fa\/&#8221;&gt;<\/em> (The directory you are trying to protect, but rewriting will take place when I enter https:\/\/www.hallam.ch\/2fa\/ in my web-browser as you will see).<\/p>\r\n\r\n\r\n\r\n<p><em>RewriteEngine On<\/em> (Should be self-explanatory)<\/p>\r\n\r\n\r\n\r\n<p><em>RewriteCond %{REQUEST_URI} !^\/auth\/<\/em><br \/><em>RewriteCond %{HTTP_COOKIE} !^.*2FA_Auth=([a-zA-Z0-9]+)<\/em><br \/><em>RewriteRule ^(.*)$ \/auth\/auth?%{REQUEST_URI} [L,R=302]<\/em><\/p>\r\n\r\n\r\n\r\n<p>To fully understand the above 3 lines please read the Apache documentation rewrite rules. Basically it states if the &#8220;<em>RewriteCond<\/em>&#8221; conditions are met it will execute the &#8220;<em>RewriteRule<\/em>&#8220;.\u00a0 The following explanation might well be good enough for you.<br \/>The first Rewrite Condition &#8220;<em>RewriteCond %{REQUEST_URI} !^\/auth\/<\/em>&#8220;. If the requested URI is not &#8220;\/auth\/&#8221;. It won&#8217;t be initially as it will be &#8220;\/2fa\/&#8221; (https:\/\/www.hallam.ch\/2fa\/).<br \/>The second Rewrite Condition &#8220;<em>RewriteCond %{HTTP_COOKIE} !^.*2FA_Auth=([a-zA-Z0-9]+)<\/em>&#8221; is basically checking whether the Cookie &#8220;2FA_Auth&#8221; does not exist. Initially it won&#8217;t.<br \/>Assuming the Rewrite Conditions are met the Rewrite Rule will execute <em>RewriteRule ^(.*)$ \/auth\/auth?%{REQUEST_URI} [L,R=302]<\/em><br \/>This will cause the Apache server to execute https:\/\/www.hallam.ch\/auth\/auth?\/2fa\/ &#8211; do you remember the line &#8220;<em>ScriptAlias \/auth\/ \/usr\/share\/apache_2fa\/&#8221;<\/em> from above? What happens is that Apache goes to \/usr\/share\/apache_2fa\/ and executes the python script &#8220;auth&#8221;. The python program uses everything after the &#8220;?&#8221;, so \/2fa\/ in my case &#8211; https:\/\/www.hallam.ch\/auth\/auth?\/2fa\/.<\/p>\r\n\r\n\r\n\r\n<p>I&#8217;m not going to show you the &#8220;auth&#8221; python script and I&#8217;m not going into details on what the &#8220;auth&#8221; script does. You can always get the code from Github. What I will tell you about the &#8220;auth&#8221; python script is that it creates a cookie with an expiration time and a file in the directory \/usr\/share\/apache_2fa\/state\/. The filename is the same as the cookie value. I&#8217;ve explained this because of the next part of the rewrite rules.<\/p>\r\n\r\n\r\n\r\n<p><em>RewriteCond %{REQUEST_URI} !^\/auth\/<\/em><br \/><em>RewriteCond %{HTTP_COOKIE} ^.*2FA_Auth=([a-zA-Z0-9]+)<\/em><br \/><em>RewriteCond \/usr\/share\/apache_2fa\/state\/%1 !-f<\/em><br \/><em>RewriteRule ^(.*)$ \/auth\/auth?%{REQUEST_URI} [L,R=302]<\/em><\/p>\r\n\r\n\r\n\r\n<p>Let&#8217;s go straight to the second rewrite condition as I&#8217;ve already explained the first.<br \/>The second rewrite condition practically the same as as the second rewrite condition above except this time it is checking whether the cookie &#8220;2FA_Auth&#8221; exist.<br \/>The third rewrite condition <em>RewriteCond \/usr\/share\/apache_2fa\/state\/%1 !-f<\/em> is looking to see if there is not a file that matches the cookie value under &#8220;\/usr\/share\/apache_2fa\/state\/&#8221;.<br \/>The <em>RewriteRule<\/em> has also previously been explained.<\/p>\r\n\r\n\r\n\r\n<p>PLEASE NOTE: I&#8217;ve also included further directives after the rewrite rules (a repeat of the directives in the 1st authentication). I believe these directives are superfluous and you can exclude them. I only put them there because that&#8217;s how things were setup in the <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a>, and leaving them there is harmless.<\/p>\r\n\r\n\r\n\r\n<h1><strong>Generating secret keys and QR codes<\/strong><\/h1>\r\n\r\n\r\n\r\n<p>I don&#8217;t intend to go into too much detail, but will tell you enough for you to get things working. For the generation of the secret keys one just needs to issue this CLI command:<\/p>\r\n<p><em> &#8220;head -10 \/dev\/urandom | md5sum | cut -b 1-30 | xargs oathtool &#8211;verbose &#8211;totp | grep &#8220;Base32&#8221; | cut -b 16-&#8220;<\/em><\/p>\r\n<p>This will give a result of something like this &#8211; TBSYABA5VOLRMYWSF5SGTTY5<\/p>\r\n<p>you will then need to put the result into the &#8220;tokens.json&#8221; file which you&#8217;ll find under <em>\/usr\/share\/apache_2fa<\/em>. I&#8217;ve done things for a user with the email address of &#8220;test.user@acme.com&#8221; so my &#8220;tokens.json&#8221; file looks like this<\/p>\r\n<p><em>{<\/em><br \/><em>&#8220;test.user@acme.com&#8221;: &#8220;TBSYABA5VOLRMYWSF5SGTTY5&#8221;<\/em><br \/><em>}<\/em><\/p>\r\n<p>You can leave things like this and tell the user what their secret key is so they can add it to the Mobile phone App, or you can be a bit more user-friendly and generate a QR code for their Mobile phone App to scan in.<\/p>\r\n<p>To generate the QR code using the above secret key enter the following CLI command (NOTE: it&#8217;s a single line command):<\/p>\r\n<p><em>qr &#8220;otpauth:\/\/totp\/test.user@acme.com?secret=TBSYABA5VOLRMYWSF5SGTTY5&#8221;<\/em><\/p>\r\n<p>You can always save the QR generate to an image file by saving the output, so:<\/p>\r\n<p><em>qr &#8220;otpauth:\/\/totp\/test.user@acme.com?secret=TBSYABA5VOLRMYWSF5SGTTY5&#8221; &gt; testuser.png<\/em><\/p>\r\n\r\n\r\n\r\n<h1><strong>Let&#8217;s try it out<\/strong><\/h1>\r\n\r\n\r\n\r\n<p>So you can see how it should work for you, I have set things up so you can access what&#8217;s behind https:\/\/www.hallam.ch\/2fa\/ .<\/p>\r\n<p>To start with you will need an App on your smartphone for the 2nd authentication. I am using an Open Source App called &#8220;Aegis&#8221;, but if you want you can use Apps like &#8220;Authy&#8221; or &#8220;Google Authenticator&#8221;. You can add a new profile by adding the Authentication secret key manually which is <strong>TBSYABA5VOLRMYWSF5SGTTY5<\/strong>, but you&#8217;ll probably find it easier to just scan the QR code that I generated which you will find here &#8211; https:\/\/www.hallam.ch\/QRcode\/ .<\/p>\r\n\r\n\r\n\r\n<p>You are now ready to go, so go to https:\/\/www.hallam.ch\/2fa\/ and when the dialogue box appears for &#8220;User Name&#8221; and &#8220;Password&#8221; enter the following credentials:<br \/>User Name = test.user@acme.com<br \/>Password =\u00a0 testuserxx<\/p>\r\n\r\n\r\n\r\n<p>Assuming you have entered the credential correctly you will get the page for the 2nd Authentication for the TOTP code from your smartphone App.<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image\"><img loading=\"lazy\" width=\"300\" height=\"273\" class=\"wp-image-173\" src=\"https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/token-300x273.png\" alt=\"\" srcset=\"https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/token-300x273.png 300w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/token.png 333w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/figure>\r\n\r\n\r\n\r\n<p>Enter the token value that is presented by your smartphone App (Authy, Google Authenticator, Aegis etc.) and you should see the following page.<\/p>\r\n\r\n\r\n\r\n<figure class=\"wp-block-image\"><img loading=\"lazy\" class=\"alignnone wp-image-175\" src=\"https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/2fa-page-300x39.png\" alt=\"\" width=\"450\" height=\"58\" srcset=\"https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/2fa-page-300x39.png 300w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/2fa-page-768x99.png 768w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/2fa-page-1024x132.png 1024w, https:\/\/www.hallam.ch\/blog\/wp-content\/uploads\/2020\/01\/2fa-page.png 1305w\" sizes=\"(max-width: 450px) 100vw, 450px\" \/><\/figure>\r\n\r\n\r\n\r\n<h1><strong>Additional thoughts and information<\/strong><\/h1>\r\n\r\n\r\n\r\n<ul>\r\n<li>Take a look at the python script <em>auth<\/em> (in my case \/usr\/share\/apache_2fa\/auth), and try and figure out what it&#8217;s doing. The beauty about <em>auth<\/em> is that you can play around with it to meet your needs.<\/li>\r\n<li>I made a small change to the <em>template.html<\/em> to use my own image for the 2nd Authentication instead of getting the *Google Authenticator&#8221; image from the Internet.<\/li>\r\n<li>If you want to protect another part of your website with this solution, you&#8217;ll have to think a bit. For example, you won&#8217;t want to use the same cookie generate by the<em> auth<\/em> script is an immediate thought.<\/li>\r\n<li>You can put a bit of session control in place by changing the expiration time of the<em> 2FA_Auth<\/em> cookie that <em>auth<\/em> generates, and maybe one would like to change <em>auth\u00a0<\/em>so that the cookie expiration time is updated everytime the website is accessed. If you have a short expiration time, <em>auth<\/em> will force the 2nd Authentication to take place again. Current expiration time is 6 hours.<\/li>\r\n<li>Don&#8217;t forget to implement the latter part of the <strong>Maintenance<\/strong> section of <a href=\"https:\/\/github.com\/itemir\/apache_2fa#instruction\">Apache 2FA instructions<\/a> (the state clean part).<\/li>\r\n<li>You can play around with solution to fit your need. For example, it might be nice to keep the tokens within your LDAP directory instead of the file &#8220;tokens.json&#8221;.<\/li>\r\n<li>Maybe I should spend some of my time to come up with a &#8220;Forms Based&#8221; 2FA using PHP \ud83d\ude42<\/li>\r\n<\/ul>\r\n<p>&nbsp;<\/p>\r\n","protected":false},"excerpt":{"rendered":"<p>Introduction Although I am happy locking down my Apache web server so I can\u00a0 just use web management tools from my local network, I&#8217;m also interested in potentially doing this from the Internet, therefore I decided to try and find a secure way to do this. For several years I just protected my web sites &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.hallam.ch\/blog\/index.php\/2020\/01\/13\/apache-and-two-factor-authentication-2fa-using-ldap-accounts\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Apache and Two-factor Authentication (2FA) using LDAP accounts&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9],"tags":[10,12,18,19,13,15,11],"_links":{"self":[{"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/posts\/152"}],"collection":[{"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=152"}],"version-history":[{"count":29,"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/posts\/152\/revisions"}],"predecessor-version":[{"id":186,"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/posts\/152\/revisions\/186"}],"wp:attachment":[{"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=152"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=152"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.hallam.ch\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=152"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}