 On today's Visual Studio Toolbox, Paul's going to show us a couple of ways to add security to WPF apps. Hi, welcome to Visual Studio Toolbox. I'm your host Robert Green and joining me today is Paul Sheriff. Hey, Paul. Hey, Robert, how are you? Great. Welcome on the show. Thank you. Thank you. It's been many years. It's good to be back. Yeah. Paul and I have known each other for a very, very long time, so I'm glad that you had an opportunity to come on the show and talk to us about adding security to WPF applications. Well, I've been doing a lot of WPF lately with a client, and we had to add this in, and I'd written this years ago, so it was nice to actually come back around and clean it up for the latest stuff lately, so it's been nice. Cool. It can be an important topic, but I can imagine it's not necessarily intuitive how to get started doing it. I think you agree with that. Not really because unlike the web apps, that Microsoft kind of includes it right out of the box, there's nothing for WPF, so it's basically roll your own. You wrote an article about this that was in a recent issue of Code Magazine. We'll put a link to that that has the full write-up as well as the code. But here, I thought you could give us kind of a quicker and not dirtier because it's the same code, but a quicker overview of how it all works. What do you think? That sounds like a good idea. Let's jump into it. All right, let's do it. Well, I thought, Robert, it might be important to start out with the goals of why you need a security system. The major goals are really just let's make controls disappear, right? Hit item or collapse them. Let's make some other controls might need to be disabled. You might want some to be read-only. I think the major goal, which we're going to get to is do all these disks without having to recompile code. Yes. Right? So that would be the ideal. So we're going to kind of build up to that. But I thought I'd take you through a little screen. So I made a little screen here where we've got a new button. We've got some employee data and then we got a save button. And maybe we want to hide that new button. We want to disable the employee ID. Maybe we want to hide the salary text box, disable the SSN and maybe disable the save button. So I thought I'd kind of show you going through basically securing this form. We're going to do it a couple of different ways because I've got a couple of different techniques. And I'll point out the good and the bad of each one of those. So here we are in Visual Studio. And I wrote a little sample app and we'll give you a link to this as well. So you'll be able to download this exact sample. I've got four samples for you, four or five actually. Now here's a question first. Are you relying on any particular version of the .NET framework or any particular version of Visual Studio here? You know, I'm not. I've used this sample for many, many years. It's written using the latest. So Visual Studio 2019, but it should work fine in just about anything. Okay. Yeah, good question though. All right, so what I've done in this one, you can see that screen has popped up. But notice that the salary box is gone, that the SSN is disabled and the save button is disabled. And I thought I'd show you just a little bit about what I'm doing here. So underneath in the loaded event for the window loaded, you can see on line 22. I call this set security principle. And one of the things you typically want to do when you're doing windows security, and I'm just using the windows security right now. So built-in roles, whatever you have set up are groups, AD groups. You could also do your own generic principle here if you wanted to. But it's important to set that principle into the thread. Once you've done that, I've got, as you can see on line 25, I'm calling a view model because this is WPF, so MVVM. ViewModel.secureControls. And if we take a look, what I'm doing is I'm grabbing the current principle, and then I'm gonna just use the isInRole method. I'm sure a lot of you are familiar with that. And we can check to see if a user is in the user's role, maybe the administrator's role, the supervisor role. And all I'm doing is I'm tying that to some properties here. IsInUser'sRole, isInAdminRole, isInSupervisorRole. So I've got some different properties up here that you can see. I'm simply doing the raise property changed. So I've got those three. I also added a couple other ones because I said, hey, maybe I wanna be in a user's or supervisor role, or isInAdmin or isInSupervisorRole. And that's basically the amount of code that I have for this particular sample. Now, let's take a look at my main window here. And what I've done is I've simply used a user control called employee control. And this is that control that I showed you on the slides. So you can see that here. But let's take a look at the XAML because this is where everything happens here. So down here in the XAML on that new button, I have a visibility property and look at the path. Am I in the user's or supervisor role? And then I'm using a converter for the visibility converter, of course. So each one of these visibility is read only. The down here we've got the isAdminRole, you use supervisor role for each control that you want to secure, you simply bind it up to a property. Did you have to write that converter? The visibility? That's built-in WPF converter. All I had to do was make a resource out of it. That's very simple to do. There's some problems with this. Let's talk about those problems before I show you how we fix it. So instead, what we wanna do is map a table in a database to a set of security objects. So here I've got a table with an element identifier such as new button, employee ID, salary, those match up to that user control that we saw. I have a mode which could be collapsed, read only, hidden, disabled. And those are the modes that we have in WPF and in the role. So if the user's in one of these roles, this common limited list, then we're not gonna collapse it, we're not gonna make it read only, we're not gonna make it hidden, otherwise it would be. So we're gonna take the data out of this table, we're gonna map it into a list of what I call security control objects. So we've got each one of those fields is mapped up to each property. And then we're gonna use that to apply to this screen. And the way we do that is we simply match up the element identifier to each button's name or maybe a tag property. So I wanted to give us a couple, kinda give us some flexibility so we could map up the element identifier to the name or the tag. And all we have to do then is once we have that list of security control objects, we loop through the controls on the form, find that form and then we either set it disabled or collapsed or whatever it says to do. So let's take a look at how we do that. Okay. So what I've done now, Robert, is I've taken and I've broken out things into a couple of different projects. I have a WPF security project. And this will make it easier for the users when they download this to be able to take this DLL and put it right into their application. I also did create, in this particular instance, I created this security control class that we saw that has those various properties, container name, element identifier, mode. And all we're gonna do is map this from SQL server to here, eventually. What I'm gonna do for right now, just to keep things really simple. And let's see if I can find this. I apologize, there we go. Is I'm gonna go ahead right now and just hard code this in. So just so we can see what this looks like and then we'll just take it from the database in the next one. But here you can see. So I was going to, it did look like you were hard coding that and if you made any changes to who got to do what, you'd have to recompile the code. But this is an interim step. Exactly. And it really just makes it easier for me to explain how we get from step B, step A to step B, right? Right. All right. So what I'm doing is again, I've got the container name, which is our employee control. So you can see the employee control right here. Then we have the element identifier, which is the new button or the employee ID and then what the mode is gonna be. Okay. And oops. Don't click on those. What the mode's gonna be and then the roles as a string. And I made this one users one, two, three. And then we're gonna go ahead and run this. I'll show you what it looks like first and then we're gonna just step through the code really quickly. Because it's not a lot of code. All right. See, the new button is gone. Okay. If I then come back here and I change this to users, I should be in the user's role on my machine. It comes back. Yeah. All right. Now let's take a look. Cause what's important now is I got rid of all of those bindings. Mm-hmm. Okay. No visibility, no read only. All of those are just gone, aren't they? Okay. So that's great. So that means all we're doing now is we're matching it up on the name or maybe a tag element if I'm using a tag like right down here. Yeah. All right. So now let's go ahead and step through this and we'll see how this works. So I'll set a break point right here. So I changed the secure controls from last time because I need to pass in an instance, right? This instance of this particular form because I need to be able to go through the controls in that form, don't I? Yes. To match those up. Excellent. And I've called employee control because I may have more than one or two or three or 10 different forms and I wanna be able to have one table and be able to specify which form I'm on so we know which set of controls to get. All right, hopefully that's clear as much. All right, so let's drive into this. So we come into the secure controls and the first thing I'm gonna do is I'm gonna get the current principal. I'm gonna call this load controls to secure and this is where we're gonna now jump into that one that we just built, right? That has the hard coded values. Okay. Then we're gonna go through and I'm just gonna use a little bit of WPF code to grab all the controls in the container. And we can take a look at this. I'll let you kind of look at this in more depth later but all it is is a recursive call to loop through and grab all of the different objects and I'm gonna create a list basically of all of the controls that are on this particular screen. And one of the key things I'm doing here is I'm gonna check to see whether we should consider this control that I just grabbed for security. So that means that it either has to have a control name or a tag name, right? The name property or the tag name has to be set. Okay. Because if not, I don't have any way to match it up to those controls, do I? So I would need to make sure those are there. And then as you can see, I'm gonna go through and look for any child objects and I'm gonna recursively call this until we're all done. When I'm all done, set a break point here, I now have a list of those controls that either have a name or a tag property and there's only five of them. And if we look, those are the ones that we saw that I wanna now connect up to, right? The new button, the employee ID, the salary, the social security number, the save button. All right. So now all I'm gonna do is that you find that you typically use name or tag because if you're ever going to reference a control in code, you'll wind up naming it but it may not need to be secured, right? Oh, I'm so glad you asked that. Oh, I'd like to remind my straight man for today. The last sample that I have is if you don't wanna set the name or the tag but you have a binding, we can do it on the binding as well but that's a lot more code. So I wanted to start out this way first and then later I'll show you how to actually do it with a binding. So you don't even have to have the name or the tag property. Got it. Okay. Yeah. All right, cool. Nice straight man there. So the first thing I'm gonna do is I'm gonna simply go through in my look now for that element identifier and see if I found it in that control. Hey, I did. Great. So now that I found it, all I have to do now is check to see, hey, let's loop through the roles now and am I in one of those roles? Okay, and if I am, I skip it, I don't have to do anything. Let's then go to the next control. We're gonna search for that one. We found it. And now we're gonna check and say, hey, am I in any one of those roles? Oops, I'm not. So this control that we're on, which is the employee ID, okay? What mode am I gonna do? Read only, okay? So we come into this method that I call change state and all I'm doing is checking to see what came from that mode, right? That disabled read only and I'm gonna then set the appropriate thing. So in read only, I'm gonna set the is enabled equal to true and the visibility to true and then I'm gonna change, what? There is read only property, okay? So I'm taking from whatever it was before, making sure it's wiped out and then I'm gonna apply whatever it was. I'm using just a little bit of reflection here, okay? So I'm using a little reflection but this is the quick way to do it when you do the set value, okay? This is the way the entity framework does it, not the old way. So this is very efficient to do and I'm gonna set that controls is read only property to true. So we just do this for every single control and when we're done, I hit F5 here, everyone's been set to whatever those security permissions are. All right, now that's the first thing. Now the next one we're gonna do, right? So now what we're gonna do is we wanna take that data and get it out of SQL Server. So we're not gonna hard code it anymore. So what we'll do is we'll have a securitycontrol.sql file and what I've done is I've simply created that little table that I showed you in that screenshot in the slides and I've also given you this sample data here. So I created this in my SQL Server and you will create this as well in order to get this particular application to work. Now the way that this works is I had to change a couple of things. So first off, the load controls to secure is no longer hard coded. As you can see now, I'm using a class called securitycontrolmanager and it has getsecuritycontrols. If we go over to this particular guy here, I'm simply using a little entity framework code. I've got a security context, a DB context setup called WPF Security DB context and I'm going out to grab the data from that security control table. That's what gives me my control list. All right. Then after that, everything else is pretty much the same. Let's go ahead, set our breakpoint again. We'll go ahead and run. And the nice thing about this is you now don't have to look through every single control in the form. You already know what the list of controls is, right? That's true, because you wrote the form, right? So you know which things you wanna secure up. So all you're doing is going into the SQL Server database and adding or taking away controls based on what you need. All right, so if we take a look, the code for the secure controls, exactly the same. The only difference is this particular method here, the load control secure goes to the database now that then loads up the controls in XAML. It then loops through all the code. Same exact code. Isn't that nice? So we just switched from the hard coded version now to the database version. Excellent. So now we don't have to redistribute anything. Now we can just change something in our database. But there's one more thing. That's what you asked about earlier, Robert. So it's, if we take a look at now, if you don't wanna set the name or you don't wanna set the tag, I added one more bit of code on it. And I'll show you the little changes that I had to make here. And if we take a look at my user control, and again, we'll look at the XAML. And so now you can see on the button, okay? I did still have it in there, I apologize, but if the button doesn't have any bindings, I do need a name, okay? Now look, no name or tag on the text box, there's just the binding. That employee ID has that same exact identifier, and I can use that. Same thing with the first name or last name. So I've gotten rid of name or tag when I can, okay? And if you don't wanna use name, because you don't wanna have it show up in your code behind, you can always use the tag as well. Because remember that's still there as well, that's an option, all right? So it just depends on what you wanna, you have an option of name, tag, or binding. What do you typically use more often than not in real life? I try to use the binding because normally I'm trying to bind something that, you know, I'm trying to secure something that is bound. Okay. But for buttons, right? Because sometimes I don't want it, I don't want some user to save a button or click on that save button. They can save, that's one of their permissions that they don't have. Then I have to use name or tag. Now, if you think about it, the name, I usually have a click event associated with this. So I typically have a name on it anyway, cause I want a nice name to show up for the click event. Right, okay. So now let's take a look at a couple of little things that I added here, okay? So one of the things is, when I go into the secure controls here, and I load the controls, that hasn't changed. The load controls in the XAML container. So if we scroll down here, this most of this code is the same, but I marked it out right here, begin new code. This is the only new code I added. So in this one, I have a method called get binding names. So I'm gonna pass in the control as we're looping through the set of controls on the form, right? Or on the, I'm gonna say take this control and let's go find out what the binding property is. So this is all the code I had to write to actually figure out. So I had to figure out code by code, or I had to figure out control by control, which value would have that bound property? And then I grab that property and I can then get the binding expression. This is built into WPF. Cool. So once I have that binding expression, I can get the path. And remember what the path is? We go back here. The path is that. Yep. And that's what I can do next table, right? There was just one more thing that I had to do and it's this line of code immediately after the new code I added, get binding name. It's that consider for security. If you remember before, we considered a control to be secureable if it had a name or a tag property, right? And now as you can see, I had to add one more, is there a binding path? So if it has a binding path, a control name or a tag, we can consider this for security. And that's it. That's all the changes we had to make. So we now have it accomplished our goals. We can make any control read only. We can make it hidden. We can make it collapsed. We can do disabled. And we can do it all from a database table and with just a little bit of code. And I've given you a nice class library that you'll be able to drop this right into your application. Very, very cool. Do you, have you tried this in UWP? You know, I haven't, but I don't see any reason why it wouldn't work exactly the same way. I guess it depends on, do you have the same ability to read the paths and dig down into the controls, right? The binding expression might be the only thing. That might be a little bit different under UWP. Everything else should be the same because we're just using the reflection there and that's still available in UWP. Yeah, and then you have the same question of how would you do this in something like Xamarin? Yeah, that could be maybe a little bit more difficult. I'm not sure you have all those expressions, so. Right. Yeah, but there you go. Easy way, I think, to secure your WPF app. Very, very cool. Right. So all of these samples and the full article will put links to in the show notes so people can go try this out themselves. Absolutely. And thank you so much for coming on and showing us this, Paul. Well, thanks for having me on. I appreciate it and we'll see you again soon. All right, I hope you guys enjoyed that and we will see you next time on Visual Studio Toolbox.