return authorize_v2(store, auth_registry, s);
}
-int RGW_Auth_S3::authorize_aws4_auth_complete(RGWRados *store, struct req_state *s)
-{
- return authorize_v4_complete(store, s, "", false);
-}
-
-int RGW_Auth_S3::authorize_v4_complete(RGWRados *store, struct req_state *s, const string& request_payload, bool unsigned_payload)
-{
- const char *expected_request_payload_hash = \
- rgw::auth::s3::get_v4_exp_payload_hash(s->info);
-
- /* In AWSv4 the hash of real, transfered payload IS NOT necessary to form
- * a Canonical Request, and thus verify a Signature. x-amz-content-sha256
- * header lets get the information very early -- before seeing first byte
- * of HTTP body. As a consequence, we can decouple Signature verification
- * from payload's fingerprint check. */
- std::string payload_hash;
- if (unsigned_payload) {
- payload_hash = "UNSIGNED-PAYLOAD";
- } else {
- if (s->aws4_auth_needs_complete) {
- payload_hash = AWS_AUTHv4_IO(s)->grab_aws4_sha256_hash();
- } else {
- if (s->aws4_auth_streaming_mode) {
- payload_hash = "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
- } else {
- payload_hash = \
- rgw::auth::s3::hash_string_sha256(request_payload.c_str(),
- request_payload.size());
- }
- }
- }
-
- /* Validate x-amz-sha256 */
- if (s->aws4_auth_needs_complete) {
- if (payload_hash.compare(expected_request_payload_hash) != 0) {
- ldout(s->cct, 10) << "ERROR: x-amz-content-sha256 does not match" << dendl;
- return -ERR_AMZ_CONTENT_SHA256_MISMATCH;
- }
- }
-
- return 0;
-
-}
-
-static inline bool is_base64_for_content_md5(unsigned char c) {
- return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '='));
-}
-
-/*
- * handle v4 signatures (rados auth only)
- */
-int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s, bool force_boto2_compat /* = true */)
-{
- string::size_type pos;
- bool using_qs;
-
- /* v4 requires rados auth */
- if (!store->ctx()->_conf->rgw_s3_auth_use_rados) {
- return -EPERM;
- }
-
- try {
- s->aws4_auth = std::unique_ptr<rgw_aws4_auth>(new rgw_aws4_auth);
- } catch (std::bad_alloc&) {
- return -ENOMEM;
- }
-
- std::string access_key_id;
- std::string signed_hdrs;
- std::string client_signature;
- int ret = rgw::auth::s3::parse_credentials(s->info,
- access_key_id,
- s->aws4_auth->credential_scope,
- signed_hdrs,
- client_signature,
- s->aws4_auth->date,
- using_qs);
- if (ret < 0) {
- return ret;
- }
-
- /* grab user information */
-
- if (rgw_get_user_info_by_access_key(store, access_key_id, *s->user) < 0) {
- dout(10) << "error reading user info, uid=" << access_key_id
- << " can't authenticate" << dendl;
- return -ERR_INVALID_ACCESS_KEY;
- }
-
- /*
- * create a canonical request
- *
- * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
- */
-
- /* craft canonical uri */
- const auto canonical_uri = rgw::auth::s3::get_v4_canonical_uri(s->info);
-
- /* craft canonical query string */
- const auto canonical_qs = rgw::auth::s3::get_v4_canonical_qs(s->info,
- using_qs);
-
- /* craft canonical headers */
- boost::optional<std::string> canonical_headers = \
- rgw::auth::s3::get_v4_canonical_headers(s->info,
- signed_hdrs,
- using_qs,
- force_boto2_compat);
- if (canonical_headers) {
- ldout(s->cct, 10) << "canonical headers format = " << *canonical_headers
- << dendl;
- } else {
- return -EPERM;
- }
-
- /* handle request payload */
-
- string request_payload;
-
- bool unsigned_payload = false;
- s->aws4_auth_streaming_mode = false;
-
- if (using_qs) {
- /* query parameters auth */
- unsigned_payload = true;
- } else {
- /* header auth */
- const char *request_payload_hash = s->info.env->get("HTTP_X_AMZ_CONTENT_SHA256");
- if (request_payload_hash) {
- unsigned_payload = string("UNSIGNED-PAYLOAD").compare(request_payload_hash) == 0;
- if (!unsigned_payload) {
- s->aws4_auth_streaming_mode = string("STREAMING-AWS4-HMAC-SHA256-PAYLOAD").compare(request_payload_hash) == 0;
- }
- }
- }
-
- /* Get the expected hash. */
- auto exp_payload_hash = rgw::auth::s3::get_v4_exp_payload_hash(s->info);
-
- /* craft canonical request */
- std::string canonical_req_hash = \
- rgw::auth::s3::get_v4_canon_req_hash(s->cct,
- s->info.method,
- canonical_uri,
- canonical_qs,
- *canonical_headers,
- signed_hdrs,
- exp_payload_hash);
-
- /*
- * create a string to sign
- *
- * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
- */
-
- std::string string_to_sign = \
- rgw::auth::s3::get_v4_string_to_sign(s->cct, "AWS4-HMAC-SHA256",
- s->aws4_auth->date,
- s->aws4_auth->credential_scope,
- canonical_req_hash);
-
- /*
- * calculate the AWS signature
- *
- * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
- */
-
- const auto iter = s->user->access_keys.find(access_key_id);
- if (iter == std::end(s->user->access_keys)) {
- ldout(s->cct, 10) << "ERROR: access key not encoded in user info" << dendl;
- return -EPERM;
- }
- const RGWAccessKey& k = iter->second;
-
- s->aws4_auth->signing_key = \
- rgw::auth::s3::get_v4_signing_key(s->cct,
- s->aws4_auth->credential_scope, k.key);
- const std::string server_signature = \
- rgw::auth::s3::get_v4_signature(s->cct, s->aws4_auth->signing_key,
- string_to_sign);
-
-
- ldout(s->cct, 10) << "----------------------------- Verifying signatures" << dendl;
- ldout(s->cct, 10) << "Signature = " << client_signature << dendl;
- ldout(s->cct, 10) << "New Signature = " << server_signature << dendl;
- ldout(s->cct, 10) << "-----------------------------" << dendl;
-
- /* verify signature */
- if (client_signature != server_signature) {
- ret = -ERR_SIGNATURE_NO_MATCH;
- ldout(s->cct, 20) << "delayed aws4 auth failed" << dendl;
- return ret;
- }
-
- s->aws4_auth->seed_signature = server_signature;
-
- /* from rfc2616 - 4.3 Message Body
- *
- * "The presence of a message-body in a request is signaled by the inclusion of a
- * Content-Length or Transfer-Encoding header field in the request's message-headers."
- */
- bool body_available = s->content_length != 0 || s->info.env->get("HTTP_TRANSFER_ENCODING") != NULL;
-
- if (unsigned_payload || !body_available) {
-
- /* requests lacking of body or shipping with 'UNSIGNED-PAYLOAD' are authenticated now */
-
- /* complete aws4 auth */
-
- int err = authorize_v4_complete(store, s, request_payload, unsigned_payload);
- if (err) {
- return err;
- }
-
- /* authorization ok */
- dout(10) << "v4 auth ok" << dendl;
-
- /* aws4 auth completed */
-
- s->aws4_auth_needs_complete = false;
-
- } else {
-
- /* aws4 auth not completed... delay aws4 auth */
-
- if (!s->aws4_auth_streaming_mode) {
-
- dout(10) << "delaying v4 auth" << dendl;
-
- /* payload in a single chunk */
-
- switch (s->op_type)
- {
- case RGW_OP_CREATE_BUCKET:
- case RGW_OP_PUT_OBJ:
- case RGW_OP_PUT_ACLS:
- case RGW_OP_PUT_CORS:
- case RGW_OP_COMPLETE_MULTIPART:
- case RGW_OP_SET_BUCKET_VERSIONING:
- case RGW_OP_DELETE_MULTI_OBJ:
- case RGW_OP_ADMIN_SET_METADATA:
- case RGW_OP_SET_BUCKET_WEBSITE:
- case RGW_OP_PUT_BUCKET_POLICY:
- break;
- default:
- dout(10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED" << dendl;
- return -ERR_NOT_IMPLEMENTED;
- }
-
- s->aws4_auth_needs_complete = true;
-
- } else {
-
- dout(10) << "body content detected in multiple chunks" << dendl;
-
- /* payload in multiple chunks */
-
- switch(s->op_type)
- {
- case RGW_OP_PUT_OBJ:
- break;
- default:
- dout(10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED (streaming mode)" << dendl;
- return -ERR_NOT_IMPLEMENTED;
- }
-
- /* calculate seed */
-
- int err = authorize_v4_complete(store, s, "", unsigned_payload);
- if (err) {
- return err;
- }
-
- dout(10) << "aws4 seed signature ok... delaying v4 auth" << dendl;
-
- s->aws4_auth_needs_complete = false;
-
- }
-
- }
-
- if (!k.subuser.empty()) {
- map<string, RGWSubUser>::iterator uiter = s->user->subusers.find(k.subuser);
- if (uiter == s->user->subusers.end()) {
- dout(0) << "NOTICE: could not find subuser: " << k.subuser << dendl;
- return -EPERM;
- }
- RGWSubUser& subuser = uiter->second;
- s->perm_mask = subuser.perm_mask;
- } else {
- s->perm_mask = RGW_PERM_FULL_CONTROL;
- }
-
- if (s->user->system) {
- s->system_request = true;
- dout(20) << "system request" << dendl;
- s->info.args.set_system();
- string euid = s->info.args.get(RGW_SYS_PARAM_PREFIX "uid");
- rgw_user effective_uid(euid);
- RGWUserInfo effective_user;
- if (!effective_uid.empty()) {
- int ret = rgw_get_user_info_by_uid(store, effective_uid, effective_user);
- if (ret < 0) {
- ldout(s->cct, 0) << "User lookup failed!" << dendl;
- return -EACCES;
- }
- *(s->user) = effective_user;
- }
- }
-
- // populate the owner info
- s->owner.set_id(s->user->user_id);
- s->owner.set_name(s->user->display_name);
-
- return 0;
-}
/*
* handle v2 signatures