partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

WSSEAuthenticationProvider.js (4403B)


      1 /**
      2  * WSSE Authentication Provider
      3  */
      4 Ext.define('PartKeepr.Auth.WSSEAuthenticationProvider', {
      5     extend: 'PartKeepr.Auth.AuthenticationProvider',
      6 
      7     /**
      8      * @var {String} The WSSE secret
      9      */
     10     secret: null,
     11 
     12     /**
     13      * @var {String} The user's salt
     14      */
     15     salt: null,
     16 
     17     /**
     18      * Retrieves the salt for the user. Note that the authentication for WSSE is a two-part process:
     19      * In order to authenticate, we require the salt first to build the password hash.
     20      */
     21     authenticate: function ()
     22     {
     23         PartKeepr.AuthBundle.Entity.User.callPostCollectionAction("getSalt",
     24             {
     25                 username: this.getUsername()
     26             },
     27             Ext.bind(this.onSaltRetrieved, this)
     28         );
     29     },
     30 
     31     /**
     32      * Callback when the salt was received. Generates the secret and attempts to login the user.
     33      *
     34      * @param {Object} options
     35      * @param {Object} success
     36      * @param {Object} response
     37      */
     38     onSaltRetrieved: function (options, success, response)
     39     {
     40         this.salt = Ext.decode(response.responseText);
     41 
     42         this.generateSecret();
     43 
     44         PartKeepr.AuthBundle.Entity.User.callPostCollectionAction("login",
     45             {},
     46             Ext.bind(this.onLogin, this),
     47             true
     48         );
     49 
     50     },
     51 
     52     /**
     53      * @method add
     54      * @inheritdoc PartKeepr.Auth.AuthenticationProvider#getHeaders
     55      */
     56     getHeaders: function ()
     57     {
     58         if (this.secret !== null) {
     59             return {"X-WSSE": this.getWSSE()};
     60         }
     61     },
     62 
     63     /**
     64      * Generates the WSSE Secret
     65      */
     66     generateSecret: function ()
     67     {
     68         this.secret = CryptoJS.enc.Base64.stringify(CryptoJS.SHA512(this.getPassword() + "{" + this.salt + "}"));
     69     },
     70 
     71     /**
     72      * Generates the nonce
     73      *
     74      * @param {Integer} length The length of the nonce
     75      * @return {String} The generated nonce
     76      */
     77     generateNonce: function (length)
     78     {
     79         var nonceChars = "0123456789abcdef";
     80         var result = "";
     81         for (var i = 0; i < length; i++) {
     82             result += nonceChars.charAt(Math.floor(Math.random() * nonceChars.length));
     83         }
     84         return result;
     85     },
     86 
     87     /**
     88      * Returns a W3C-Compliant date
     89      *
     90      * @param {Object} date The DateTime object to convert
     91      * @return {String} The W3C-compliant date
     92      */
     93     getW3CDate: function (date)
     94     {
     95         var yyyy = date.getUTCFullYear();
     96         var mm = (date.getUTCMonth() + 1);
     97         if (mm < 10) {
     98             mm = "0" + mm;
     99         }
    100         var dd = (date.getUTCDate());
    101         if (dd < 10) {
    102             dd = "0" + dd;
    103         }
    104         var hh = (date.getUTCHours());
    105         if (hh < 10) {
    106             hh = "0" + hh;
    107         }
    108         var mn = (date.getUTCMinutes());
    109         if (mn < 10) {
    110             mn = "0" + mn;
    111         }
    112         var ss = (date.getUTCSeconds());
    113         if (ss < 10) {
    114             ss = "0" + ss;
    115         }
    116         return yyyy + "-" + mm + "-" + dd + "T" + hh + ":" + mn + ":" + ss + "Z";
    117     },
    118 
    119     /**
    120      * Returns the WSSE string for authentication
    121      *
    122      * @return {String}
    123      */
    124     getWSSE: function ()
    125     {
    126         var nonce = this.generateNonce(16);
    127         var nonce64 = base64_encode(nonce);
    128         var created = this.getW3CDate(new Date());
    129 
    130         var digest = this.encodePassword(nonce + created + this.secret, this.salt, 1);
    131         return "UsernameToken Username=\""
    132             + this.getUsername() + "\", PasswordDigest=\""
    133             + digest + "\", Nonce=\""
    134             + nonce64 + "\", Created=\""
    135             + created + "\"";
    136     },
    137 
    138     /**
    139      * Merges the password and salt
    140      *
    141      * @param {String} raw The raw password
    142      * @param {String} salt The salt
    143      */
    144     mergePasswordAndSalt: function (raw, salt)
    145     {
    146         return raw + "{" + salt + "}";
    147     },
    148 
    149     /**
    150      * Encodes the password with the salt and a specific number of iterations
    151      *
    152      * @param {String} raw The raw password
    153      * @param {String} salt The salt
    154      * @param {Integer} iterations The number of iterations
    155      */
    156     encodePassword: function (raw, salt, iterations)
    157     {
    158         var salted = this.mergePasswordAndSalt(raw, salt);
    159 
    160         var digest = CryptoJS.SHA512(salted);
    161 
    162         for (var i = 1; i < digest; i++) {
    163             digest = CryptoJS.SHA512(digest + salted);
    164         }
    165 
    166         return CryptoJS.enc.Base64.stringify(digest);
    167     }
    168 });