2.4 Login Tickets, Part 1
The CAS protocol refers to an asset called the login ticket. We'll learn about its role in the login process and test drive its implementation.
1.Introduction2 lessons, 07:43
2.Creating the API Server12 lessons, 2:10:56
3.A Client Demonstration App2 lessons, 20:49
4.Conclusion1 lesson, 01:35
2.4 Login Tickets, Part 1
Up until now, we have been building a sign-up mechanism for users to post their information and create new accounts. We did the simplest possible approach, which is just to provide an email and password, and they're signed up. There's no activation mechanism, no confirmations whatsoever. The important part is the log in process, which we're going to cover right now. The log in process is kind of convoluted, but I'm going to walk you on what we should do. As you can see here in the specification, I'm on section 2.2.2., in regards to the parameters for user name and password authentication. We're gonna cover the authentication via a cookie later on in the course. So the first thing is to provide an user name, a password, and a login ticket. The login ticket is described later on but, I'm going to tell you exactly what it does. When you provide the form for the user to login, it should have a login ticket. Basically, it is a random string that should be created in the server and validated after submitting the request. The details on how to create a login ticket are on section 3.5. So if we go there really quick, you can see that the login ticket has some properties. It must be unique, then it must be discarded once a login submission is done. And it should begin with LT dash, that's all there is to it. So we're going to focus on this particular scenario first. For that, I'm going to create a new service called login, which is basically the entire login process and a test for it. So we'll use a login_test.rb, which I'm going to open, and then the login class on the side. So the login test case will have a series of tests which I'm going to paste. So for all these tests I've only focused the first one, the remaining ones have the skip method to it so that we don't lose track. Let's go over these one at a time. The first test considers a user that's already in there. So, we are going to have a spawn user method, which we're going to create later on. For now, I want to explain what this does. We're going to create a brand new login class. And we're going to call the service method on it. Then we're going to assert that the ticket in the service is a kind of login ticket. With this test we are going to make sure that whenever we pass in new parameters to the login class, we are expected a login ticket. So let's do that. First of all, let me go to the test helper and create that method. I'm going to create it inside mini test spec so that we encapsulate it in the context of a test. So spawn user will be something like this, user dot create. Then we're going to pass in an email, which we can pass in as an argument with a default value and a password argument, which will default to password. Really doesn't matter. So we can create something like this, or we can even call the services method in order to create that password. So services sign up will create a new instance of it and email will be that email and the password will be that password. Then we're going to call that service, so we'll assign this to a service variable. Call service dot call and finally retrieve the services user. Let's see if this makes up for what we had in the actual service. The signup class takes an email and a password. The call method creates a new user, sets the encrypted password, and saves the user. Okay. This looks really good. Let's move on to the next step, which is to actually run the tests. Let's go ahead and type in bundle exec rake, and you will see at the bottom that we don't have that login class. That's as easy as associating this file with that class. So we'll type in the module API::Services and then the login class. So type in class login, close that up. And then we need to go to the API general class, there you go, and associate that file within the context of the global file. With this we can run the tests again. So we'll do that, and you will see that the next step is to have the call method. In here, the login class should have that call method. And the call method will expect a ticket to be there. The ticket is undefined. So let's go ahead and create an atir reader for it. So atir reader for that ticket variable, which we're going to create in the call method. The ticket will be a new instance of log in ticket as you can see on line 11 here. We expect a log in ticket to be there. So we're just gonna call Ticket dot save and that's it. Now the login ticket should have a particular name, you know, the code that goes right inside, so LT dash and then some random string. The random string will be something like this, we're going to use the digest module, the SHA1 class in-specific and call the hex digest method and what value should we pass into this method? Well the specification tells that this should be probabilistically unique. And so what better way to, so what better way to achieve that than by using the current time? After all one action is going to be executed in one point in time. So if we type in, for example, Time dot new and then dot to_s. This will be an instance of time that will not repeat itself ever again. So this should do the trick really well. Let's save this and run the test again. We will fall into the same error as we had before, because the login ticket class is still not being loaded. Well, simply put, we don't have that class yet. Let's create it. I'm going to edit a new file under lib, app, api, models and then, log in ticket. Actually, I'm going to paste this into a new tab directly, so we don't mess up with this setup. So the login ticket will be our new class. It is going to inherit from active record, base. This is going to be a model that will store the login tickets. You might be asking yourself, why we are doing this, you know, persisting the ticket in the database. Well, for specification reasons, it tells that the login ticket should be expired. You know, any time we authenticate once, the ticket should not be valid from there on. So, we need to have some sort of information place where we store that kind of information. So, the login ticket class it's just this, we still don't have anything else for that matter. So, we just need to require it from the API class, so let's do that. I'm going to require API models and then plugin ticket. Let's now see if this works. Most likely it won't, because we still don't have that table. There you go, as you can see in the message, we couldn't find the login tickets table. For that we're gonna go to the migrations folder under lib API migrations and we're going to create a new file called create_login_tickets. There you go. Let's open it in a new tab and define the create login tickets class, which we'll inherit from active record, double colon, migration. Inside, we'll have a change method, which will basically create the table, so let's type in create_table. We'll call it login_tickets and we'll pass a block that will define several different attributes for this table. So the first one should be the name of the login ticket which will be that code. I mean I'm just passing in name to be a little more generic. So we'll do that, and we'll pass in null, false, so that we require the name to be there. Let's also define a set of time stamps created at and updated at. And also we'll provide a boolean called, for example, active. Let's also provide a default value of true. This means that whenever we don't define any active condition, this means that when creating a login ticket we don't need to specify whether it's active or not. It will default to being active. With this we can go straight ahead and run the migrations. So I'll type in bundle exec rake dbmigrate. And let's also take the chance to pass in api env=test, so that we force ourselves to migrate the test database. So let's do that. You can see that we now have the new table. Let's run the test from here, and see what the next error is. Well it seems that we still have this error. Let's check our rake file really quick because I think I forgot to fix something. That's right, you can see that we are forcing the api environment variable to be development, but we only want to do it in case the variable isn't already defined. Because we forced the test database to be there, then developments shouldn't be forcibly set up. So passing double pipe equal to define the variable in case it doesn't exist already. With this, I can go ahead and run this command again. And you will notice here, that the instruction will run again. There you go. This time the table is being created in the test database. If we run the tests now, we will get a different result. Well, there you go. It works. The test is now passing. This means that in the test you can see that we are asserting that the log in ticket is there as the ticket message in the service. And that's exactly what we're doing. We are creating a new instance variable that's a login ticket. Now let's check the other tests. I'm going to fold this one up since we are not interested in it and read the contents of the next test.