WEBVTT 00:00.000 --> 00:10.960 So, I think we are ready to start the next to the last session of the day. 00:10.960 --> 00:16.720 We have been the whole day talking about passwordless, pseudo, SSH. 00:16.720 --> 00:22.000 But now we are going to switch the topic to something completely different, and we have 00:22.000 --> 00:30.000 here together with us, Carla, she is the main developer for the modern UI in the free 00:30.000 --> 00:36.800 P.A. and she is going to talk about some internal aspects. 00:36.800 --> 00:41.520 Thank you very much. 00:41.520 --> 00:47.680 This is my first time at PhosThem, so please welcome there with me. 00:47.680 --> 00:53.440 So, as you already know, so I am Carla, I am super engineer in Red Hat more specifically, 00:53.440 --> 01:02.560 I am on the free A.P.A. team, and I will talk about how we migrated the web UI from the 01:03.680 --> 01:06.480 current version to the modern one. 01:06.480 --> 01:11.120 So, especially I am going to focus on the multifactor authentication. 01:11.120 --> 01:16.880 Okay, this is the agenda that we will follow in today. 01:16.880 --> 01:24.560 So, I will start with some context, speaking about the free A.P.A. 01:24.560 --> 01:28.160 The web UI and some things that are important to know. 01:28.160 --> 01:34.800 I will provide a very more context on the legacy states, so that means the current web UI. 01:34.960 --> 01:42.960 And I want to make a note, so I will make reference to the current web UI as the 01:42.960 --> 01:49.040 all the web UI, but this is not discontinued yet, okay, but in order to make the difference, 01:49.040 --> 01:52.080 I will refer to the current one as the old one. 01:52.080 --> 01:59.280 Then I will follow up with the modern approach and what we did to modernize the web UI, 01:59.280 --> 02:03.920 and I will end up with the conclusion and what will be working next. 02:05.360 --> 02:08.560 Okay, so let's start with the immigration context. 02:09.680 --> 02:16.720 So, as many of you already know, so free A, it's an integrated identity and authentication solution 02:16.720 --> 02:23.280 that combines a lot of administrative tools and to manage the security of Linux and 02:23.280 --> 02:25.600 Unix network environment. 02:25.600 --> 02:30.240 So, actually there are currently two ways of using free A.P.A. 02:30.320 --> 02:37.120 You can either using the I.B.A. commands directly, or you can use the web interface. 02:37.120 --> 02:43.040 This is the modern, not the modern, the web UI, and this is what we will be talking today. 02:44.320 --> 02:47.840 So, free A, it's quite an old tool. 02:49.040 --> 02:55.680 It was born, I think, 15 years old, and its web UI has been around since 2000 and 02:55.680 --> 02:58.560 you live, and so basically they are like two teenagers. 02:59.760 --> 03:07.040 And yeah, that's why since 2022, there is a network to modernize the current web UI into 03:08.720 --> 03:14.320 modern one, using some changing the new infrastructure and using modern tools. 03:16.560 --> 03:21.360 Because the changes won't be made on the top of the existing web UI. 03:21.680 --> 03:27.120 As we need a fundamental shift, we are implementing a new web UI. 03:27.120 --> 03:33.520 Independent from the 1801, because eventually the modern web UI will replace the current one, 03:33.520 --> 03:34.640 the all the one. 03:36.480 --> 03:41.840 I won't type deep matching to the main reasons for why this change, because this was already 03:41.840 --> 03:47.520 covered in one first and top that we did in 2004, actually it was junior percent in it. 03:48.400 --> 03:55.440 But in a nutshell, so it contains a lot of legacy code that over time became 03:55.440 --> 04:02.400 very difficult to maintain, and this is partly because of the use of the percated libraries 04:02.400 --> 04:10.800 and the framework tools, and this leads to poor accessibility, responsiveness, issue, and 04:10.800 --> 04:22.080 security. And with this reasons, it is important to perform a radical change to adapt the web UI. 04:22.080 --> 04:27.280 And that includes the way we manage the authentication flows and methods. 04:30.400 --> 04:36.960 Okay, so currently there are three ways of types of, there are three ways of 04:37.760 --> 04:43.520 outenticating into the modern web UI, not the modern thing, regular UI. 04:44.400 --> 04:48.640 So you can authenticate either using the user name and password. 04:49.280 --> 04:52.960 Secondly, you can enhance it with two patterns of authentication. 04:53.520 --> 04:58.800 You can authenticate using the curver of tickets and the client certificates. 04:59.360 --> 05:06.320 And the goals for this new adaptation and the challenge that we have ahead of us is to 05:07.120 --> 05:14.320 preserve the multifactor authentication functionality, but modernizing the implementation following 05:14.320 --> 05:18.640 those better practice that we will be mentioning in this talk. 05:20.240 --> 05:28.240 Okay, to understand why we migrated, I would like to provide more context about what we are 05:28.240 --> 05:32.240 migrating from, especially in terms of the authentication methods. 05:33.120 --> 05:41.840 Okay, our legacy goal was built in JavaScript, more specific using the tool kit and 05:41.840 --> 05:48.480 BigQuery. And at the time this was built, it was cutting edge. But remember, 05:49.520 --> 05:56.160 it's already 15 or 60, I don't remember, 16 years old, so it's quite old. 05:56.960 --> 06:03.680 And over the last decade, this architecture revealed some structural weaknesses that made 06:03.680 --> 06:13.520 maintaining complex flows increasingly painful. And we identified five friction points that were 06:13.520 --> 06:21.040 slowing down in terms of how to properly adapt this to a modern solution. 06:21.040 --> 06:29.520 So, we were working with a monolithic architecture. Where logic was tightly coupled with 06:29.520 --> 06:37.040 the manipulation and that forced us into writing imperative methods to create and manage the UI elements. 06:39.200 --> 06:45.600 Also, where application was not centralized, but rather scattering to multiple 06:45.600 --> 06:52.160 width instances. And in the top of that, we were using a massive dependency web to load models, 06:53.280 --> 07:01.760 which was heavy to load and had to optimize. I won't type deep into all these reasons, 07:01.760 --> 07:08.720 but I would like to highlight some, the most relevant ones, because that will be important to 07:08.720 --> 07:15.040 know when we start talking about the, um, some aspects of the modernization of the modern 07:15.040 --> 07:23.120 web UI. Okay, this is what I mean by monolithic. This is a single file, so the login screen 07:23.120 --> 07:30.240 GFs. This is the one that performs the authentication of the users of the all web UI. This is, 07:30.240 --> 07:36.480 of course, a simplification, because the code is very extensive. But, uh, and it is supposed to be a 07:37.120 --> 07:44.080 view, but this is not behaving as a view. Because, as you can see here, it's managing heavy, 07:44.080 --> 07:51.760 and this is not working. It's managing a heavy dependencies. It's all dependencies. It's manually 07:51.760 --> 08:00.640 building the HTML. And this is specifically method that's for some buttons. And it's directly 08:00.640 --> 08:10.240 managing the business logic and the API call. Because everything it's dropped in this single file, 08:10.800 --> 08:17.200 you can't reuse the logic. So you can test it properly, and you can change the UI with a 08:17.200 --> 08:25.600 risking security flow. This is a massive got object that knows too much, and, uh, handles too many 08:25.680 --> 08:32.320 things for being a view. And this is not how a view should behave. Oops, moment. 08:36.640 --> 08:50.480 This is not working. Oops, I jumped away. Okay, so this is another problem, 08:50.480 --> 08:58.080 representing the, in the approach. So how we build the UI elements. Look at the coat of the 08:58.080 --> 09:05.120 left, because, uh, this is juicing, I mean, this is a practical meaning that we have to tell the 09:05.120 --> 09:13.120 browser how to build the interface step by step. So this, for example, this code here, 09:14.000 --> 09:21.600 this is corresponds to the login button from this, um, login screen, uh, file that we mentioned 09:21.600 --> 09:30.960 before. But we're into saying show buttons. So we are telling, we are defining an object in memory. 09:30.960 --> 09:39.120 We are defining the properties. We are finding a specific container and we are explicitly 09:39.120 --> 09:48.400 placing that into this container. And this is exhausting. It's like going to a restaurant, 09:48.400 --> 09:54.720 heading to the kitchen and telling the chef, hey, got the meat, little fire, put the meat, 09:54.720 --> 10:02.640 cook it, wait five minutes, put it the right service. Uh, yeah, that's imperative. So for 10:02.640 --> 10:08.880 example, you know, I mean, in a smaller framework like React, we need to say I want a hamburger. 10:08.880 --> 10:16.240 We define what we want and the framework handles the kitchen work. Wait, easier, right, I mean. 10:19.360 --> 10:24.960 Okay, so finally we have the problem of the head of the, how the pendant sees. 10:25.840 --> 10:30.000 So this corresponds to the same file, the login screen, and this is the top of the file. 10:30.720 --> 10:40.000 So before this file can run before it can even render a single pixel, it demands a lift of 50 10:40.000 --> 10:45.840 different models. So the constructor, the topic, because the login screen, the authentication 10:45.840 --> 10:54.080 library, etc. So this has so many problems because it's difficult to maintain and test. 10:54.160 --> 10:59.920 You have to mock the entire universe and you have to feel out all these requirements in order 10:59.920 --> 11:06.400 to make it work. It's more authentic. The browser has to download and analyze holding models before 11:07.840 --> 11:14.320 doing anything. And it's fragile if any dependency fails. If I don't know, you have a network 11:14.320 --> 11:20.560 leads on a file that you don't even need that moment, the entire login page can crash. 11:21.280 --> 11:27.120 So it's the difference between saying, I just need a hammer to work and saying, 11:27.120 --> 11:31.920 I cannot start working until you bring it entire toolbox, the mechanic and the truck. 11:32.960 --> 11:41.360 Because why not? Okay, so we had a heavy dependence chain. We have imperative code and the 11:41.360 --> 11:49.120 monolithic architecture. That's why I mentioned before that we couldn't just tweak the current solution. 11:49.200 --> 11:55.600 We needed a fundamental shift in how we build the applications so that brings us to our solution. 11:57.520 --> 12:03.440 Okay, so what are the new things care? First of all, the tech is stuck. So we are relying on 12:03.440 --> 12:09.440 react as the main framework using VIT because it provides a lot of optimizations for the browser. 12:09.440 --> 12:14.480 And for the UI elements, we are relying on patternplace 6 currently in the latest version. 12:15.120 --> 12:21.680 As we are using a modern framework, which is react, the way of declaring the components is made in a 12:21.680 --> 12:30.400 declarative way versus the imperative way that we saw before. And apart from the regular states, 12:30.400 --> 12:37.200 a really learning react, redaxe also provide global unified state to manage the login state, 12:37.200 --> 12:44.880 meaning the application will need to know if the current session is authenticated or not. 12:45.840 --> 12:50.880 And for consuming the API commands, we rely on another library called RTK Query. 12:51.760 --> 12:57.600 This allows to have a better separation of concerns between the services and the components. 12:58.480 --> 13:04.320 Yeah, since we are using a TypeScript that also ensures some strict type safety. 13:05.040 --> 13:12.800 Okay, you can see here how different the architecture or the approach is in comparison with the 13:12.800 --> 13:19.760 monolithic view that we saw before. So in terms of the authentication, we have the view, 13:19.760 --> 13:25.760 which is managed by this specific components, the app component and the login main page. 13:25.760 --> 13:32.720 I will explain the difference of them in a second. I said that we are relying in the global 13:32.720 --> 13:41.360 state on this file managed by the authentication slide and the multifactor authentication 13:41.360 --> 13:50.000 endpoint, aka the API calls, that will be managed by the RTK Query library. And this will be the 13:50.000 --> 13:56.640 name of the file. Don't worry, we are not able to remember anything but I will keep mentioning it 13:56.640 --> 14:04.960 and I will remember it for you. Okay, we have the main overview. Let's see how some details have 14:04.960 --> 14:10.800 about how we fix some issues in comparison with the legacy approach. 14:12.800 --> 14:19.680 Okay, this is one of the solutions. On the left, you can see the all-dojo imperative call and 14:19.680 --> 14:25.840 here's the new approach. Notice that we are in calling, construct, place any more obvious, 14:25.840 --> 14:32.800 we change to another framework. But what I mean by that is that we are not manually manipulating 14:32.800 --> 14:42.320 the DOM anymore. Yay. So we are declaring what we want, the login form. So in this case, the UI 14:42.320 --> 14:49.520 is pure reflection of a state. For example, is the authentication value is true. The login 14:49.520 --> 14:57.040 button is disabled and this is handled by React. We don't need to call explicitly or look for 14:57.040 --> 15:05.360 the button ID and call disabled because React handles this work. So we change this imperative code 15:05.360 --> 15:14.320 by a declarative one. And another remarkable change is related to the state management. So in order to 15:14.320 --> 15:22.640 tell the other React components, if there is an existing session and some data, for example, 15:22.640 --> 15:28.080 this one. If the user is logged in, which is a Boolean, the user that has been authenticated 15:28.080 --> 15:36.320 and this error, in case there is any. So we are relying on global statuses and this is tracking 15:36.320 --> 15:42.960 values that I said before. But this is not only helpful to determine if a given session is 15:42.960 --> 15:51.040 or given user has been authenticated. It is also helpful to manage the routes because there will 15:51.040 --> 15:59.280 be protected routes. Sorry, protected pages in this case. And the very important thing is that 15:59.840 --> 16:10.480 we have an initial state with some of the fine values. And we are not updating the manually, 16:10.480 --> 16:16.560 but we are relying on these reducers. Set is login and set is logout. I will explain it in a minute 16:16.560 --> 16:22.400 with an example. But these specific reducers are calling two different scenarios. 16:23.440 --> 16:30.640 When the application initialize and that will be taken by the app component. And via any user 16:30.640 --> 16:38.320 logging by any authentication mechanism and that will be shown by the login main page component. 16:38.320 --> 16:45.360 So I'm not sure if you are more or less familiar with the react, but it follows this hierarchy 16:45.360 --> 16:51.600 way of the find the components. So a component can have a parent and multiple children. 16:52.320 --> 17:00.480 But the parent of all of them, it's the app component, meaning that this is the component, 17:00.480 --> 17:07.360 the first component that renders and initialize when any free application begins. 17:08.080 --> 17:14.560 So that's why this is important because when the modern web UI starts and initializes, 17:14.560 --> 17:21.360 we need to know if there is an existing session. So this operation needs to be done. We need to 17:21.360 --> 17:27.840 know if there is an existing session. And also the way we consume, maybe, I call have 17:28.480 --> 17:37.040 changed. So the API logic is setting what we call the communication layer, aka the service. 17:38.080 --> 17:45.360 And this is where the hooks, um, I mean, the endpoints of all the authentication methods are defined. 17:45.360 --> 17:50.400 In this example, so I only put the user and password logging. So we defined here 17:50.400 --> 17:57.200 the URL and some parameters here. I'm not sure if you can see it in the bottom of the 17:58.320 --> 18:05.920 half of the anyway. So you define this endpoint here. I haven't added it in the code, but 18:05.920 --> 18:13.840 you can export it here and from any other component, you can export it. And in this case, this is being 18:13.840 --> 18:22.240 used in the login button event clicker. So you call it here, you provide some payload and you handle 18:22.320 --> 18:29.120 the response. And after considering that there is no error, you can call this function that we 18:29.120 --> 18:36.320 saw before the global state. And of course, then I will show it in a minute, because if not, 18:36.320 --> 18:43.600 I will repeat so much. Okay, how is this work in the important part? So I have mentioned 18:44.320 --> 18:51.520 in one of the previous slides that this status, the state, um, the global state, um, 18:51.600 --> 18:56.880 modifies, it's simply continuous scenarios when the application initializes and when the user 18:56.880 --> 19:03.280 wants to login. And I would like to describe the first, um, case. And if we have some time, 19:03.280 --> 19:08.640 I will explain the other one. Otherwise, it will be in the slides anyway. So at the very beginning, 19:08.640 --> 19:16.080 when the model and web UI loads, it performs an initial handshake. That means that there is a 19:16.160 --> 19:23.600 batch of API calls that are called. So and it gets like some information about the configuration 19:23.600 --> 19:32.000 environment. And this is the same as it happens in the all web UI. But the, the value that 19:32.000 --> 19:37.440 are interesting is the who am I because if there is an existing session, you will see which 19:37.440 --> 19:44.320 you ID, which user has been authenticated. So if there is a valid session, we will call the 19:44.320 --> 19:51.120 set is login function. Otherwise, we will call the set is logout. If they're depending if there 19:51.120 --> 19:59.280 is some session, some routes will be unlocked or not. So if there is, and this is performed by this 19:59.840 --> 20:05.840 Boolean, if this is true, there is authentication. So the protected pages are shown. 20:06.560 --> 20:12.960 Otherwise, it will redirect to the login page or you can have some access to non protected 20:12.960 --> 20:21.280 pages. Okay, this is basically the same thing that I choose to explain about more details. 20:21.280 --> 20:30.080 I will skip this slide and I will explain, I'm not sure if I have some time, I will need to speed up. 20:30.800 --> 20:37.760 So this is the same thing, but this is the other approach. So what happens if a user is authenticated? 20:37.760 --> 20:44.320 How is this managed? So the process is quite similar. But the main difference is that the user needs 20:44.320 --> 20:49.360 to introduce the user and password. This is only the example for a user and password. 20:50.240 --> 20:58.080 But it works similarly in other authentication methods. So once the user enters the credentials 20:58.080 --> 21:06.000 and clicks login, the component that is performing the work is the login main pitch component. 21:06.080 --> 21:16.240 And it's calling a different hook, which is the one that locks in and gets the user and password. 21:16.240 --> 21:22.800 And there is this the same. If you get a success, the redix store and the status will be changed, 21:22.800 --> 21:29.360 and the page will be reload, and you will be able to see the main page, which is the active user's page. 21:30.160 --> 21:38.400 Okay, this is the demo, but I'm not sure if I will be have to show it. So if you're free to check it in the slides, 21:38.400 --> 21:46.880 they are already available. And oops, I'm not sure. Okay, let's get the conclusion super quick. 21:47.600 --> 21:54.560 So we changed from an imperative way of constructing the elements, the UI elements into a declarative way. 21:55.520 --> 22:02.320 Also the global state, which in the legacy code where distributed in widgets, now we rely on redaxed 22:02.320 --> 22:10.640 to manage them. And the back can, while it was mixed in the view, now it's encapsulated in the hooks, 22:10.640 --> 22:17.200 using the RTK query library, the safety well from JavaScript, the tapescript, from implicit 22:17.280 --> 22:24.400 to strict. And I put here some examples of the bundler that we're using one approach on the other, 22:24.400 --> 22:30.480 and how the integration tests libraries are using each of them. 22:32.800 --> 22:40.960 And this is the last slide, I think. So one thing that we want to improve in the future is that 22:41.920 --> 22:47.040 we would like to optimize the code in terms of good separation of constraints, because when we were 22:47.040 --> 22:53.600 adapting this legacy code, we took some of the same choices to simplify the migration process, 22:53.600 --> 23:01.200 and that included adopting some anti patterns that even though they are not so super critical, 23:01.200 --> 23:06.880 the code could be written in a more readable or structural way, so this would be one goal. 23:07.040 --> 23:12.240 Another goal will be providing the passwordless authentication method to log in into 23:12.240 --> 23:19.520 for IPA, most likely using well too. Since we are currently working on optimizing the integration 23:19.520 --> 23:27.680 test of the modern web UI to run them faster, we will adapt also belonging and the authentication 23:27.680 --> 23:32.720 method to test for them. And of course we would like to add some internationalization, 23:32.720 --> 23:39.360 so belonging, the belonging pitch will be affected by that. I put here some resources and 23:39.360 --> 23:44.640 the fuzz and talk in case you want to locally test the solution and try the other authentication 23:44.640 --> 23:50.320 methods I added here some design docs that are adapted to the main to the modern web UI. 23:51.520 --> 23:53.840 And that's all from my side, any questions? 24:02.960 --> 24:10.160 Any questions from anyone? 24:12.560 --> 24:14.080 Where the granola bars? 24:20.720 --> 24:24.240 Okay, if there is no questions, thank you for coming.