 Welcome to this access denied talk is going to be talk about authorization rails And it's gonna be a little bit theoretical in the first part and much more practical in the second part So if you consider the first part boring, please wait to the end If you know about myself Wrong button, sorry Okay. Hi, my name is Vladimir. I Can call me for short blood because it's much more simpler Even palcane is if you prefer to call people by that github handles I came from Moscow From New York City and have a long drive yesterday To Pittsburgh and bro some snow with me. Sorry for that I Wanted for a company and called evil Martians Well, a few words about who Martians we do in a lot of product development for large corporates small startups Both sides of the ocean any ocean actually and We do in a lot of open source development. There's a few of our mass popular tools for front-end development back-end development Feel free to ask me about some of them and Of course, we were writing about everything about this now block was beautiful illustrations I guess most of you so at least something from that there's rails 5 to post was pretty popular and Recently has landed to this book. It's me only most of our team is Brooklyn If you got any questions relating to product development open source conferences blog posting feel free to contact us or me at the conference enough advertisement Let's talk about the talk itself and the first part as I promised are going to be theory part and We're talking about some namings Because it's hard and let's start with the definition. Well, this is talk about authorization, right? So, what is it according to camber's dictionary? It's pretty authoritative source of knowledge It's an act of giving someone an official permission to do something. So there are two main things. We got someone and we Make him to do something or not make him And The problem is the first problem authorization is that's pretty often confused with other type of Asians and the first one is authentication Raise your hand if you don't know what's the difference between authentication and authorization. I Sure that everyone knows. Okay, let's try to check It's easy to To figure out whether it is people person talking about authorization authentication because there are some Properties of both first. Let's talk about questions Authentication answers the question. Why are you is it really you there actually two questions? I Combined two notions here But to not make it even more complex because it's identification and authentication But these two mostly often happen simultaneously, so do not distinguish them for now So that's a simple question and the authorization answers in another question. Am I allowed to do that? So That's when we're talking about organizations that we're talking about kind of permissions and something like that From the coach perspective, you know rails application where rails go. So let's talk about rails Authentication happens like this. We initialize a context of our for example request execution usually its current user in 90% of all applications and authorizations as happens when we operate on this Context in checking some kind of properties explicitly or not From the ruby gems perspective There are not so many gems for authentications, of course, everyone knows at least a few of them and It's much more for authorization and I don't know why so I guess most of you know this too Can can can can can or maybe can can can can I don't know if it exists or not and Pundit, we're mostly gonna talk about them a little bit later There are many others as information from a ruby toolbox. So That's an official list of tools for authorizations Just want to remind you that So the typical stack of a full problem. Hey, what do you say station? I'm using device. What's wrong with it? So it's okay. I guess everyone in this Room now knows what's the difference and never answer like this Oh There are another type of things that could be also confused as authorization actually It's not authorization. I call the system constraints. It's a little tricky. Let me show the example. Oh This is just read the code. It's pretty obvious. What's the system constraint? It's something it's kind of environmental condition It doesn't relate to a particular subject particular user and to particular resource so it's something out of that and usually deals with Accounts limit and sales applications and some kind of subscriptions or whatever So it differs in type of response code even what that you show to your user to your client That's not authorization. It's something that goes after authorization So you're still allowed to do this kind of thing, but there are some restrictions that doesn't depend on you And of course there is that amount of constraints or we call invalidation. So it's pretty obvious Just to sum up. We've got a four lines of defense and applications. Not a real application has this all for but That's a typical diagram of Trying to get to the data Authorization itself consists of two parts The first one is authorization model. That's how we grant and rework access That's our model from the business logic point of view. So that's where roles leaves permissions I know what other sections you use to describe Kind of abilities and the next part is I call it authorization layer It's how to check these abilities how to integrate this model with Your entry point to your data typically again, it's in Rails applications Controllers, but we're going to talk about other users as a use cases, too a few words about models and some The most boring part of the talk, but I don't want to get rid of it because it's Brings a lot of information. So in computer science, there are some popular models to Build access control business logic in your application They're all looks pretty similar. There are a few First letters differs. Let's quickly Watch what they are The first one who kind of all these ones called discretionary access control It's pretty simple. We got users. We got resources and we want to grant access. We just created intermediate models Okay, so call it permission. So just a record in the database which describes which activity this user is allowed to do with this resource and authorization itself the act of Authorization which I call this user can read resources artificial kind of DSL It's pretty simple. We're just checking the database whether the records exist if it's exist Okay, we're allowed to do that if it's not we do not allow to do that the problem with this approach is You know only this kind of Of the station logic is prone to the database explosion if you get a lot of records or all the users a lot of Relationship between them you had to care about all this permission records how to clean the map So that's a pretty complex and that's why people try to invent other models My data model is kind of the same time Born as a discretionary model, but it works differently it it assumes that you got Security levels for your resources are kind of top secret not secret at all or whatever and every user has a security clearance Which is from the same setup as the security level is all you need to is to check that clearance is greater or equal to level so if it's if it is then Their action is allowed if it's not saying it is not allowed. It's pretty simple, but you do not have an ability To know to combine all these clearances in multiple dimensions, so to get one dimension of your Physician models for most applications. It's not an option to Then a row based models. It's pretty popular abbreviation or bug It operates it's kind of evolution of discretionary model, but It describes it at intermediate abstraction role. We just collect all the set of permissions, so we got resource we got action and Some kind of level maybe but the problem with this one again is that it doesn't operate on exactly on single resources You either access had access to all resources of the type are known That's a problem. And that's why the final model attribute-based model appeared. It's It's kind of top level of our models evolution I intentionally put Jason script here because most of the frameworks not only in Ruby, but mostly actually in enterprise Like languages like Java dot net Operates on configuration slide that do like configuration files and do they write their access control policies like this Usually we do this with Ruby for example scan can it's an example of attribute-based authorization, but The idea here is that we got the resource got some property the Context say user get some property we can't compare them and write it as just a plain text almost and If you big fan of standards There's a project, but National Institute of standards of stabilization remember which is describes The role of a big book writing about action-based success control. They invented XML-based language to describe this control policies and they think that that's a future I'm not sure about it, but If you're working on something maybe governmental They initially that was burning the medical institutions for track access to patient records And they build this framework and now they want to spread it Beyond this kind of usage. So take a look at if you looking for something good Just a second so Enough theory this talk is about the second part of Australia's sorry authorization, it's about How to verify access how to integrate this business logic? We do not want to talk much about how to demand trolls how to users permissions and whatever how to verify the access and They're gonna be more code and that's part of the talk First a beautiful diagram. I call it a place of authorization in rails That's an authentication just to remind you that it's different part of our defense line So we use authorization actually for two things you mostly so to protect our resources How a business logic and as a side effect when talking about rails web frameworks We also use the same authorization layer to modify the output. That's kind of For example, you've got some kind of additional checks on your view templates So if you're allowed to destroy the resource you added the link If not, you do not actually use the same logic as to protect the data. So it's kind of Another place where we use authorization. We also Should use authorization channels. I don't know whether you use an action cable anyone oh Now I know why my talk on action cable and other cables were not accepted no one is interested in it Okay, so we also do Authorizations there should do I don't think anyone doing that actually because existing frameworks doesn't provide out-of-the-box support for action cable and Also as a proof speaker talk about a graph keel and sorry, I missed the talk But I'm not sure whether he was talking about authorization or not But we should authorize our graph keel actions to a tater so queries So there is no good solution yet, too But that's a place where you should do that just to remind. Okay, let's talk about these two tools and the first a little bit of survey here and raise your hands if you're using can-can as your first Choice or almost a half great. So it's actually Typical situation I've conducted a survey a month ago. Not so many answers a couple of hundreds, but Distractions that half of people using can-can another half using pundits as typical pros people answered so why they chose can-can or why they chose pounded and And speaking about can-can the most reasonable. It's a simple readable config a lot of documentation Community easy to use and also all it was the only framework. I knew that's why I showed it. Okay. That's the reason why not For those who are not familiar with can-can it's kind of configuration based actually a Framework we describe everything in our one file and we use them Alpharize helper and our controllers It looks pretty simple. It's Readable, we know what's going on in our application when we do with a couple of models, maybe two maybe three when we do with a real-life application which You know support some kind of business and ability class looks like this It's an readable. It's Actually, it's a real class that from the project I've been working on and my task my first task was to get rid of can-can That's why because even I didn't understand what's going on here and no one didn't understand So I don't think that ability or be should be called ability anymore And so that's why I'm not going to talk about can-can a lot in this talk Mostly about pundit and similar approach. So what's a pundit? It's just a plain old ruby files for your policies. So for every source you define Class with methods Which just your usually controller actions in a predicate form and their response actually as predicate to true Returns true or false and that's it. So it's pretty simple. It's deadly simple and the simplicity well brings its own advantages The main differential pundits prone to be in to contain a lot of duplication in your policies It doesn't have some feature support for examples amongst missing feature is namespaces support if you get namespaces of your application For example API and main application whatever you cannot simply use different policies for them. You have to hack this Policy resolvers from pundits. That's not a good idea And actually policy is always as everything pundits is everything else you write by yourself So that's why usually people either hack pundit or either try to invent their own wheel And so I already talked about the common common evolution. It's many project I've been working on and our team been working on been working on So can-can is good for start when you don't know what's going to be tomorrow, but In one day you realize it's okay. I don't know to understand what's going on. I don't want to support it I it's impossible and It's what it was more worse Sometimes having such kind of magic in controllers mostly from can-can some kind of load enough riser source It's really easy to Got some kind of false positives for positive authorization, which when a physician doesn't happen actually So many people migrate to pundit and they feel a little bit happier but they try to Enhance it because it doesn't solve all the needs. It's too simple to be a full-feature framework to work for everyone and Why we need to customize a serve few kind of Problems which we're trying to solve by Customizing this simple solution. We want to do some boiler parades I was a main one of the kind of that make us happy as a developers right to write less code to reuse code We do want it. We write in Ruby and not go where the application is. Okay. We just don't have generics We want performance because one year rules and it's a typical situation Deals with database queries. So you ask a database for whether there's a record which gives access to perform this Method of this resource you call database and sometimes this queries could be complex and not as fast as it could should be and We want to test our physician because we need to test it a little bit more about it later You want to make it to be flexible? So like a previously mentioned in the keynote Lego blocks we want to build our own from some kind of existing blocks our own solution So that all leads us to Thought that we need to build something new Actually, I need to build something because that's what I was thinking about because having doing the same Customizations from for every project about three four times. I decided well, it's time to extract all these features and wrapping in a new jam When I was accepted to the rails come files file why there is no authorization solution in rails out of the box we got a lot of Building tools even action cable with no no one use it But we don't have anything for authorization, which it's actually much more popular. I think then web circuits Thinking about this question. Well, the answer is Well, maybe we will when it will be extracted from the base camp, but it hasn't been yet. So let's wait but Trying to think about this question I end up with a good title for a new jam and I call it action policy Because we are in rails so action or active as a first part of framework and then a meaning so action policy introducing a new jam and I want to Do all the rest of the talk. Oh, we got a lot of time Okay to this So in shot so it based on ponded in terms of Conception so we use the same policy objects. We do not use Pundits code because that's the main thing which is doesn't work in pundit. We we write all things into internals And it's born in production because so as I already told it's an extraction kind of a jam And it has been released today. I actually pretty least I haven't finished everything to be wrapped into a jam So that's a special pretty least for rails call Let's take a look how it looks like right? Oh, well in your controllers There is pretty similar to other frameworks. You just can have this alpha rise with exclamation mark Because it's raising errors. So that's why the exclamation mark Methods with a couple more additional options you may to pass And another method called allowed to Which is predicate method non-raising you can use it in your views you can Anywhere else And let's talk about bolder print now That's the first problem want to solve with section policy to reduce the duplication to make our rules more clear More readable. That's an example Yeah, that's pretty simple example from pundit typical situation We got a admin or super admin and some other powerful creature in your application which allows to do pretty anything, right? and in your when using poorer objects for Policies you have to add this check in front of which admin or Manager or whatever admin or assigned admin or manager or owner and so on so forth and This makes the logic for this exact resource Less clear because well, what's about this resource? What's about the common logic as admin? It's not readable. It's it doesn't look great What's different with action policy, okay, we got a notion of pre-check That's kind of you know before action before apply. It's not bill on top of active support notifications Not it's it has its own mechanism, but it looks like this. So it's a way to Help the execution of the rule faster. So you don't need to Call the rule itself for example if a user admin just allow everything to it the same way you can deny for some reason For every action. So just adding this to every policy we can end up with this it's much less caught and Now with the logic is more clear and if you want to Check for kind of admin ability you can even skip it. Okay, the interface is pretty similar to our every rails callbacks So we can skip you can specify modifiers only accept whatever and That's the way you can reduce the number amount of code you write and extract the common logic from Concrete policies Another simple example, let's go to this slide. It's just a Small small addition to what we usually have We use a convention or a configuration to not specify policies every time explicitly in your controllers because while we in rails Why not we already know that we are in products controllers and we use product policy. That's responded it looked like this I don't know. It's not readable as a human language. It's not really like style and The final few slides That's an inspiration actually from can can that's the last time I gonna guess Mentioned this framework and ability to add the default rule instead of defining every rule For every action because usually we extract authorization to kind of before action callback load resource and then authorize and instead of adding every Rule to a policy file or any an alias we can just mark some rule as a default one and when the rule is not explicitly set We just call it. It's a dangerous kind of thing actually because there could be a typo and then the default rule is applied So I don't sure it's good and bad, but I'm using it If you're afraid of this typos you can specify Aliases like this it differs from Ruby aliases, but I'm not going to deep to explain actually Maybe in the end of the talk where we can find why we need these kind of aliases specific Not Ruby based. Okay. Let's talk about performance First of all what we want to measure and when dealing with authorization What we're looking for When we use authorization in our controllers Every action usually for every action we call this authorized method and it calls this policy and so on and so forth It already told some rules and imply calling database inside so it could be Performance heavy Not so often, but one call won't break everything But what if there isn't more than one call if we use it in our views for example I started with a limitation of measurement tools and We Use in Rails, so let's try active support notifications framework and add our own events to Offersation calls there are two kind of events one just for alpha rice coal and one for every Rule that is applied. So every policy call and I've tried to Play with it Edit our application and I found this Wow, we didn't expect it. It turned out that some Pages some controller actions we made in So 45 policy checks 45 calls to policy something check something. Why does this happen? Well, it's pretty common situation when you render in a list of resources and you check Whether I want to show this edit link or destroy link and I'm calling a policy to check I'm allowed to do it edit to the stress resource. I'm not so We end up with this situation. I call the impulse finalization obviously and in some cases when we again Do with database and transforms to an post one query and that's better situation We want to avoid it and to avoid it. We build a complex system of caching Well, it's two levels and multiple layers in each actually center internal Think you shouldn't care about it when using action policy It's built the way you can enable and disable any layer and don't use it and don't think about it the idea is to reuse policy object as much as possible and To avoid Calling the same rule twice during the execution context Even between multiple processes we use a cash store. Oh so it's pretty Good rails interface just Set up cash store to for example brand new ready sketch store for rails 5 to and mark your Just work. No Mark your methods with cash. That's it And we store this the result of the execution of this slow heavy rule in So readies and we use it between Processes between requests and we can Then draw some kind of beautiful pictures to measure the impact of the cash. So Many diagrams Top two it's a Hit miss rate so we can see that in our application mostly hit rate. So if we're using data from cash, we do not execute rules too often and The lower graphics show The amount of time spent for cash done on cash rule. So the left one shows Policy rules. So our calls to offer eyes and the right one top bottom bottom right shows We don't have this. Okay Policy scopes cash. We do do cash scopes too and for scopes Impact is great. We we save Hundreds of milliseconds per request and for policies actually it's great, too Even that one check is only self thousands of milliseconds when you have dozens of calls to policy in a request You've got to be on hundreds. So First of all try to measure then try to add cash and that's it Let's talk about tests. That's my favorite topic actually I Hope I have enough water for the rest of the talk So when we're talking about testing and authorization first thing we should care about is a coverage But don't worry Hey, yeah 100% coverage, but I'm not talking about code coverage. No, it's kind of useless thing I'm talking about business logic coverage. You should be You must be sure that your test cover all your edge cases related to authorization because well if you miss something Then the bad guy can access your data or spoil it or whatever so every entry point where you use authorization should be covered 100% and it's Not easy because where to test authorization I Ask this question and got the following results most people test test authorization logic in their requests controllers and unit tests Well, when you test authorization in request and controller you have to provide a whole context and for every edge case In your rule you have to make request. Yeah. Oh, thank you Great and that in our situation in our application. That's a controller controllers test. I Don't have a number here though about three thousand of tests It's all and almost half of them was just to test the access control Not the logic of controllers self actually but the way we Okay, but give access to users If you're gonna talk about time, so it's four minutes out of nine. It's really slow and How can we sell this problem? Actually, we do not have to test everything in our functional layer in our controllers But we have to be sure that Their exact policy is cold and only it is so With action policy, we got a simple helper for our spec. I mean it has to Prefer aspects of the examples in our pack What is what is doing the first thing I want to notice that? Action policy built with testability in mind. So it was for design solution and To make it testable It has a test mode in which it tracks every code to authorize methods during Like the test for example Like I don't like web mock or VCR works in for HTTP request And then you can check it with this aspect or mini test matcher that the exact policy have been called And if it hasn't been called we can show you pretty beautiful message showing which Policies were used during this quest that we need only one test per action to verify our Access control. That's it. So we can reduce the amount of testing drastically in our controllers and As for policy itself where we can test it as simple Ruby object there is no magic you can just call this show method for example and Assert that is true for this kind of setup That's it. So Your test become faster and well actually Easily to maintain Well more features That's a end of the talk, but not quick end. I Mentioned that we use scopes, but currently it's not available on github. I'm walking on it They got a kind of active record like interface not like pundit with its classes for scopes, sorry So the main idea here except from default scope which modifies Their relation collection is a namescope because in some cases you might be want to use something else some other kind of filtration of your collection and So the usage pretty simple just go with only collection and that's it And you can reuse everything you write in your policy so the scopes lives within policy instance, so You have all the helpers all the context user record whatever The the big question with scopes I showed a couple of diagrams charts Where I show that we cash scopes and it's pretty pretty cool But I as for now, I'm not sure how to make it available to everyone because we use our own logic to cash scopes and It's a little bit tricky to make it More general for everyone to use so we give an active record relation cash somehow. Oh, sorry Cash it somehow and Well, it works as magic currently I'm working it if you got some ideas share namespaces I mentioned it as a one of disadvantage of pundit and pre-example so In action policy there is a medical Inferral of policies for resources when you work working within a namespace So if you work in an admin namespace We try to find first an admin product policy for example like this and only then fall backs to product policy Global policy kind of and you can also manually specify their namespace dynamic namespaces also Available, so the namespace is set for all their execution context and we'll be talking about controls Also, we got some tools to integrate with internationalization Just show example, so I Should policy raisin specific kind of exception when a physician fails you can rescue from it to provide some kind of feedback to user and The message here will be something specified in your locale for this kind of rule rule that fails and That's where you can easily using your common locale's provide more specific Messages to users then you're not allowed to perform the section. Well, okay, what should I do then? I don't know And more about this in the next feature Call failure reasons So it's an ability to track which checks fails during the rule application So in that example, we wrap our checks into allowed to Which is the same as in controller so we can use it for example to use another policy within this one so kind of delegation and When an exception happens we got a special reason subject which contains keys for Failed Policies so let's come back to the example the show Rule fail in two cases when you're not allowed to view Applicants in that case and you're not allowed to show stage. You don't have access to a stage whatever it is So if first one fails, we got the first Actually second kind of reasons messages applicant for you So we failed due to not you don't have enough permissions to view Applicants and the second one fails. We got the first one case You don't have access to the stage and that way we can specify custom message even add Call to action for a user. You don't have to stage Maybe you want to call a manager to add you to the stage or you don't have access Permission to manage users. Maybe you want to ask manager to add this permission for you something like that And of course you can even put it into your locales again and As with active model errors object, we got full messages to provide translation of these keys. Oh more features I've been talking mostly about controllers and a little bit about channels But action policy build that way that you can actually add this kind of alpha rice code and allow to anywhere you want Just quick example Pretty artificial. We got a model called action policy behavior just included into your class and Add some kind of configuration. So you have to specify your authorization of authorization context, so for the subject performer So that case user and you can just go alpha rice and everything else works like in your controller So if you're using maybe you're not using rails. So for example, Hanami, you can use action policy with it So it's not actually not a real specific framework. It's built to be not real specific in dependency less well, I Started to talk about authorization context. Actually, I forgot to add it to slides So just was finishing five minutes before the talk. So But that's a key feature actually one of the common disadvantage of frameworks that They think that you always have current user. It's it. That's all you want to offer rise. That's your authorization context, but Well, usually it's not you've got some kind of other context For example, if you were building multi-tenancy application, you've got a tenant so called account and you can use it in your rules, too So with action policy, you can specify any number of this context You have to do that in two places in your policy to make policy works expect this context during the Initialization and in your say controller or where where is your behavior leaves? I know that time is over. I'm always over too. So that's The way you can provide more context without you know creating artificial structures to wrap your current user with something else just tell the action policy that you want to add More context more environment to your rule checks and that's it well useful links, so we got it You'd have we got a Pretty cool documentation a lot of things out there I'm not mentioned in the talk because I got only 45 minutes and Thank you very much