1 // ${project.version}
2 var exec = require('cordova/exec');
3
4 /**
5 * The AuthProxy plugin provides the ability to make HTTPS requests with mutual authentication.<br/>
6 * <br/>
7 * The regular XMLHttpRequest does not
8 * support mutual authentication. The AuthProxy plugin allows you to specify a certificate to include in an HTTPS request
9 * to identify the client to the server. This allows the server to verify the identity of the client. An example of where you
10 * might need mutual authentication is the onboarding process to register with an application, or, to access an
11 * OData producer. This occurs mostly in Business to Business (B2B) applications. This is different from most business to
12 * consumer (B2C) Web sites, where it is only the server that authenticates itself to the client with a certificate.<br/>
13 * <br/>
14 * <b>Adding and Removing the AuthProxy Plugin</b><br/>
15 * Add or remove the AuthProxy plugin using the
16 * <a href="http://cordova.apache.org/docs/en/edge/guide_cli_index.md.html#The%20Command-line%20Interface">Cordova CLI</a>.<br/>
17 * <br/>
18 * To add the AuthProxy plugin to your project, use the following command:<br/>
19 * cordova plugin add <path to directory containing Kapsel plugins>\authproxy<br/>
20 * <br/>
21 * To remove the AuthProxy plugin from your project, use the following command:<br/>
22 * cordova plugin rm com.sap.mp.cordova.plugins.authproxy
23 * @namespace
24 * @alias AuthProxy
25 * @memberof sap
26 */
27 var AuthProxy = function () {};
28
29
30 /**
31 * Constant definitions for registration methods
32 */
33
34 /**
35 * Constant indicating the operation failed with unknown error. Used as a possible value for the
36 * errorCode in {@link sap.AuthProxy~errorCallback}.
37 * @constant
38 * @type number
39 */
40 AuthProxy.prototype.ERR_UNKNOWN = -1;
41
42 /**
43 * Constant indicating the operation failed due to an invalid parameter (for example, a string was passed where a number was
44 * required). Used as a possible value for the errorCode in {@link sap.AuthProxy~errorCallback}.
45 * @constant
46 * @type number
47 */
48 AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE = -2;
49
50 /**
51 * Constant indicating the operation failed because of a missing parameter. Used as a possible value for the
52 * errorCode in {@link sap.AuthProxy~errorCallback}.
53 * @constant
54 * @type number
55 */
56 AuthProxy.prototype.ERR_MISSING_PARAMETER = -3;
57
58 /**
59 * Constant indicating there is no such Cordova action for the current service. When a Cordova plugin calls into native
60 * code it specifies an action to perform. If the action provided by the JavaScript is unknown to the native code this
61 * error occurs. This error should not occur as long as authproxy.js is unmodified. Used as a possible
62 * value for the errorCode in {@link sap.AuthProxy~errorCallback}.
63 * @constant
64 * @type number
65 */
66 AuthProxy.prototype.ERR_NO_SUCH_ACTION = -100;
67
68 /**
69 * Constant indicating the certificate from file is not supported on the current platform. Used as a possible value for the
70 * errorCode in {@link sap.AuthProxy~errorCallback}.
71 * @constant
72 * @type number
73 */
74 AuthProxy.prototype.ERR_FILE_CERTIFICATE_SOURCE_UNSUPPORTED = -101;
75
76 /**
77 * Constant indicating the certificate from the system keystore is not supported on the current platform. Used as a possible value
78 * for the errorCode in {@link sap.AuthProxy~errorCallback}.
79 * @constant
80 * @type number
81 */
82 AuthProxy.prototype.ERR_SYSTEM_CERTIFICATE_SOURCE_UNSUPPORTED = -102;
83
84 /**
85 * Constant indicating the certificate with the given alias could not be found. Used as a possible value for the
86 * errorCode in {@link sap.AuthProxy~errorCallback}.
87 * @constant
88 * @type number
89 */
90 AuthProxy.prototype.ERR_CERTIFICATE_ALIAS_NOT_FOUND = -104;
91
92 /**
93 * Constant indicating the certificate file could not be found. Used as a possible value for the
94 * errorCode in {@link sap.AuthProxy~errorCallback}.
95 * @constant
96 * @type number
97 */
98 AuthProxy.prototype.ERR_CERTIFICATE_FILE_NOT_EXIST = -105;
99
100 /**
101 * Constant indicating incorrect certificate file format. Used as a possible value for the
102 * errorCode in {@link sap.AuthProxy~errorCallback}.
103 * @constant
104 * @type number
105 */
106 AuthProxy.prototype.ERR_CERTIFICATE_INVALID_FILE_FORMAT = -106;
107
108 /**
109 * Constant indicating failure in getting the certificate. Used as a possible value for the
110 * errorCode in {@link sap.AuthProxy~errorCallback}.
111 * @constant
112 * @type number
113 */
114 AuthProxy.prototype.ERR_GET_CERTIFICATE_FAILED = -107;
115
116 /**
117 * Constant indicating the provided certificate failed validation on the server side. Used as a possible value for the
118 * errorCode in {@link sap.AuthProxy~errorCallback}.
119 * @constant
120 * @type number
121 */
122 AuthProxy.prototype.ERR_CLIENT_CERTIFICATE_VALIDATION = -108;
123
124 /**
125 * Constant indicating the server certificate failed validation on the client side. This is likely because the server certificate
126 * is self-signed, or not signed by a well-known certificate authority. This constant is used as a possible value for the
127 * errorCode in {@link sap.AuthProxy~errorCallback}.
128 * @constant
129 * @type number
130 */
131 AuthProxy.prototype.ERR_SERVER_CERTIFICATE_VALIDATION = -109;
132
133 /**
134 * Constant indicating the server request failed. Used as a possible value for the
135 * errorCode in {@link sap.AuthProxy~errorCallback}.
136 * @constant
137 * @type number
138 */
139 AuthProxy.prototype.ERR_SERVER_REQUEST_FAILED = -110;
140
141 /**
142 * Constant indicating the Logon Manager core library is not available. Getting this error code means you tried
143 * to use Logon plugin features (for example, a certificate from Logon) without adding the Logon plugin to the app.
144 * A possible value for the errorCode in {@link sap.AuthProxy~errorCallback}.
145 * @constant
146 * @type number
147 */
148 AuthProxy.prototype.ERR_LOGON_MANAGER_CORE_NOT_AVAILABLE = -111;
149
150 /**
151 * Constant indicating the Logon Manager certifciate method is not available. Used as a possible value for the
152 * errorCode in {@link sap.AuthProxy~errorCallback}.
153 * @constant
154 * @type number
155 */
156 AuthProxy.prototype.ERR_LOGON_MANAGER_CERTIFICATE_METHOD_NOT_AVAILABLE = -112;
157
158 /**
159 * Constant indicating timeout error while connecting to the server. Used as a possible value for the
160 * errorCode in {@link sap.AuthProxy~errorCallback}.
161 * @constant
162 * @type number
163 */
164 AuthProxy.prototype.ERR_HTTP_TIMEOUT = -120;
165
166 /**
167 * Constant indicating timeout error while connecting to the server. Used as a possible value for the
168 * errorCode in {@link sap.AuthProxy~errorCallback}.
169 * @constant
170 * @type number
171 */
172
173 /**
174 * Constant indicating a missing required parameter message. Used as a possible value for the description
175 * in (@link sap.AuthProxy~errorCallback}.
176 * @constant
177 * @type string
178 * @private
179 */
180 AuthProxy.prototype.MSG_MISSING_PARAMETER = "Missing a required parameter: ";
181
182 /**
183 * Constant indicating invalid parameter value message. Used as a possible value for the description
184 * in (@link sap.AuthProxy~errorCallback}.
185 * @constant
186 * @type string
187 * @private
188 */
189 AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE = "Invalid Parameter Value for parameter: ";
190
191 /**
192 * Create certificate source description object for a certificate from a keystore file. The keystore file must be of type PKCS12
193 * (usually a .p12 extension) since that is the only certificate file type that can contain a private key (a private key is needed
194 * to authenticate the client to the server). You might want to use this method if you know the desired certificate resides in a
195 * file on the filesystem.
196 * @class
197 * @param {string} Path The Path of the keystore file.<br/>For iOS clients, it first tries to load the
198 * relative file path from the application's Documents folder. If it fails, it then tries
199 * to load the file path from the application's main bundle. In addition, before trying
200 * to load the certificate from the file system, the iOS client first checks whether the
201 * specified certificate key already exists in the key store. If it does, it loads
202 * the existing certificate from the key store, instead of loading the certificate from the
203 * file system.<br/>
204 * For Android clients, the file path is first treated as an absolute path. If the certificate
205 * is not found, the file path is treated as relative to the root of the SD card.
206 * @param {string} Password The password of the keystore.
207 * @param {string} CertificateKey A unique key (alias) that is used to locate the certificate.
208 * @example
209 * // Create the certificate source description object.
210 * var fileCert = new sap.AuthProxy.CertificateFromFile("directory/certificateName.p12", "certificatePassword", "certificateKey");
211 * // callbacks
212 * var successCB = function(serverResponse){
213 * alert("Status: " + JSON.stringify(serverResponse.status));
214 * alert("Headers: " + JSON.stringify(serverResponse.headers));
215 * alert("Response: " + JSON.stringify(serverResponse.response));
216 * }
217 * var errorCB = function(errorObject){
218 * alert("Error making request: " + JSON.stringify(errorObject));
219 * }
220 * // Make the request with the certificate source description object.
221 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, fileCert);
222 *
223 */
224 AuthProxy.prototype.CertificateFromFile = function (Path, Password, CertificateKey) {
225 this.Source = "FILE";
226 this.Path = Path;
227 this.Password = Password;
228 this.CertificateKey = CertificateKey;
229 };
230
231 /**
232 * Create a certificate source description object for certificates from the system keystore. You might want to use a certificate
233 * from the system keystore if you know the user's device will have the desired certificate installed on it.<br/>
234 * On Android, sending a request with a certificate from the system store results in UI being shown, where the user can pick
235 * the certificate to use (the certificate with the alias matching the given CertificateKey is pre-selected).
236 * @class
237 * @param {string} CertificateKey A unique key (alias) that is used to locate the certificate.
238 * @example
239 * // Create the certificate source description object.
240 * var systemCert = new sap.AuthProxy.CertificateFromStore("certificatekey");
241 * // callbacks
242 * var successCB = function(serverResponse){
243 * alert("Status: " + JSON.stringify(serverResponse.status));
244 * alert("Headers: " + JSON.stringify(serverResponse.headers));
245 * alert("Response: " + JSON.stringify(serverResponse.response));
246 * }
247 * var errorCB = function(errorObject){
248 * alert("Error making request: " + JSON.stringify(errorObject));
249 * }
250 * // Make the request with the certificate source description object.
251 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, systemCert);
252 */
253 AuthProxy.prototype.CertificateFromStore = function (CertificateKey) {
254 this.Source = "SYSTEM";
255 this.CertificateKey = CertificateKey;
256 };
257
258
259 /**
260 * Create a certificate source description object for certificates from Logon Manager. Using the resulting certificate source description
261 * object on subsequent calls to AuthProxy.sendRequest or AuthProxy.get causes AuthProxy to retrieve a certificate from Logon Manager
262 * to use for client authentication. The appID parameter is used to indicate which application's certificate to use.<br/>
263 * Note: To use a certificate from Logon Manager, the application must have already registered with the server using a certificate from Afaria.
264 * @class
265 * @param {string} appID application identifier
266 * @example
267 * // Create the certificate source description object.
268 * var logonCert = new sap.AuthProxy.CertificateFromLogonManager("applicationID");
269 * // callbacks
270 * var successCB = function(serverResponse){
271 * alert("Status: " + JSON.stringify(serverResponse.status));
272 * alert("Headers: " + JSON.stringify(serverResponse.headers));
273 * alert("Response: " + JSON.stringify(serverResponse.response));
274 * }
275 * var errorCB = function(errorObject){
276 * alert("Error making request: " + JSON.stringify(errorObject));
277 * }
278 * // Make the request with the certificate source description object.
279 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null, null, 0, logonCert);
280 */
281 AuthProxy.prototype.CertificateFromLogonManager = function (appID) {
282 this.Source = "LOGON";
283 this.AppID = appID;
284 };
285
286
287 /**
288 * Verifies that a certificate source description object (created with {@link sap.AuthProxy#CertificateFromFile},
289 * {@link sap.AuthProxy#CertificateFromStore}, or {@link sap.AuthProxy#CertificateFromLogonManager}) has all the required fields and that the values
290 * for those fields are the correct type. This function verifies only the certificate description object, not the certificate itself. So, for example,
291 * if the certificate source description object was created with {@link sap.AuthProxy#CertificateFromFile} and has a string for the file path and a
292 * string for the key/alias, <b>this function considers it valid even if no certificate actually exists on the file system</b>. If the certificate
293 * source description object is valid but the certificate itself is not, then an error occurs during the call to {@link sap.AuthProxy#get} or
294 * {@link sap.AuthProxy#sendRequest}.
295 * @param {object} certSource The certificate source object.
296 * @param {sap.AuthProxy~errorCallback} errorCB The error callback invoked if the certificate source is not valid. Will have an object with 'errorCode'
297 * and 'description' properties.
298 * @example
299 * var notValidCert = {};
300 * var errorCallback = function(error){
301 * alert("certificate not valid!\nError code: " + error.errorCode + "\ndescription: " + error.description);
302 * }
303 * var isCertValid = sap.AuthProxy.validateCertSource(notValidCert, errorCallback);
304 * if( isCertValid ){
305 * // do stuff with the valid certificate source description object
306 * } else {
307 * // at this point we know the cert is not valid, and the error callback is invoked with extra information.
308 * }
309 *
310 *
311 * Developers are not expected to call this function.
312 * @private
313 */
314 AuthProxy.prototype.validateCertSource = function (certSource, errorCB) {
315 if (!certSource) {
316 // The certificate is not present, so just ignore it.
317 return true;
318 }
319
320 // errorCB required.
321 // First check this one. We may need it to return errors
322 if (errorCB && (typeof errorCB !== "function")) {
323 console.log("AuthProxy Error: errorCB is not a function");
324 return false;
325 }
326
327 try {
328 // First check whether it is an object
329 if (typeof certSource !== "object") {
330 errorCB({
331 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
332 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certSource"
333 });
334 return false;
335 }
336
337 if (certSource.Source === "FILE") {
338 if (!certSource.Path) {
339 errorCB({
340 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
341 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "keystore path"
342 });
343 return false;
344 }
345
346 if (typeof certSource.Path !== "string") {
347 errorCB({
348 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
349 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "keystore path"
350 });
351 return false;
352 }
353
354 if (!certSource.CertificateKey) {
355 errorCB({
356 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
357 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "certificate key"
358 });
359 return false;
360 }
361
362 if (typeof certSource.CertificateKey !== "string") {
363 errorCB({
364 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
365 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certificate key"
366 });
367 return false;
368 }
369 } else if (certSource.Source === "SYSTEM") {
370 if (!certSource.CertificateKey) {
371 errorCB({
372 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
373 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "certificate key"
374 });
375 return false;
376 }
377
378 if (typeof certSource.CertificateKey !== "string") {
379 errorCB({
380 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
381 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certificate key"
382 });
383 return false;
384 }
385 } else if (certSource.Source === "LOGON") {
386 if (!certSource.AppID) {
387 errorCB({
388 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
389 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "AppID"
390 });
391 return false;
392 }
393
394 if (typeof certSource.AppID !== "string") {
395 errorCB({
396 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
397 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "AppID"
398 });
399 return false;
400 }
401 } else {
402 errorCB({
403 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
404 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certSource"
405 });
406 return false;
407 }
408
409 return true;
410 } catch (ex) {
411 errorCB({
412 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
413 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "certSource"
414 });
415 }
416 };
417
418
419 /**
420 * Send an HTTP(S) request to a remote server. This function is the centerpiece of the AuthProxy plugin. It handles
421 * mutual authentication if a certificate source is provided.
422 * The success callback is invoked upon any response from the server, even responses not generally considered to be
423 * successful (such as 404 or 500 status codes) result in the success callback being invoked. The error callback
424 * is reserved for problems that prevent the AuthProxy from creating the request or contacting the server. It is, therefore,
425 * important to always check the status property on the object given to the success callback.
426 * @param {string} method Standard HTTP request method name.
427 * @param {string} url The HTTP URL with format http(s)://[user:password]@hostname[:port]/path.
428 * @param {Object} header HTTP header to send to the server. This is an Object. Can be null.
429 * @param {string} requestBody Data to send to the server with the request. Can be null.
430 * @param {sap.AuthProxy~successCallback} successCB Callback method invoked upon a response from the server.
431 * @param {sap.AuthProxy~errorCallback} errorCB Callback method invoked in case of failure.
432 * @param {string} [user] User ID for basic authentication.
433 * @param {string} [password] User password for basic authentication.
434 * @param {number} [timeout] Timeout setting in seconds. Default value (0) means there is no timeout.
435 * @param {Object} [certSource] Certificate description object. It can be one of {@link sap.AuthProxy#CertificateFromFile},
436 * {@link sap.AuthProxy#CertificateFromStore}, or {@link sap.AuthProxy#CertificateFromLogonManager}.
437 * @return {function} A JavaScript function object to abort the operation. Calling the abort function results in neither the success or error
438 * callback being invoked for the original request (excepting the case where the success or error callback was invoked before calling the
439 * abort function). Note: The request itself cannot be unsent, and the server will still receive the request, but the JavaScript will
440 * not know the results of that request.
441 * @example
442 * // callbacks
443 * var successCB = function(serverResponse){
444 * alert("Status: " + JSON.stringify(serverResponse.status));
445 * alert("Headers: " + JSON.stringify(serverResponse.headers));
446 * alert("Response: " + JSON.stringify(serverResponse.response));
447 * }
448 * var errorCB = function(errorObject){
449 * alert("Error making request: " + JSON.stringify(errorObject));
450 * }
451 * // To send a post request to the server, call the method
452 * var abortFunction = sap.AuthProxy.sendRequest("POST", "http://www.google.com", null, "THIS IS THE BODY", successCB, errorCB);
453 * // An example of aborting the request
454 * abortFunction();
455 *
456 * // To send a post request to the server with headers, call the method
457 * sap.AuthProxy.sendRequest("POST", url, {HeaderName : "Header value"}, "THIS IS THE BODY", successCB, errorCB);
458 *
459 * // To send a post request to the server with basic authentication, call the method
460 * sap.AuthProxy.sendRequest("POST", url, headers, "THIS IS THE BODY", successCB, errorCB, "username", "password");
461 *
462 * // To send a post request to the server with mutual authentication, call the method
463 * sap.AuthProxy.sendRequest("POST", "https://hostname", headers, "THIS IS THE BODY", successCB, errorCB, null,
464 * null, 0, new sap.AuthProxy.CertificateFromLogonManager("theAppId"));
465 */
466 AuthProxy.prototype.sendRequest = function (method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource) {
467
468 // errorCB required.
469 // First check this one. We may need it to return errors
470 if (!errorCB || (typeof errorCB !== "function")) {
471 console.log("AuthProxy Error: errorCB is not a function");
472 // if error callback is invalid, throw an exception to notify the caller
473 throw new Error("AuthProxy Error: errorCB is not a function");
474 }
475
476 // method required
477 if (!method) {
478 console.log("AuthProxy Error: method is required");
479 errorCB({
480 errorCode: AuthProxy.prototype.ERR_MISSING_PARAMETER,
481 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "method"
482 });
483 return;
484 }
485
486
487 // We only support GET, POST, HEAD, PUT, DELETE method
488 if (method !== "GET" && method !== "POST" && method !== "HEAD" && method !== "PUT" && method !== "DELETE") {
489 console.log("Invalid Parameter Value for parameter: " + method);
490 errorCB({
491 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
492 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "method"
493 });
494 return;
495 }
496
497
498 // url required
499 if (!url) {
500 console.log("AuthProxy Error: url is required");
501 errorCB({
502 errorCode: AuthProxy.prototype.ERR_MISSING_PARAMETER,
503 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "url"
504 });
505 return;
506 }
507
508
509 // successCB required
510 if (!successCB) {
511 console.log("AuthProxy Error: successCB is required");
512 errorCB({
513 errorCode: AuthProxy.prototype.ERR_MISSING_PARAMETER,
514 description: AuthProxy.prototype.MSG_MISSING_PARAMETER + "successCB"
515 });
516 return;
517 }
518
519
520 if (typeof successCB !== "function") {
521 console.log("AuthProxy Error: successCB is not a function");
522 errorCB({
523 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
524 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "successCB"
525 });
526 return;
527 }
528
529
530 if (user && typeof user !== "string") {
531 errorCB({
532 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
533 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "user"
534 });
535 return;
536 }
537
538
539 if (password && typeof password !== "string") {
540 errorCB({
541 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
542 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "password"
543 });
544 return;
545 }
546
547
548 if (timeout && typeof timeout !== "number") {
549 errorCB({
550 errorCode: AuthProxy.prototype.ERR_INVALID_PARAMETER_VALUE,
551 description: AuthProxy.prototype.MSG_INVALID_PARAMETER_VALUE + "timeout"
552 });
553 return;
554 }
555
556 if (!this.validateCertSource(certSource, errorCB)) {
557 return;
558 }
559
560
561 try {
562 var client = new Client(method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource);
563 return client.send();
564 } catch (ex) {
565 errorCB({
566 errorCode: AuthProxy.prototype.ERR_UNKNOWN,
567 description: ex.message
568 });
569 }
570
571 };
572
573 /**
574 * Send an HTTP(S) GET request to a remote server. This is a convenience function that simply calls {@link sap.AuthProxy#sendRequest}
575 * with "GET" as the method and null for the request body. All given parameters are passed as-is to sap.AuthProxy.sendRequest.
576 * The success callback is invoked upon any response from the server, even responses not generally considered to be
577 * successful (such as 404 or 500 status codes) result in the success callback being invoked. The error callback
578 * is reserved for problems that prevent the AuthProxy from creating the request or contacting the server. It is, therefore,
579 * important to always check the status property on the object given to the success callback.
580 * @param {string} url The URL against which to make the request.
581 * @param {Object} header HTTP header to send to the server. This is an Object. Can be null.
582 * @param {sap.AuthProxy~successCallback} successCB Callback method invoked upon a response from the server.
583 * @param {sap.AuthProxy~errorCallback} errorCB Callback method invoked in case of failure.
584 * @param {string} [user] User ID for basic authentication.
585 * @param {string} [password] User password for basic authentication.
586 * @param {number} [timeout] Timeout setting in seconds. Default value (0) means there is no timeout.
587 * @param {Object} [certSource] Certificate description object. It can be one of {@link sap.AuthProxy#CertificateFromFile},
588 * {@link sap.AuthProxy#CertificateFromStore}, or {@link sap.AuthProxy#CertificateFromLogonManager}.
589 * @return {function} A JavaScript function object to abort the operation. Calling the abort function results in neither the success or error
590 * callback being invoked for the original request (excepting the case where the success or error callback was invoked before calling the
591 * abort function). Note: The request itself cannot be unsent, and the server will still receive the request, but the JavaScript will
592 * not know the results of that request.
593 * @example
594 * var successCB = function(serverResponse){
595 * alert("Status: " + JSON.stringify(serverResponse.status));
596 * alert("Headers: " + JSON.stringify(serverResponse.headers));
597 * if (serverResponse.responseText){
598 * alert("Response: " + JSON.stringify(serverResponse.responseText));
599 * }
600 * }
601 * var errorCB = function(errorObject){
602 * alert("Error making request: " + JSON.stringify(errorObject));
603 * }
604 * // To send a GET request to server, call the method
605 * var abortFunction = sap.AuthProxy.get("http://www.example.com", null, successCB, errorCB);
606 * // An example of aborting the request
607 * abortFunction();
608 * // To send a GET request to the server with headers, call the method
609 * sap.AuthProxy.get("http://www.example.com", {HeaderName : "Header value"}, successCB, errorCB);
610 * // To send a GET request to the server with basic authentication, call the method
611 * sap.AuthProxy.get("https://www.example.com", headers, successCB, errorCB, "username", "password");
612 * // To send a GET request to the server with mutual authentication, call the method
613 * sap.AuthProxy.get("https://www.example.com", headers, successCB, errorCB, null, null, 0,
614 * new sap.AuthProxy.CertificateFromLogonManager("theAppId"));
615 */
616 AuthProxy.prototype.get = function (url, header, successCB, errorCB, user, password, timeout, certSource) {
617 return this.sendRequest("GET", url, header, null, successCB, errorCB, user, password, timeout, certSource);
618 };
619
620 /**
621 * Delete a cached certificate from the keychain. iOS clients always check the cached certificate first to see if it is available before
622 * loading the certificate from the file system. If the cached certificate is no longer valid, use this method to delete it from the keychain.
623 * <br/><b>This function is supported only on iOS.</b>
624 * @param {sap.AuthProxy~deleteCertificateSuccessCallback} successCB Callback method upon success.
625 * @param {sap.AuthProxy~errorCallback} [errorCB] Callback method upon failure.
626 * @param {string} certificateKey The key of the certificate to delete.
627 * @example
628 * var successCB = function(){
629 * alert("certificate successfully deleted.");
630 * }
631 * var errorCB = function(error){
632 * alert("error deleting certificate: " + JSON.stringify(error));
633 * }
634 * sap.AuthProxy.deleteCertificateFromStore(successCB, errorCB, "certificateKeyToDelete");
635 */
636 AuthProxy.prototype.deleteCertificateFromStore = function (successCB, errorCB, certificateKey) {
637 cordova.exec(successCB, errorCB, "AuthProxy", "deleteCertificateFromStore", [certificateKey]);
638 };
639
640 /**
641 * @private
642 */
643 var Client = function (method, url, header, requestBody, successCB, errorCB, user, password, timeout, certSource) {
644
645 //ios plugin parameter does not support object type, convert Header and CertSource to JSON string
646 if (device.platform === "iOS" || (device.platform && device.platform.indexOf("iP") === 0)) {
647 if (header) {
648 header = JSON.stringify(header);
649 }
650 if (certSource) {
651 certSource = JSON.stringify(certSource);
652 }
653 }
654
655 this.Method = method;
656 this.Url = url;
657 this.Header = header;
658 this.RequestBody = requestBody;
659 this.SuccessCB = successCB;
660 this.ErrorCB = errorCB;
661 this.User = user;
662 this.Password = password;
663 this.Timeout = timeout;
664 this.CertSource = certSource;
665 this.IsAbort = false;
666
667 this.abort = function () {
668 this.IsAbort = true;
669 };
670
671
672 this.send = function () {
673
674 var args = [this.Method, this.Url, this.Header, this.RequestBody, this.User, this.Password, this.Timeout, this.CertSource];
675
676 var me = this;
677
678 var successCallBack = function (data) {
679 if (me.IsAbort === true) {
680 return;
681 }
682
683 successCB(data);
684 };
685
686 var errorCallBack = function (data) {
687 if (me.IsAbort === true) {
688 return;
689 }
690
691 errorCB(data);
692 };
693
694 exec(successCallBack, errorCallBack, "AuthProxy", "sendRequest", args);
695
696 return this.abort;
697 };
698 };
699
700 /**
701 * Generates an OData client that uses the AuthProxy plugin to make requests. This is useful if you are using Datajs, but want
702 * to make use of the certificate features of AuthProxy. Datajs is a JavaScript library useful for accessing OData services.
703 * Datajs has a concept of an HttpClient, which does the work of making the request. This function generates an HttpClient that
704 * you can specify to Datajs so you can provide client certificates for requests. If you want to use the generated HTTP client
705 * for all future Datajs requests, you can do that by setting the OData.defaultHttpClient property to the return value of this
706 * function. Once that is done, then doing OData stuff with Datajs is almost exactly the same, but you can add a
707 * certificateSource to a request.
708 * @example
709 * OData.defaultHttpClient = sap.AuthProxy.generateODataHttpClient();
710 *
711 * // Using a certificate from file, for example.
712 * fileCert = new sap.AuthProxy.CertificateFromFile("mnt/sdcard/cert.p12", "password", "certKey");
713 *
714 * // This is the same request object you would have created if you were just using Datajs, but now
715 * // you can add the extra 'certificateSource' property.
716 * var createRequest = {
717 * requestUri: "http://www.example.com/stuff/etc/example.svc",
718 * certificateSource : fileCert,
719 * user : "username",
720 * password : "password",
721 * method : "POST",
722 * data:
723 * {
724 * Description: "Created Record",
725 * CategoryName: "Created Category"
726 * }
727 * }
728 *
729 * // Use Datajs to send the request.
730 * OData.request( createRequest, successCallback, failureCallback );
731 *
732 */
733 AuthProxy.prototype.generateODataHttpClient = function () {
734 var httpClient = {
735 request: function (request, success, error) {
736 var url, requestHeaders, requestBody, statusCode, statusText, responseHeaders;
737 var responseBody, requestTimeout, requestUserName, requestPassword, requestCertificate;
738 var client, result;
739
740 url = request.requestUri;
741 requestHeaders = request.headers;
742 requestBody = request.body;
743
744 var successCB = function (data) {
745 var response = {
746 requestUri: url,
747 statusCode: data.status,
748 statusText: data.status,
749 headers: data.headers,
750 body: (data.responseText ? data.responseText : data.responseBase64)
751 };
752
753 if (response.statusCode >= 200 && response.statusCode <= 299) {
754 if (success) {
755 success(response);
756 }
757 } else {
758 if (error) {
759 error({
760 message: "HTTP request failed",
761 request: request,
762 response: response
763 });
764 }
765 }
766 };
767
768 var errorCB = function (data) {
769 if (error) {
770 error({
771 message: data
772 });
773 }
774 };
775
776 if (request.timeoutMS) {
777 requestTimeout = request.timeoutMS / 1000;
778 }
779
780 if (request.certificateSource) {
781 requestCertificate = request.certificateSource;
782 }
783
784 if (request.user) {
785 requestUserName = request.user;
786 }
787
788 if (request.password) {
789 requestPassword = request.password;
790 }
791
792 client = AuthProxy.prototype.sendRequest(request.method || "GET", url, requestHeaders, requestBody, successCB, errorCB, requestUserName, requestPassword, requestTimeout, requestCertificate);
793
794 result = {};
795 result.abort = function () {
796 client.abort();
797
798 if (error) {
799 error({
800 message: "Request aborted"
801 });
802 }
803 };
804 return result;
805 }
806 };
807 return httpClient;
808 };
809
810 var AuthProxyPlugin = new AuthProxy();
811
812 module.exports = AuthProxyPlugin;
813
814
815 /**
816 * Callback function that is invoked in case of an error.
817 *
818 * @callback sap.AuthProxy~errorCallback
819 *
820 * @param {Object} errorObject An object containing two properties: 'errorCode' and 'description.'
821 * The 'errorCode' property corresponds to one of the {@link sap.AuthProxy} constants. The 'description'
822 * property is a string with more detailed information of what went wrong.
823 *
824 * @example
825 * function errorCallback(errCode) {
826 * //Set the default error message. Used if an invalid code is passed to the
827 * //function (just in case) but also to cover the
828 * //sap.AuthProxy.ERR_UNKNOWN case as well.
829 * var msg = "Unkown Error";
830 * switch (errCode) {
831 * case sap.AuthProxy.ERR_INVALID_PARAMETER_VALUE:
832 * msg = "Invalid parameter passed to method";
833 * break;
834 * case sap.AuthProxy.ERR_MISSING_PARAMETER:
835 * msg = "A required parameter was missing";
836 * break;
837 * case sap.AuthProxy.ERR_HTTP_TIMEOUT:
838 * msg = "The request timed out";
839 * break;
840 * };
841 * //Write the error to the log
842 * console.error(msg);
843 * //Let the user know what happened
844 * navigator.notification.alert(msg, null, "AuthProxy Error", "OK");
845 * };
846 */
847
848 /**
849 * Callback function that is invoked upon a response from the server.
850 *
851 * @callback sap.AuthProxy~successCallback
852 *
853 * @param {Object} serverResponse An object containing the response from the server. Contains a 'headers' property,
854 * a 'status' property, and a 'responseText' property.<br/>
855 * 'headers' is an object containing all the headers in the response.<br/>
856 * 'status' is an integer corresponding to the HTTP status code of the response. It is important to check the status of
857 * the response, since <b>this success callback is invoked upon any response from the server</b> - including responses that are
858 * not normally thought of as successes (for example, the status code could be 404 or 500).<br/>
859 * 'responseText' is a string containing the body of the response.
860 */
861
862 /**
863 * Callback function that is invoked upon successfully deleting a certificate from the store.
864 *
865 * @callback sap.AuthProxy~deleteCertificateSuccessCallback
866 */