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 });