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.

