diff --git a/Extensibility/Security/AuthorizationPolicy/Client/Client.csproj b/Extensibility/Security/AuthorizationPolicy/Client/Client.csproj
new file mode 100644
index 0000000..001b3a1
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Client/Client.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Extensibility/Security/AuthorizationPolicy/Client/Connected Services/CoreWcf.Samples.AuthorizationPolicy/ConnectedService.json b/Extensibility/Security/AuthorizationPolicy/Client/Connected Services/CoreWcf.Samples.AuthorizationPolicy/ConnectedService.json
new file mode 100644
index 0000000..81ff117
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Client/Connected Services/CoreWcf.Samples.AuthorizationPolicy/ConnectedService.json
@@ -0,0 +1,17 @@
+{
+ "ExtendedData": {
+ "inputs": [
+ "https://localhost:5001/CalculatorService?wsdl"
+ ],
+ "collectionTypes": [
+ "System.Array",
+ "System.Collections.Generic.Dictionary`2"
+ ],
+ "namespaceMappings": [
+ "*, CoreWcf.Samples.AuthorizationPolicy"
+ ],
+ "sync": true,
+ "targetFramework": "net6.0",
+ "typeReuseMode": "All"
+ }
+}
\ No newline at end of file
diff --git a/Extensibility/Security/AuthorizationPolicy/Client/Connected Services/CoreWcf.Samples.AuthorizationPolicy/Reference.cs b/Extensibility/Security/AuthorizationPolicy/Client/Connected Services/CoreWcf.Samples.AuthorizationPolicy/Reference.cs
new file mode 100644
index 0000000..40a2627
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Client/Connected Services/CoreWcf.Samples.AuthorizationPolicy/Reference.cs
@@ -0,0 +1,180 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace CoreWcf.Samples.AuthorizationPolicy
+{
+
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
+ [System.ServiceModel.ServiceContractAttribute(Namespace="http://CoreWcf.Samples.AuthorizationPolicy", ConfigurationName="CoreWcf.Samples.AuthorizationPolicy.ICalculatorService")]
+ public interface ICalculatorService
+ {
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Add", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/AddResponse")]
+ double Add(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Add", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/AddResponse")]
+ System.Threading.Tasks.Task AddAsync(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Subtract", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/SubtractResponse")]
+ double Subtract(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Subtract", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/SubtractResponse")]
+ System.Threading.Tasks.Task SubtractAsync(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Multiply", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/MultiplyResponse")]
+ double Multiply(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Multiply", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/MultiplyResponse")]
+ System.Threading.Tasks.Task MultiplyAsync(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Divide", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/DivideResponse")]
+ double Divide(double n1, double n2);
+
+ [System.ServiceModel.OperationContractAttribute(Action="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Divide", ReplyAction="http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/DivideResponse")]
+ System.Threading.Tasks.Task DivideAsync(double n1, double n2);
+ }
+
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
+ public interface ICalculatorServiceChannel : CoreWcf.Samples.AuthorizationPolicy.ICalculatorService, System.ServiceModel.IClientChannel
+ {
+ }
+
+ [System.Diagnostics.DebuggerStepThroughAttribute()]
+ [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Tools.ServiceModel.Svcutil", "2.1.0")]
+ public partial class CalculatorServiceClient : System.ServiceModel.ClientBase, CoreWcf.Samples.AuthorizationPolicy.ICalculatorService
+ {
+
+ ///
+ /// Implement this partial method to configure the service endpoint.
+ ///
+ /// The endpoint to configure
+ /// The client credentials
+ static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);
+
+ public CalculatorServiceClient(EndpointConfiguration endpointConfiguration) :
+ base(CalculatorServiceClient.GetBindingForEndpoint(endpointConfiguration), CalculatorServiceClient.GetEndpointAddress(endpointConfiguration))
+ {
+ this.Endpoint.Name = endpointConfiguration.ToString();
+ ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
+ }
+
+ public CalculatorServiceClient(EndpointConfiguration endpointConfiguration, string remoteAddress) :
+ base(CalculatorServiceClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
+ {
+ this.Endpoint.Name = endpointConfiguration.ToString();
+ ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
+ }
+
+ public CalculatorServiceClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) :
+ base(CalculatorServiceClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
+ {
+ this.Endpoint.Name = endpointConfiguration.ToString();
+ ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
+ }
+
+ public CalculatorServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
+ base(binding, remoteAddress)
+ {
+ }
+
+ public double Add(double n1, double n2)
+ {
+ return base.Channel.Add(n1, n2);
+ }
+
+ public System.Threading.Tasks.Task AddAsync(double n1, double n2)
+ {
+ return base.Channel.AddAsync(n1, n2);
+ }
+
+ public double Subtract(double n1, double n2)
+ {
+ return base.Channel.Subtract(n1, n2);
+ }
+
+ public System.Threading.Tasks.Task SubtractAsync(double n1, double n2)
+ {
+ return base.Channel.SubtractAsync(n1, n2);
+ }
+
+ public double Multiply(double n1, double n2)
+ {
+ return base.Channel.Multiply(n1, n2);
+ }
+
+ public System.Threading.Tasks.Task MultiplyAsync(double n1, double n2)
+ {
+ return base.Channel.MultiplyAsync(n1, n2);
+ }
+
+ public double Divide(double n1, double n2)
+ {
+ return base.Channel.Divide(n1, n2);
+ }
+
+ public System.Threading.Tasks.Task DivideAsync(double n1, double n2)
+ {
+ return base.Channel.DivideAsync(n1, n2);
+ }
+
+ public virtual System.Threading.Tasks.Task OpenAsync()
+ {
+ return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action(((System.ServiceModel.ICommunicationObject)(this)).EndOpen));
+ }
+
+ private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
+ {
+ if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_ICalculatorService))
+ {
+ System.ServiceModel.WSHttpBinding result = new System.ServiceModel.WSHttpBinding();
+ result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
+ result.MaxReceivedMessageSize = int.MaxValue;
+ result.AllowCookies = true;
+ result.Security.Mode = System.ServiceModel.SecurityMode.TransportWithMessageCredential;
+ result.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.None;
+ result.Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.UserName;
+ return result;
+ }
+ if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_ICalculatorService1))
+ {
+ System.ServiceModel.WSHttpBinding result = new System.ServiceModel.WSHttpBinding();
+ result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
+ result.MaxReceivedMessageSize = int.MaxValue;
+ result.AllowCookies = true;
+ result.Security.Mode = System.ServiceModel.SecurityMode.TransportWithMessageCredential;
+ result.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.None;
+ result.Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.Certificate;
+ return result;
+ }
+ throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
+ }
+
+ private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration)
+ {
+ if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_ICalculatorService))
+ {
+ return new System.ServiceModel.EndpointAddress("https://localhost:5001/CalculatorService/Username");
+ }
+ if ((endpointConfiguration == EndpointConfiguration.WSHttpBinding_ICalculatorService1))
+ {
+ return new System.ServiceModel.EndpointAddress("https://localhost:5001/CalculatorService/Certificate");
+ }
+ throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
+ }
+
+ public enum EndpointConfiguration
+ {
+
+ WSHttpBinding_ICalculatorService,
+
+ WSHttpBinding_ICalculatorService1,
+ }
+ }
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Client/Program.cs b/Extensibility/Security/AuthorizationPolicy/Client/Program.cs
new file mode 100644
index 0000000..1ed26ab
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Client/Program.cs
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+using System.Security.Cryptography.X509Certificates;
+using System.ServiceModel;
+using System.ServiceModel.Security;
+
+//The service contract is defined using Connected Service "WCF Web Service", generated from the service by the dotnet svcutil tool.
+
+// Create a client with Username endpoint configuration
+WSHttpBinding binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
+binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
+var endpointAddress = new EndpointAddress("https://localhost:5001/CalculatorService/Username");
+
+CalculatorServiceClient client = new CalculatorServiceClient(binding, endpointAddress);
+client.ClientCredentials.UserName.UserName = "test1";
+client.ClientCredentials.UserName.Password = "1test";
+
+CallServiceOperations(client);
+
+// Create a client with Certificate endpoint configuration
+binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
+binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
+endpointAddress = new EndpointAddress("https://localhost:5001/CalculatorService/Certificate");
+
+client = new CalculatorServiceClient(binding, endpointAddress);
+client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "test1");
+client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerTrust;
+
+CallServiceOperations(client);
+
+Console.WriteLine();
+Console.WriteLine("Press to terminate client.");
+Console.ReadLine();
+
+
+void CallServiceOperations(CalculatorServiceClient client)
+{
+ try
+ {
+ // Call the Add service operation.
+ double value1 = 100.00D;
+ double value2 = 15.99D;
+ double result = client.Add(value1, value2);
+ Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);
+
+ // Call the Subtract service operation.
+ value1 = 145.00D;
+ value2 = 76.54D;
+ result = client.Subtract(value1, value2);
+ Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);
+
+ // Call the Multiply service operation.
+ value1 = 9.00D;
+ value2 = 81.25D;
+ result = client.Multiply(value1, value2);
+ Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);
+
+ // Call the Divide service operation.
+ value1 = 22.00D;
+ value2 = 7.00D;
+ result = client.Divide(value1, value2);
+ Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine("Call failed : {0}", e.Message);
+ }
+ //Closing the client gracefully closes the connection and cleans up resources
+ client.CloseAsync();
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Extensibility.Security.AuthorizationPolicy.sln b/Extensibility/Security/AuthorizationPolicy/Extensibility.Security.AuthorizationPolicy.sln
new file mode 100644
index 0000000..721f7bd
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Extensibility.Security.AuthorizationPolicy.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.2.32422.2
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Service", "Service\Service.csproj", "{BF126326-3393-407C-B24A-8FCCC388BE27}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "Client\Client.csproj", "{B533CADA-93BB-40E1-8FBA-FE37100062C3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolicyLibrary", "PolicyLibrary\PolicyLibrary.csproj", "{7D922471-13A2-4C41-9113-914B475B903D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {BF126326-3393-407C-B24A-8FCCC388BE27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BF126326-3393-407C-B24A-8FCCC388BE27}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BF126326-3393-407C-B24A-8FCCC388BE27}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BF126326-3393-407C-B24A-8FCCC388BE27}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B533CADA-93BB-40E1-8FBA-FE37100062C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B533CADA-93BB-40E1-8FBA-FE37100062C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B533CADA-93BB-40E1-8FBA-FE37100062C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B533CADA-93BB-40E1-8FBA-FE37100062C3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7D922471-13A2-4C41-9113-914B475B903D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7D922471-13A2-4C41-9113-914B475B903D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7D922471-13A2-4C41-9113-914B475B903D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7D922471-13A2-4C41-9113-914B475B903D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {AD996EFD-70DC-4431-B411-5A2771DD02D3}
+ EndGlobalSection
+EndGlobal
diff --git a/Extensibility/Security/AuthorizationPolicy/GetComputerName.vbs b/Extensibility/Security/AuthorizationPolicy/GetComputerName.vbs
new file mode 100644
index 0000000..9bdad3e
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/GetComputerName.vbs
@@ -0,0 +1,17 @@
+'
+' This script uses WMI to get the name of the machine be used as the CN ' for the certificates for WCF security samples.
+'
+set wmi = Getobject("winmgmts:")
+wql = "select * from win32_computersystem"
+set results = wmi.execquery(wql)
+for each compsys in results
+ 'check if the machine is in the workgroup or domain
+ if compsys.PartOfDomain = 0 or compsys.Domain = compsys.Workgroup then
+ ' only get the name of the machine
+ WScript.echo compsys.name
+ else
+ ' get the fully qualified name of the machine
+ n = compsys.name & "." & compsys.domain
+ WScript.echo n
+ end if
+next
\ No newline at end of file
diff --git a/Extensibility/Security/AuthorizationPolicy/PolicyLibrary/CustomAuthorizationPolicy.cs b/Extensibility/Security/AuthorizationPolicy/PolicyLibrary/CustomAuthorizationPolicy.cs
new file mode 100644
index 0000000..5b7e53a
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/PolicyLibrary/CustomAuthorizationPolicy.cs
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using CoreWCF.IdentityModel.Claims;
+using CoreWCF.IdentityModel.Policy;
+
+namespace CoreWcf.Samples.AuthorizationPolicy
+{
+ public class CustomAuthorizationPolicy : IAuthorizationPolicy
+ {
+ string id;
+
+ public CustomAuthorizationPolicy()
+ {
+ id = Guid.NewGuid().ToString();
+ }
+
+ public bool Evaluate(EvaluationContext evaluationContext, ref object state)
+ {
+ bool bRet = false;
+ CustomAuthState customstate = null;
+
+ // If state is null, then we've not been called before so we need
+ // to set up our custom state
+ if (state == null)
+ {
+ customstate = new CustomAuthState();
+ state = customstate;
+ }
+ else
+ customstate = (CustomAuthState)state;
+
+ Console.WriteLine("Inside MyAuthorizationPolicy::Evaluate");
+
+ // If we've not added claims yet...
+ if (!customstate.ClaimsAdded)
+ {
+ // Create an empty list of Claims
+ IList claims = new List();
+
+ // Iterate through each of the claimsets in the evaluation context
+ foreach (ClaimSet cs in evaluationContext.ClaimSets)
+ // Look for Name claims in the current claimset...
+ foreach (Claim c in cs.FindClaims(ClaimTypes.Name, Rights.PossessProperty))
+ // Get the list of operations the given username is allowed to call...
+ foreach (string s in GetAllowedOpList(c.Resource.ToString()))
+ {
+ // Check numbers aren't too large
+
+
+ // Add claims to the list
+ claims.Add(new Claim("http://example.org/claims/allowedoperation", s, Rights.PossessProperty));
+ Console.WriteLine("Claim added {0}", s);
+ }
+
+ // Add claims to the evaluation context
+ evaluationContext.AddClaimSet(this, new DefaultClaimSet(this.Issuer, claims));
+
+ // record that we've added claims
+ customstate.ClaimsAdded = true;
+
+ // return true, indicating we do not need to be called again.
+ bRet = true;
+ }
+ else
+ {
+ // Should never get here, but just in case...
+ bRet = true;
+ }
+
+
+ return bRet;
+ }
+
+ public ClaimSet Issuer
+ {
+ get { return ClaimSet.System; }
+ }
+
+ public string Id
+ {
+ get { return id; }
+ }
+
+ // This method returns a collection of action strings that indicate the
+ // operations the specified username is allowed to call.
+ private static IEnumerable GetAllowedOpList(string username)
+ {
+ IList ret = new List();
+
+ if (username == "test1")
+ {
+ ret.Add("http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Add");
+ ret.Add("http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Multiply");
+ ret.Add("http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Subtract");
+ }
+ else if (username == "test2")
+ {
+ ret.Add("http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Add");
+ ret.Add("http://CoreWcf.Samples.AuthorizationPolicy/ICalculatorService/Subtract");
+ }
+ return ret;
+ }
+
+ // internal class for state
+ class CustomAuthState
+ {
+ bool bClaimsAdded;
+
+ public CustomAuthState()
+ {
+ }
+
+ public bool ClaimsAdded
+ {
+ get { return bClaimsAdded; }
+ set { bClaimsAdded = value; }
+ }
+ }
+ }
+
+}
+
diff --git a/Extensibility/Security/AuthorizationPolicy/PolicyLibrary/PolicyLibrary.csproj b/Extensibility/Security/AuthorizationPolicy/PolicyLibrary/PolicyLibrary.csproj
new file mode 100644
index 0000000..e9cbfd4
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/PolicyLibrary/PolicyLibrary.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Library
+ net6.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/CalculatorService.cs b/Extensibility/Security/AuthorizationPolicy/Service/CalculatorService.cs
new file mode 100644
index 0000000..34ae206
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/CalculatorService.cs
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace CoreWcf.Samples.AuthorizationPolicy
+{
+ // Service class which implements the service contract interface.
+ public class CalculatorService : ICalculatorService
+ {
+ public double Add(double n1, double n2)
+ {
+ return n1 + n2;
+ }
+
+ public double Subtract(double n1, double n2)
+ {
+ return n1 - n2;
+ }
+
+ public double Multiply(double n1, double n2)
+ {
+ return n1 * n2;
+ }
+
+ public double Divide(double n1, double n2)
+ {
+ return n1 / n2;
+ }
+ }
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/CustomPolicyManager.cs b/Extensibility/Security/AuthorizationPolicy/Service/CustomPolicyManager.cs
new file mode 100644
index 0000000..31d8a24
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/CustomPolicyManager.cs
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using CoreWCF.IdentityModel.Claims;
+using CoreWCF.IdentityModel.Selectors;
+using CoreWCF.IdentityModel.Tokens;
+
+namespace CoreWcf.Samples.AuthorizationPolicy
+{
+ public class CustomServiceAuthorizationManager : ServiceAuthorizationManager
+ {
+ protected override ValueTask CheckAccessCoreAsync(OperationContext operationContext)
+ {
+ // Extract the action URI from the OperationContext. We will use this to match against the claims
+ // in the AuthorizationContext
+ string action = operationContext.RequestContext.RequestMessage.Headers.Action;
+ Console.WriteLine("action: {0}", action);
+
+ // Iterate through the various claimsets in the authorizationcontext
+ foreach (ClaimSet cs in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
+ {
+ // Only look at claimsets issued by System.
+ if (cs.Issuer == ClaimSet.System)
+ {
+ // Iterate through claims of type "http://example.org/claims/allowedoperation"
+ foreach (Claim c in cs.FindClaims("http://example.org/claims/allowedoperation", Rights.PossessProperty))
+ {
+ // Dump the Claim resource to the console.
+ Console.WriteLine("resource: {0}", c.Resource.ToString());
+
+ // If the Claim resource matches the action URI then return true to allow access
+ if (action == c.Resource.ToString())
+ return ValueTask.FromResult(true);
+ }
+ }
+ }
+
+ // If we get here, return false, denying access.
+ return ValueTask.FromResult(false);
+ }
+ }
+
+ public class CustomUserNameValidator : UserNamePasswordValidator
+ {
+ // This method validates users. It allows in two users, test1 and test2
+ // with passwords 1test and 2test respectively.
+ // This code is for illustration purposes only and
+ // MUST NOT be used in a production environment because it is NOT secure.
+ public override ValueTask ValidateAsync(string userName, string password)
+ {
+ if (null == userName || null == password)
+ {
+ throw new ArgumentNullException();
+ }
+
+ if (!(userName == "test1" && password == "1test") && !(userName == "test2" && password == "2test"))
+ {
+ throw new SecurityTokenException("Unknown Username or Password");
+ }
+
+ return default;
+ }
+ }
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/ICalculatorService.cs b/Extensibility/Security/AuthorizationPolicy/Service/ICalculatorService.cs
new file mode 100644
index 0000000..b05a1c5
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/ICalculatorService.cs
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace CoreWcf.Samples.AuthorizationPolicy
+{
+ // Define a service contract.
+ [ServiceContract(Namespace = "http://CoreWcf.Samples.AuthorizationPolicy")]
+ public interface ICalculatorService
+ {
+ [OperationContract]
+ double Add(double n1, double n2);
+ [OperationContract]
+ double Subtract(double n1, double n2);
+ [OperationContract]
+ double Multiply(double n1, double n2);
+ [OperationContract]
+ double Divide(double n1, double n2);
+ }
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/Program.cs b/Extensibility/Security/AuthorizationPolicy/Service/Program.cs
new file mode 100644
index 0000000..964c5a7
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/Program.cs
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Security.Cryptography.X509Certificates;
+using CoreWCF.IdentityModel.Policy;
+
+var builder = WebApplication.CreateBuilder();
+
+//Enable CoreWCF Services, with metadata (WSDL) support
+builder.Services.AddServiceModelServices()
+ .AddServiceModelMetadata()
+ .AddSingleton()
+ .AddSingleton();
+
+var app = builder.Build();
+
+app.UseServiceModel(builder =>
+{
+ // Add the Calculator Service
+ builder.AddService(serviceOptions =>
+ {
+ serviceOptions.BaseAddresses.Clear();
+ // Set the default host name:port in generated WSDL and the base path for the address
+ serviceOptions.BaseAddresses.Add(new Uri("https://localhost/CalculatorService"));
+ })
+ // Add WSHttpBinding endpoint
+ .AddServiceEndpoint(ServiceWSHttpBinding(MessageCredentialType.UserName), "Username")
+ .AddServiceEndpoint(ServiceWSHttpBinding(MessageCredentialType.Certificate), "Certificate");
+
+ Action serviceHost = host => ChangeHostBehavior(host);
+ builder.ConfigureServiceHostBase(serviceHost);
+
+ ServiceAuthorizationBehavior authBehavior = app.Services.GetRequiredService();
+ var authPolicies = new List { new CustomAuthorizationPolicy() };
+ var externalAuthPolicies = new System.Collections.ObjectModel.ReadOnlyCollection(authPolicies);
+ authBehavior.ExternalAuthorizationPolicies = externalAuthPolicies;
+
+ // Configure WSDL to be available
+ var serviceMetadataBehavior = app.Services.GetRequiredService();
+ serviceMetadataBehavior.HttpsGetEnabled = true;
+});
+
+app.Run();
+
+static Binding ServiceWSHttpBinding(MessageCredentialType clientCredentialType)
+{
+ WSHttpBinding binding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);
+ binding.Security.Message.ClientCredentialType = clientCredentialType;
+ return binding;
+}
+
+void ChangeHostBehavior(ServiceHostBase host)
+{
+ var srvCredentials = new ServiceCredentials();
+ srvCredentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "localhost");
+ srvCredentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerTrust;
+ srvCredentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
+ srvCredentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNameValidator();
+ host.Description.Behaviors.Add(srvCredentials);
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/Properties/launchSettings.json b/Extensibility/Security/AuthorizationPolicy/Service/Properties/launchSettings.json
new file mode 100644
index 0000000..941fac5
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/Properties/launchSettings.json
@@ -0,0 +1,13 @@
+{
+ "profiles": {
+ "Service": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "https://localhost:5001/CalculatorService",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/Service.csproj b/Extensibility/Security/AuthorizationPolicy/Service/Service.csproj
new file mode 100644
index 0000000..9f47aeb
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/Service.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net6.0
+ enable
+ true
+ InProcess
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/appsettings.Development.json b/Extensibility/Security/AuthorizationPolicy/Service/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/Service/appsettings.json b/Extensibility/Security/AuthorizationPolicy/Service/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/Service/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/Extensibility/Security/AuthorizationPolicy/cleanup.bat b/Extensibility/Security/AuthorizationPolicy/cleanup.bat
new file mode 100644
index 0000000..91e82a7
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/cleanup.bat
@@ -0,0 +1,67 @@
+echo off
+setlocal
+set CLIENT_NAME=test1
+call :setcomputername
+ECHO ****************************************************************
+ECHO WARNING: This script will not remove service certificates on a
+ECHO client machine from a cross machine run of this
+ECHO sample.
+
+ECHO If you have run WCF samples that use Certs across machines,
+ECHO be sure to clear the service certs that have been installed in
+ECHO the CurrentUser - TrustedPeople store.
+ECHO To do this, use the following command:
+
+ECHO "certmgr.exe -del -r CurrentUser -s TrustedPeople -c -n "
+
+ECHO For example:
+
+ECHO "certmgr.exe -del -r CurrentUser -s TrustedPeople -c -n server1.contoso.com"
+call :cleancerts
+DEL client.cer > NUL 2>&1
+DEL service.cer > NUL 2>&1
+GOTO end
+
+:cleancerts
+REM cleans up certs from previous runs.
+echo ****************
+echo Cleanup starting
+echo ****************
+
+echo -------------------------
+echo del client certs
+echo -------------------------
+certmgr.exe -del -r CurrentUser -s My -c -n %CLIENT_NAME%
+certmgr.exe -del -r CurrentUser -s TrustedPeople -c -n localhost
+
+echo -------------------------
+echo del service certs
+echo -------------------------
+certmgr.exe -del -r LocalMachine -s My -c -n localhost
+certmgr.exe -del -r LocalMachine -s TrustedPeople -c -n %CLIENT_NAME%
+certmgr.exe -put -r LocalMachine -s My -c -n %COMPUTER_NAME% computer.cer
+IF %ERRORLEVEL% EQU 0 (
+ DEL computer.cer
+ echo ****************
+ echo "You have a certificate with a Subject name matching your Machine name."
+ echo "If this certificate is from a cross machine run of WCF samples press any key to delete it."
+ echo "Otherwise press Ctrl + C to abort this script."
+ pause
+ certmgr.exe -del -r LocalMachine -s My -c -n %COMPUTER_NAME%
+)
+
+:cleanupcompleted
+echo *****************
+echo Cleanup completed
+echo *****************
+
+GOTO :EOF
+
+
+:setcomputername
+REM Puts the Fully Qualified Name of the Computer into a variable named COMPUTER_NAME
+for /F "delims=" %%i in ('cscript /nologo GetComputerName.vbs') do set COMPUTER_NAME=%%i
+GOTO :EOF
+
+:end
+
diff --git a/Extensibility/Security/AuthorizationPolicy/importclientcert.bat b/Extensibility/Security/AuthorizationPolicy/importclientcert.bat
new file mode 100644
index 0000000..6106ab6
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/importclientcert.bat
@@ -0,0 +1,7 @@
+echo off
+echo ************
+echo Client cert import starting
+echo ************
+echo copying client cert to server's CurrentUser store
+echo ************
+certmgr.exe -add client.cer -r CurrentUser -s TrustedPeople
diff --git a/Extensibility/Security/AuthorizationPolicy/importservicecert.bat b/Extensibility/Security/AuthorizationPolicy/importservicecert.bat
new file mode 100644
index 0000000..fd4bef4
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/importservicecert.bat
@@ -0,0 +1,7 @@
+echo off
+echo ************
+echo Server cert import starting
+echo ************
+echo copying server cert to client's CurrentUser store
+echo ************
+certmgr.exe -add service.cer -r CurrentUser -s TrustedPeople
diff --git a/Extensibility/Security/AuthorizationPolicy/setup.bat b/Extensibility/Security/AuthorizationPolicy/setup.bat
new file mode 100644
index 0000000..0459365
--- /dev/null
+++ b/Extensibility/Security/AuthorizationPolicy/setup.bat
@@ -0,0 +1,143 @@
+echo off
+setlocal
+echo ************
+echo cert setup starting
+echo ************
+
+call :setscriptvariables %1
+IF NOT DEFINED SUPPORTED_MODE call :displayusage
+IF DEFINED SUPPORTED_MODE call :cleancerts
+IF DEFINED SETUP_SERVICE call :setupservice
+IF DEFINED SETUP_CLIENT call :setupclient
+GOTO end
+
+:cleancerts
+REM cleans up certs from previous runs.
+echo ****************
+echo Cleanup starting
+echo ****************
+
+echo -------------------------
+echo del client certs
+echo -------------------------
+certmgr.exe -del -r CurrentUser -s My -c -n %CLIENT_NAME%
+certmgr.exe -del -r CurrentUser -s TrustedPeople -c -n localhost
+
+echo -------------------------
+echo del service certs
+echo -------------------------
+certmgr.exe -del -r LocalMachine -s My -c -n localhost
+certmgr.exe -del -r LocalMachine -s TrustedPeople -c -n %CLIENT_NAME%
+certmgr.exe -put -r LocalMachine -s My -c -n %COMPUTER_NAME% computer.cer
+IF %ERRORLEVEL% EQU 0 (
+ DEL computer.cer
+ echo ****************
+ echo "You have a certificate with a Subject name matching your Machine name: %COMPUTER_NAME%"
+ echo "If this certificate is from a cross machine run of WCF samples press any key to delete it."
+ echo "Otherwise press Ctrl + C to abort this script."
+ pause
+ certmgr.exe -del -r LocalMachine -s My -c -n %COMPUTER_NAME%
+)
+
+:cleanupcompleted
+echo *****************
+echo Cleanup completed
+echo *****************
+
+GOTO :EOF
+
+:setupclient
+
+echo ************
+echo making client cert
+echo ************
+makecert.exe -sr CurrentUser -ss MY -a sha1 -n CN=%CLIENT_NAME% -sky exchange -pe
+
+IF DEFINED EXPORT_CLIENT (
+ echo ************
+ echo exporting client cert to client.cer
+ echo ************
+ certmgr.exe -put -r CurrentUser -s My -c -n %CLIENT_NAME% client.cer
+) ELSE (
+ echo ************
+ echo copying client cert to server's LocalMachine store
+ echo ************
+ certmgr.exe -add -r CurrentUser -s My -c -n %CLIENT_NAME% -r LocalMachine -s TrustedPeople
+)
+GOTO :EOF
+
+:setupservice
+
+echo ************
+echo Server cert setup starting
+echo %SERVER_NAME%
+echo ************
+echo making server cert
+echo ************
+makecert.exe -sr LocalMachine -ss MY -a sha1 -n CN=%SERVER_NAME% -sky exchange -pe
+
+IF DEFINED EXPORT_SERVICE (
+ echo ************
+ echo exporting service cert to service.cer
+ echo ************
+ certmgr.exe -put -r LocalMachine -s My -c -n %SERVER_NAME% service.cer
+) ELSE (
+ echo ************
+ echo copying server cert to client's CurrentUser store
+ echo ************
+ certmgr.exe -add -r LocalMachine -s My -c -n %SERVER_NAME% -r CurrentUser -s TrustedPeople
+)
+GOTO :EOF
+
+:setscriptvariables
+REM Parses the input to determine if we are setting this up for a single machine, client, or server
+REM sets the appropriate name variables
+call :setcomputername
+IF [%1]==[] CALL :singlemachine
+IF [%1]==[service] CALL :service
+IF [%1]==[client] CALL :client
+
+set CLIENT_NAME=test1
+
+GOTO :EOF
+
+:singlemachine
+echo ************
+echo Running setup script for Single Machine
+echo ************
+SET SUPPORTED_MODE=1
+SET SETUP_CLIENT=1
+SET SETUP_SERVICE=1
+SET SERVER_NAME=localhost
+GOTO :EOF
+
+:service
+echo ************
+echo Running setup script for Service
+echo ************
+SET SUPPORTED_MODE=1
+SET SETUP_SERVICE=1
+SET EXPORT_SERVICE=1
+SET SERVER_NAME=%COMPUTER_NAME%
+GOTO :EOF
+
+:client
+echo ************
+echo Running setup script for Client
+echo ************
+SET SUPPORTED_MODE=1
+SET SETUP_CLIENT=1
+SET EXPORT_CLIENT=1
+GOTO :EOF
+
+:setcomputername
+REM Puts the Fully Qualified Name of the Computer into a variable named COMPUTER_NAME
+for /F "delims=" %%i in ('cscript /nologo GetComputerName.vbs') do set COMPUTER_NAME=%%i
+GOTO :EOF
+
+:displayusage
+ECHO Correct usage:
+ECHO Single Machine - Setup.bat
+ECHO Client Machine - Setup.bat client
+ECHO Service Machine - Setup.bat service
+:end