-
Notifications
You must be signed in to change notification settings - Fork 256
Expand file tree
/
Copy pathobjectGetACL.js
More file actions
189 lines (181 loc) · 7.54 KB
/
objectGetACL.js
File metadata and controls
189 lines (181 loc) · 7.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
const async = require('async');
const { errors } = require('arsenal');
const aclUtils = require('../utilities/aclUtils');
const collectCorsHeaders = require('../utilities/collectCorsHeaders');
const { pushMetric } = require('../utapi/utilities');
const { decodeVersionId, getVersionIdResHeader }
= require('./apiUtils/object/versioning');
const vault = require('../auth/vault');
const { metadataValidateBucketAndObj } = require('../metadata/metadataUtils');
// Sample XML response:
/*
<AccessControlPolicy>
<Owner>
<ID>75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a</ID>
<DisplayName>CustomersName@amazon.com</DisplayName>
</Owner>
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="CanonicalUser">
<ID>75aa57f09aa0c8caeab4f8c24e99d10f8
e7faeebf76c078efc7c6caea54ba06a</ID>
<DisplayName>CustomersName@amazon.com</DisplayName>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
</AccessControlList>
</AccessControlPolicy>
*/
/**
* objectGetACL - Return ACL for object
* @param {AuthInfo} authInfo - Instance of AuthInfo class with requester's info
* @param {object} request - http request object
* @param {object} log - Werelogs logger
* @param {function} callback - callback to respond to http request
* @return {undefined}
*/
function objectGetACL(authInfo, request, log, callback) {
log.debug('processing request', { method: 'objectGetACL' });
const bucketName = request.bucketName;
const objectKey = request.objectKey;
const decodedVidResult = decodeVersionId(request.query);
if (decodedVidResult instanceof Error) {
log.trace('invalid versionId query', {
versionId: request.query.versionId,
error: decodedVidResult,
});
return callback(decodedVidResult);
}
const versionId = decodedVidResult;
const metadataValParams = {
authInfo,
bucketName,
objectKey,
versionId,
requestType: 'objectGetACL',
request,
};
const grantInfo = {
grants: [],
ownerInfo: {
ID: undefined,
displayName: undefined,
},
};
return async.waterfall([
function validateBucketAndObj(next) {
return metadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log,
(err, bucket, objectMD) => {
if (err) {
log.trace('request authorization failed',
{ method: 'objectGetACL', error: err });
return next(err);
}
if (!objectMD) {
const err = versionId ? errors.NoSuchVersion :
errors.NoSuchKey;
log.trace('error processing request',
{ method: 'objectGetACL', error: err });
return next(err, bucket);
}
if (objectMD.isDeleteMarker) {
if (versionId) {
log.trace('requested version is delete marker',
{ method: 'objectGetACL' });
return next(errors.MethodNotAllowed);
}
log.trace('most recent version is delete marker',
{ method: 'objectGetACL' });
return next(errors.NoSuchKey);
}
return next(null, bucket, objectMD);
});
},
function gatherACLs(bucket, objectMD, next) {
const verCfg = bucket.getVersioningConfiguration();
const resVersionId = getVersionIdResHeader(verCfg, objectMD);
const objectACL = objectMD.acl;
grantInfo.ownerInfo.ID = objectMD['owner-id'];
grantInfo.ownerInfo.displayName = objectMD['owner-display-name'];
// Object owner always has full control
const ownerGrant = {
ID: objectMD['owner-id'],
displayName: objectMD['owner-display-name'],
permission: 'FULL_CONTROL',
};
if (objectACL.Canned !== '') {
/**
* If bucket owner and object owner are different
* need to send info about bucket owner from bucket
* metadata to handleCannedGrant function
*/
let cannedGrants;
if (bucket.getOwner() !== objectMD['owner-id']) {
cannedGrants = aclUtils.handleCannedGrant(
objectACL.Canned, ownerGrant, bucket);
} else {
cannedGrants = aclUtils.handleCannedGrant(
objectACL.Canned, ownerGrant);
}
grantInfo.grants = grantInfo.grants.concat(cannedGrants);
const xml = aclUtils.convertToXml(grantInfo);
return next(null, bucket, xml, resVersionId);
}
/**
* Build array of all canonicalIDs used in ACLs so duplicates
* will be retained (e.g. if an account has both read and write
* privileges, want to display both and not lose the duplicate
* when receive one dictionary entry back from Vault)
*/
const canonicalIDs = aclUtils.getCanonicalIDs(objectACL);
// Build array with grants by URI
const uriGrantInfo = aclUtils.getUriGrantInfo(objectACL);
if (canonicalIDs.length === 0) {
/**
* If no acl's set by account canonicalID, just add URI
* grants (if any) and return
*/
grantInfo.grants = grantInfo.grants.concat(uriGrantInfo);
const xml = aclUtils.convertToXml(grantInfo);
return next(null, bucket, xml, resVersionId);
}
/**
* If acl's set by account canonicalID,
* get emails from Vault to serve
* as display names
*/
return vault.getEmailAddresses(canonicalIDs, log, (err, emails) => {
if (err) {
log.trace('error processing request',
{ method: 'objectGetACL', error: err });
return next(err, bucket);
}
const individualGrants = aclUtils.getIndividualGrants(objectACL,
canonicalIDs, emails);
// Add to grantInfo any individual grants and grants by uri
grantInfo.grants = grantInfo.grants
.concat(individualGrants).concat(uriGrantInfo);
// parse info about accounts and owner info to convert to xml
const xml = aclUtils.convertToXml(grantInfo);
return next(null, bucket, xml, resVersionId);
});
},
], (err, bucket, xml, resVersionId) => {
const resHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket);
if (err) {
return callback(err, null, resHeaders);
}
pushMetric('getObjectAcl', log, {
authInfo,
bucket: bucketName,
keys: [objectKey],
versionId: resVersionId,
location: bucket ? bucket.getLocationConstraint() : undefined,
});
resHeaders['x-amz-version-id'] = resVersionId;
return callback(null, xml, resHeaders);
});
}
module.exports = objectGetACL;