ACL + SonataAdminBundle + SonataUserBundle - symfony

In my Symfony2 project I managed to setup FOSUserBundle + SonataUserBundle + SonataAdminBundle following official docs. Now comes the time to setup the ACL (Access control list).
What I did :
Created an AdminClass called AdminReport
app/console sonata:admin:setup-acl
install ACL for sonata.admin.report
update role: ROLE_SONATA_ADMIN_REPORT_GUEST, permissions: ["LIST"]
update role: ROLE_SONATA_ADMIN_REPORT_STAFF, permissions: ["LIST","CREATE"]
update role: ROLE_SONATA_ADMIN_REPORT_EDITOR, permissions: ["OPERATOR","EXPORT"]
created a new user, granted him with ROLE_SONATA_ADMIN_REPORT_STAFF
app/console sonata:admin:generate-object-acl
Logged in with this user and accessed the default /admin/dashboard
The block containing the AdminReport should appear but it's not... I am missing something ?
Here's my config.yml
sonata_admin:
security:
handler: sonata.admin.security.handler.acl
information:
GUEST: [VIEW, LIST]
STAFF: [EDIT, LIST, CREATE]
EDITOR: [OPERATOR, EXPORT]
ADMIN: [MASTER]
admin_permissions: [CREATE, LIST, DELETE, UNDELETE, EXPORT, OPERATOR, MASTER]
object_permissions: [VIEW, EDIT, DELETE, UNDELETE, OPERATOR, MASTER, OWNER]
EDIT
I tried to access directly app_dev.php/admin/app/report/list with this user, and Symfony throws an Access Denied error. Log says
DEBUG - Access denied, the user is neither anonymous, nor remember-me.
And if I access app_dev.php/admin/app/report/list it works !
So I tried to change the handler from sonata.admin.security.handler.acl to sonata.admin.security.handler.roles
It works because I can see the block in admin dashboard. I also tried to change access_decision_manager:
strategy: unanimous
to affirmative but it doesn't work...
I am definitely missing something but where ?

Well, after some tweaking I achieved to make it working.
First, in my 'sonata.yml' in app/config/ I have changed the perms like the following :
app/config/sonata.yml :
sonata_admin:
security:
handler: sonata.admin.security.handler.acl
# acl security information
information:
# GUEST: [VIEW, LIST]
# STAFF: [EDIT, LIST, CREATE]
# EDITOR: [OPERATOR, EXPORT]
# ADMIN: [MASTER]
EDIT: EDIT
LIST: LIST
CREATE: CREATE
VIEW: VIEW
DELETE: DELETE
EXPORT: EXPORT
MASTER: MASTER
To avoid this...
DEBUG - Access denied, the user is neither anonymous, nor remember-me
... i've commented out the following, because i think the firewall voter block the access to my user. Maybe not the wiser solution, but runs good for now :)
app/config/security.yml :
# set access_strategy to unanimous, else you may have unexpected behaviors
# access_decision_manager:
# strategy: unanimous
Notice that my app is built only around the admin dahboard, so each user needs to have the dashboard access when they're created.
In that way, I've modified my User constructor like this :
src/Application/Sonata/UserBundle/Entity/User.php :
class User extends BaseUser
{
/**
* #var integer $id
*/
protected $id;
public function __construct() {
parent::__construct();
// your own logic
$this->roles = array('ROLE_USER', 'ROLE_SONATA_ADMIN', 'ROLE_SONATA_PAGE_ADMIN_PAGE_EDIT');
}
/**
* Get id
*
* #return integer $id
*/
public function getId()
{
return $this->id;
}
}
EDIT : It seems that, without knowing it, I replied to another of your questions ^^" (How can I assign default role to user in Symfony2)
Now each user can access the dashboard but like your issue, they cannot see anything.
I needed to use ACL, but like roles my users belong to groups who have their own ACL.
Once my user belong to one or many groups, he got the groups permissions in addition of his own permissions.
By managing one group's permissions, each user belonging to this group have his permissions modified. And by editing a user's permissions, I can make it access some pages that a group won't allow.
For example :
┌─────────────┐
│ GROUP_1 │ ┌───────────────┐
├─────────────┤ │ USER_1 │
│ CAT2_VIEW │ │ applied perms │
│ CAT2_LIST │ ├───────────────┤
│ CAT2_EDIT │ │ CAT1_VIEW │
│ CAT2_DELETE │ │ CAT1_LIST │
├─────────────┤ ├───────────────┤
│ CAT3_VIEW │ ├────┐ │ CAT2_VIEW │
┌─────────────┐ │ CAT3_LIST │ │ │ CAT2_LIST │
│ USER_A │ │ CAT3_EDIT │ │ │ CAT2_EDIT │
├─────────────┤<────────┤ CAT3_DELETE │ │ │ CAT2_DELETE │
│ CAT1_VIEW │ └─────────────┘ │ ├───────────────┤
│ CAT1_LIST │ ├────> │ CAT3_VIEW │
│ │ ┌─────────────┐ │ │ CAT3_LIST │
│ │<────────┤ GROUP_2 │ │ │ CAT3_EDIT │
└─────────────┘ ├─────────────┤ │ │ CAT3_DELETE │
│ CAT4_VIEW │ │ ├───────────────┤
│ CAT4_LIST │ │ │ CAT4_VIEW │
│ CAT4_EDIT │ ├────┘ │ CAT4_LIST │
│ CAT4_DELETE │ │ CAT4_EDIT │
│ CAT4_EXPORT │ │ CAT4_DELETE │
└─────────────┘ │ CAT4_EXPORT │
└───────────────┘
I managed to make it work this way, like I wanted, but I don't know if this is the best solution for your issue.
I hope this will help you :)
PS : If anyone see any mistake or any illogical thing, don't hesitate to tell me in comment, i'm still learning to use it, and it'll be helpful :)

The PermissionMap of SonataAdminBundle extends Symfony's BasicPermissionMap. Only if you change this default configuration, the AclVoter supports the attributes 'LIST' and 'EXPORT' and can possibly vote to grant the wanted permissions.
parameters:
security.acl.permission.map.class: Sonata\AdminBundle\Security\Acl\Permission\AdminPermissionMap
See my answer to AclVoter denies access to 'LIST'

Related

How and when to strip the url to serve a static site?

I have the following directory structure for my static web site:
│ infinote.exe
└───spa
│ favicon.ico
│ index.html
│
├───css
│ app.f99f51d4.css
│ vendor.d9e2261d.css
│
├───fonts
│ flUhRq6tzZclQEJ-Vdg-IuiaDsNa.40fa1be9.woff
│ flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.cf9862e8.woff2
│ KFOkCnqEu92Fr1MmgVxIIzQ.9391e6e2.woff
│ KFOlCnqEu92Fr1MmEU9fBBc-.ddd11dab.woff
│ KFOlCnqEu92Fr1MmSU5fBBc-.877b9231.woff
│ KFOlCnqEu92Fr1MmWUlfBBc-.0344cc3c.woff
│ KFOlCnqEu92Fr1MmYUtfBBc-.b555d228.woff
│ KFOmCnqEu92Fr1Mu4mxM.9b78ea3b.woff
│ PatuaOne-Regular.ttf
│ Poppins-Regular.ttf
│
├───icons
│ apple-icon-120x120.png
│ apple-launch-828x1792.png
│ favicon-128x128.png
│ favicon-16x16.png
│ favicon-32x32.png
│ favicon-96x96.png
│ icon-128x128.png
│ safari-pinned-tab.svg
│
└───js
app.3a5b0240.js
vendor.a9a3886c.js
infinote.exe is a binary compiled from Go and the line where I define how to serve the web site is
r.Handle("/spa/", http.StripPrefix("/spa/", http.FileServer(http.Dir("./spa"))))
I use chi as the router, and r := chi.NewRouter().
I expect http://example.com/spa/ to:
first request http://example.com/spa/ → this is ./spa/index.html
and then after parsing index.html, to request other files in ./spa
An example would be http://example.com/spa/js/vendor.a9a3886c.js → ./spa/js/vendor.a9a3886c.js
What happens is that index.html is retrieved correctly, and then all the referenced files return a 404 Not Found.
To be frank I do not exactly understand the mechanics (and need) of http.StripPrefix. Is this because the files in spa are relative to the full URL, in other words to ./spa/spa/...- which is not correct (and thus the need to strip app first)?
If so, why is only index.html retrieved correctly? Even favicon.ico is a 404 despite being in the same directory as index.html.
All credit goes to #mkopriva and #Zombo whose comments were, for some reason, deleted
After several iterations and tests, I managed to find a working version:
r.Handle("/spa/*",http.StripPrefix("/spa/", ttp.FileServer(http.Dir("spa"))))
The key part was the * in the first "pattern". I did not find anything about wildcards in the documentation but with a * it works - and without it does not (I get the 404`).
I would be delighted to have an answer that is better than that

Firebase Realtime Database Profiler $wildcard

I ran the database profiler recently for about 50 minutes, where about 200k operations were performed. I was most interested in bandwidth to keep an eye on costs. However, when stopping the profiler, I had difficulty understanding the bandwidth report. Here it is:
┌──────────────────────────────────────────────────────────┬───────────┬────────┬─────────────────────┐
│ Path │ Total │ Count │ Average │
├──────────────────────────────────────────────────────────┼───────────┼────────┼─────────────────────┤
│ /event/$wildcard/$wildcard/$wildcard │ 267.76 MB │ 49,171 │ 5.45 kB │
├──────────────────────────────────────────────────────────┼───────────┼────────┼─────────────────────┤
│ /event/$wildcard/$wildcard │ 75.85 MB │ 9,833 │ 7.71 kB │
├──────────────────────────────────────────────────────────┼───────────┼────────┼─────────────────────┤
│ /event/$wildcard/$wildcard/$wildcard/$wildcard/$wildcard │ 1.50 MB │ 45,513 │ 32.96106606903522 B │
├──────────────────────────────────────────────────────────┼───────────┼────────┼─────────────────────┤
│ /event/$wildcard/$wildcard/$wildcard/$wildcard │ 1.38 MB │ 14,133 │ 97.86648270006368 B │
├──────────────────────────────────────────────────────────┼───────────┼────────┼─────────────────────┤
│ / │ 529.45 kB │ 33 │ 16.04 kB │
└──────────────────────────────────────────────────────────┴───────────┴────────┴─────────────────────┘
I understand this about the $wildcard:
"Path: The path in your database where the operations occurred. If there are more than 25 child nodes, the profiler tool collapses these into a parent path and adds a $wildcard marker. You might see your database's root directory in the report, represented by a forward slash /."
Looking at the biggest bandwidth consumer, /event/$wildcard/$wildcard/$wildcard , I do not know what to make of it. Those wildcards could be anything. Is there a way to interpret it that I am missing?

Firebase function status failed

D:\work\ocr\receiptWeb\functions>functions list
┌────────┬────────┬─────────┬─────────────────────────────────────────────────────────────────┐
│ Status │ Name │ Trigger │ Resource │
├────────┼────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ FAILED │ upload │ HTTP │ http://localhost:8010/invoice-manager-251609/us-central1/upload │
├────────┼────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ FAILED │ tst │ HTTP │ http://localhost:8010/invoice-manager-251609/us-central1/tst │
├────────┼────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ FAILED │ tst1 │ HTTP │ http://localhost:8010/invoice-manager-251609/us-central1/tst1 │
└────────┴────────┴─────────┴─────────────────────────────────────────────────────────────────┘
D:\work\ocr\receiptWeb\functions>functions describe tst1
┌────────────┬───────────────────────────────────────────────────────────────────┐
│ Property │ Value │
├────────────┼───────────────────────────────────────────────────────────────────┤
│ Name │ tst1 │
├────────────┼───────────────────────────────────────────────────────────────────┤
│ Trigger │ HTTP │
├────────────┼───────────────────────────────────────────────────────────────────┤
│ Resource │ http://localhost:8010/invoice-manager-251609/us-central1/tst1 │
├────────────┼───────────────────────────────────────────────────────────────────┤
│ Timeout │ 60 seconds │
├────────────┼───────────────────────────────────────────────────────────────────┤
│ Local path │ D:\work\ocr\receiptWeb\functions │
├────────────┼───────────────────────────────────────────────────────────────────┤
│ Archive │ file://C:\Users\USER\AppData\Local\Temp\tmp-12096kv8vKcUEnCAt.zip │
└────────────┴───────────────────────────────────────────────────────────────────┘
When I go to the url I get
Function worker crashed with exit code: 1\nundefinedWarning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail[2019-10-06T12:57:02.376Z] #firebase/database: FIREBASE FATAL ERROR: Cannot parse Firebase url. Please use https://<YOUR FIREBASE>.firebaseio.com
I did
set FIREBASE_CONFIG={"projectId":"invoice-manager-251609","appId":"1:127001043239:web:e3c996dc4dab60b7c94902","databaseURL":"https://invoice-manager-251609.firebaseio.com","storageBucket":"invoice-manager-251609.appspot.com","locationId":"europe-west","apiKey":"AIzaSyCaV3vpQaEMUPjz9CftkYdp888l7cLy8Gw","authDomain":"invoice-manager-251609.firebaseapp.com","messagingSenderId":"127001043239"}
and the url is correct
How can I get more info on reason for the FAILED status?
When a Cloud Function encounters an error, it typically logs details. You can view the log files of the local emulator with $ functions logs read.

debugging firebase on local windows

I'm trying to debug firebase function on my local windows
as described in https://medium.com/#mwebler/debugging-firebase-functions-with-vs-code-3afab528bb36
I do
set FIREBASE_CONFIG={ databaseURL: 'https://invoice-manager-251609.firebaseio.com', storageBucket: 'invoice-manager-251609.appspot.com', projectId: 'invoice-manager-251609'}
functions start
and get
┌────────┬────────┬─────────┬─────────────────────────────────────────────────────────────────┐
│ Status │ Name │ Trigger │ Resource │
├────────┼────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ FAILED │ upload │ HTTP │ http://localhost:8010/invoice-manager-251609/us-central1/upload │
├────────┼────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ FAILED │ tst │ HTTP │ http://localhost:8010/invoice-manager-251609/us-central1/tst │
├────────┼────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ FAILED │ tst1 │ HTTP │ http://localhost:8010/invoice-manager-251609/us-central1/tst1 │
└────────┴────────┴─────────┴─────────────────────────────────────────────────────────────────┘
if I do
firebase emulators:start
I get
undefinedWarning, estimating Firebase Config based on GCLOUD_PROJECT.
Initializing firebase-admin may fail[2019-10-06T11:44:51.932Z]
#firebase/database: FIREBASE FATAL ERROR: Cannot parse Firebase url.
Please use https://.firebaseio.com
I also tried:
functions debug tst1
and get:
ERROR: Function worker crashed with exit code: 9
undefined(node:21096) [DEP0062] DeprecationWarning: `node --debug
and
node --debug-brkare invalid. Please usenode --inspectornode --inspect-brk` instead.
I tried with node-10 and node-8
I also tried this:
https://medium.com/#david_mccoy/build-and-debug-firebase-functions-in-vscode-73efb76166cf
and this
https://rominirani.com/google-cloud-functions-tutorial-debugging-local-functions-357c24829198
I get the same errors
whats going on?
how do I debugging firebase on local windows?
The guides in the question are correct, but
when running in Emulator, u have to set the db url manually
admin.initializeApp({
databaseURL: "https://<YOUR FIREBASE>.firebaseio.com"
});
here is the full cmd list:
functions start
functions deploy --trigger-http --timeout 600s funcName
functions inspect funcName
After that u can use chrome://inspect/ to connect to the process with the chrome debugger.
If you have issues, u can use:
functions logs read
NOTE: after functions start I still get the table with FAILED status - I ignore it

What requests do browsers' "F5" and "Ctrl + F5" refreshes generate?

Is there a standard for what actions F5 and Ctrl+F5 trigger in web browsers?
I once did experiment in IE6 and Firefox 2.x. The F5 refresh would trigger a HTTP request sent to the server with an If-Modified-Since header, while Ctrl+F5 would not have such a header. In my understanding, F5 will try to utilize cached content as much as possible, while Ctrl+F5 is intended to abandon all cached content and just retrieve all content from the servers again.
But today, I noticed that in some of the latest browsers (Chrome, IE8) it doesn't work in this way anymore. Both F5 and Ctrl+F5 send the If-Modified-Since header.
So how is this supposed to work, or (if there is no standard) how do the major browsers differ in how they implement these refresh features?
It is up to the browser, but they behave in similar ways.
F5 usually updates the page only if it is modified. Modern browsers send Cache-Control: max-age=0 to tell any cache the maximum amount of time a resource is considered fresh, relative to the time of the request.
CTRL-F5 is used to force an update, disregarding any cache. Modern browsers send Cache-Control: no-cache and Pragma: No-cache
If I remember correctly, it was Netscape that was the first browser to add support for cache-control by adding Pragma: No-cache when you pressed CTRL-F5.
┌───────────┬──────────────┬─────┬─────────────────┬──────────────────────────────┐
│ Version 4 │ F5 │ R │ CLICK │ Legend: │
│2021 MAY 19├──┬──┬──┬──┬──┼──┬──┼──┬──┬──┬──┬──┬──┤ C = Cache-Control: no-cache │
│ │ │S │C │A │A │C │C │ │S │C │A │A │C │ I = If-Modified-Since │
│ │ │H │T │L │L │T │T │ │H │T │L │L │T │ M = Cache-Control: max-age=0 │
│ │ │I │R │T │T │R │R │ │I │R │T │T │R │ N = Not tested │
│ │ │F │L │ │G │L │L │ │F │L │ │G │L │ P = Pragma: No-cache │
│ │ │T │ │ │R │ │+ │ │T │ │ │R │+ │ - = ignored │
│ │ │ │ │ │ │ │S │ │ │ │ │ │S │ │
│ │ │ │ │ │ │ │H │ │ │ │ │ │H │ With 'CLICK' I refer to a │
│ │ │ │ │ │ │ │I │ │ │ │ │ │I │ mouse click on the browsers │
│ │ │ │ │ │ │ │F │ │ │ │ │ │F │ refresh-icon. │
│ │ │ │ │ │ │ │T │ │ │ │ │ │T │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ 1: Version 3.0.6 sends I │
├───────────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ and C, but 3.1.6 opens │
│Brave 1.24 │M │CP│CP│- │- │M │CP│M │CP│CP│M │CP│CP│ the page in a new tab, │
├───────────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ making a normal request │
│Chrome 1 │MI│MI│MI│- │- │MI│- │MI│MI│MI│MI│MI│N │ with only I. │
│Chrome 6 │MI│CP│CP│- │- │MI│CP│MI│CP│CP│MI│- │N │ 2: Version 10.62 does │
│Chrome 90 │M │CP│CP│- │- │M │CP│M │CP│CP│M │CP│CP│ nothing. 9.61 might do C │
├───────────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ unless it was a typo in │
│Edge 90 │M │CP│CP│- │- │M │CP│M │CP│CP│M │CP│CP│ my old table. │
├───────────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ 3: Opens the currernt tab in │
│Firefox 3.x│MI│- │CP│- │- │MI│CP│MI│CP│1 │M │MI│N │ a new tab, but does not │
│Firefox 89 │M │- │CP│- │M │M │CP│M │CP│3 │M │M │3 │ refresh the page if it is │
├───────────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ cached in the browser. │
│MSIE 8, 7 │I │- │C │- │I │I │ │I │I │C │I │I │N │ │
├───────────┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
│Opera 10, 9│C │- │- │2 │- │C │- │C │C │C │C │- │N │ │
│Opera 76 │M │CP│CP│- │- │M │- │M │CP│CP│M │CP│CP│ │
├───────────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──────────────────────────────┤
│ https://stackoverflow.com/a/385491/36866 │
└─────────────────────────────────────────────────────────────────────────────────┘
Note about Chrome 6.0.472: If you do a forced reload (like CTRL-F5) it behaves like the url is internally marked to always do a forced reload. The flag is cleared if you go to the address bar and press enter.
Generally speaking:
F5 may give you the same page even if the content is changed, because it may load the page from cache. But Ctrl+F5 forces a cache refresh, and will guarantee that if the content is changed, you will get the new content.
I've implemented cross-browser compatible page to test browser's refresh behavior (here is the source code) and get results similar to #some, but for modern browsers:
At least in Firefox (v3.5), cache seems to be disabled rather than simply cleared. If there are multiple instances of the same image on a page, it will be transferred multiple times. That is also the case for img tags that are added subsequently via Ajax/JavaScript.
So in case you're wondering why the browser keeps downloading the same little icon a few hundred times on your auto-refresh Ajax site, it's because you initially loaded the page using CTRL-F5.
IE7/8/9 seem to behave differently depending on whether the page has focus or not.
If you click on the page and CTRL+F5 then "Cache-Control: no-cache" is included in the request headers. If you click in the Location/Address bar then press CTRL+F5 it isn't.
When user press F5 although new request goes to web server and get a responce for the request as well. But when the responce header is Parsed it check the required information in browser cache. If the required information in cache has not expired then that information is restored from in cache itself.
When user click on CTRL-F5 even then new request goes to web server and get a responce. But this time when the responce header is Parsed it do not check any required information in cache, and bring all updated information form server only.

Resources