acl_helper.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. package s3acl
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil"
  6. "github.com/aws/aws-sdk-go/service/s3"
  7. "github.com/seaweedfs/seaweedfs/weed/glog"
  8. "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
  9. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
  10. "github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
  11. "github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
  12. "github.com/seaweedfs/seaweedfs/weed/util"
  13. "net/http"
  14. "strings"
  15. )
  16. // GetAccountId get AccountId from request headers, AccountAnonymousId will be return if not presen
  17. func GetAccountId(r *http.Request) string {
  18. id := r.Header.Get(s3_constants.AmzAccountId)
  19. if len(id) == 0 {
  20. return s3account.AccountAnonymous.Id
  21. } else {
  22. return id
  23. }
  24. }
  25. // ExtractAcl extracts the acl from the request body, or from the header if request body is empty
  26. func ExtractAcl(r *http.Request, accountManager *s3account.AccountManager, ownership, bucketOwnerId, ownerId, accountId string) (grants []*s3.Grant, errCode s3err.ErrorCode) {
  27. if r.Body != nil && r.Body != http.NoBody {
  28. defer util.CloseRequest(r)
  29. var acp s3.AccessControlPolicy
  30. err := xmlutil.UnmarshalXML(&acp, xml.NewDecoder(r.Body), "")
  31. if err != nil || acp.Owner == nil || acp.Owner.ID == nil {
  32. return nil, s3err.ErrInvalidRequest
  33. }
  34. //owner should present && owner is immutable
  35. if *acp.Owner.ID != ownerId {
  36. glog.V(3).Infof("set acl denied! owner account is not consistent, request account id: %s, expect account id: %s", accountId, ownerId)
  37. return nil, s3err.ErrAccessDenied
  38. }
  39. return ValidateAndTransferGrants(accountManager, acp.Grants)
  40. } else {
  41. _, grants, errCode = ParseAndValidateAclHeadersOrElseDefault(r, accountManager, ownership, bucketOwnerId, accountId, true)
  42. return grants, errCode
  43. }
  44. }
  45. // ParseAndValidateAclHeadersOrElseDefault will callParseAndValidateAclHeaders to get Grants, if empty, it will return Grant that grant `accountId` with `FullControl` permission
  46. func ParseAndValidateAclHeadersOrElseDefault(r *http.Request, accountManager *s3account.AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
  47. ownerId, grants, errCode = ParseAndValidateAclHeaders(r, accountManager, ownership, bucketOwnerId, accountId, putAcl)
  48. if errCode != s3err.ErrNone {
  49. return
  50. }
  51. if len(grants) == 0 {
  52. //if no acl(both customAcl and cannedAcl) specified, grant accountId(object writer) with full control permission
  53. grants = append(grants, &s3.Grant{
  54. Grantee: &s3.Grantee{
  55. Type: &s3_constants.GrantTypeCanonicalUser,
  56. ID: &accountId,
  57. },
  58. Permission: &s3_constants.PermissionFullControl,
  59. })
  60. }
  61. return
  62. }
  63. // ParseAndValidateAclHeaders parse and validate acl from header
  64. func ParseAndValidateAclHeaders(r *http.Request, accountManager *s3account.AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
  65. ownerId, grants, errCode = ParseAclHeaders(r, ownership, bucketOwnerId, accountId, putAcl)
  66. if errCode != s3err.ErrNone {
  67. return
  68. }
  69. if len(grants) > 0 {
  70. grants, errCode = ValidateAndTransferGrants(accountManager, grants)
  71. }
  72. return
  73. }
  74. // ParseAclHeaders parse acl headers
  75. // When `putAcl` is true, only `CannedAcl` is parsed, such as `PutBucketAcl` or `PutObjectAcl`
  76. // is requested, `CustomAcl` is parsed from the request body not from headers, and only if the
  77. // request body is empty, `CannedAcl` is parsed from the header, and will not parse `CustomAcl` from the header
  78. //
  79. // Since `CustomAcl` has higher priority, it will be parsed first; if `CustomAcl` does not exist, `CannedAcl` will be parsed
  80. func ParseAclHeaders(r *http.Request, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
  81. if !putAcl {
  82. errCode = ParseCustomAclHeaders(r, &grants)
  83. if errCode != s3err.ErrNone {
  84. return "", nil, errCode
  85. }
  86. }
  87. if len(grants) > 0 {
  88. return accountId, grants, s3err.ErrNone
  89. }
  90. cannedAcl := r.Header.Get(s3_constants.AmzCannedAcl)
  91. if len(cannedAcl) == 0 {
  92. return accountId, grants, s3err.ErrNone
  93. }
  94. //if canned acl specified, parse cannedAcl (lower priority to custom acl)
  95. ownerId, grants, errCode = ParseCannedAclHeader(ownership, bucketOwnerId, accountId, cannedAcl, putAcl)
  96. if errCode != s3err.ErrNone {
  97. return "", nil, errCode
  98. }
  99. return ownerId, grants, errCode
  100. }
  101. func ParseCustomAclHeaders(r *http.Request, grants *[]*s3.Grant) s3err.ErrorCode {
  102. customAclHeaders := []string{s3_constants.AmzAclFullControl, s3_constants.AmzAclRead, s3_constants.AmzAclReadAcp, s3_constants.AmzAclWrite, s3_constants.AmzAclWriteAcp}
  103. var errCode s3err.ErrorCode
  104. for _, customAclHeader := range customAclHeaders {
  105. headerValue := r.Header.Get(customAclHeader)
  106. switch customAclHeader {
  107. case s3_constants.AmzAclRead:
  108. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionRead, grants)
  109. case s3_constants.AmzAclWrite:
  110. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionWrite, grants)
  111. case s3_constants.AmzAclReadAcp:
  112. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionReadAcp, grants)
  113. case s3_constants.AmzAclWriteAcp:
  114. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionWriteAcp, grants)
  115. case s3_constants.AmzAclFullControl:
  116. errCode = ParseCustomAclHeader(headerValue, s3_constants.PermissionFullControl, grants)
  117. }
  118. if errCode != s3err.ErrNone {
  119. return errCode
  120. }
  121. }
  122. return s3err.ErrNone
  123. }
  124. func ParseCustomAclHeader(headerValue, permission string, grants *[]*s3.Grant) s3err.ErrorCode {
  125. if len(headerValue) > 0 {
  126. split := strings.Split(headerValue, ", ")
  127. for _, grantStr := range split {
  128. kv := strings.Split(grantStr, "=")
  129. if len(kv) != 2 {
  130. return s3err.ErrInvalidRequest
  131. }
  132. switch kv[0] {
  133. case "id":
  134. var accountId string
  135. _ = json.Unmarshal([]byte(kv[1]), &accountId)
  136. *grants = append(*grants, &s3.Grant{
  137. Grantee: &s3.Grantee{
  138. Type: &s3_constants.GrantTypeCanonicalUser,
  139. ID: &accountId,
  140. },
  141. Permission: &permission,
  142. })
  143. case "emailAddress":
  144. var emailAddress string
  145. _ = json.Unmarshal([]byte(kv[1]), &emailAddress)
  146. *grants = append(*grants, &s3.Grant{
  147. Grantee: &s3.Grantee{
  148. Type: &s3_constants.GrantTypeAmazonCustomerByEmail,
  149. EmailAddress: &emailAddress,
  150. },
  151. Permission: &permission,
  152. })
  153. case "uri":
  154. var groupName string
  155. _ = json.Unmarshal([]byte(kv[1]), &groupName)
  156. *grants = append(*grants, &s3.Grant{
  157. Grantee: &s3.Grantee{
  158. Type: &s3_constants.GrantTypeGroup,
  159. URI: &groupName,
  160. },
  161. Permission: &permission,
  162. })
  163. }
  164. }
  165. }
  166. return s3err.ErrNone
  167. }
  168. func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl string, putAcl bool) (ownerId string, grants []*s3.Grant, err s3err.ErrorCode) {
  169. err = s3err.ErrNone
  170. ownerId = accountId
  171. //objectWrite automatically has full control on current object
  172. objectWriterFullControl := &s3.Grant{
  173. Grantee: &s3.Grantee{
  174. ID: &accountId,
  175. Type: &s3_constants.GrantTypeCanonicalUser,
  176. },
  177. Permission: &s3_constants.PermissionFullControl,
  178. }
  179. switch cannedAcl {
  180. case s3_constants.CannedAclPrivate:
  181. grants = append(grants, objectWriterFullControl)
  182. case s3_constants.CannedAclPublicRead:
  183. grants = append(grants, objectWriterFullControl)
  184. grants = append(grants, s3_constants.PublicRead...)
  185. case s3_constants.CannedAclPublicReadWrite:
  186. grants = append(grants, objectWriterFullControl)
  187. grants = append(grants, s3_constants.PublicReadWrite...)
  188. case s3_constants.CannedAclAuthenticatedRead:
  189. grants = append(grants, objectWriterFullControl)
  190. grants = append(grants, s3_constants.AuthenticatedRead...)
  191. case s3_constants.CannedAclLogDeliveryWrite:
  192. grants = append(grants, objectWriterFullControl)
  193. grants = append(grants, s3_constants.LogDeliveryWrite...)
  194. case s3_constants.CannedAclBucketOwnerRead:
  195. grants = append(grants, objectWriterFullControl)
  196. if bucketOwnerId != "" && bucketOwnerId != accountId {
  197. grants = append(grants,
  198. &s3.Grant{
  199. Grantee: &s3.Grantee{
  200. Type: &s3_constants.GrantTypeCanonicalUser,
  201. ID: &bucketOwnerId,
  202. },
  203. Permission: &s3_constants.PermissionRead,
  204. })
  205. }
  206. case s3_constants.CannedAclBucketOwnerFullControl:
  207. if bucketOwnerId != "" {
  208. // if set ownership to 'BucketOwnerPreferred' when upload object, the bucket owner will be the object owner
  209. if !putAcl && bucketOwnership == s3_constants.OwnershipBucketOwnerPreferred {
  210. ownerId = bucketOwnerId
  211. grants = append(grants,
  212. &s3.Grant{
  213. Grantee: &s3.Grantee{
  214. Type: &s3_constants.GrantTypeCanonicalUser,
  215. ID: &bucketOwnerId,
  216. },
  217. Permission: &s3_constants.PermissionFullControl,
  218. })
  219. } else {
  220. grants = append(grants, objectWriterFullControl)
  221. if accountId != bucketOwnerId {
  222. grants = append(grants,
  223. &s3.Grant{
  224. Grantee: &s3.Grantee{
  225. Type: &s3_constants.GrantTypeCanonicalUser,
  226. ID: &bucketOwnerId,
  227. },
  228. Permission: &s3_constants.PermissionFullControl,
  229. })
  230. }
  231. }
  232. }
  233. case s3_constants.CannedAclAwsExecRead:
  234. err = s3err.ErrNotImplemented
  235. default:
  236. err = s3err.ErrInvalidRequest
  237. }
  238. return
  239. }
  240. // ValidateAndTransferGrants validate grant & transfer Email-Grant to Id-Grant
  241. func ValidateAndTransferGrants(accountManager *s3account.AccountManager, grants []*s3.Grant) ([]*s3.Grant, s3err.ErrorCode) {
  242. var result []*s3.Grant
  243. for _, grant := range grants {
  244. grantee := grant.Grantee
  245. if grantee == nil || grantee.Type == nil {
  246. glog.Warning("invalid grantee! grantee or granteeType is nil")
  247. return nil, s3err.ErrInvalidRequest
  248. }
  249. switch *grantee.Type {
  250. case s3_constants.GrantTypeGroup:
  251. if grantee.URI == nil {
  252. glog.Warning("invalid group grantee! group URI is nil")
  253. return nil, s3err.ErrInvalidRequest
  254. }
  255. ok := s3_constants.ValidateGroup(*grantee.URI)
  256. if !ok {
  257. glog.Warningf("invalid group grantee! group name[%s] is not valid", *grantee.URI)
  258. return nil, s3err.ErrInvalidRequest
  259. }
  260. result = append(result, grant)
  261. case s3_constants.GrantTypeCanonicalUser:
  262. if grantee.ID == nil {
  263. glog.Warning("invalid canonical grantee! account id is nil")
  264. return nil, s3err.ErrInvalidRequest
  265. }
  266. _, ok := accountManager.IdNameMapping[*grantee.ID]
  267. if !ok {
  268. glog.Warningf("invalid canonical grantee! account id[%s] is not exists", *grantee.ID)
  269. return nil, s3err.ErrInvalidRequest
  270. }
  271. result = append(result, grant)
  272. case s3_constants.GrantTypeAmazonCustomerByEmail:
  273. if grantee.EmailAddress == nil {
  274. glog.Warning("invalid email grantee! email address is nil")
  275. return nil, s3err.ErrInvalidRequest
  276. }
  277. accountId, ok := accountManager.EmailIdMapping[*grantee.EmailAddress]
  278. if !ok {
  279. glog.Warningf("invalid email grantee! email address[%s] is not exists", *grantee.EmailAddress)
  280. return nil, s3err.ErrInvalidRequest
  281. }
  282. result = append(result, &s3.Grant{
  283. Grantee: &s3.Grantee{
  284. Type: &s3_constants.GrantTypeCanonicalUser,
  285. ID: &accountId,
  286. },
  287. Permission: grant.Permission,
  288. })
  289. default:
  290. return nil, s3err.ErrInvalidRequest
  291. }
  292. }
  293. return result, s3err.ErrNone
  294. }
  295. // DetermineReqGrants generates the grant set (Grants) according to accountId and reqPermission.
  296. func DetermineReqGrants(accountId, aclAction string) (grants []*s3.Grant) {
  297. // group grantee (AllUsers)
  298. grants = append(grants, &s3.Grant{
  299. Grantee: &s3.Grantee{
  300. Type: &s3_constants.GrantTypeGroup,
  301. URI: &s3_constants.GranteeGroupAllUsers,
  302. },
  303. Permission: &aclAction,
  304. })
  305. grants = append(grants, &s3.Grant{
  306. Grantee: &s3.Grantee{
  307. Type: &s3_constants.GrantTypeGroup,
  308. URI: &s3_constants.GranteeGroupAllUsers,
  309. },
  310. Permission: &s3_constants.PermissionFullControl,
  311. })
  312. // canonical grantee (accountId)
  313. grants = append(grants, &s3.Grant{
  314. Grantee: &s3.Grantee{
  315. Type: &s3_constants.GrantTypeCanonicalUser,
  316. ID: &accountId,
  317. },
  318. Permission: &aclAction,
  319. })
  320. grants = append(grants, &s3.Grant{
  321. Grantee: &s3.Grantee{
  322. Type: &s3_constants.GrantTypeCanonicalUser,
  323. ID: &accountId,
  324. },
  325. Permission: &s3_constants.PermissionFullControl,
  326. })
  327. // group grantee (AuthenticateUsers)
  328. if accountId != s3account.AccountAnonymous.Id {
  329. grants = append(grants, &s3.Grant{
  330. Grantee: &s3.Grantee{
  331. Type: &s3_constants.GrantTypeGroup,
  332. URI: &s3_constants.GranteeGroupAuthenticatedUsers,
  333. },
  334. Permission: &aclAction,
  335. })
  336. grants = append(grants, &s3.Grant{
  337. Grantee: &s3.Grantee{
  338. Type: &s3_constants.GrantTypeGroup,
  339. URI: &s3_constants.GranteeGroupAuthenticatedUsers,
  340. },
  341. Permission: &s3_constants.PermissionFullControl,
  342. })
  343. }
  344. return
  345. }
  346. func SetAcpOwnerHeader(r *http.Request, acpOwnerId string) {
  347. r.Header.Set(s3_constants.ExtAmzOwnerKey, acpOwnerId)
  348. }
  349. func GetAcpOwner(entryExtended map[string][]byte, defaultOwner string) string {
  350. ownerIdBytes, ok := entryExtended[s3_constants.ExtAmzOwnerKey]
  351. if ok && len(ownerIdBytes) > 0 {
  352. return string(ownerIdBytes)
  353. }
  354. return defaultOwner
  355. }
  356. func SetAcpGrantsHeader(r *http.Request, acpGrants []*s3.Grant) {
  357. if len(acpGrants) > 0 {
  358. a, err := json.Marshal(acpGrants)
  359. if err == nil {
  360. r.Header.Set(s3_constants.ExtAmzAclKey, string(a))
  361. } else {
  362. glog.Warning("Marshal acp grants err", err)
  363. }
  364. }
  365. }
  366. // GetAcpGrants return grants parsed from entry
  367. func GetAcpGrants(entryExtended map[string][]byte) []*s3.Grant {
  368. acpBytes, ok := entryExtended[s3_constants.ExtAmzAclKey]
  369. if ok && len(acpBytes) > 0 {
  370. var grants []*s3.Grant
  371. err := json.Unmarshal(acpBytes, &grants)
  372. if err == nil {
  373. return grants
  374. }
  375. }
  376. return nil
  377. }
  378. // AssembleEntryWithAcp fill entry with owner and grants
  379. func AssembleEntryWithAcp(objectEntry *filer_pb.Entry, objectOwner string, grants []*s3.Grant) s3err.ErrorCode {
  380. if objectEntry.Extended == nil {
  381. objectEntry.Extended = make(map[string][]byte)
  382. }
  383. if len(objectOwner) > 0 {
  384. objectEntry.Extended[s3_constants.ExtAmzOwnerKey] = []byte(objectOwner)
  385. } else {
  386. delete(objectEntry.Extended, s3_constants.ExtAmzOwnerKey)
  387. }
  388. if len(grants) > 0 {
  389. grantsBytes, err := json.Marshal(grants)
  390. if err != nil {
  391. glog.Warning("assemble acp to entry:", err)
  392. return s3err.ErrInvalidRequest
  393. }
  394. objectEntry.Extended[s3_constants.ExtAmzAclKey] = grantsBytes
  395. } else {
  396. delete(objectEntry.Extended, s3_constants.ExtAmzAclKey)
  397. }
  398. return s3err.ErrNone
  399. }
  400. // GrantEquals Compare whether two Grants are equal in meaning, not completely
  401. // equal (compare Grantee.Type and the corresponding Value for equality, other
  402. // fields of Grantee are ignored)
  403. func GrantEquals(a, b *s3.Grant) bool {
  404. // grant
  405. if a == b {
  406. return true
  407. }
  408. if a == nil || b == nil {
  409. return false
  410. }
  411. // grant.Permission
  412. if a.Permission != b.Permission {
  413. if a.Permission == nil || b.Permission == nil {
  414. return false
  415. }
  416. if *a.Permission != *b.Permission {
  417. return false
  418. }
  419. }
  420. // grant.Grantee
  421. ag := a.Grantee
  422. bg := b.Grantee
  423. if ag != bg {
  424. if ag == nil || bg == nil {
  425. return false
  426. }
  427. // grantee.Type
  428. if ag.Type != bg.Type {
  429. if ag.Type == nil || bg.Type == nil {
  430. return false
  431. }
  432. if *ag.Type != *bg.Type {
  433. return false
  434. }
  435. }
  436. // value corresponding to granteeType
  437. if ag.Type != nil {
  438. switch *ag.Type {
  439. case s3_constants.GrantTypeGroup:
  440. if ag.URI != bg.URI {
  441. if ag.URI == nil || bg.URI == nil {
  442. return false
  443. }
  444. if *ag.URI != *bg.URI {
  445. return false
  446. }
  447. }
  448. case s3_constants.GrantTypeCanonicalUser:
  449. if ag.ID != bg.ID {
  450. if ag.ID == nil || bg.ID == nil {
  451. return false
  452. }
  453. if *ag.ID != *bg.ID {
  454. return false
  455. }
  456. }
  457. case s3_constants.GrantTypeAmazonCustomerByEmail:
  458. if ag.EmailAddress != bg.EmailAddress {
  459. if ag.EmailAddress == nil || bg.EmailAddress == nil {
  460. return false
  461. }
  462. if *ag.EmailAddress != *bg.EmailAddress {
  463. return false
  464. }
  465. }
  466. }
  467. }
  468. }
  469. return true
  470. }