A few things to watch for with Laravel policies

Joel Clermont (00:00):
Welcome to No Compromises, a peek into the mind of two old web devs who have seen some things. This is Joel.

Aaron Saray (00:08):
And this is Aaron.
Joel, on my current project I'm working a little bit with policies which I normally try to do for most projects obviously. There's been a of couple things that I thought I would share with you, Joel, because I think we don't ever talk about them or we don't consider them and really how it affects the project. When we're writing policies which are one of the tools in our authorization toolbox, we have the different types of requests that can happen and in different methods. For like viewAny allows just can we view any of these results. View, can I view the specific one? Create, can I create or store? And all those different things. So sometimes it's-

Joel Clermont (00:58):
You follow the CRUD actions for the most part, right?

Aaron Saray (01:01):
Yeah. Once you create those you can also then... If you have resourceful controllers, you can use the controller helper authorize resource, pass in there. So there's this nice setup and that's not really what I wanted to talk about. I wanted to talk about, in specific, what happens when you're inside of the methods of each one of these policies?

Joel Clermont (01:23):
Okay.

Aaron Saray (01:24):
The very first thing that I end up doing, because I'm a typical programmer, is I think I give myself a programmer and an admin account in my application.

Joel Clermont (01:34):
Yeah, sure.

Aaron Saray (01:35):
Then policies have this interception, I think they call it, but basically it's you can make this method called Before which runs before any of the other methods run. Then it's a little weird because it's either you have to avoid return or return true. And returning true means you're allowed to have this action, otherwise all the other returns I think cause it to fail. I can't remember, I just know that it always bothers me because I can't fully type the result of the return. Maybe that's changed. But anyway, I normally will start out my project. I'll create myself an admin account, I'll write that before and I'll either then extend a base policy so all of mine have that same before which checks to see if I'm the admin or I'll use it as a trade, or something like that. And then I proceed to do my development and I got my other policies and everything is working fine. Let's just assume I haven't written the right tests, stop me if this has happened to you before. Everything works fine and you give it to a client and some things are 403-ing in them.

Joel Clermont (02:46):
I've never had that happen.

Aaron Saray (02:48):
Yeah, me either. It has to do with because you just ran through the whole application always probably as your admin user. Because, I mean, I'm in a hurry I'm trying to develop stuff, I'm going to use my own account and whatnot. But that's the biggest thing there is I find that when I use that method, I really tend to potentially then not remember to test the rest of this stuff, so obviously tests can help for that. But I wonder, is there anything else that we could think of? Is there some sort of process that you put in place in your projects to make sure you don't fall for this?

Joel Clermont (03:21):
Nothing formal. But a lot of times where I will test this is, especially if you're about to hand it off to a client, I've generally pushed it to some sort of QA or test environment and I'll have to give them credentials to log in. I'll usually just kind of quickly kick the tires as them before sending them the URL. Because I've had stupid things happen too where actually it all works fine locally but then I did something wrong in deployment and they go to try it and it's like, "Sorry, cannot connect to Redis," or something, you know, completely unrelated to what I'm asking them to test. So that's the first thing that came to my mind but it doesn't seem like a great solution either to catch this 100%.

Aaron Saray (04:06):
Yeah. One of the things that I'm trying to do is when I set up my seeders for my migrations, and you know I have my migrations in seeders, I'll write one that checks to make sure the environment does only local and then it'll create a number of different types of test users. I'll basically try to force myself to remember to use those instead of using my main account. For example, I always seed in my one account with no password so I have to do a forgot password soon as I do it to production then I get my admin account with a new password, et cetera. So that account's always there. In the past, in development I always just use that. But now I have this other data for development to sort of seeder and I make sure that I run with those because none of those are an admin account or a programmer account, or however you want to look at it. So they will actually then have the policies in effect.

Joel Clermont (05:07):
Okay. I guess, suppose if you had the reverse problem where for some reason the programmer 403-ed in the live environment that would be less of an issue, right?

Aaron Saray (05:16):
Right.

Joel Clermont (05:16):
I kind of like flipping it that way, gives you a better real world smoke test of behavior than using the programmer account that maybe is a little bit more convenient.

Aaron Saray (05:28):
Well, and that's a good point too. I mean, depending on the size of your project and what controls you have in place, but if the programmer account doesn't work you can fix that.

Joel Clermont (05:38):
Right, yeah.

Aaron Saray (05:38):
Whereas if a user's account doesn't work they can't fix that. So it's much more important to have the user type accounts or whatever working and not. That's the first sort of thing I wanted to bring up because that's bitten me a couple times. But I think I guess the more interesting question then I'll ask you to see what your opinion is, is should we even use those methods at all? Or should we always use our roles and permissions and just never have an admin sort of override method and just always give all the permissions to that role of admin? And then always in our policies, check the permission and then whatever other things we have to check.

Joel Clermont (06:21):
Yeah, you raise a good point. Because I don't think you'd ever use that before style check for lower level accounts. I mean, I think you could but I think you would more naturally reach for a role in that case. If you have like a manager or approver or something like that, you would do that as a role, you wouldn't do that as before. So I'm just kind of thinking about it here for the first time. But I think I can see the logic in just being consistent. I mean, that's kind of one of our overriding principles is consistency. Yeah, maybe don't have a special case for this one role, just give that role all the permissions it needs and then just do a normal permission check like we would for every other user.

Aaron Saray (07:05):
If you want to sort of force your hand with this then, I guess I haven't tried this out, but I wonder if you could make it like a normal abstract role and then declare the before final in there and return just void. You know, return nothing. That way anything that extends it can't use it anyway, so you kind of force yourself and other programmers and team to not try to overwrite that.

Joel Clermont (07:35):
You mean like a base policy, where you're literally kind of changing the shape of the class so that you can't slip into old habits or anything like that?

Aaron Saray (07:48):
Yeah.

Joel Clermont (07:48):
Yeah, I don't know. I guess I'm far too confident in my own skills. I'd be like, "I wouldn't need to do that. I would always remember the right way to do this." But I could see a case being made, maybe especially on a team or something where you have more people interacting with it. That that could be one valid way to enforce it.

Aaron Saray (08:06):
Well, I mean obviously a coder using all that kind of stuff too but then I just...

Joel Clermont (08:10):
Sure, yeah.

Aaron Saray (08:10):
When I come up with these ideas I always then have an argument with myself. Because I'm like, "Also I know I don't really like abstract final stuff," because there's always like, "Oh, so you knew better three years from now what we'd have to do?" So there are other ways to enforce that in your team I guess.

Joel Clermont (08:29):
Yeah, that was my gut reaction. Is like, "Oh, I just don't like that," but I could see you making the case for it. But then again if you're trying to prevent your team from doing something, they could change that class, right? I mean, how far do you go with it?

Aaron Saray (08:43):
Yeah. Or just not extend it.

Joel Clermont (08:44):
(Inaudible 00:08:43). Yeah. Fine, I won't extend it.

Aaron Saray (08:47):
All right. I really had those checks and that bit me a couple times. The final thing I wanted to bring up about policies today was that don't forget that there is delete and force delete.

Joel Clermont (09:05):
You mean there's valid actions to check?

Aaron Saray (09:07):
Yeah. I've had that come up a few times in something like Nova. Which uses policies and where I thought that I was going to just disable deleting but there was a way to force delete something.

Joel Clermont (09:23):
Oh, okay.

Aaron Saray (09:24):
What I've really been doing now is always writing force deletes with return false, because there's never been really a time when I really wanted to force delete something and I just don't want that to ever pop up even with programming mistakes that I might make.

Joel Clermont (09:42):
I'm trying to remember, if you scaffold a policy does it include that method in there or is that one not included?

Aaron Saray (09:48):
Okay, so I have to admit, I tend... I've fall into old habits when you've been doing this for 20+ years. I remember my first experiences with scaffolding code and code generation.

Joel Clermont (10:05):
Okay, yeah.

Aaron Saray (10:05):
That's always burnt into my head. I know Laravel does a great job. You say, "Make me this thing," and it makes it and it is great. In my mind I'm just used to 15 years ago, you would do that and it would just come out as some sort of spaghetti and you're like, "Ah." So to be honest I tend to just create my policies brand new which is probably not a great idea so I can't answer that question for you. Probably it does, I'm probably just behind the times now.

Joel Clermont (10:30):
I do scaffold it and I can't remember. So I think it does but I don't know, I forget things quickly.

Aaron Saray (10:42):
It's been a while since I've seen these things, but I'm sure everyone knows how to use them. But let me ask you a question, Joel.

Joel Clermont (10:52):
Okay.

Aaron Saray (10:53):
If you use a vending machine for snacks and you see something as stuck, like someone tried to get in and got stuck, do you immediately go then for that thing? Or do you get to what we're normally going to get anyway? Like, are you just normal?

Joel Clermont (11:07):
Well step one is, I kind of push the machine a little bit to see if I'd get that one for free.

Aaron Saray (11:11):
That's true because the person who was there before never thought of that.

Joel Clermont (11:15):
I'm stronger than them, it could have been a child. No, if it's something... I'm trying to think of something gross I don't like. Some candy that's just nougat and nuts or something weird, then for sure I would not. The value of possibly getting two for one would not exceed my desired snack selection.

Aaron Saray (11:39):
Yeah, I don't know if I ever consider whether I want it. I just know that I could possibly get this and then I go for it.

Joel Clermont (11:49):
The thought is you get two though?

Aaron Saray (11:51):
Yeah.

Joel Clermont (11:51):
It's not like you're going to get the one that's dangling there. You'll put in your money and you'll get that one, plus the one you paid for?

Aaron Saray (11:58):
Yeah, I just don't want the thing, I want two of the thing that I may or may not want.
I know what you're thinking. You want us to cover something else but you just don't have the time. You know you could just tweet at us, right?

Joel Clermont (12:11):
Well, you could tweet at me because, Aaron, I know you don't check Twitter that much.

Aaron Saray (12:16):
Oh, yeah.

Joel Clermont (12:16):
Tweet me @JClermont with other topics or questions.

No Compromises, LLC