1 00:00:03,030 --> 00:00:08,490 Once your users can access your application, you still need to make authorization decisions, and there 2 00:00:08,490 --> 00:00:10,470 are different approaches to doing that. 3 00:00:11,100 --> 00:00:16,110 The one I want to show you here is to use the groups that a user has been assigned in Active Directory 4 00:00:16,110 --> 00:00:20,220 as roles in your application with which you can make authorization decisions. 5 00:00:20,850 --> 00:00:26,910 Let's start by opening the application group in PDFs and the web application portion that we're accessing. 6 00:00:26,910 --> 00:00:29,610 And let's modify the issuance transform roles. 7 00:00:30,210 --> 00:00:35,730 Let's delete the one created in the previous example that returned all claims in a custom rule. 8 00:00:36,360 --> 00:00:40,500 So let's add a new rule, and we've got several templates we can choose from. 9 00:00:41,100 --> 00:00:42,630 Let's use the first one. 10 00:00:42,630 --> 00:00:44,940 Send LDAP attributes as claims. 11 00:00:45,540 --> 00:00:51,150 Let's give this rule a name for the interface, and now we can map incoming claims to outgoing claims. 12 00:00:51,810 --> 00:00:56,040 First I'm going to choose the display name coming from Active Directory. 13 00:00:56,700 --> 00:01:02,370 And let's map that to the common name claim in the outgoing claims that are returned to the application. 14 00:01:03,000 --> 00:01:06,630 Next lets choose token groups unqualified name. 15 00:01:07,200 --> 00:01:11,310 And these are the groups that the user has been assigned in Active Directory. 16 00:01:11,970 --> 00:01:15,240 This will create a separate claim for each group assigned. 17 00:01:15,840 --> 00:01:18,960 And let's map this to role in the outgoing claim. 18 00:01:19,530 --> 00:01:25,230 The reason I'm using role instead of group is because ASP.NET Core will map these to a special collection 19 00:01:25,230 --> 00:01:30,390 on the user identity object so you can query them as roles rather than treating them like every other 20 00:01:30,390 --> 00:01:31,020 claim. 21 00:01:31,590 --> 00:01:34,740 But they are still claims, as you'll see in the code. 22 00:01:35,430 --> 00:01:40,560 Okay, let's choose the attribute store, which is Active Directory and click Finish. 23 00:01:41,190 --> 00:01:44,760 Now I'll apply these changes and click okay and okay again. 24 00:01:45,330 --> 00:01:51,690 Now let's go back to Visual Studio and let's go to the code behind for the homepage indexed CSV, HTML, 25 00:01:51,960 --> 00:01:52,650 CSS. 26 00:01:53,310 --> 00:01:58,140 Let's put some code in the on get method just so we can set a breakpoint and step through it. 27 00:01:58,810 --> 00:02:00,820 I'm going to paste in some code. 28 00:02:01,450 --> 00:02:06,310 This is just so you can see some of the properties on the user object that's available in your code 29 00:02:06,310 --> 00:02:07,060 behind. 30 00:02:07,690 --> 00:02:13,150 Let's resolve this by importing the correct using statement and let's set a breakpoint and debug the 31 00:02:13,150 --> 00:02:14,140 application. 32 00:02:14,860 --> 00:02:20,680 I'll enter my user information in the ad FS login page and because we're sent back to the home page, 33 00:02:20,680 --> 00:02:23,080 we hit the breakpoint in our application. 34 00:02:23,680 --> 00:02:29,650 Now let's see how those raw claims we saw on the screen previously are being parsed by ASP.NET Core. 35 00:02:30,340 --> 00:02:36,940 User Identity Name gives us the Windows Domain name for the user, and the authentication type is federation, 36 00:02:36,940 --> 00:02:38,230 which is interesting. 37 00:02:38,800 --> 00:02:43,240 Now this next piece of code is why I translated the group names to roles. 38 00:02:43,870 --> 00:02:49,930 When you do that, you can use this as an method on the user object because ASP.NET Core will parse 39 00:02:49,930 --> 00:02:54,310 the role claims into a special collection that's available right on the user object. 40 00:02:54,940 --> 00:03:00,370 You can do it long way also by using the has claim method and passing in the actual claim type. 41 00:03:01,000 --> 00:03:03,730 And this is the most generic way to do it. 42 00:03:04,390 --> 00:03:09,700 Or for common claim types, the framework has an enumeration that provides a shortcut to typing the 43 00:03:09,700 --> 00:03:11,320 long claimed type names. 44 00:03:11,950 --> 00:03:16,330 Here I'm using clean types role and passing in the same value as above. 45 00:03:16,930 --> 00:03:20,230 Now I'll press continue and we get brought to the page. 46 00:03:20,830 --> 00:03:25,900 You can see the role claims are available here and each roll has its own claim issued. 47 00:03:26,500 --> 00:03:28,770 So that's how to access claims and code. 48 00:03:28,780 --> 00:03:31,600 But let's see how we can make authorization easier. 49 00:03:32,360 --> 00:03:37,970 I'm going to go back to Startup Dot CSS and in the Configure Services method, let's add this code below 50 00:03:37,970 --> 00:03:44,270 the authentication code we added earlier services, add authorization and the options we're going to 51 00:03:44,270 --> 00:03:50,330 configure is to add an authorization policy, let's call it can access add me area. 52 00:03:50,930 --> 00:03:56,780 And on the policy builder use the method require claim and the claim we require is a role claim with 53 00:03:56,780 --> 00:03:58,490 the value domain admins. 54 00:03:59,120 --> 00:04:03,230 Let's just resolve this by adding the using statement at the top. 55 00:04:03,830 --> 00:04:06,830 Now this is just a definition at this point. 56 00:04:07,400 --> 00:04:10,430 We need to apply it somewhere in order to use it. 57 00:04:11,060 --> 00:04:14,210 We're going to set this policy on a page in the application. 58 00:04:14,210 --> 00:04:19,220 But before we can do that, we need to tell the middleware what to do when the user is denied access 59 00:04:19,220 --> 00:04:20,210 to the page. 60 00:04:20,810 --> 00:04:26,090 We do that in the ad cookie extension method here by configuring the access to night path. 61 00:04:26,720 --> 00:04:32,690 We could redirect the user to a custom error page, but let's just redirect to the root of the application, 62 00:04:32,690 --> 00:04:34,340 which is the index page. 63 00:04:34,970 --> 00:04:38,150 So let's go to a different page in the application. 64 00:04:38,750 --> 00:04:43,040 The template we used has this privacy page, so let's just use that. 65 00:04:43,640 --> 00:04:48,650 Let's add the authorized attribute onto the class and resolve the missing using statement. 66 00:04:49,310 --> 00:04:54,080 This will require that the user be authenticated in order to access this page. 67 00:04:54,680 --> 00:05:00,020 But for this particular page, we want to use the authorization policy we just created in startup. 68 00:05:00,740 --> 00:05:06,620 So let's add a parameter in brackets policy equals and the name of the authorization policy we created. 69 00:05:07,250 --> 00:05:09,440 Now let's run the application. 70 00:05:10,160 --> 00:05:14,330 I'll log in with my user credentials and were brought to the breakpoint again. 71 00:05:14,930 --> 00:05:18,320 Let's remove this and click continue in the debugger. 72 00:05:18,950 --> 00:05:23,510 We get brought to the home page and I'll click on the link to the privacy page. 73 00:05:24,110 --> 00:05:29,750 This user account has the domain admins role assigned, so I'm successfully brought to the page. 74 00:05:30,350 --> 00:05:33,200 Now let's close this and test the app again. 75 00:05:33,770 --> 00:05:38,990 But this time I'll log in with a different user, one that's not a member of the Domain Admits Group. 76 00:05:39,620 --> 00:05:43,310 You can see this user only has the domain users role assigned. 77 00:05:43,310 --> 00:05:45,920 So let's click on the privacy page link. 78 00:05:46,530 --> 00:05:48,270 And it looks like nothing happened. 79 00:05:48,270 --> 00:05:53,910 But you can see in the address bar at the top that the returned URL parameter was added and we've actually 80 00:05:53,910 --> 00:05:58,980 been redirected to the home page because that's what we configured to happen when the user doesn't meet 81 00:05:58,980 --> 00:06:01,710 the criteria of our authorization policy. 82 00:06:02,310 --> 00:06:06,600 So that's how you can use claims for authorization within your application. 83 00:06:07,230 --> 00:06:13,080 Next, let's deploy this test app to an IIS server so we can focus on authentication methods in the 84 00:06:13,080 --> 00:06:14,070 next module. 85 00:06:14,740 --> 00:06:20,020 Now let's package the sample application and deploy to an IIS server where we'll run it for the rest 86 00:06:20,020 --> 00:06:20,860 of the course. 87 00:06:21,530 --> 00:06:25,640 I've made a small change to the code here in the startup CSS class. 88 00:06:26,290 --> 00:06:32,440 Instead of hard coding the URL to the ADF's server and the client ID of the application in the application 89 00:06:32,440 --> 00:06:37,630 group, I've used configuration to store those values in the app settings dot JSON file. 90 00:06:38,230 --> 00:06:43,540 We won't need to change them in ADF RFS though since we're going to use the same application group. 91 00:06:44,160 --> 00:06:46,680 But we will need to make one small change. 92 00:06:47,280 --> 00:06:49,090 Let's go to Solution Explorer. 93 00:06:49,110 --> 00:06:52,440 Right click on the project name and click on Publish. 94 00:06:53,040 --> 00:06:56,580 That brings up the dialog where we choose a published target. 95 00:06:57,240 --> 00:07:00,750 I'm just going to pick a local folder here to publish to. 96 00:07:01,350 --> 00:07:06,990 Let's choose a folder and I'll go to the desktop and choose an empty folder I created for this purpose. 97 00:07:07,580 --> 00:07:10,250 And then we just click on Create Profile. 98 00:07:10,880 --> 00:07:15,020 Now we can publish to this profile without having to configure it again. 99 00:07:15,620 --> 00:07:17,570 So I'll click on publish. 100 00:07:18,210 --> 00:07:23,670 It will take a few seconds for Visual Studio to compile the project and publish the files to the local 101 00:07:23,670 --> 00:07:24,330 folder. 102 00:07:25,020 --> 00:07:29,730 Then we can open up File Explorer and navigate to that folder on the desktop. 103 00:07:30,340 --> 00:07:35,950 Now we're going to copy these files over to the IIS server for a simple copy paste deployment. 104 00:07:36,620 --> 00:07:42,050 I have a virtual machine configured with the IIS web server role, but one additional thing I had to 105 00:07:42,050 --> 00:07:48,140 do was download the ASP.NET Core 3.1 runtime and install it on this web server because it doesn't come 106 00:07:48,140 --> 00:07:50,000 as part of the operating system. 107 00:07:50,660 --> 00:07:56,420 Over on the IIS server, we're just going to use the default website that gets configured when you install 108 00:07:56,420 --> 00:07:57,290 IIS. 109 00:07:57,920 --> 00:08:03,860 So let's open up file explorer on the IIS server and navigate to the C drive and that pub and the root 110 00:08:03,860 --> 00:08:06,680 folder which is the root of the default website. 111 00:08:07,310 --> 00:08:13,520 There are a few default files here, so let's delete these and now I'll paste in the files for the new 112 00:08:13,520 --> 00:08:14,330 website. 113 00:08:15,010 --> 00:08:19,060 I need to provide administrator permissions to paste these in the folder. 114 00:08:19,720 --> 00:08:22,270 Let's just go back to Ice Manager. 115 00:08:22,930 --> 00:08:27,220 And I did make an additional configuration here to enable Zsl. 116 00:08:27,820 --> 00:08:33,730 I added a binding to the default website for https and enrolled the server with a certificate issued 117 00:08:33,730 --> 00:08:38,890 from Active Directory Certificate Services, which is used as the SSL certificate. 118 00:08:39,520 --> 00:08:45,760 That's important because we need to configure the redirect URI in advance to redirect back to the address 119 00:08:45,760 --> 00:08:49,480 of this web server, which will be an https URL. 120 00:08:50,080 --> 00:08:56,140 So let's bring up the ad FS server and in application groups, there's the app we created earlier. 121 00:08:56,870 --> 00:08:58,130 I'll double click on it. 122 00:08:58,130 --> 00:09:04,010 And we don't need to change the web application because we're not changing the client ID, we need to 123 00:09:04,010 --> 00:09:06,110 change the native application portion. 124 00:09:06,110 --> 00:09:09,980 So I'll double click on that and let's delete the redirect. 125 00:09:09,980 --> 00:09:15,290 Uri that points to local host on the development VM and let's replace that with the name of the web 126 00:09:15,290 --> 00:09:15,980 server. 127 00:09:16,680 --> 00:09:22,800 Because remember, we installed the application at the root of the default website, not in a subfolder. 128 00:09:23,430 --> 00:09:25,380 And that's all we need to do. 129 00:09:25,950 --> 00:09:26,360 Let's. 130 00:09:26,370 --> 00:09:26,730 Okay. 131 00:09:26,730 --> 00:09:30,570 Out of this configuration and let's go back to the management VM. 132 00:09:31,170 --> 00:09:36,570 Now I'll open up Microsoft Edge and navigate to HTTP, colon, slash, slash server one. 133 00:09:37,350 --> 00:09:42,810 Pry, which is the root of the web server and I'm redirected to the ADF's login page. 134 00:09:43,440 --> 00:09:48,990 So I'll enter my credentials and I'm authenticated to the application and the claims are displayed. 135 00:09:49,590 --> 00:09:54,540 You can see in the address bar that we're now getting this web application from the deployed files on 136 00:09:54,540 --> 00:09:56,490 the server one IIS server. 137 00:09:57,150 --> 00:10:03,510 Since Windows Server 2016, ADF RFS has supported access control policy templates. 138 00:10:04,140 --> 00:10:08,400 These replaced the need for writing policies using claims rule language. 139 00:10:09,070 --> 00:10:15,010 Access control policy templates allow an administrator to enforce policy settings by assigning the template 140 00:10:15,010 --> 00:10:16,810 to a group of relying parties. 141 00:10:17,440 --> 00:10:23,410 Subsequent changes to the policy template will then be applied to all the relying parties automatically. 142 00:10:24,160 --> 00:10:29,470 ETFs comes with default access control policy templates for common scenarios. 143 00:10:30,100 --> 00:10:31,870 For increased flexibility. 144 00:10:31,870 --> 00:10:34,450 You can create your own custom templates. 145 00:10:35,050 --> 00:10:40,420 Lets right click on the Access Control Policies tab and click Add Access Control Policy. 146 00:10:41,130 --> 00:10:45,300 I'll give this new policy a name and let's add a rule for permitting access. 147 00:10:45,930 --> 00:10:48,060 There are two main areas here. 148 00:10:48,690 --> 00:10:52,770 The permit options at the top and then a list of exceptions we can add. 149 00:10:53,340 --> 00:10:58,800 We could allow access for everyone to start, but lets limit access to users coming from a specific 150 00:10:58,800 --> 00:11:02,370 network and in the box at the bottom we can choose the network. 151 00:11:02,970 --> 00:11:08,910 We can limit this to the corporate intranet from the internet or from a specific IP address or range 152 00:11:08,910 --> 00:11:10,320 of IP addresses. 153 00:11:10,950 --> 00:11:11,850 Let's select that. 154 00:11:11,850 --> 00:11:15,330 We want this rule to apply to users coming from the Internet. 155 00:11:15,930 --> 00:11:22,680 Now, let's say we want this policy to require that these users perform multifactor authentication and 156 00:11:22,680 --> 00:11:28,260 let's choose a group of users to exclude from this policy so they won't need to perform MFA when coming 157 00:11:28,260 --> 00:11:29,280 from the Internet. 158 00:11:29,850 --> 00:11:35,640 We can require that this group is configured each time this custom access control policies apply to 159 00:11:35,640 --> 00:11:36,720 relying party. 160 00:11:37,430 --> 00:11:41,990 Or we can choose a security group here in the template that will always be used. 161 00:11:42,650 --> 00:11:45,590 Let's select security groups and I'll add one. 162 00:11:46,220 --> 00:11:51,770 I've created a custom security group in Active Directory and called it Excluded Users List. 163 00:11:52,460 --> 00:11:54,380 I'll verify that name and let's click. 164 00:11:54,380 --> 00:11:55,910 Okay and okay again. 165 00:11:56,510 --> 00:12:02,390 Now we have a policy that requires users coming from the Internet to perform multifactor authentication, 166 00:12:02,390 --> 00:12:06,170 except if they're included in the excluded users list security group. 167 00:12:06,920 --> 00:12:09,140 Okay, let's save this policy. 168 00:12:09,770 --> 00:12:13,700 Now, the policy shows up in our access control policies list. 169 00:12:14,340 --> 00:12:19,830 If I open up the application group we created in the server application being accessed, there's a tab 170 00:12:19,830 --> 00:12:22,170 of the top for access control policy. 171 00:12:22,830 --> 00:12:27,990 Now, besides all the built in policies, we can select the custom policy we just added. 172 00:12:28,590 --> 00:12:35,070 So that's how you can add a custom access control policy to add ZFS for use with relying party applications. 173 00:12:36,250 --> 00:12:44,740 A new feature in ADF's 2019 is the ability to customize the HTTP security response headers sent by ADF's. 174 00:12:45,370 --> 00:12:50,500 So why would you as an administrator of ADF's want or need to do that? 175 00:12:51,130 --> 00:12:56,110 Well, there are advancements in browser based protection mechanisms that you might want or need to 176 00:12:56,110 --> 00:12:57,280 take advantage of. 177 00:12:57,990 --> 00:13:03,240 A good example is if you're publishing single page applications that need to take advantage of cross 178 00:13:03,240 --> 00:13:10,200 origin resource sharing web browser security prevents a web page from making cross origin requests from 179 00:13:10,200 --> 00:13:11,280 within scripts. 180 00:13:11,940 --> 00:13:18,450 Cross Origin Resource Sharing is a W3C standard that allows the server to relax this policy for approved 181 00:13:18,450 --> 00:13:21,210 URLs using CRTs. 182 00:13:21,240 --> 00:13:25,230 The server can allow some cross origin requests and reject others. 183 00:13:25,830 --> 00:13:32,250 CRC is turned off by default in ADF's, but you can enable it and set the origin domains to allow a 184 00:13:32,250 --> 00:13:35,580 page to access a web API within another domain. 185 00:13:36,240 --> 00:13:39,270 Another example is the X Frame Options header. 186 00:13:39,900 --> 00:13:46,890 By default adds FFS doesn't allow external applications to use iframes when performing interactive logins. 187 00:13:47,490 --> 00:13:50,220 This is to prevent certain types of phishing attacks. 188 00:13:50,220 --> 00:13:56,100 But when you do want to trust a specific application to use an iframe capable interactive ADF's login 189 00:13:56,100 --> 00:14:01,500 page, you can specify origins in the HTTP header that the page must match. 190 00:14:02,130 --> 00:14:07,770 The PowerShell command accepts any header name and value though, so you can use it for many purposes, 191 00:14:07,770 --> 00:14:14,010 like setting a content security policy, setting HTTP, strict transport security or setting completely 192 00:14:14,010 --> 00:14:17,400 new custom headers specifically for your applications. 193 00:14:18,030 --> 00:14:25,500 The ability to customize HTTP security headers can also be added to add 2016 by installing a couple 194 00:14:25,500 --> 00:14:26,850 of KB patches. 195 00:14:27,480 --> 00:14:32,820 Now let's see how to configure this in PowerShell and we'll see what the headers look like by examining 196 00:14:32,820 --> 00:14:33,810 them in Fiddler. 197 00:14:34,540 --> 00:14:39,910 I'm on my Windows ten Management VM and let's start by opening up the Windows Admin Center. 198 00:14:40,600 --> 00:14:44,380 I already have the ADF's server added as a remote connection. 199 00:14:44,380 --> 00:14:46,030 So let's navigate to that. 200 00:14:46,630 --> 00:14:52,960 And once the connection is made, let's scroll down to the PowerShell tab that opens up a PowerShell 201 00:14:52,960 --> 00:14:55,300 connection to the ADF's server. 202 00:14:55,930 --> 00:14:59,650 Now let me clear the screen and let's zoom in the browser window a bit. 203 00:14:59,650 --> 00:15:01,360 So this is easier to see. 204 00:15:02,090 --> 00:15:08,090 Okay, let's use the new ADF's PowerShell command set out for response headers and type the parameter 205 00:15:08,090 --> 00:15:09,260 enable course. 206 00:15:09,920 --> 00:15:15,320 This will enable a cross origin resource sharing that I mentioned and let's set the value to true. 207 00:15:15,920 --> 00:15:21,350 Now let's set the list of trusted origins by typing the set at Response Headers Command again, and 208 00:15:21,350 --> 00:15:27,080 this time the source trusted origins parameter is used and you can list the domains that are permitted 209 00:15:27,080 --> 00:15:28,790 separated by commas. 210 00:15:29,430 --> 00:15:30,630 And that's it. 211 00:15:31,200 --> 00:15:36,090 Now let's set a custom header and you can do this for whatever purpose you might need. 212 00:15:36,730 --> 00:15:39,490 It's just a flexible way of having a PDFs. 213 00:15:39,490 --> 00:15:41,530 Send an HTTP header. 214 00:15:42,190 --> 00:15:47,590 Will you syntax response headers again this time using the generic parameters, set header name and 215 00:15:47,590 --> 00:15:48,610 set header value. 216 00:15:48,610 --> 00:15:49,570 And that's it. 217 00:15:50,200 --> 00:15:55,660 Now let's see what these HTTP headers look like when returned from PDFs to the browser. 218 00:15:56,370 --> 00:16:00,510 I have Fiddler installed on this VM to monitor the HTTP traffic. 219 00:16:00,510 --> 00:16:06,120 So let's start monitoring by turning on captured traffic and let's go to Visual Studio on this VM and 220 00:16:06,120 --> 00:16:10,110 run the sample project that opens up a web browser. 221 00:16:10,110 --> 00:16:12,750 And let's zoom out to normal text size first. 222 00:16:13,380 --> 00:16:18,870 Now I'll log in with my account and when we're redirected back to the local web server, I'll open up 223 00:16:18,870 --> 00:16:22,530 Fiddler and let's look at the HTTP traffic that was captured. 224 00:16:23,220 --> 00:16:28,920 I'll select one of the connections to the ADF's server and this is the token endpoint where the access 225 00:16:28,920 --> 00:16:35,310 token is retrieved from after authentication in the response headers under miscellaneous, there's the 226 00:16:35,310 --> 00:16:39,390 test header, name and value we just configured on the ADF's server. 227 00:16:40,090 --> 00:16:46,450 In this module you learn about claims and ADF's and the protocols that ADF's supports for the authentication 228 00:16:46,450 --> 00:16:48,550 process and the tokens returned. 229 00:16:49,180 --> 00:16:54,880 You saw how application groups are used to organise groups of clients and servers that form an application. 230 00:16:54,880 --> 00:17:00,490 And you created an ASP.NET Core application to display claims return from ADF's. 231 00:17:01,090 --> 00:17:07,090 We examined configuring claims rules in ADF, PFS as well as how to use claims for authorization in 232 00:17:07,090 --> 00:17:07,690 code. 233 00:17:08,320 --> 00:17:14,410 Then we looked at custom access policies that make it easy to configure access rules in the claims pipeline. 234 00:17:14,980 --> 00:17:21,460 And finally, you saw how to customize HTTP response headers that are returned from ADF's in order to 235 00:17:21,460 --> 00:17:24,400 take advantage of browser based protection mechanisms. 236 00:17:25,000 --> 00:17:31,480 In the next module we're going to start configuring our ADF server to perform different types of authentication, 237 00:17:31,480 --> 00:17:36,400 including integrating with Azure Active Directory to enable multi-factor authentication.