Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS4 Authentication Protocol Required by Some Regions #440

Closed
jaswrks opened this issue Jan 8, 2015 · 6 comments
Closed

AWS4 Authentication Protocol Required by Some Regions #440

jaswrks opened this issue Jan 8, 2015 · 6 comments
Assignees
Milestone

Comments

@jaswrks
Copy link
Contributor

jaswrks commented Jan 8, 2015

Amazon S3 supports Signature Version 4, a protocol for authenticating inbound API requests to AWS services, in all AWS regions. At this time, existing AWS regions continue to support the previous protocol, Signature Version 2. Any new regions after January 30, 2014 will support only Signature Version 4 and therefore all requests to those regions must be made with Signature Version 4. Note that Signature Version 4 requires the request body to be signed for added security. This requirement creates additional computation load that is not required in Signature Version 2.

Referencing: http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html

@jaswrks jaswrks self-assigned this Jan 8, 2015
@jaswrks jaswrks added this to the Next Release milestone Jan 8, 2015
@jaswrks
Copy link
Contributor Author

jaswrks commented Jan 8, 2015

jaswrks pushed a commit that referenced this issue Jan 8, 2015
- `amazon_s3_files_bucket_region`

See: #440
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
jaswrks pushed a commit that referenced this issue Jan 8, 2015
@jaswrks
Copy link
Contributor Author

jaswrks commented Jan 8, 2015

Holy hell! I dunno what the folks at AWS are thinking! Their signature algo is just ridiculous. haha

All of this just to get a signature for the Authorization header. Unbelievable! Gotta love the ridiculous attempt at making it more complex by nesting a date key inside a region key, inside a date/region key, just to get the key that you should sign with. On top of that there are a whole bunch of other stars that need to fall inline. Have they never heard of oAuth?

~ Ugh, 4 hours I'll never get back. It's working now though. I'll merge it in shortly :-)

This is one article I hope I don't need to read again anytime soon.
http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html

        /**
         * Creates an Amazon S3 AWS4-HMAC-SHA256 signature.
         *
         * @package s2Member\Files
         * @since 150108
         *
         * @param string $string Input string/data, to be signed by this routine.
         *
         * @return string An AWS4-HMAC-SHA256 signature for Amazon S3.
         */
        public static function amazon_s34_sign($string = '')
        {
            $s3c = array(); // Initialize config. keys.
            foreach($GLOBALS['WS_PLUGIN__']['s2member']['o'] as $option => $option_value)
                if(preg_match('/^amazon_s3_files_/', $option) && ($option = preg_replace('/^amazon_s3_files_/', '', $option)))
                    $s3c[$option] = $option_value;

            $s3_date_key                = c_ws_plugin__s2member_utils_strings::hmac_sha256_sign(date('Ymd'), 'AWS4'.$s3c['secret_key'], TRUE);
            $s3_date_region_key         = c_ws_plugin__s2member_utils_strings::hmac_sha256_sign($s3c['bucket_region'], $s3_date_key, TRUE);
            $s3_date_region_service_key = c_ws_plugin__s2member_utils_strings::hmac_sha256_sign('s3', $s3_date_region_key, TRUE);
            $s3_signing_key             = c_ws_plugin__s2member_utils_strings::hmac_sha256_sign('aws4_request', $s3_date_region_service_key, TRUE);

            return c_ws_plugin__s2member_utils_strings::hmac_sha256_sign((string)$string, $s3_signing_key);
        }

        /**
         * Creates an Amazon S3 AWS4-HMAC-SHA256 signature/authorization header.
         *
         * @package s2Member\Files
         * @since 150108
         *
         * @param string $s3_date The date header; e.g. `YYYYMMDD'T'HHMMSS'Z'`.
         * @param string $s3_domain The API endpoint domain; e.g. `[bucket].s3.amazonaws.com`.
         * @param string $s3_location The API endpoint URI; e.g. `/?acl`.
         * @param string $s3_method The request method; e.g. `GET`, `PUT`, `POST`, etc.
         * @param array  $s3_headers An associative array of all headers.
         * @param string $s3_body Any input data sent with the request.
         *
         * @return string An AWS4-HMAC-SHA256 signature/authorization header for Amazon S3.
         */
        public static function amazon_s34_authorization($s3_date = '',
                                                        $s3_domain = 's3.amazonaws.com',
                                                        $s3_location = '/', $s3_method = 'GET',
                                                        $s3_headers = array(), $s3_body = '')
        {
            $s3_date     = trim((string)$s3_date);
            $s3_domain   = trim(strtolower((string)$s3_domain));
            $s3_location = trim((string)$s3_location);
            $s3_method   = trim(strtoupper((string)$s3_method));
            $s3_headers  = (array)$s3_headers;
            $s3_body     = trim((string)$s3_body);

            $s3c = array(); // Initialize config. keys.
            foreach($GLOBALS['WS_PLUGIN__']['s2member']['o'] as $option => $option_value)
                if(preg_match('/^amazon_s3_files_/', $option) && ($option = preg_replace('/^amazon_s3_files_/', '', $option)))
                    $s3c[$option] = $option_value;

            $s3_iso8601_date   = date('Ymd\THis\Z');
            $s3_location_parts = parse_url($s3_location);
            $s3_canonical_path = !empty($s3_location_parts['path']) ? '/'.ltrim($s3_location_parts['path'], '/') : '/';
            $s3_scope          = date('Ymd').'/'.$s3c['bucket_region'].'/s3/aws4_request';

            $s3_canonical_query = ''; // Initialize.
            wp_parse_str((string)@$s3_location_parts['query'], $query_args);
            ksort($query_args, SORT_STRING);

            foreach($query_args as $_key => $_value)
                $s3_canonical_query .= '&'.c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(rawurlencode($_key)).
                                       '='.c_ws_plugin__s2member_utils_strings::urldecode_ur_chars_deep(rawurlencode($_value));
            $s3_canonical_query = ltrim($s3_canonical_query, '&');
            unset($_key, $_value); // Housekeeping.

            $s3_canonical_headers     = '';
            $s3_canonical_header_keys = array();
            ksort($s3_headers, SORT_STRING);

            foreach($s3_headers as $_key => $_value)
                if(is_string($_key) && ($_key = strtolower($_key)))
                    if(in_array($_key, array('host', 'content-type'), TRUE) || stripos($_key, 'X-Amz-') === 0)
                    {
                        $s3_canonical_headers .= strtolower($_key).':'.trim($_value)."\n";
                        $s3_canonical_header_keys[] = strtolower($_key);
                    }
            unset($_key, $_value); // Housekeeping.

            $s3_canonicial_request = $s3_method."\n".
                                     $s3_canonical_path."\n".
                                     $s3_canonical_query."\n".
                                     $s3_canonical_headers."\n".
                                     implode(';', $s3_canonical_header_keys)."\n".
                                     hash('sha256', $s3_body);
            $s3_string_to_sign     = 'AWS4-HMAC-SHA256'."\n".
                                     $s3_date."\n".
                                     $s3_scope."\n".
                                     hash('sha256', $s3_canonicial_request);
            $s3_signature          = self::amazon_s34_sign($s3_string_to_sign);

            $s3_authorization_header_signature = 'AWS4-HMAC-SHA256 Credential='.$s3c['access_key'].'/'.$s3_scope.','.
                                                 'SignedHeaders='.implode(';', $s3_canonical_header_keys).','.
                                                 'Signature='.$s3_signature;

            return $s3_authorization_header_signature;
        }

jaswrks pushed a commit that referenced this issue Jan 8, 2015
@jaswrks
Copy link
Contributor Author

jaswrks commented Jan 8, 2015

ha ~ I'm deleting 38 CloudFront Distros I created while testing this. That's funny 😄

jaswrks pushed a commit that referenced this issue Jan 9, 2015
jaswrks pushed a commit that referenced this issue Jan 9, 2015
@jaswrks
Copy link
Contributor Author

jaswrks commented Jan 14, 2015

Reopening this issue. It's come to my attention that digital signatures leading to specific resources may also require AWS4-HMAC-SHA256 in some regions.

@jaswrks
Copy link
Contributor Author

jaswrks commented Jan 23, 2015

Next Release Changelog:

  • (s2Member/s2Member Pro) AWS v4 Authentication: This release of s2Member adds AWS v4 Authentication support for Amazon Web Service Regions that only accept the AWS v4 authentication scheme. If you had trouble integrating s2Member with S3 Buckets (or with CloudFront) in regions outside the USA, this release should resolve those issues for you. See also: this GitHub issue if you'd like additional technical details.

@jaswrks
Copy link
Contributor Author

jaswrks commented Feb 4, 2015

This issue was resolved in the release of s2Member v150203. Please see: http://www.s2member.com/kb/v150203/ If there are any follow-ups needed, please open a new issue and we will investigate. Thanks!

@wpsharks wpsharks locked and limited conversation to collaborators Feb 4, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant