<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Leo Lanchas</title>
    <description>The latest articles on Forem by Leo Lanchas (@leolanchas).</description>
    <link>https://forem.com/leolanchas</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F90364%2Ff701e9d6-0915-46ad-80c8-8848589388b5.jpg</url>
      <title>Forem: Leo Lanchas</title>
      <link>https://forem.com/leolanchas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/leolanchas"/>
    <language>en</language>
    <item>
      <title>How to implement Http Digest (RFC 2617) in Javascript in Node, using Passport.JS</title>
      <dc:creator>Leo Lanchas</dc:creator>
      <pubDate>Wed, 08 Aug 2018 23:03:43 +0000</pubDate>
      <link>https://forem.com/leolanchas/how-to-implement-http-digest-rfc-2617-in-javascript-in-node-using-passportjs-17l8</link>
      <guid>https://forem.com/leolanchas/how-to-implement-http-digest-rfc-2617-in-javascript-in-node-using-passportjs-17l8</guid>
      <description>&lt;p&gt;When implementing an API need to protect its endpoints in each request. So you need to authenticate them.&lt;/p&gt;

&lt;p&gt;PassportJS is authentication middleware for &lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt;.It is extremely flexible and modular, and designed to serve a  purpoose: authenticate requests. It can be unobtrusively dropped in to any &lt;a href="http://expressjs.com"&gt;Express&lt;/a&gt;-based web application.&lt;/p&gt;

&lt;p&gt;Passport recognizes that each application has unique authentication requirements. Authentication mechanisms, known as strategies, are packaged as individual modules. Applications can choose which strategies to employ, without creating unnecessary dependencies.&lt;/p&gt;

&lt;p&gt;Basic &amp;amp; Digest&lt;/p&gt;

&lt;p&gt;Along with defining HTTP’s authentication framework, RFC 2617 also defined the Basic and Digest authentications schemes. These two schemes both use usernames and passwords as credentials to authenticate users, and are often used to protect API endpoints.&lt;/p&gt;

&lt;p&gt;It should be noted that relying on username and password creditials can have adverse security impacts, especially in scenarios where there is not a high degree of trust between the server and client. In these situations, it is recommended to use an authorization framework such as &lt;a href="https://github.com/jaredhanson/passport-oauth2#readme"&gt;OAuth 2.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post I’ll explain how to implement the Digest scheme.&lt;/p&gt;

&lt;p&gt;I presume Node.JS is installed on your system. You also need Express:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install express
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;/p&gt;

&lt;p&gt;Passportjs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install passport
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and its basic and digest strategies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ npm install passport-http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The source is hosted at github: &lt;a href="https://github.com/leolanchas/http-digest-passport-js"&gt;https://github.com/leolanchas/http-digest-passport-js&lt;/a&gt; and you can run it at c9.io:  &lt;a href="https://c9.io/leolanchas/http-digest-passport-js"&gt;https://c9.io/leolanchas/http-digest-passport-js&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first file works only to test in localhost (no need to use it at c9 or in a real server) because the domain of the request cannot be null. So if you clone the repo from github, the first thing you need to do is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ node Server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then on your browser you must go to “localhost:2563” It will just serve you Httpdigest.html (where you only have to click the button.).&lt;/p&gt;

&lt;p&gt;‘Server.js’&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var express = require('express');
var app = express();

app.all('/', function(req, res) { res.sendfile('digest.html'); } );

app.listen(2563);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s a simple html file that displays a button that calls the HttpDigest function.&lt;/p&gt;

&lt;p&gt;IMPORTANT: for simplicity, I’ve omitted the token generation. This token should be generated via sdk and also be different in each call. Otherwise, it can be easily intercepted.&lt;/p&gt;

&lt;p&gt;The process consists basically of 2 http requests as detailed here: &lt;a href="http://en.wikipedia.org/wiki/Digest_access_authentication"&gt;http://en.wikipedia.org/wiki/Digest_access_authentication&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can ignore the first part of the script. It is the md5 algorithm compressed.&lt;/p&gt;

&lt;p&gt;‘HttpDigest.html’&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;style&amp;gt; body { font-family: consolas} table { border-collapse:collapse; } table, td, th { border:1px solid black;} td.H { text-align: center; } &amp;lt;/style&amp;gt;
        &amp;lt;script src="http://code.jquery.com/jquery-latest.js"&amp;gt;&amp;lt;/script&amp;gt;
        &amp;lt;script&amp;gt;
            var hexcase=0;var b64pad="";function hex_md5(a){return rstr2hex(rstr_md5(str2rstr_utf8(a)))}function b64_md5(a){return rstr2b64(rstr_md5(str2rstr_utf8(a)))}function any_md5(a,b){return rstr2any(rstr_md5(str2rstr_utf8(a)),b)}function hex_hmac_md5(a,b){return rstr2hex(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function b64_hmac_md5(a,b){return rstr2b64(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(b)))}function any_hmac_md5(a,c,b){return rstr2any(rstr_hmac_md5(str2rstr_utf8(a),str2rstr_utf8(c)),b)}function md5_vm_test(){return hex_md5("abc").toLowerCase()=="900150983cd24fb0d6963f7d28e17f72"}function rstr_md5(a){return binl2rstr(binl_md5(rstr2binl(a),a.length*8))}function rstr_hmac_md5(c,f){var e=rstr2binl(c);if(e.length&amp;gt;16){e=binl_md5(e,c.length*8)}var a=Array(16),d=Array(16);for(var b=0;b&amp;lt;16;b++){a[b]=e[b]^909522486;d[b]=e[b]^1549556828}var g=binl_md5(a.concat(rstr2binl(f)),512+f.length*8);return binl2rstr(binl_md5(d.concat(g),512+128))}function rstr2hex(c){try{hexcase}catch(g){hexcase=0}var f=hexcase?"0123456789ABCDEF":"0123456789abcdef";var b="";var a;for(var d=0;d&amp;lt;c.length;d++){a=c.charCodeAt(d);b+=f.charAt((a&amp;gt;&amp;gt;&amp;gt;4)&amp;amp;15)+f.charAt(a&amp;amp;15)}return b}function rstr2b64(c){try{b64pad}catch(h){b64pad=""}var g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b="";var a=c.length;for(var f=0;f&amp;lt;a;f+=3){var k=(c.charCodeAt(f)&amp;lt;&amp;lt;16)|(f+1&amp;lt;a?c.charCodeAt(f+1)&amp;lt;&amp;lt;8:0)|(f+2&amp;lt;a?c.charCodeAt(f+2):0);for(var d=0;d&amp;lt;4;d++){if(f*8+d*6&amp;gt;c.length*8){b+=b64pad}else{b+=g.charAt((k&amp;gt;&amp;gt;&amp;gt;6*(3-d))&amp;amp;63)}}}return b}function rstr2any(m,c){var b=c.length;var l,f,a,n,e;var k=Array(Math.ceil(m.length/2));for(l=0;l&amp;lt;k.length;l++){k[l]=(m.charCodeAt(l*2)&amp;lt;&amp;lt;8)|m.charCodeAt(l*2+1)}var h=Math.ceil(m.length*8/(Math.log(c.length)/Math.log(2)));var g=Array(h);for(f=0;f&amp;lt;h;f++){e=Array();n=0;for(l=0;l&amp;lt;k.length;l++){n=(n&amp;lt;&amp;lt;16)+k[l];a=Math.floor(n/b);n-=a*b;if(e.length&amp;gt;0||a&amp;gt;0){e[e.length]=a}}g[f]=n;k=e}var d="";for(l=g.length-1;l&amp;gt;=0;l--){d+=c.charAt(g[l])}return d}function str2rstr_utf8(c){var b="";var d=-1;var a,e;while(++d&amp;lt;c.length){a=c.charCodeAt(d);e=d+1&amp;lt;c.length?c.charCodeAt(d+1):0;if(55296&amp;lt;=a&amp;amp;&amp;amp;a&amp;lt;=56319&amp;amp;&amp;amp;56320&amp;lt;=e&amp;amp;&amp;amp;e&amp;lt;=57343){a=65536+((a&amp;amp;1023)&amp;lt;&amp;lt;10)+(e&amp;amp;1023);d++}if(a&amp;lt;=127){b+=String.fromCharCode(a)}else{if(a&amp;lt;=2047){b+=String.fromCharCode(192|((a&amp;gt;&amp;gt;&amp;gt;6)&amp;amp;31),128|(a&amp;amp;63))}else{if(a&amp;lt;=65535){b+=String.fromCharCode(224|((a&amp;gt;&amp;gt;&amp;gt;12)&amp;amp;15),128|((a&amp;gt;&amp;gt;&amp;gt;6)&amp;amp;63),128|(a&amp;amp;63))}else{if(a&amp;lt;=2097151){b+=String.fromCharCode(240|((a&amp;gt;&amp;gt;&amp;gt;18)&amp;amp;7),128|((a&amp;gt;&amp;gt;&amp;gt;12)&amp;amp;63),128|((a&amp;gt;&amp;gt;&amp;gt;6)&amp;amp;63),128|(a&amp;amp;63))}}}}}return b}function str2rstr_utf16le(b){var a="";for(var c=0;c&amp;lt;b.length;c++){a+=String.fromCharCode(b.charCodeAt(c)&amp;amp;255,(b.charCodeAt(c)&amp;gt;&amp;gt;&amp;gt;8)&amp;amp;255)}return a}function str2rstr_utf16be(b){var a="";for(var c=0;c&amp;lt;b.length;c++){a+=String.fromCharCode((b.charCodeAt(c)&amp;gt;&amp;gt;&amp;gt;8)&amp;amp;255,b.charCodeAt(c)&amp;amp;255)}return a}function rstr2binl(b){var a=Array(b.length&amp;gt;&amp;gt;2);for(var c=0;c&amp;lt;a.length;c++){a[c]=0}for(var c=0;c&amp;lt;b.length*8;c+=8){a[c&amp;gt;&amp;gt;5]|=(b.charCodeAt(c/8)&amp;amp;255)&amp;lt;&amp;lt;(c%32)}return a}function binl2rstr(b){var a="";for(var c=0;c&amp;lt;b.length*32;c+=8){a+=String.fromCharCode((b[c&amp;gt;&amp;gt;5]&amp;gt;&amp;gt;&amp;gt;(c%32))&amp;amp;255)}return a}function binl_md5(p,k){p[k&amp;gt;&amp;gt;5]|=128&amp;lt;&amp;lt;((k)%32);p[(((k+64)&amp;gt;&amp;gt;&amp;gt;9)&amp;lt;&amp;lt;4)+14]=k;var o=1732584193;var n=-271733879;var m=-1732584194;var l=271733878;for(var g=0;g&amp;lt;p.length;g+=16){var j=o;var h=n;var f=m;var e=l;o=md5_ff(o,n,m,l,p[g+0],7,-680876936);l=md5_ff(l,o,n,m,p[g+1],12,-389564586);m=md5_ff(m,l,o,n,p[g+2],17,606105819);n=md5_ff(n,m,l,o,p[g+3],22,-1044525330);o=md5_ff(o,n,m,l,p[g+4],7,-176418897);l=md5_ff(l,o,n,m,p[g+5],12,1200080426);m=md5_ff(m,l,o,n,p[g+6],17,-1473231341);n=md5_ff(n,m,l,o,p[g+7],22,-45705983);o=md5_ff(o,n,m,l,p[g+8],7,1770035416);l=md5_ff(l,o,n,m,p[g+9],12,-1958414417);m=md5_ff(m,l,o,n,p[g+10],17,-42063);n=md5_ff(n,m,l,o,p[g+11],22,-1990404162);o=md5_ff(o,n,m,l,p[g+12],7,1804603682);l=md5_ff(l,o,n,m,p[g+13],12,-40341101);m=md5_ff(m,l,o,n,p[g+14],17,-1502002290);n=md5_ff(n,m,l,o,p[g+15],22,1236535329);o=md5_gg(o,n,m,l,p[g+1],5,-165796510);l=md5_gg(l,o,n,m,p[g+6],9,-1069501632);m=md5_gg(m,l,o,n,p[g+11],14,643717713);n=md5_gg(n,m,l,o,p[g+0],20,-373897302);o=md5_gg(o,n,m,l,p[g+5],5,-701558691);l=md5_gg(l,o,n,m,p[g+10],9,38016083);m=md5_gg(m,l,o,n,p[g+15],14,-660478335);n=md5_gg(n,m,l,o,p[g+4],20,-405537848);o=md5_gg(o,n,m,l,p[g+9],5,568446438);l=md5_gg(l,o,n,m,p[g+14],9,-1019803690);m=md5_gg(m,l,o,n,p[g+3],14,-187363961);n=md5_gg(n,m,l,o,p[g+8],20,1163531501);o=md5_gg(o,n,m,l,p[g+13],5,-1444681467);l=md5_gg(l,o,n,m,p[g+2],9,-51403784);m=md5_gg(m,l,o,n,p[g+7],14,1735328473);n=md5_gg(n,m,l,o,p[g+12],20,-1926607734);o=md5_hh(o,n,m,l,p[g+5],4,-378558);l=md5_hh(l,o,n,m,p[g+8],11,-2022574463);m=md5_hh(m,l,o,n,p[g+11],16,1839030562);n=md5_hh(n,m,l,o,p[g+14],23,-35309556);o=md5_hh(o,n,m,l,p[g+1],4,-1530992060);l=md5_hh(l,o,n,m,p[g+4],11,1272893353);m=md5_hh(m,l,o,n,p[g+7],16,-155497632);n=md5_hh(n,m,l,o,p[g+10],23,-1094730640);o=md5_hh(o,n,m,l,p[g+13],4,681279174);l=md5_hh(l,o,n,m,p[g+0],11,-358537222);m=md5_hh(m,l,o,n,p[g+3],16,-722521979);n=md5_hh(n,m,l,o,p[g+6],23,76029189);o=md5_hh(o,n,m,l,p[g+9],4,-640364487);l=md5_hh(l,o,n,m,p[g+12],11,-421815835);m=md5_hh(m,l,o,n,p[g+15],16,530742520);n=md5_hh(n,m,l,o,p[g+2],23,-995338651);o=md5_ii(o,n,m,l,p[g+0],6,-198630844);l=md5_ii(l,o,n,m,p[g+7],10,1126891415);m=md5_ii(m,l,o,n,p[g+14],15,-1416354905);n=md5_ii(n,m,l,o,p[g+5],21,-57434055);o=md5_ii(o,n,m,l,p[g+12],6,1700485571);l=md5_ii(l,o,n,m,p[g+3],10,-1894986606);m=md5_ii(m,l,o,n,p[g+10],15,-1051523);n=md5_ii(n,m,l,o,p[g+1],21,-2054922799);o=md5_ii(o,n,m,l,p[g+8],6,1873313359);l=md5_ii(l,o,n,m,p[g+15],10,-30611744);m=md5_ii(m,l,o,n,p[g+6],15,-1560198380);n=md5_ii(n,m,l,o,p[g+13],21,1309151649);o=md5_ii(o,n,m,l,p[g+4],6,-145523070);l=md5_ii(l,o,n,m,p[g+11],10,-1120210379);m=md5_ii(m,l,o,n,p[g+2],15,718787259);n=md5_ii(n,m,l,o,p[g+9],21,-343485551);o=safe_add(o,j);n=safe_add(n,h);m=safe_add(m,f);l=safe_add(l,e)}return Array(o,n,m,l)}function md5_cmn(h,e,d,c,g,f){return safe_add(bit_rol(safe_add(safe_add(e,h),safe_add(c,f)),g),d)}function md5_ff(g,f,k,j,e,i,h){return md5_cmn((f&amp;amp;k)|((~f)&amp;amp;j),g,f,e,i,h)}function md5_gg(g,f,k,j,e,i,h){return md5_cmn((f&amp;amp;j)|(k&amp;amp;(~j)),g,f,e,i,h)}function md5_hh(g,f,k,j,e,i,h){return md5_cmn(f^k^j,g,f,e,i,h)}function md5_ii(g,f,k,j,e,i,h){return md5_cmn(k^(f|(~j)),g,f,e,i,h)}function safe_add(a,d){var c=(a&amp;amp;65535)+(d&amp;amp;65535);var b=(a&amp;gt;&amp;gt;16)+(d&amp;gt;&amp;gt;16)+(c&amp;gt;&amp;gt;16);return(b&amp;lt;&amp;lt;16)|(c&amp;amp;65535)}function bit_rol(a,b){return(a&amp;lt;&amp;lt;b)|(a&amp;gt;&amp;gt;&amp;gt;(32-b))};

            function genNonce(b){var c=[],e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",a=e.length;for(var d=0;d&amp;lt;b;++d){c.push(e[Math.random()*a|0])}return c.join("")};

            $(function()
            {
                $('#btn').click(
                    function() { HttpDigest("John", 'pass', 'http://localhost:3000', '/', function(d){ console.log(d) } ); }
                );
            });

            //function addInfo( key, val ) { $('#data').append( '&amp;lt;tr&amp;gt;&amp;lt;td class="H"&amp;gt;&amp;lt;b&amp;gt;' + key + '&amp;lt;/b&amp;gt;&amp;amp;nbsp&amp;amp;nbsp&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;' + val + '&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;' ); }

            function HttpDigest( USER, TOKEN, URL, URI, callback )
            {
                var nonce,  // unique string value specified by the server
                    realm,  // authentication realm, defaults to "IsmuserAPI"
                    qop;    // list of quality of protection values supported by the server (auth | auth-int); auth set.

                var cnonce  = genNonce( 10 ); // opaque random string value provided by the client
                var nc      = 0;              // count of the number of requests (including the current request) that the client has sent with the nonce value

                /* 
                 * Simple tokenization to start with:
                 *
                 * This will turn a WWW-Authenticate header field like:

                 * WWW-Authenticate: Digest realm="your.realm",
                                            qop="auth",
                                            nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093"
                 * into:
                 *
                 *  ['Digest', 'realm="your.realm"', 'qop="auth"', 'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093"']
                 */
                var ws      = '(?:(?:\\r\\n)?[ \\t])+',
                    token   = '(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2E\\x30-\\x39\\x3F\\x41-\\x5A\\x5E-\\x7A\\x7C\\x7E]+)',
                    quotedString = '"(?:[\\x00-\\x0B\\x0D-\\x21\\x23-\\x5B\\\\x5D-\\x7F]|'+ws+'|\\\\[\\x00-\\x7F])*"',
                    tokenizer = RegExp(token+'(?:=(?:'+quotedString+'|'+token+'))?', 'g');


                // Parse the parameters (check existence and validity) and extract the values. 
                // Note that quoted-string values can be folded, so you need to unfold them with this function                  
                function unq(quotedString) { return quotedString.substr(1, quotedString.length-2).replace(/(?:(?:\r\n)?[ \t])+/g, " "); }


                var method  = "GET";
                var dType   = "JSON";

                // 1º ajax call, to get the cnonce (server nonce)
                var ajaxObj = $.ajax
                ({
                    url         : URL,
                    type        : method,
                    dataType    : dType,
                    crossDomain : true,
                    statusCode:
                    {
                        401: function () 
                        {
                            // Read the HTTP authentication header to get the nonce, realm and qop
                            var tokens = ( ajaxObj.getResponseHeader("WWW-Authenticate")
                                        // this is nasty, ugly-looking and disgusting but necessary to cheat "the great Safari browser"
                                        || ajaxObj.getResponseHeader("Content-Type") ) 
                                            .match(tokenizer);

                            $.each(tokens, function(index, value)
                            {
                                if (value.match ("WWW-Authenticate")) nonce = unq(value.split('=')[1]);
                                if (value.match ("realm"))            realm = unq(value.split('=')[1]);
                                if (value.match ("qop"))              qop   = unq(value.split('=')[1]);
                            });

                            /*
                             * HA1 = MD5(USER:REALM:PASS) --&amp;gt; john:your.realm:pass
                             */
                            var HA1 = hex_md5(USER + ":" + realm + ":" + TOKEN);

                            /*
                             * HA2 = MD5(METHOD:URI)--&amp;gt; GET:your.realm
                             */
                            var HA2 = hex_md5(method + ":" + URI);

                            /*
                             * response = digest = MD5(HA1 + ":" + NONCE + ":" + NC + ":" + CNONCE + ":" + QOP + ":" + HA2);
                             */
                            var res = hex_md5(HA1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + HA2);

                            /*
                             *  Authorization header:
                             *
                             *  Authorization:  Digest username="John", realm="your.realm", 
                                                nonce="k7KYbGJOCIw4RAK0IcaUQsYszXwsJGOU", uri="/", 
                                                cnonce="MDAwODM0", nc=00000001, qop="auth", 
                                                response="77f88f3f6b4623eedf17af206098ebf8"
                             */
                            var header = 'Digest username="' + USER + '", realm="' + realm
                                        + '", nonce="' + nonce + '", uri="' + URI + '", cnonce="' 
                                        + cnonce + '", nc="' + nc + '", qop="' + qop + '", response="' 
                                        + res + '"';

                            // now we've already built the digest, let's make another request to the server to get the data
                            var request = $.ajax
                            ({
                                url         : URL,
                                type        : method,
                                dataType    : dType,
                                crossDomain : true,
                                contentType : 'application/json',
                                headers     : { "Authorization": header }
                            })
                            .fail(function ( jqXHR, status, error ) { callback( { status : status, error : error, statusCode : jqXHR.status } ); })
                            .done(function ( data, status, jqXHR )  { callback( data ); });
                        } // end 401 status code
                    } // end statusCode
                }); // end ajaxCall
            } // end HttpDigest()

        &amp;lt;/script&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;center&amp;gt;
            &amp;lt;p&amp;gt; Http Digest &amp;lt;/p&amp;gt;
            &amp;lt;button id="btn" type="button"&amp;gt;Request&amp;lt;/button&amp;gt;
            &amp;lt;table id="data"&amp;gt;&amp;lt;/table&amp;gt;
        &amp;lt;/center&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and App.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var express= require('express'),
    passport       = require('passport'), // passportjs
    DigestStrategy = require('passport-http').DigestStrategy; // http digest

// #############################################################################################################

// ----------------
// Environment conf
// ----------------
var app = express();

// configure Express
app.configure(function()
{
    app.use(express.logger());

    app.use(express.methodOverride());

    // Initialize Passport! Note: no need to use session middleware when each
    // request carries authentication credentials, as is the case with HTTP
    // Digest.
    app.use(passport.initialize());

    app.use(app.router);
    app.use(express.static( __dirname + '/public' ));
});

app.configure( 'development', function () { app.use( express.errorHandler( { dumpExceptions: true, showStack: true } ) ); });
app.configure( 'production',  function () { app.use( express.errorHandler() ); } );

// #############################################################################################################

// fake database
var users = [
    { id: 1, username: 'John', password: 'pass',     domain: "http://localhost:2563/", email: 'john@example.com' }
  , { id: 2, username: 'joe',  password: 'birthday', domain: "www.domain.com",         email: 'joe@example.com' }
];

// #############################################################################################################

function findByUsername( username, fn )
{
    for (var i = 0, len = users.length; i &amp;lt; len; i++)
    {
        var user = users[i];
        if (user.username === username) return fn( null, user );
    }
    return fn(null, null);
}

// -------------
// Passport conf
// -------------

// Use the DigestStrategy within Passport.
// This strategy requires a `secret`function, which is used to look up the
// use and the user's password known to both the client and server. The
// password is used to compute a hash, and authentication will fail if the
// computed value does not match that of the request. Also required is a
// `validate` function, which can be used to validate nonces and other
// authentication parameters contained in the request.
passport.use
(
  new DigestStrategy(
    { qop: 'auth', realm: 'your.realm' },
    function( username, done )
    {
        // Find the user by username. If there is no user with the given username
        // set the user to `false` to indicate failure. Otherwise, return the
        // user and user's password.
        findByUsername(
            username, 
            function( err, user )
            {
                if ( err )   return done( err );
                if ( !user ) return done( null, false );
                return done( null, user, user.password );
            }
        );
    },
    function( params, done ) // second callback
    {
        // asynchronous validation, for effect...
        process.nextTick(
            function ()
            {
                // check nonces in params here, if desired
                console.log( params );
                /*
                nonce: 'MYto1vSuu6eK9PMNNYAqIdsmUXOA2ppU',
                cnonce: 'MDA4NjY5',
                nc: '00000001',
                opaque: undefined }
                */
                return done( null, true );
            }
        );
    }
));

// #################################################################################

app.all(
    '/',
    // Authenticate using HTTP Digest credentials, with session support disabled.
    passport.authenticate( 'digest', { session: false } ),
    function( req, res )
    {
        /************************************************/
        //  CROSS-DOMAIN RESOURCE SHARING
        res.setHeader( 'Access-Control-Allow-Origin', '*' );
        /************************************************/

        // domain check
        if ( req.user.domain.match( req.headers.origin ) )
          res.json( { logged: true, username: req.user.username, email: req.user.email } );
    }
);

app.listen( 3000 );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In digest.js you can specify your authentication realm.&lt;/p&gt;

&lt;p&gt;‘digest.js’  (line 74; node_modules/passport-http/lib/passport-http/strategies)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this._realm = options.realm || 'your.realm';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authenticate.js (node_modules/passport/lib/passport/middleware; line 150).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The W3 spec for CORS preflight requests clearly states that user credentials should be excluded. There is a bug in Chrome and WebKit where OPTIONS requests returning a status of 401 still send the subsequent request.

Firefox has a related bug filed that ends with a link to the W3 public webapps mailing list asking for the CORS spec to be changed to allow authentication headers to be sent on the OPTIONS request at the benefit of IIS users. Basically, they are waiting for those servers to be obsoleted.

How can I get the OPTIONS request to send and respond consistently?

Simply have the server (API in this example) respond to OPTIONS requests without requiring authentication (http://stackoverflow.com/a/15734032).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In order to allow CORS requests ant to be able to read the info that the server sends, we need to expose the WWW-Authenticate header and the GET and OPTIONS methods.&lt;/p&gt;

&lt;p&gt;A special situation happens. Safari for windows does not read theWWW-Authenticate header though exposed. So we have to expose another one.&lt;/p&gt;

&lt;p&gt;‘Authenticate.js’&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; res.statusCode = rstatus || 401;
      if ( req.method === "OPTIONS" ) res.statusCode = rstatus || 200;

      if (rchallenge.length)
      {
        res.setHeader('WWW-Authenticate', rchallenge);
        res.setHeader('Content-Type', rchallenge);

        /**********************************/
        /* MODIFIED TO FULFIL DIGEST AUTH */
        /**********************************/
        res.setHeader('Access-Control-Expose-Headers', 'WWW-Authenticate, Content-Type');

        res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
        res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
        res.setHeader('Access-Control-Allow-Origin', '*');

        /**********************************/
      }
      res.end('Unauthorized');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Why not to change the working directory on Microsoft Machine Learning Server</title>
      <dc:creator>Leo Lanchas</dc:creator>
      <pubDate>Sat, 14 Apr 2018 13:10:56 +0000</pubDate>
      <link>https://forem.com/leolanchas/why-not-to-change-the-working-directory-on-microsoft-machine-learning-server-2bnm</link>
      <guid>https://forem.com/leolanchas/why-not-to-change-the-working-directory-on-microsoft-machine-learning-server-2bnm</guid>
      <description>

&lt;p&gt;Some time ago I was developing an R service that used MicrosoftR, now called Machine Learning Server, which instead of creating a model as suggested in the documentation &lt;a href="https://docs.microsoft.com/en-us/machine-learning-server/operationalize/how-to-deploy-web-service-publish-manage-in-r#standard-workflow-examples"&gt;&lt;strong&gt;&lt;em&gt;examples&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; it just run R routines which operated over a &lt;a href="https://cran.r-project.org/web/packages/data.table/vignettes/datatable-intro.html"&gt;&lt;strong&gt;&lt;em&gt;data.table&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; . Therefore, I needed to load my code on each call to the API service since you are not able to use &lt;a href="https://docs.microsoft.com/en-us/machine-learning-server/r/how-to-execute-code-remotely#r-session-snapshots"&gt;&lt;strong&gt;&lt;em&gt;snapshots&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; but only when working with the R-Client (not on any web application).&lt;/p&gt;

&lt;p&gt;The problem rises at the moment I tried to change the working directory. As I used relative paths for my different modules, for example:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source('/home/administrator/src/MyMainFile.R')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;which in turn loaded some other modules, but as I say, through relative routes:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source('/utils.R')
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I needed to set my base directory. As a consequence, after 3 or, luckily, 4 really slow executions, the web node crushed and the only log message I got was:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "Link": null, "Message": "c66b3558-9d60-4620-adba-1429fc5355ab", "ExceptionType": null } { "Link": null, "Message": "b16bdf62-1396-4be9-ad54-bd1ed59f0d35", "ExceptionType": null }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No one in MicrosoftR forums gave just only 1 answer. So after days of hitting my head against the wall (because I had deeply and thoroughly tested my code), I decided to just republish the service one line at a time and run it 3 or 4 times. My surprise was huge when only the first line &lt;strong&gt;setwd(‘my/base/directory’)&lt;/strong&gt; was responsible for my desperation. It’s even worse when you see that this is not documented in Microsoft docs.&lt;/p&gt;

&lt;p&gt;So the solution was simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove &lt;strong&gt;setwd()&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use absolute paths&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Nevertheless, after that experience I decided to never work again with MLS without making a package, so from that moment on I use &lt;a href="https://cran.r-project.org/web/packages/Rcpp/index.html"&gt;&lt;strong&gt;&lt;em&gt;Rcpp&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; and &lt;a href="https://cran.r-project.org/web/packages/R6/vignettes/Introduction.html"&gt;&lt;strong&gt;&lt;em&gt;R6Classes&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="http://leolanchas.ml/blog/2018/04/14/not-change-working-directory-machine-learning-server/"&gt;&lt;em&gt;leolanchas.ml&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on April 14, 2018.&lt;/em&gt;&lt;/p&gt;


</description>
      <category>datascience</category>
      <category>microsoft</category>
      <category>machinelearning</category>
      <category>r</category>
    </item>
    <item>
      <title>Debugging a Node.js application, with node-inspector, within a virtual machine.</title>
      <dc:creator>Leo Lanchas</dc:creator>
      <pubDate>Sat, 15 Mar 2014 06:11:00 +0000</pubDate>
      <link>https://forem.com/leolanchas/debugging-a-nodejs-application-with-node-inspector-within-a-virtual-machine-cmp</link>
      <guid>https://forem.com/leolanchas/debugging-a-nodejs-application-with-node-inspector-within-a-virtual-machine-cmp</guid>
      <description>&lt;p&gt;If you use a virtual machine to develop your Node.js app and probably you use &lt;a href="http://vagrantup.com/" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; to configure and port your work environment, sooner or later you are going to need to debug.While node has a &lt;a href="http://vimeo.com/19465332" rel="noopener noreferrer"&gt;built in debugger&lt;/a&gt;, &lt;a href="https://github.com/node-inspector/node-inspector" rel="noopener noreferrer"&gt;node-inspector&lt;/a&gt; provides a pleasant graphical interface for debugging node programs. Node Inspector is a debugger interface for node.js using the WebKit Web Inspector, the familiar javascript debugger from Safari and Chrome.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;With &lt;a href="http://github.com/isaacs/npm" rel="noopener noreferrer"&gt;npm&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g node-inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Forwarding ports
&lt;/h3&gt;

&lt;p&gt;– The straight forward option is to open VirtualBox and go to the machine configuration settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F650%2F0%2ACCeEmqmKBIGrfPh0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F650%2F0%2ACCeEmqmKBIGrfPh0.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Virtual box machine settings&lt;/p&gt;

&lt;p&gt;And then to Network -&amp;gt; advanced-&amp;gt; port forwarding:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F650%2F0%2A5lR_0ZguAMkRlaCQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F650%2F0%2A5lR_0ZguAMkRlaCQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Virtual box port forwarding&lt;/p&gt;

&lt;p&gt;There you use VirtualBox’s Port Forwarding Rules window to forward ports. You don’t have to specify any IP addresses. Changes take effect immediately. — If you are using Vagrant, it’s easier. Write down this line in your vagrantfile (I use 3001 as an example)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config.vm.network :forwarded\_port, guest: 3001, host: 3001 # node-inspector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chages will take effect next time you start your virtual machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging with node-inspector
&lt;/h3&gt;

&lt;p&gt;Now you are all set to start using node-inspector. Go to your virtual machine console and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node --debug your\_program.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NOTE: make sure that the –debug flag comes before your/node/program.js or else you may see an EADDRINUSE error. and then, in another console, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node-inspector --web-port=3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use 3001 just as an example, you could use whatever you want. Now open &lt;a href="http://127.0.0.1:3001/debug?port=5858" rel="noopener noreferrer"&gt;http://127.0.0.1:3001/debug?port=5858&lt;/a&gt; in your favorite WebKit based browser. You should now see the javascript source from node. If you don’t, click the scripts tab. Select a script and set some breakpoints (far left line numbers) or simply add a debugger call in your code (node will break automatically on the call, just as V8 does).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="http://leolanchas.com/blog/2014/03/15/debugging-a-nodejs-application-with-node-inspector-within-a-virtual-machine/" rel="noopener noreferrer"&gt;&lt;em&gt;leolanchas.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on March 15, 2014.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>debugging</category>
      <category>node</category>
      <category>development</category>
    </item>
  </channel>
</rss>
