1
1
/* Copyright (C) 2020 NooBaa */
2
- /*eslint max-lines: ["error", 2200 ]*/
2
+ /*eslint max-lines: ["error", 2500 ]*/
3
3
/*eslint max-lines-per-function: ["error", 1300]*/
4
4
/*eslint max-statements: ["error", 80, { "ignoreTopLevelFunctions": true }]*/
5
5
'use strict' ;
@@ -12,10 +12,16 @@ const util = require('util');
12
12
const http = require ( 'http' ) ;
13
13
const mocha = require ( 'mocha' ) ;
14
14
const assert = require ( 'assert' ) ;
15
+ const http_utils = require ( '../../util/http_utils' ) ;
15
16
const config = require ( '../../../config' ) ;
16
17
const fs_utils = require ( '../../util/fs_utils' ) ;
17
- const { stat, open } = require ( '../../util/nb_native' ) ( ) . fs ;
18
+ const fetch = require ( 'node-fetch' ) ;
19
+ const P = require ( '../../util/promise' ) ;
20
+ const cloud_utils = require ( '../../util/cloud_utils' ) ;
21
+ const SensitiveString = require ( '../../util/sensitive_string' ) ;
22
+ const S3Error = require ( '../../../src/endpoint/s3/s3_errors' ) . S3Error ;
18
23
const test_utils = require ( '../system_tests/test_utils' ) ;
24
+ const { stat, open } = require ( '../../util/nb_native' ) ( ) . fs ;
19
25
const { get_process_fs_context } = require ( '../../util/native_fs_utils' ) ;
20
26
const { TYPES } = require ( '../../manage_nsfs/manage_nsfs_constants' ) ;
21
27
const ManageCLIError = require ( '../../manage_nsfs/manage_nsfs_cli_errors' ) . ManageCLIError ;
@@ -1848,3 +1854,140 @@ async function update_account_nsfs_config(email, default_resource, new_nsfs_acco
1848
1854
}
1849
1855
}
1850
1856
1857
+ mocha . describe ( 'Presigned URL tests' , function ( ) {
1858
+ this . timeout ( 50000 ) ; // eslint-disable-line no-invalid-this
1859
+ const nsr = 'presigned_url_nsr' ;
1860
+ const account_name = 'presigned_url_account' ;
1861
+ const fs_path = path . join ( TMP_PATH , 'presigned_url_tests/' ) ;
1862
+ const presigned_url_bucket = 'presigned-url-bucket' ;
1863
+ const presigned_url_object = 'presigned-url-object.txt' ;
1864
+ const presigned_body = 'presigned_body' ;
1865
+ let s3_client ;
1866
+ let access_key ;
1867
+ let secret_key ;
1868
+ CORETEST_ENDPOINT = coretest . get_http_address ( ) ;
1869
+ let valid_default_presigned_url ;
1870
+ let presigned_url_params ;
1871
+
1872
+ mocha . before ( async function ( ) {
1873
+ await fs_utils . create_fresh_path ( fs_path ) ;
1874
+ await rpc_client . pool . create_namespace_resource ( { name : nsr , nsfs_config : { fs_root_path : fs_path } } ) ;
1875
+ const new_buckets_path = '/' ; // manual fix for 5.16/5.15 since we didn't backport the related test refactoring
1876
+ const nsfs_account_config = {
1877
+ uid : process . getuid ( ) , gid : process . getgid ( ) , new_buckets_path, nsfs_only : true
1878
+ } ;
1879
+ const account_params = { ...new_account_params , email : `${ account_name } @noobaa.io` , name : account_name , default_resource : nsr , nsfs_account_config } ;
1880
+ const res = await rpc_client . account . create_account ( account_params ) ;
1881
+ access_key = res . access_keys [ 0 ] . access_key ;
1882
+ secret_key = res . access_keys [ 0 ] . secret_key ;
1883
+ s3_client = generate_s3_client ( access_key . unwrap ( ) , secret_key . unwrap ( ) , CORETEST_ENDPOINT ) ;
1884
+ await s3_client . createBucket ( { Bucket : presigned_url_bucket } ) ;
1885
+ await s3_client . putObject ( { Bucket : presigned_url_bucket , Key : presigned_url_object , Body : presigned_body } ) ;
1886
+
1887
+ presigned_url_params = {
1888
+ bucket : new SensitiveString ( presigned_url_bucket ) ,
1889
+ key : presigned_url_object ,
1890
+ endpoint : CORETEST_ENDPOINT ,
1891
+ access_key : access_key ,
1892
+ secret_key : secret_key
1893
+ } ;
1894
+ valid_default_presigned_url = cloud_utils . get_signed_url ( presigned_url_params ) ;
1895
+ } ) ;
1896
+
1897
+ mocha . after ( async function ( ) {
1898
+ if ( ! is_nc_coretest ) return ;
1899
+ await s3_client . deleteObject ( { Bucket : presigned_url_bucket , Key : presigned_url_object } ) ;
1900
+ await s3_client . deleteBucket ( { Bucket : presigned_url_bucket } ) ;
1901
+ await rpc_client . account . delete_account ( { email : `${ account_name } @noobaa.io` } ) ;
1902
+ await fs_utils . folder_delete ( fs_path ) ;
1903
+ } ) ;
1904
+
1905
+ it ( 'fetch valid presigned URL - 604800 seconds - epoch expiry - should return object data' , async ( ) => {
1906
+ const data = await fetchData ( valid_default_presigned_url ) ;
1907
+ assert . equal ( data , presigned_body ) ;
1908
+ } ) ;
1909
+
1910
+ it ( 'fetch valid presigned URL - 604800 seconds - should return object data - with valid date + expiry in seconds' , async ( ) => {
1911
+ const now = new Date ( ) ;
1912
+ const valid_url_with_date = valid_default_presigned_url + '&X-Amz-Date=' + now . toISOString ( ) + '&X-Amz-Expires=' + 604800 ;
1913
+ const data = await fetchData ( valid_url_with_date ) ;
1914
+ assert . equal ( data , presigned_body ) ;
1915
+ } ) ;
1916
+
1917
+ it ( 'fetch invalid presigned URL - 604800 seconds - epoch expiry + with future date' , async ( ) => {
1918
+ const now = new Date ( ) ;
1919
+ // Add one hour (3600000 milliseconds)
1920
+ const one_hour_in_ms = 60 * 60 * 1000 ;
1921
+ const one_hour_from_now = new Date ( now . getTime ( ) + one_hour_in_ms ) ;
1922
+ const future_presigned_url = valid_default_presigned_url + '&X-Amz-Date=' + one_hour_from_now . toISOString ( ) ;
1923
+ const expected_err = new S3Error ( S3Error . RequestNotValidYet ) ;
1924
+ await assert_throws_async ( fetchData ( future_presigned_url ) , expected_err . message ) ;
1925
+ } ) ;
1926
+
1927
+ it ( 'fetch invalid presigned URL - 604800 expiry seconds + with future date' , async ( ) => {
1928
+ const now = new Date ( ) ;
1929
+ // Add one hour (3600000 milliseconds)
1930
+ const one_hour_in_ms = 60 * 60 * 1000 ;
1931
+ const one_hour_from_now = new Date ( now . getTime ( ) + one_hour_in_ms ) ;
1932
+ const future_presigned_url = valid_default_presigned_url + '&X-Amz-Date=' + one_hour_from_now . toISOString ( ) + '&X-Amz-Expires=' + 604800 ;
1933
+ const expected_err = new S3Error ( S3Error . RequestNotValidYet ) ;
1934
+ await assert_throws_async ( fetchData ( future_presigned_url ) , expected_err . message ) ;
1935
+ } ) ;
1936
+
1937
+ it ( 'fetch invalid presigned URL - 604800 seconds - epoch expiry - URL expired' , async ( ) => {
1938
+ const expired_presigned_url = cloud_utils . get_signed_url ( presigned_url_params , 1 ) ;
1939
+ // wait for 2 seconds before fetching the url
1940
+ await P . delay ( 2000 ) ;
1941
+ const expected_err = new S3Error ( S3Error . RequestExpired ) ;
1942
+ await assert_throws_async ( fetchData ( expired_presigned_url ) , expected_err . message ) ;
1943
+ } ) ;
1944
+
1945
+ it ( 'fetch invalid presigned URL - 604800 expiry seconds - URL expired' , async ( ) => {
1946
+ const now = new Date ( ) ;
1947
+ const expired_presigned_url = cloud_utils . get_signed_url ( presigned_url_params , 1 ) + '&X-Amz-Date=' + now . toISOString ( ) + '&X-Amz-Expires=' + 1 ;
1948
+ // wait for 2 seconds before fetching the url
1949
+ await P . delay ( 2000 ) ;
1950
+ const expected_err = new S3Error ( S3Error . RequestExpired ) ;
1951
+ await assert_throws_async ( fetchData ( expired_presigned_url ) , expected_err . message ) ;
1952
+ } ) ;
1953
+
1954
+ it ( 'fetch invalid presigned URL - expiry expoch - expire in bigger than limit' , async ( ) => {
1955
+ const invalid_expiry = 604800 + 10 ;
1956
+ const invalid_expiry_presigned_url = cloud_utils . get_signed_url ( presigned_url_params , invalid_expiry ) ;
1957
+ const expected_err = new S3Error ( S3Error . AuthorizationQueryParametersError ) ;
1958
+ await assert_throws_async ( fetchData ( invalid_expiry_presigned_url ) , expected_err . message ) ;
1959
+ } ) ;
1960
+
1961
+ it ( 'fetch invalid presigned URL - expire in bigger than limit' , async ( ) => {
1962
+ const now = new Date ( ) ;
1963
+ const invalid_expiry = 604800 + 10 ;
1964
+ const invalid_expiry_presigned_url = cloud_utils . get_signed_url ( presigned_url_params , invalid_expiry ) + '&X-Amz-Date=' + now . toISOString ( ) + '&X-Amz-Expires=' + invalid_expiry ;
1965
+ const expected_err = new S3Error ( S3Error . AuthorizationQueryParametersError ) ;
1966
+ await assert_throws_async ( fetchData ( invalid_expiry_presigned_url ) , expected_err . message ) ;
1967
+ } ) ;
1968
+ } ) ;
1969
+
1970
+ async function fetchData ( presigned_url ) {
1971
+ const response = await fetch ( presigned_url , { agent : new http . Agent ( { keepAlive : false } ) } ) ;
1972
+ let data ;
1973
+ if ( ! response . ok ) {
1974
+ data = ( await response . text ( ) ) . trim ( ) ;
1975
+ const err_json = ( await http_utils . parse_xml_to_js ( data ) ) . Error ;
1976
+ const err = new Error ( err_json . Message ) ;
1977
+ err . code = err_json . Code ;
1978
+ throw err ;
1979
+ }
1980
+ data = await response . text ( ) ;
1981
+ return data . trim ( ) ;
1982
+ }
1983
+
1984
+ async function assert_throws_async ( promise , expected_message = 'Access Denied' ) {
1985
+ try {
1986
+ await promise ;
1987
+ assert . fail ( 'Test was suppose to fail on ' + expected_message ) ;
1988
+ } catch ( err ) {
1989
+ if ( err . message !== expected_message ) {
1990
+ throw err ;
1991
+ }
1992
+ }
1993
+ }
0 commit comments