├── media ├── risk10.png ├── risk11.png ├── risk12.png ├── risk13.png ├── risk14.png ├── risk15.png ├── risk16.PNG ├── risk17.png ├── risk18.PNG ├── risk19.png ├── risk2.png ├── risk20.png ├── risk21.png ├── risk22.png ├── risk23.png ├── risk24.png ├── risk25.png ├── risk26.PNG ├── risk27.png ├── risk28.PNG ├── risk29.png ├── risk3.png ├── risk30.png ├── risk4.png ├── risk5.png ├── risk6.png ├── risk7.png ├── risk8.png └── risk9.png ├── CODE_OF_CONDUCT.md ├── AssemblyInfo.cs ├── ThreatDetectionModule.sln ├── LICENSE ├── SECURITY.md ├── ThreatDetectionModule.csproj ├── UserRiskAnalyzer.cs ├── RiskyUserHelper.cs ├── __testcode40__.resx ├── .gitignore └── README.md /media/risk10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk10.png -------------------------------------------------------------------------------- /media/risk11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk11.png -------------------------------------------------------------------------------- /media/risk12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk12.png -------------------------------------------------------------------------------- /media/risk13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk13.png -------------------------------------------------------------------------------- /media/risk14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk14.png -------------------------------------------------------------------------------- /media/risk15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk15.png -------------------------------------------------------------------------------- /media/risk16.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk16.PNG -------------------------------------------------------------------------------- /media/risk17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk17.png -------------------------------------------------------------------------------- /media/risk18.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk18.PNG -------------------------------------------------------------------------------- /media/risk19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk19.png -------------------------------------------------------------------------------- /media/risk2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk2.png -------------------------------------------------------------------------------- /media/risk20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk20.png -------------------------------------------------------------------------------- /media/risk21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk21.png -------------------------------------------------------------------------------- /media/risk22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk22.png -------------------------------------------------------------------------------- /media/risk23.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk23.png -------------------------------------------------------------------------------- /media/risk24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk24.png -------------------------------------------------------------------------------- /media/risk25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk25.png -------------------------------------------------------------------------------- /media/risk26.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk26.PNG -------------------------------------------------------------------------------- /media/risk27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk27.png -------------------------------------------------------------------------------- /media/risk28.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk28.PNG -------------------------------------------------------------------------------- /media/risk29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk29.png -------------------------------------------------------------------------------- /media/risk3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk3.png -------------------------------------------------------------------------------- /media/risk30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk30.png -------------------------------------------------------------------------------- /media/risk4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk4.png -------------------------------------------------------------------------------- /media/risk5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk5.png -------------------------------------------------------------------------------- /media/risk6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk6.png -------------------------------------------------------------------------------- /media/risk7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk7.png -------------------------------------------------------------------------------- /media/risk8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk8.png -------------------------------------------------------------------------------- /media/risk9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/adfs-sample-block-user-on-adfs-marked-risky-by-AzureAD-IdentityProtection/master/media/risk9.png -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | using System.Security.Permissions; 4 | 5 | [assembly: ComVisible(false)] 6 | [assembly: AssemblyProduct("Microsoft (R) Windows (R) Operating System")] 7 | [assembly: AssemblyCopyright("Copyright (c) Microsoft Corporation. All rights reserved.")] 8 | [assembly: AssemblyCompany("Microsoft Corporation")] 9 | [assembly: AssemblyFileVersion("10.0.10011.16384")] 10 | 11 | [assembly: AssemblyDelaySign(false)] 12 | [assembly: AssemblyVersion("10.0.0.0")] 13 | 14 | -------------------------------------------------------------------------------- /ThreatDetectionModule.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreatDetectionModule", "ThreatDetectionModule.csproj", "{9D147DF5-F62A-41FE-91E2-86CE41A91D5A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {9D147DF5-F62A-41FE-91E2-86CE41A91D5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {9D147DF5-F62A-41FE-91E2-86CE41A91D5A}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {9D147DF5-F62A-41FE-91E2-86CE41A91D5A}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {9D147DF5-F62A-41FE-91E2-86CE41A91D5A}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | -------------------------------------------------------------------------------- /ThreatDetectionModule.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {9D147DF5-F62A-41FE-91E2-86CE41A91D5A} 8 | Library 9 | ThreatDetectionModule 10 | v4.7.2 11 | 10.0.0.0 12 | 512 13 | ThreatDetectionModule 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | true 37 | 38 | 39 | TDMKey.snk 40 | 41 | 42 | 43 | False 44 | ..\Windows\ADFS\Microsoft.IdentityServer.dll 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /UserRiskAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.IdentityServer.Public.ThreatDetectionFramework; 2 | using Microsoft.VisualBasic.FileIO; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Net; 6 | using System.Threading.Tasks; 7 | using Microsoft.IdentityServer.Public; 8 | using System.Security.Claims; 9 | 10 | namespace ThreatDetectionModule 11 | { 12 | /// 13 | /// UserRiskAnalyzer is the main class implementing ThreatDetectionModule abstract class and IPreAuthenticationThreatDetectionModule and IPostAuthenticationThreatDetectionModule interfaces. 14 | /// This module will allow a "No risk" user to be able to login successfully, allow "Low risk" user to login after additional auth (MFA) and block "High risk" user 15 | /// 16 | public class UserRiskAnalyzer : Microsoft.IdentityServer.Public.ThreatDetectionFramework.ThreatDetectionModule, IPreAuthenticationThreatDetectionModule, IPostAuthenticationThreatDetectionModule 17 | { 18 | 19 | public override string VendorName => "Microsoft"; 20 | public override string ModuleIdentifier => "UserRiskAnalyzer"; 21 | 22 | /// 23 | /// ADFS calls this method while loading the module 24 | /// 25 | /// 26 | /// 27 | public override void OnAuthenticationPipelineLoad(ThreatDetectionLogger logger, ThreatDetectionModuleConfiguration configData) 28 | { 29 | } 30 | 31 | 32 | /// 33 | /// ADFS calls this method while unloading the module 34 | /// 35 | /// 36 | public override void OnAuthenticationPipelineUnload(ThreatDetectionLogger logger) 37 | { 38 | } 39 | 40 | 41 | /// 42 | /// ADFS calls this method when there is any change in the configuration. 43 | /// 44 | /// 45 | /// 46 | public override void OnConfigurationUpdate(ThreatDetectionLogger logger, ThreatDetectionModuleConfiguration configData) 47 | { 48 | } 49 | 50 | public Task EvaluatePreAuthentication(ThreatDetectionLogger logger, RequestContext requestContext, SecurityContext securityContext, ProtocolContext protocolContext, IList additionalClams) 51 | { 52 | 53 | try 54 | { 55 | RiskScore isRisky = RiskyUserHelper.GetRiskScore(securityContext.UserIdentifier); 56 | 57 | if (isRisky == RiskScore.High) 58 | { 59 | logger?.WriteAdminLogErrorMessage($"EvaluatePreAuthentication: Blocked request for user {securityContext.UserIdentifier}"); 60 | return Task.FromResult(ThrottleStatus.Block); 61 | } 62 | logger?.WriteDebugMessage($"EvaluatePreAuthentication: Allowed request for user {securityContext.UserIdentifier}"); 63 | return Task.FromResult(ThrottleStatus.Allow); 64 | 65 | 66 | } 67 | catch (Exception ex) 68 | { 69 | logger.WriteAdminLogErrorMessage(ex.ToString()); 70 | throw; 71 | } 72 | 73 | throw new NotImplementedException(); 74 | } 75 | 76 | Task IPostAuthenticationThreatDetectionModule.EvaluatePostAuthentication(ThreatDetectionLogger logger, RequestContext requestContext, SecurityContext securityContext, ProtocolContext protocolContext, AuthenticationResult authenticationResult, IList additionalClams) 77 | { 78 | try 79 | { 80 | RiskScore isRisky = RiskyUserHelper.GetRiskScore(securityContext.UserIdentifier); 81 | 82 | if (isRisky == RiskScore.High || isRisky == RiskScore.Medium) 83 | { 84 | logger?.WriteAdminLogErrorMessage($"EvaluatePostAuthentication: Risk Score {isRisky} returned for user {securityContext.UserIdentifier}"); 85 | 86 | 87 | } 88 | else 89 | { 90 | logger?.WriteDebugMessage($"EvaluatePostAuthentication: Risk Score {isRisky} returned for user {securityContext.UserIdentifier}"); 91 | } 92 | return Task.FromResult(isRisky); 93 | 94 | 95 | } 96 | catch (Exception ex) 97 | { 98 | logger.WriteAdminLogErrorMessage(ex.ToString()); 99 | throw; 100 | } 101 | 102 | throw new NotImplementedException(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /RiskyUserHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Net; 5 | using System.Text; 6 | using System.Web.Script.Serialization; 7 | using Microsoft.IdentityServer.Public.ThreatDetectionFramework; 8 | //include dlls System.Web.Extensions 9 | 10 | namespace ThreatDetectionModule 11 | { 12 | public enum RiskLevel 13 | { 14 | None, 15 | Low, 16 | Medium, 17 | High 18 | } 19 | 20 | internal static class RiskyUserHelper 21 | { 22 | internal static string TenantName = "[Enter Azure AD Tenant Name]"; 23 | internal static string ClientId = "[Enter Application (client) Id]"; 24 | internal static string ClientSecret = "[Enter Application (client) Secret]"; 25 | internal static string LoginURL = String.Format("https://login.microsoft.com/{0}/oauth2/token?api-version=1.0", TenantName); 26 | internal class RiskyList 27 | { 28 | public Dictionary[] Value { get; set; } 29 | } 30 | 31 | /// 32 | /// Gets the risk of a user by lookoing at the IP data from AAD 33 | /// 34 | /// UPN of the user 35 | /// 36 | public static RiskScore GetRiskScore(string upn) 37 | { 38 | 39 | Dictionary accessTokenResponse = GetAccessToken(); 40 | RiskyList list = GetRiskyUsers(accessTokenResponse["token_type"], accessTokenResponse["access_token"]); 41 | Dictionary riskyUsers = BuildRiskyData(list); 42 | RiskScore level = RiskScore.NotEvaluated; 43 | if (null != riskyUsers) 44 | { 45 | if (riskyUsers.ContainsKey(upn)) 46 | { 47 | level = riskyUsers[upn]; 48 | } 49 | } 50 | return level; 51 | } 52 | 53 | static Dictionary BuildRiskyData(RiskyList list) 54 | { 55 | Dictionary riskyUserData = new Dictionary(); 56 | foreach (Dictionary user in list.Value) 57 | { 58 | RiskScore level = RiskScore.NotEvaluated; 59 | if (user.ContainsKey("userPrincipalName") && !String.IsNullOrEmpty(user["userPrincipalName"])) 60 | { 61 | if (!String.IsNullOrEmpty(user["riskLevel"])) 62 | 63 | { 64 | if (String.Compare(user["riskLevel"], "high", StringComparison.OrdinalIgnoreCase) == 0) 65 | { 66 | level = RiskScore.High; 67 | } 68 | else if (String.Compare(user["riskLevel"], "low", StringComparison.OrdinalIgnoreCase) == 0) 69 | { 70 | level = RiskScore.Low; 71 | } 72 | else if (String.Compare(user["riskLevel"], "medium", StringComparison.OrdinalIgnoreCase) == 0) 73 | { 74 | level = RiskScore.Medium; 75 | } 76 | riskyUserData.Add(user["userPrincipalName"], level); 77 | } 78 | } 79 | } 80 | 81 | return riskyUserData; 82 | } 83 | 84 | // Gets the access token which can be used to get the Risky user information 85 | static Dictionary GetAccessToken() 86 | { 87 | string body = String.Format("resource=https://graph.microsoft.com&grant_type=client_credentials&client_id={0}&client_secret={1}", ClientId, ClientSecret); 88 | byte[] bodyBytes = Encoding.UTF8.GetBytes(body); 89 | var req = HttpWebRequest.Create(LoginURL); 90 | 91 | req.ContentType = "application/x-www-form-urlencoded"; 92 | req.ContentLength = bodyBytes.Length; 93 | req.Method = "POST"; 94 | req.GetRequestStream().Write(bodyBytes, 0, bodyBytes.Length); 95 | 96 | var response = req.GetResponse(); 97 | Dictionary jsonResponse = new Dictionary(); 98 | using (Stream stream = response.GetResponseStream()) 99 | { 100 | using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) 101 | { 102 | String responseString = reader.ReadToEnd(); 103 | JavaScriptSerializer json_serializer = new JavaScriptSerializer(); 104 | jsonResponse = json_serializer.Deserialize>(responseString); 105 | } 106 | } 107 | 108 | return jsonResponse; 109 | } 110 | 111 | // Get the Risky user data from the graph 112 | static RiskyList GetRiskyUsers(string tokenType, string accessToken) 113 | { 114 | var riskyReq = HttpWebRequest.Create("https://graph.microsoft.com/beta/riskyUsers"); 115 | riskyReq.Headers.Add("Authorization", String.Format("{0} {1}", tokenType, accessToken)); 116 | 117 | var responseRisky = riskyReq.GetResponse(); 118 | using (Stream stream = responseRisky.GetResponseStream()) 119 | { 120 | using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) 121 | { 122 | String responseString = reader.ReadToEnd(); 123 | JavaScriptSerializer json_serializer = new JavaScriptSerializer(); 124 | return json_serializer.Deserialize(responseString); 125 | } 126 | } 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /__testcode40__.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | __TESTCODE__ 122 | 123 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | page_type: sample 3 | languages: csharp 4 | products: dotnet 5 | --- 6 | 7 | # Build AD FS plug-in to block authentication or enforce MFA based on user risk level determined by Azure AD Identity Protection 8 | 9 | Build your own plug-in with [AD FS Risk Assessment Model](https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/development/ad-fs-risk-assessment-model) that uses the risk level of a user determined by [Azure AD Identity Protection](https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection) to allow or block authentication or enforce additional authentication (MFA) while authenticating the user againsts AD FS. 10 | 11 | The plug-in once registered with AD FS runs in line with AD FS authentication process. For any user authenticating against AD FS, the plug-in pulls in the Risk Level of the user using the Azure AD Identity Protection [riskyUser API](https://docs.microsoft.com/en-us/graph/api/resources/riskyuser?view=graph-rest-beta) and initiates one of the follwing actions 12 | - Blocks authentication if user's risk level is “high” 13 | - Enforces additional authentication (MFA) if user's risk level is “low” or “medium” 14 | - Allows authentication if user's risk level is "none", "hidden" or "unknownFutureValue" 15 | 16 | >[!NOTE] 17 | >This sample is only to illustrate how cloud intelligence from Azure AD Identity Protection can be used to further strengthen the AD FS authentication process. By no means is this sample plug-in we are building an enterprise ready solution. 18 | 19 | 20 | ## Prerequisites 21 | 22 | - AD FS 2019 installed and configured 23 | - Synchronize AD (on-prem) users with Azure AD using synchronization tools such as [Azure AD Connect](https://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect) 24 | - Azure AD Premium P2 license to be able to call [riskyUser API](https://docs.microsoft.com/en-us/graph/api/resources/riskyuser?view=graph-rest-beta) (https://graph.microsoft.com/beta/riskyUsers) 25 | >[!NOTE] 26 | >This sample plug-in gets the complete list of risky users for each authentication which can cause delay in authentication process. Therefore, the plug-in should be tested against an Azure AD tenant with a few number of users to avoid delays or should be optimized to use [Get riskyUser method](https://docs.microsoft.com/en-us/graph/api/riskyusers-get?view=graph-rest-beta&tabs=http) that gets the details of a specific user 27 | - Configure additional authentication method for AD FS such as [Azure MFA](https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-ad-fs-and-azure-mfa) 28 | - .NET Framework 4.7 and above 29 | - Visual Studio 30 | 31 | 32 | ## Setting up the sample 33 | 34 | ### Build plug-in dll 35 | 36 | The following procedure will walk you through building a sample plug-in dll. 37 | 38 | 1. Download the [sample](https://github.com/Microsoft/adfs-sample-RiskAssessmentModel-RiskyIPBlock) 39 | 40 | 2. Open the project `ThreatDetectionModule.sln` using Visual Studio 41 | 42 | 3. Remove the `Microsoft.IdentityServer.dll` from the Solutions Explorer as shown below:

43 | ![model](media/risk2.png) 44 | 45 | 4. Add reference to the `Microsoft.IdentityServer.dll` of your AD FS as shown below 46 | 47 | a. Right click on **References** in **Solutions Explorer** and select **Add Reference…**

48 | ![model](media/risk3.png) 49 | 50 | b. On the **Reference Manager** window select **Browse**. In the **Select the files to reference…** dialogue, select `Microsoft.IdentityServer.dll` from your AD FS installation folder (in my case **C:\Windows\ADFS**) and click **Add**. 51 | 52 | >[!NOTE] 53 | >In my case I am building the plug-in on the AD FS server itself. If your development environment is on a different server, copy the `Microsoft.IdentityServer.dll` from your AD FS installation folder on AD FS server on to your development box.
54 | 55 | ![model](media/risk4.png) 56 | 57 | c. Click **OK** on the **Reference Manager** window after making sure `Microsoft.IdentityServer.dll` checkbox is selected

58 | ![model](media/risk5.png) 59 | 60 | 5. Open **RiskyUserHelper.cs** from the **Solutions Explorer** to update the Azure AD tenant name, Client ID and Client Secret

61 | ![model](media/risk15.png) 62 | 63 |
To get these perform the following steps as Administrator in **[Azure Portal](https://portal.azure.com/)** 64 | 65 | a. To get **Azure AD tenant name**, go to **[Azure Active Directory](https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/Overview)** blade and select **Properties** from the **Manage** section on the left navigation pane. Tenant name is the value in **Name** field under **Directory properties**)

66 | ![model](media/risk16.PNG) 67 | 68 | b. To get the **Client ID** we first need to register the plug-in in Azure Active Directory. To do so, go to **[App Registration](https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade)**, click **New Registration**

69 | ![model](media/risk17.png) 70 | 71 | On **New Registration**, enter a name for the plug-in and click **Register** (Note - For other fields, I am keeping the default values)

72 | ![model](media/risk18.PNG) 73 | 74 | Once registered, get the **Client ID** for the registered plug-in as shown below

75 | ![model](media/risk19.png) 76 | 77 | c. To get the **Client Secret** click **Certificates & secrets** from the **Manage** section on the left navigation pane as shown below

78 | ![model](media/risk20.png) 79 | 80 | On **Certificates & secrets** blade, click **New client secret** and follow the process to generate the secret

81 | ![model](media/risk21.png) 82 | 83 | Once generated, get the secret to update in the **RiskyUserHelper.cs** file. 84 | 85 | d. Though we have registered the plug-in in Azure Active Directory, we also need to provide it permission to call the Microsoft Graph API i.e. the riskyUser API 86 | 87 | To provide permission, click on **API permissions** from the **Manage** section on the left navigation pane. Then click **Add a permission**

88 | ![model](media/risk22.png) 89 | 90 | On **Request API permissions** blade, select **Microsoft Graph**

91 | ![model](media/risk23.png) 92 | 93 | Next, select **Application permissions** and search **identityriskyuser** under **Select permissions**. Select checkbox for **IdentityRiskyUser.Read.All** permission and click **Add permissions**

94 | ![model](media/risk24.png) 95 | 96 | Lastly, click on **API permissions** from the **Manage** section on the left navigation pane. Select the **IdentityRiskyUser.Read.All** permission row and click on **Grant admin consent for [tenant name]**. Click **Yes**

97 | ![model](media/risk25.png) 98 | 99 | 100 | 6. All the classes and references are now in place to do a build. However, since the output of this project is a dll, it will have to be installed into the **Global Assembly Cache**, or GAC, of the AD FS server and the dll needs to be signed first. This can be done as follows: 101 | 102 | a. **Right-click** on the name of the project, ThreatDetectionModule. From the menu, click **Properties**.

103 | ![model](media/risk6.png) 104 | 105 | b. From the **Properties** page, click **Signing**, on the left, and then check the checkbox marked **Sign the assembly**. From the **Choose a strong name key file**: pull down menu, select ****

106 | ![model](media/risk7.png) 107 | 108 | c. In the **Create Strong Name Key dialogue**, type a name (you can choose any name) for the key, uncheck the checkbox **Protect my key file with password**. Then, click **OK**

109 | ![model](media/risk8.png) 110 | 111 | d. Save the project as shown below

112 | ![model](media/risk9.png) 113 | 114 | 7. Build the project by clicking **Build** and then **Rebuild Solution** as shown below

115 | ![model](media/risk10.png) 116 | 117 | Check the **Output window**, at the bottom of the screen, to see if any errors occurred

118 | ![model](media/risk11.png) 119 | 120 | 121 | The plug-in (dll) is now ready for use and is in the **\bin\Debug** folder of the project folder (In my case, that's **C:\extensions\ThreatDetectionModule\bin\Debug\ThreatDetectionModule.dll**). 122 | 123 | The next step is to register this dll with AD FS, so it runs in line with AD FS authentication process. 124 | 125 | ### Register the plug-in dll with AD FS 126 | 127 | We need to register the dll in AD FS by using the `Register-AdfsThreatDetectionModule` PowerShell command on the AD FS server, however, before we register, we need to get the Public Key Token. This public key token was created when we created the key and signed the dll using that key. To learn what the Public Key Token for the dll is, you can use the **SN.exe** as follows 128 | 129 | 1. Copy the dll file from the **\bin\Debug** folder to another location (In my case copying it to **C:\extensions**) 130 | 131 | 2. Start the **Developer Command Prompt** for Visual Studio and go to the directory containing the **sn.exe** (In my case the directory is **C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools**)

132 | ![model](media/risk12.png) 133 | 134 | 3. Run the **SN** command with the **-T** parameter and the location of the file (In my case `SN -T "C:\extensions\ThreatDetectionModule.dll"`)

135 | ![model](media/risk13.png)

136 | The command will provide you the public key token (For me, the **Public Key Token is 714697626ef96b35**) 137 | 138 | 4. Add the dll to the **Global Assembly Cache** of the AD FS server 139 | Our best practice would be that you create a proper installer for your project and use the installer to add the file to the GAC. Another solution is to use **Gacutil.exe** (more information on **Gacutil.exe** available [here](https://docs.microsoft.com/dotnet/framework/tools/gacutil-exe-gac-tool)) on your development machine. Since I have my visual studio on the same server as AD FS, I will be using **Gacutil.exe** as follows 140 | 141 | a. On Developer Command Prompt for Visual Studio and go to the directory containing the **Gacutil.exe** (In my case the directory is **C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7.2 Tools**) 142 | 143 | b. Run the **Gacutil** command (In my case `Gacutil /IF C:\extensions\ThreatDetectionModule.dll`)

144 | ![model](media/risk14.png) 145 | 146 | >[!NOTE] 147 | >If you have an AD FS farm, the above needs to be executed on each AD FS server in the farm. 148 | 149 | 5. Open **Windows PowerShell** and run the following command to register the dll 150 | ``` 151 | Register-AdfsThreatDetectionModule -Name "" -TypeName ", , Version=10.0.0.0, Culture=neutral, PublicKeyToken=< Add the Public Key Token from Step 2. above>" 152 | ``` 153 | In my case, the command is: 154 | ``` 155 | Register-AdfsThreatDetectionModule -Name "RiskyUserPlugin" -TypeName "ThreatDetectionModule.UserRiskAnalyzer, ThreatDetectionModule, Version=10.0.0.0, Culture=neutral, PublicKeyToken=714697626ef96b35" 156 | ``` 157 | 158 | >[!NOTE] 159 | >You need to register the dll only once, even if you have an AD FS farm. 160 | 161 | 6. Restart the AD FS service after registering the dll 162 | 163 | That's it, the dll is now registered with AD FS and ready for use! 164 | 165 | >[!NOTE] 166 | > If any changes are made to the plugin and the project is rebuilt, then the updated dll needs to be registered again. Before registering, you will need to unregister the current dll using the following command:

167 | >` 168 | UnRegister-AdfsThreatDetectionModule -Name "" 169 | >`

170 | >In my case, the command is: 171 | >``` 172 | >UnRegister-AdfsThreatDetectionModule -Name "RiskyUserPlugin" 173 | >``` 174 | 175 | 176 | ### Configure MFA policies in AD FS 177 | 178 | The last step in setting up the sample is to configure the policies in AD FS to trigger additional authentication (MFA) when the user risk level is either "low" or "medium". To do so, open **Windows PowerShell** on AD FS server and run the following command 179 | ``` 180 | Set-AdfsRelyingPartyTrust -TargetName -AdditionalAuthenticationRules 'exists([Type == "http://schemas.microsoft.com/ws/2017/04/identity/claims/riskscore", Value == "low"])=>issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn"); exists([Type == "http://schemas.microsoft.com/ws/2017/04/identity/claims/riskscore", Value == "medium"])=>issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn"); exists([Type == "http://schemas.microsoft.com/ws/2017/04/identity/claims/riskscore", Value == "high"])=>issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn");' 181 | ``` 182 | In my case, the command is: 183 | ``` 184 | Set-AdfsRelyingPartyTrust -TargetName Claimsxray -AdditionalAuthenticationRules 'exists([Type == "http://schemas.microsoft.com/ws/2017/04/identity/claims/riskscore", Value == "low"])=>issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn"); exists([Type == "http://schemas.microsoft.com/ws/2017/04/identity/claims/riskscore", Value == "medium"])=>issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn"); exists([Type == "http://schemas.microsoft.com/ws/2017/04/identity/claims/riskscore", Value == "high"])=>issue(Type = "http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationmethod", Value = "http://schemas.microsoft.com/claims/multipleauthn");' 185 | ``` 186 | 187 | 188 | ## Running the sample 189 | 190 | For this demonstration, I will be using [AD FS Help Claims X-Ray tool](https://adfshelp.microsoft.com/ClaimsXray) to initiate authentication request. If you would like to use the X-Ray tool, please follow the instructions in step 1 **Federation Services Configuration** to create a relying party trust for the service in your federation deployment. 191 | 192 | 1. Enter federation server instance and hit **Test Authentication** in step 2 of Claims X-Ray tool

193 | ![model](media/risk26.PNG) 194 | 195 | 2. On the login page, enter the user id and password of a non risky user (risk level = none)

196 | ![model](media/risk27.png) 197 | 198 | The user should be able to log in. 199 | 200 | 3. Repeat step 1 above and on the login page enter a user id and password of a low risk user (risk level = Low) 201 | 202 | >[!NOTE] 203 | >To check the risk level of a user, go to **[Risky users report](https://portal.azure.com/#blade/Microsoft_AAD_IAM/SecurityMenuBlade/RiskyUsers)** in Azure Portal.
204 | >For testing purpose, to make a user risky (with risk level = Low) login with user credentials to Azure Portal from a [TOR browser](https://www.torproject.org/projects/torbrowser.html.en) 205 | 206 | The plug-in will trigger additional authentication as per the configuration (In my case I have configured Azure MFA)

207 | ![model](media/risk28.PNG) 208 | 209 | Once authenticated, the user should be able to log in. 210 | 211 | 4. Repeat step 1 above and on the login page enter a user id and password of a high risk user (risk level = High) 212 | 213 | >[!NOTE] 214 | >For testing purpose, to make a user risky (with risk level = High) login to **[Risky users report](https://portal.azure.com/#blade/Microsoft_AAD_IAM/SecurityMenuBlade/RiskyUsers)** in Azure Portal as an Administrator. Select the user you want to change the risk level to High and click **Confirm user compromised**

215 | >![model](media/risk29.png) 216 | 217 | The plug-in will block the user from authenticating

218 | ![model](media/risk30.png) 219 | 220 | 221 | 222 | ## Contributing 223 | 224 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 225 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 226 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 227 | 228 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 229 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 230 | provided by the bot. You will only need to do this once across all repos using our CLA. 231 | 232 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 233 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 234 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 235 | --------------------------------------------------------------------------------