Saleor 2067 - Guard against non-staff users logging in (#947)

* Guard against non-staff users logging in

* Scope channel permissions

* Update changelog

* Update tests
This commit is contained in:
Jakub Majorek 2021-01-18 12:19:04 +01:00 committed by GitHub
parent 0578de63c6
commit 18f09812a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 285 additions and 135 deletions

View file

@ -12,6 +12,7 @@ All notable, unreleased changes to this project will be documented in this file.
- Update quantity column in Inventory part of Product Variant view - #904 by @dominik-zeglen
- Add file attributes - #884 by @orzechdev
- Add shipping delivery days - #914 by @orzechdev
- Guard against non-staff users logging in - #947 by @jwm0
# 2.11.1

View file

@ -3032,6 +3032,9 @@
"src_dot_hooks_dot_3382262667": {
"string": "Variant {name} has been set as default."
},
"src_dot_insufficientPermissions": {
"string": "Insufficient permissions"
},
"src_dot_lastName": {
"string": "Last Name"
},
@ -6251,6 +6254,9 @@
"src_dot_translations_dot_components_dot_TranslationsVouchersPage_dot_2599922713": {
"string": "Voucher Name"
},
"src_dot_unauthorizedDashboardAccess": {
"string": "Only staff users can access the dashboard"
},
"src_dot_unconfirmed": {
"context": "order status",
"string": "Unconfirmed"

View file

@ -8,11 +8,11 @@
},
"entries": [
{
"_id": "f515e15cbc83df73e5bd41437971c2e6",
"_id": "a3088678db2635ada66ab049f76c9722",
"_order": 0,
"cache": {},
"request": {
"bodySize": 691,
"bodySize": 702,
"cookies": [],
"headers": [
{
@ -28,7 +28,7 @@
{
"_fromType": "array",
"name": "content-length",
"value": "691"
"value": "702"
},
{
"_fromType": "array",
@ -56,61 +56,53 @@
"postData": {
"mimeType": "application/json",
"params": [],
"text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTYwMjgyMTgsImV4cCI6MTU5NjAyODUxOCwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU1RPT0iLCJpc19zdGFmZiI6dHJ1ZX0.eo8_Ew98HICB4cFQN2U7mCJ8ydGVOvQLGRT4CnkufMc\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation VerifyToken($token: String!) {\\n tokenVerify(token: $token) {\\n payload\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
"text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2MzI1NDQsImV4cCI6MTYxMDYzMjg0NCwidG9rZW4iOiJrc0VWTXZnZzZCZmkiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU5BPT0iLCJpc19zdGFmZiI6dHJ1ZX0.QDp4vlm1tKhk8iFnY2MnREvO-IubI5j8g_Wylb1XJqc\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n isStaff\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation VerifyToken($token: String!) {\\n tokenVerify(token: $token) {\\n payload\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
},
"queryString": [],
"url": "http://localhost:8000/graphql/"
},
"response": {
"bodySize": 1619,
"bodySize": 1765,
"content": {
"mimeType": "application/json",
"size": 1619,
"text": "[{\"data\": {\"tokenVerify\": {\"payload\": {\"iat\": 1596028218, \"exp\": 1596028518, \"token\": \"C3Sk2kLRVuPA\", \"email\": \"admin@example.com\", \"type\": \"access\", \"user_id\": \"VXNlcjoyMQ==\", \"is_staff\": true}, \"user\": {\"id\": \"VXNlcjoyMQ==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"VerifyToken\"}}}]"
"size": 1765,
"text": "[{\"data\": {\"tokenVerify\": {\"payload\": {\"iat\": 1610632544, \"exp\": 1610632844, \"token\": \"ksEVMvgg6Bfi\", \"email\": \"admin@example.com\", \"type\": \"access\", \"user_id\": \"VXNlcjoyNA==\", \"is_staff\": true}, \"user\": {\"id\": \"VXNlcjoyNA==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"isStaff\": true, \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES\", \"name\": \"Manage product types and attributes.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"VerifyToken\"}}}]"
},
"cookies": [],
"headers": [
{
"name": "date",
"value": "Wed, 29 Jul 2020 13:10:18 GMT"
"value": "Thu, 14 Jan 2021 14:10:40 GMT"
},
{
"name": "server",
"value": "WSGIServer/0.2 CPython/3.8.1"
"value": "WSGIServer/0.2 CPython/3.8.7"
},
{
"name": "content-type",
"value": "application/json"
},
{
"name": "access-control-allow-origin",
"value": "http://localhost:9000"
},
{
"name": "access-control-allow-methods",
"value": "POST, OPTIONS"
},
{
"name": "access-control-allow-headers",
"value": "Origin, Content-Type, Accept, Authorization"
},
{
"name": "content-length",
"value": "1619"
"value": "1765"
},
{
"name": "x-content-type-options",
"value": "nosniff"
},
{
"name": "referrer-policy",
"value": "same-origin"
}
],
"headersSize": 336,
"headersSize": 194,
"httpVersion": "HTTP/1.1",
"redirectURL": "",
"status": 200,
"statusText": "OK"
},
"startedDateTime": "2020-07-29T13:10:18.327Z",
"time": 23,
"startedDateTime": "2021-01-14T14:10:40.434Z",
"time": 155,
"timings": {
"blocked": -1,
"connect": -1,
@ -118,7 +110,7 @@
"receive": 0,
"send": 0,
"ssl": -1,
"wait": 23
"wait": 155
}
}
],

View file

@ -8,11 +8,11 @@
},
"entries": [
{
"_id": "7c460842cac4a92c188d5451dfc533a2",
"_id": "a2b8a02f624e52cd2b73a831f65d9a52",
"_order": 0,
"cache": {},
"request": {
"bodySize": 587,
"bodySize": 598,
"cookies": [],
"headers": [
{
@ -28,7 +28,7 @@
{
"_fromType": "array",
"name": "content-length",
"value": "587"
"value": "598"
},
{
"_fromType": "array",
@ -56,74 +56,65 @@
"postData": {
"mimeType": "application/json",
"params": [],
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"admin\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"admin\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n isStaff\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
},
"queryString": [],
"url": "http://localhost:8000/graphql/"
},
"response": {
"bodySize": 1830,
"bodySize": 1976,
"content": {
"mimeType": "application/json",
"size": 1830,
"text": "[{\"data\": {\"tokenCreate\": {\"errors\": [], \"csrfToken\": \"rLPNMGNYKXH8VY4UNEWl4nEOFMseocljioigPl36IM2CqbdmOTEpNwvdHBAJ1ZWQ\", \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTYwMjgyMTgsImV4cCI6MTU5NjAyODUxOCwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU1RPT0iLCJpc19zdGFmZiI6dHJ1ZX0.eo8_Ew98HICB4cFQN2U7mCJ8ydGVOvQLGRT4CnkufMc\", \"user\": {\"id\": \"VXNlcjoyMQ==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"CreateToken\"}}}]"
"size": 1976,
"text": "[{\"data\": {\"tokenCreate\": {\"errors\": [], \"csrfToken\": \"UIzzJSFalS8pplfM1j5QNIUNiXb0VFH3kbe6kfTddYvLjJ9DhMasCtHJKXoGDfbw\", \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2MzI1NDQsImV4cCI6MTYxMDYzMjg0NCwidG9rZW4iOiJrc0VWTXZnZzZCZmkiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6ImFjY2VzcyIsInVzZXJfaWQiOiJWWE5sY2pveU5BPT0iLCJpc19zdGFmZiI6dHJ1ZX0.QDp4vlm1tKhk8iFnY2MnREvO-IubI5j8g_Wylb1XJqc\", \"user\": {\"id\": \"VXNlcjoyNA==\", \"email\": \"admin@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"isStaff\": true, \"userPermissions\": [{\"code\": \"MANAGE_APPS\", \"name\": \"Manage apps\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_CHECKOUTS\", \"name\": \"Manage checkouts\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_DISCOUNTS\", \"name\": \"Manage sales and vouchers.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_GIFT_CARD\", \"name\": \"Manage gift cards.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_MENUS\", \"name\": \"Manage navigation.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_ORDERS\", \"name\": \"Manage orders.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PAGES\", \"name\": \"Manage pages.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PLUGINS\", \"name\": \"Manage plugins\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES\", \"name\": \"Manage product types and attributes.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_PRODUCTS\", \"name\": \"Manage products.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SETTINGS\", \"name\": \"Manage settings.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_SHIPPING\", \"name\": \"Manage shipping.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_STAFF\", \"name\": \"Manage staff.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_TRANSLATIONS\", \"name\": \"Manage translations.\", \"__typename\": \"UserPermission\"}, {\"code\": \"MANAGE_USERS\", \"name\": \"Manage customers.\", \"__typename\": \"UserPermission\"}], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"CreateToken\"}}}]"
},
"cookies": [
{
"httpOnly": true,
"name": "refreshToken",
"path": "/",
"secure": true,
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTYwMjgyMTgsImV4cCI6MTU5ODYyMDIxOCwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lNUT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6InJMUE5NR05ZS1hIOFZZNFVORVdsNG5FT0ZNc2VvY2xqaW9pZ1BsMzZJTTJDcWJkbU9URXBOd3ZkSEJBSjFaV1EifQ.boD8G4pkSnZF-PLl5oOg85Uj-mqTiAzOkua9aAG3Bz4"
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2MzI1NDQsImV4cCI6MTYxMzIyNDU0NCwidG9rZW4iOiJrc0VWTXZnZzZCZmkiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lOQT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6IlVJenpKU0ZhbFM4cHBsZk0xajVRTklVTmlYYjBWRkgza2JlNmtmVGRkWXZMako5RGhNYXNDdEhKS1hvR0RmYncifQ.Br0GWGPPcnysyUxukjBBfXNbwCAm2qlR5OYClwFF3ZQ"
}
],
"headers": [
{
"name": "date",
"value": "Wed, 29 Jul 2020 13:10:18 GMT"
"value": "Thu, 14 Jan 2021 13:55:44 GMT"
},
{
"name": "server",
"value": "WSGIServer/0.2 CPython/3.8.1"
"value": "WSGIServer/0.2 CPython/3.8.7"
},
{
"name": "content-type",
"value": "application/json"
},
{
"name": "access-control-allow-origin",
"value": "http://localhost:9000"
},
{
"name": "access-control-allow-methods",
"value": "POST, OPTIONS"
},
{
"name": "access-control-allow-headers",
"value": "Origin, Content-Type, Accept, Authorization"
},
{
"name": "content-length",
"value": "1830"
"value": "1976"
},
{
"name": "x-content-type-options",
"value": "nosniff"
},
{
"name": "referrer-policy",
"value": "same-origin"
},
{
"_fromType": "array",
"name": "set-cookie",
"value": "refreshToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1OTYwMjgyMTgsImV4cCI6MTU5ODYyMDIxOCwidG9rZW4iOiJDM1NrMmtMUlZ1UEEiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lNUT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6InJMUE5NR05ZS1hIOFZZNFVORVdsNG5FT0ZNc2VvY2xqaW9pZ1BsMzZJTTJDcWJkbU9URXBOd3ZkSEJBSjFaV1EifQ.boD8G4pkSnZF-PLl5oOg85Uj-mqTiAzOkua9aAG3Bz4; HttpOnly; Path=/; Secure"
"value": "refreshToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2MzI1NDQsImV4cCI6MTYxMzIyNDU0NCwidG9rZW4iOiJrc0VWTXZnZzZCZmkiLCJlbWFpbCI6ImFkbWluQGV4YW1wbGUuY29tIiwidHlwZSI6InJlZnJlc2giLCJ1c2VyX2lkIjoiVlhObGNqb3lOQT09IiwiaXNfc3RhZmYiOnRydWUsImNzcmZUb2tlbiI6IlVJenpKU0ZhbFM4cHBsZk0xajVRTklVTmlYYjBWRkgza2JlNmtmVGRkWXZMako5RGhNYXNDdEhKS1hvR0RmYncifQ.Br0GWGPPcnysyUxukjBBfXNbwCAm2qlR5OYClwFF3ZQ; HttpOnly; Path=/"
}
],
"headersSize": 768,
"headersSize": 618,
"httpVersion": "HTTP/1.1",
"redirectURL": "",
"status": 200,
"statusText": "OK"
},
"startedDateTime": "2020-07-29T13:10:18.064Z",
"time": 118,
"startedDateTime": "2021-01-14T13:55:44.094Z",
"time": 392,
"timings": {
"blocked": -1,
"connect": -1,
@ -131,7 +122,7 @@
"receive": 0,
"send": 0,
"ssl": -1,
"wait": 118
"wait": 392
}
}
],

View file

@ -8,11 +8,11 @@
},
"entries": [
{
"_id": "4836098613648775386c1e10728424dd",
"_id": "b1557b45bbbf7aed1a4a53f5141ca324",
"_order": 0,
"cache": {},
"request": {
"bodySize": 428,
"bodySize": 439,
"cookies": [],
"headers": [
{
@ -28,7 +28,7 @@
{
"_fromType": "array",
"name": "content-length",
"value": "428"
"value": "439"
},
{
"_fromType": "array",
@ -56,7 +56,7 @@
"postData": {
"mimeType": "application/json",
"params": [],
"text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"NotAToken\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation VerifyToken($token: String!) {\\n tokenVerify(token: $token) {\\n payload\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
"text": "[{\"operationName\":\"VerifyToken\",\"variables\":{\"token\":\"NotAToken\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n isStaff\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation VerifyToken($token: String!) {\\n tokenVerify(token: $token) {\\n payload\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
},
"queryString": [],
"url": "http://localhost:8000/graphql/"
@ -72,28 +72,16 @@
"headers": [
{
"name": "date",
"value": "Wed, 29 Jul 2020 13:10:18 GMT"
"value": "Thu, 14 Jan 2021 14:10:40 GMT"
},
{
"name": "server",
"value": "WSGIServer/0.2 CPython/3.8.1"
"value": "WSGIServer/0.2 CPython/3.8.7"
},
{
"name": "content-type",
"value": "application/json"
},
{
"name": "access-control-allow-origin",
"value": "http://localhost:9000"
},
{
"name": "access-control-allow-methods",
"value": "POST, OPTIONS"
},
{
"name": "access-control-allow-headers",
"value": "Origin, Content-Type, Accept, Authorization"
},
{
"name": "content-length",
"value": "89"
@ -101,16 +89,20 @@
{
"name": "x-content-type-options",
"value": "nosniff"
},
{
"name": "referrer-policy",
"value": "same-origin"
}
],
"headersSize": 334,
"headersSize": 192,
"httpVersion": "HTTP/1.1",
"redirectURL": "",
"status": 200,
"statusText": "OK"
},
"startedDateTime": "2020-07-29T13:10:18.368Z",
"time": 6,
"startedDateTime": "2021-01-14T14:10:40.611Z",
"time": 25,
"timings": {
"blocked": -1,
"connect": -1,
@ -118,7 +110,7 @@
"receive": 0,
"send": 0,
"ssl": -1,
"wait": 6
"wait": 25
}
}
],

View file

@ -0,0 +1,132 @@
{
"log": {
"_recordingName": "User/will not be logged if is non-staff",
"creator": {
"comment": "persister:fs",
"name": "Polly.JS",
"version": "5.0.0"
},
"entries": [
{
"_id": "0b09ec35ecae5b17a2ccda062b1d6ef5",
"_order": 0,
"cache": {},
"request": {
"bodySize": 602,
"cookies": [],
"headers": [
{
"_fromType": "array",
"name": "accept",
"value": "*/*"
},
{
"_fromType": "array",
"name": "content-type",
"value": "application/json"
},
{
"_fromType": "array",
"name": "content-length",
"value": "602"
},
{
"_fromType": "array",
"name": "user-agent",
"value": "node-fetch/1.0 (+https://github.com/bitinn/node-fetch)"
},
{
"_fromType": "array",
"name": "accept-encoding",
"value": "gzip,deflate"
},
{
"_fromType": "array",
"name": "connection",
"value": "close"
},
{
"name": "host",
"value": "localhost:8000"
}
],
"headersSize": 254,
"httpVersion": "HTTP/1.1",
"method": "POST",
"postData": {
"mimeType": "application/json",
"params": [],
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"client@example.com\",\"password\":\"password\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n isStaff\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
},
"queryString": [],
"url": "http://localhost:8000/graphql/"
},
"response": {
"bodySize": 616,
"content": {
"mimeType": "application/json",
"size": 616,
"text": "[{\"data\": {\"tokenCreate\": {\"errors\": [], \"csrfToken\": \"Gac5v8mZt6dW0HBXp5RNt8GAWciTbVzsycpqtUKV797npCXajke5h9VoF4l9MreP\", \"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2OTg2MzMsImV4cCI6MTYxMDY5ODkzMywidG9rZW4iOiJ6MDc2QndLZkNEMmYiLCJlbWFpbCI6ImNsaWVudEBleGFtcGxlLmNvbSIsInR5cGUiOiJhY2Nlc3MiLCJ1c2VyX2lkIjoiVlhObGNqb3pNQT09IiwiaXNfc3RhZmYiOmZhbHNlfQ.RVYwqQSPEZoi2E_ImC30Ml37RJ2Fu6AnSmfDkAYMcqY\", \"user\": {\"id\": \"VXNlcjozMA==\", \"email\": \"client@example.com\", \"firstName\": \"\", \"lastName\": \"\", \"isStaff\": false, \"userPermissions\": [], \"avatar\": null, \"__typename\": \"User\"}, \"__typename\": \"CreateToken\"}}}]"
},
"cookies": [
{
"httpOnly": true,
"name": "refreshToken",
"path": "/",
"value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2OTg2MzMsImV4cCI6MTYxMzI5MDYzMywidG9rZW4iOiJ6MDc2QndLZkNEMmYiLCJlbWFpbCI6ImNsaWVudEBleGFtcGxlLmNvbSIsInR5cGUiOiJyZWZyZXNoIiwidXNlcl9pZCI6IlZYTmxjam96TUE9PSIsImlzX3N0YWZmIjpmYWxzZSwiY3NyZlRva2VuIjoiR2FjNXY4bVp0NmRXMEhCWHA1Uk50OEdBV2NpVGJWenN5Y3BxdFVLVjc5N25wQ1hhamtlNWg5Vm9GNGw5TXJlUCJ9.jUF_9vvtwT8EUbQ4GM7u0YVivk7TiSoSecHDZ0jJ2MI"
}
],
"headers": [
{
"name": "date",
"value": "Fri, 15 Jan 2021 08:17:13 GMT"
},
{
"name": "server",
"value": "WSGIServer/0.2 CPython/3.8.7"
},
{
"name": "content-type",
"value": "application/json"
},
{
"name": "content-length",
"value": "616"
},
{
"name": "x-content-type-options",
"value": "nosniff"
},
{
"name": "referrer-policy",
"value": "same-origin"
},
{
"_fromType": "array",
"name": "set-cookie",
"value": "refreshToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MTA2OTg2MzMsImV4cCI6MTYxMzI5MDYzMywidG9rZW4iOiJ6MDc2QndLZkNEMmYiLCJlbWFpbCI6ImNsaWVudEBleGFtcGxlLmNvbSIsInR5cGUiOiJyZWZyZXNoIiwidXNlcl9pZCI6IlZYTmxjam96TUE9PSIsImlzX3N0YWZmIjpmYWxzZSwiY3NyZlRva2VuIjoiR2FjNXY4bVp0NmRXMEhCWHA1Uk50OEdBV2NpVGJWenN5Y3BxdFVLVjc5N25wQ1hhamtlNWg5Vm9GNGw5TXJlUCJ9.jUF_9vvtwT8EUbQ4GM7u0YVivk7TiSoSecHDZ0jJ2MI; HttpOnly; Path=/"
}
],
"headersSize": 619,
"httpVersion": "HTTP/1.1",
"redirectURL": "",
"status": 200,
"statusText": "OK"
},
"startedDateTime": "2021-01-15T08:17:12.850Z",
"time": 623,
"timings": {
"blocked": -1,
"connect": -1,
"dns": -1,
"receive": 0,
"send": 0,
"ssl": -1,
"wait": 623
}
}
],
"pages": [],
"version": "1.2"
}
}

View file

@ -8,11 +8,11 @@
},
"entries": [
{
"_id": "86487093ff8b070d496fcdc566e01adf",
"_id": "d94d7821dc951e48c410d691d7eccdef",
"_order": 0,
"cache": {},
"request": {
"bodySize": 603,
"bodySize": 614,
"cookies": [],
"headers": [
{
@ -28,7 +28,7 @@
{
"_fromType": "array",
"name": "content-length",
"value": "603"
"value": "614"
},
{
"_fromType": "array",
@ -56,7 +56,7 @@
"postData": {
"mimeType": "application/json",
"params": [],
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"NotAValidPassword123!\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
"text": "[{\"operationName\":\"TokenAuth\",\"variables\":{\"email\":\"admin@example.com\",\"password\":\"NotAValidPassword123!\"},\"query\":\"fragment User on User {\\n id\\n email\\n firstName\\n lastName\\n isStaff\\n userPermissions {\\n code\\n name\\n __typename\\n }\\n avatar {\\n url\\n __typename\\n }\\n __typename\\n}\\n\\nmutation TokenAuth($email: String!, $password: String!) {\\n tokenCreate(email: $email, password: $password) {\\n errors: accountErrors {\\n field\\n message\\n __typename\\n }\\n csrfToken\\n token\\n user {\\n ...User\\n __typename\\n }\\n __typename\\n }\\n}\\n\"}]"
},
"queryString": [],
"url": "http://localhost:8000/graphql/"
@ -72,28 +72,16 @@
"headers": [
{
"name": "date",
"value": "Wed, 29 Jul 2020 13:10:18 GMT"
"value": "Thu, 14 Jan 2021 13:55:45 GMT"
},
{
"name": "server",
"value": "WSGIServer/0.2 CPython/3.8.1"
"value": "WSGIServer/0.2 CPython/3.8.7"
},
{
"name": "content-type",
"value": "application/json"
},
{
"name": "access-control-allow-origin",
"value": "http://localhost:9000"
},
{
"name": "access-control-allow-methods",
"value": "POST, OPTIONS"
},
{
"name": "access-control-allow-headers",
"value": "Origin, Content-Type, Accept, Authorization"
},
{
"name": "content-length",
"value": "214"
@ -101,16 +89,20 @@
{
"name": "x-content-type-options",
"value": "nosniff"
},
{
"name": "referrer-policy",
"value": "same-origin"
}
],
"headersSize": 335,
"headersSize": 193,
"httpVersion": "HTTP/1.1",
"redirectURL": "",
"status": 200,
"statusText": "OK"
},
"startedDateTime": "2020-07-29T13:10:18.208Z",
"time": 99,
"startedDateTime": "2021-01-14T13:55:44.521Z",
"time": 1183,
"timings": {
"blocked": -1,
"connect": -1,
@ -118,7 +110,7 @@
"receive": 0,
"send": 0,
"ssl": -1,
"wait": 99
"wait": 1183
}
}
],

View file

@ -20,12 +20,17 @@ function renderAuthProvider(apolloClient: ApolloClient<any>) {
return result;
}
const credentials = {
const adminCredentials = {
email: "admin@example.com",
password: "admin",
token: null
};
const nonStaffUserCredentials = {
email: "client@example.com",
password: "password"
};
beforeEach(() => {
localStorage.clear();
sessionStorage.clear();
@ -36,10 +41,10 @@ describe("User", () => {
const hook = renderAuthProvider(apolloClient);
await act(() =>
hook.current.login(credentials.email, credentials.password)
hook.current.login(adminCredentials.email, adminCredentials.password)
);
expect(hook.current.userContext.email).toBe(credentials.email);
credentials.token = getTokens().auth;
expect(hook.current.userContext.email).toBe(adminCredentials.email);
adminCredentials.token = getTokens().auth;
done();
});
@ -48,19 +53,33 @@ describe("User", () => {
const hook = renderAuthProvider(apolloClient);
await act(() =>
hook.current.login(credentials.email, "NotAValidPassword123!")
hook.current.login(adminCredentials.email, "NotAValidPassword123!")
);
expect(hook.current.userContext).toBe(null);
done();
});
it("will not be logged in if is non-staff", async done => {
const hook = renderAuthProvider(apolloClient);
await act(() =>
hook.current.login(
nonStaffUserCredentials.email,
nonStaffUserCredentials.password
)
);
expect(hook.current.userContext).toBe(undefined);
done();
});
it("will be logged if has valid token", async done => {
setAuthToken(credentials.token, false);
setAuthToken(adminCredentials.token, false);
const hook = renderAuthProvider(apolloClient);
await act(() => hook.current.autologinPromise.current);
expect(hook.current.userContext.email).toBe(credentials.email);
expect(hook.current.userContext.email).toBe(adminCredentials.email);
done();
});

View file

@ -2,6 +2,7 @@ import { IMessageContext } from "@saleor/components/messages";
import { DEMO_MODE } from "@saleor/config";
import { User } from "@saleor/fragments/types/User";
import useNotifier from "@saleor/hooks/useNotifier";
import { commonMessages } from "@saleor/intl";
import { getMutationStatus } from "@saleor/misc";
import {
isSupported as isCredentialsManagementAPISupported,
@ -41,6 +42,26 @@ export function useAuthProvider(
const autologinPromise = useRef<Promise<any>>();
const refreshPromise = useRef<Promise<boolean>>();
useEffect(() => {
const token = getTokens().auth;
if (!!token && !userContext) {
autologinPromise.current = tokenVerify({ variables: { token } });
} else {
autologinPromise.current = loginWithCredentialsManagementAPI(login);
}
}, []);
useEffect(() => {
if (userContext && !userContext.isStaff) {
logout();
notify({
status: "error",
text: intl.formatMessage(commonMessages.unauthorizedDashboardAccess),
title: intl.formatMessage(commonMessages.insufficientPermissions)
});
}
}, [userContext]);
const logout = () => {
setUserContext(undefined);
if (isCredentialsManagementAPISupported) {
@ -54,22 +75,18 @@ export function useAuthProvider(
TokenAuthVariables
>(tokenAuthMutation, {
client: apolloClient,
onCompleted: result => {
if (result.tokenCreate.errors.length > 0) {
onCompleted: ({ tokenCreate }) => {
if (tokenCreate.errors.length > 0) {
logout();
}
const user = result.tokenCreate.user;
const user = tokenCreate.user;
// FIXME: Now we set state also when auth fails and returned user is
// `null`, because the LoginView uses this `null` to display error.
setUserContext(user);
if (user) {
setTokens(
result.tokenCreate.token,
result.tokenCreate.csrfToken,
persistToken
);
setTokens(tokenCreate.token, tokenCreate.csrfToken, persistToken);
}
},
onError: logout
@ -115,15 +132,6 @@ export function useAuthProvider(
}
};
useEffect(() => {
const token = getTokens().auth;
if (!!token && !userContext) {
autologinPromise.current = tokenVerify({ variables: { token } });
} else {
autologinPromise.current = loginWithCredentialsManagementAPI(login);
}
}, []);
const login = async (email: string, password: string) => {
const result = await tokenAuth({ variables: { email, password } });

View file

@ -31,6 +31,7 @@ export interface SetPassword_setPassword_user {
email: string;
firstName: string;
lastName: string;
isStaff: boolean;
userPermissions: (SetPassword_setPassword_user_userPermissions | null)[] | null;
avatar: SetPassword_setPassword_user_avatar | null;
}

View file

@ -31,6 +31,7 @@ export interface TokenAuth_tokenCreate_user {
email: string;
firstName: string;
lastName: string;
isStaff: boolean;
userPermissions: (TokenAuth_tokenCreate_user_userPermissions | null)[] | null;
avatar: TokenAuth_tokenCreate_user_avatar | null;
}

View file

@ -25,6 +25,7 @@ export interface VerifyToken_tokenVerify_user {
email: string;
firstName: string;
lastName: string;
isStaff: boolean;
userPermissions: (VerifyToken_tokenVerify_user_userPermissions | null)[] | null;
avatar: VerifyToken_tokenVerify_user_avatar | null;
}

View file

@ -33,8 +33,8 @@ export const AppChannelProvider: React.FC = ({ children }) => {
const [isPickerActive, setPickerActive] = React.useState(false);
React.useEffect(() => {
if (!selectedChannel) {
setSelectedChannel(channelData?.channels[0].id);
if (!selectedChannel && channelData?.channels) {
setSelectedChannel(channelData.channels[0].id);
}
}, [channelData]);

View file

@ -17,6 +17,7 @@ const user: User = {
email: "email@example.com",
firstName: "User",
id: "123",
isStaff: true,
lastName: "User",
userPermissions: [
{

View file

@ -6,6 +6,7 @@ export const fragmentUser = gql`
email
firstName
lastName
isStaff
userPermissions {
code
name

View file

@ -25,6 +25,7 @@ export interface User {
email: string;
firstName: string;
lastName: string;
isStaff: boolean;
userPermissions: (User_userPermissions | null)[] | null;
avatar: User_avatar | null;
}

View file

@ -95,6 +95,10 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
<ResponsiveTable>
<TableBody className={classes.tableRow}>
{noChannel && (
<RequirePermissions
userPermissions={userPermissions}
requiredPermissions={[PermissionEnum.MANAGE_CHANNELS]}
>
<TableRow hover={true} onClick={onCreateNewChannelClick}>
<TableCell>
<Typography>
@ -105,6 +109,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
<KeyboardArrowRight />
</TableCell>
</TableRow>
</RequirePermissions>
)}
<RequirePermissions
userPermissions={userPermissions}

View file

@ -49,6 +49,9 @@ export const commonMessages = defineMessages({
generalInformations: {
defaultMessage: "General Information"
},
insufficientPermissions: {
defaultMessage: "Insufficient permissions"
},
lastName: {
defaultMessage: "Last Name"
},
@ -89,6 +92,9 @@ export const commonMessages = defineMessages({
summary: {
defaultMessage: "Summary"
},
unauthorizedDashboardAccess: {
defaultMessage: "Only staff users can access the dashboard"
},
uploadImage: {
defaultMessage: "Upload image",
description: "button"