I have this WCF service and I'm trying to apply authentication and authorization mechanism in it.
It's my first time to do this, what I have is this web.config serviceModel tag for the service:
<system.serviceModel>
<services>
<service name="RoleBasedServices.SecureServiceExternal" behaviorConfiguration="externalServiceBehavior">
<endpoint contract="AuthService.IService1" binding="wsHttpBinding" bindingConfiguration="wsHttpUsername" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="wsHttpUsername">
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!--To avoid disclosing metadata information, set the values below to false before deployment-->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!--To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information-->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
<behavior name="externalServiceBehavior">
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" />
<serviceCertificate findValue="RPKey" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
What I want to do is very simple, I don't know if I need all this tags I'm just trying.
What I want to do is from the client side to add reference for the service and first call the MyLogin:
AuthService.Service1Client s = new AuthService.Service1Client();
s.Login();
Then call the other restricted method and let it be GetData:
s.GetData()
At service side in Login method, and only for test purposes, I'm doing this:
public void Login()
{
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob"), new[] { "Admin" });
FormsAuthentication.SetAuthCookie("BobUserName", false);
}
An the restricted method will be:
[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
public void GetData()
{
return "Hello";
}
That all I have in service and client, what I'm missing?
Every time ,in debug, I check Thread.CurrentPrincipal in Login method I found Thread.CurrentPrincipal.Identity.IsAuthenticated equals true but even though when the client calls the GetData() method it's Access Denied.
PS: I'm using console application to do my tests does it make any difference ?
Thanks
Here is a very nice article that could possibly lead to a solution.
The general idea is that you have 2 object for the Principal.
HttpContext.Current.User and Thread.CurrentPrincipal. You are setting the Thread.CurrentPrincipal at the time HttpContext.Current.User is already instantiated and the role of it is left to default. You may want to try something like:
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity("Bob"), new[] { "Admin" });
The reason calls to GetData() are denied is because WCF doesn't know anything about the Forms Authentication cookie that was set during Login().
It doesn't make a difference that you're a using console app. You could try the following approach.
Set the cookie in Login():
var cookie = FormsAuthentication.GetAuthCookie(username, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), null);
FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name, true);
Then in your console app:
public static void TestLoginAndGetData()
{
var sharedCookie = string.Empty;
using (var client = new YourClient())
using (new OperationContextScope(client.InnerChannel))
{
client.Login("username", "password");
// get the cookie from the response
HttpResponseMessageProperty response = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[
HttpResponseMessageProperty.Name];
sharedCookie = response.Headers["Set-Cookie"];
// add it to the request
HttpRequestMessageProperty request = new HttpRequestMessageProperty();
request.Headers["Cookie"] = sharedCookie;
OperationContext.Current.OutgoingMessageProperties[
HttpRequestMessageProperty.Name] = request;
var result = client.GetData();
Console.WriteLine(result);
}
}
You might also consider changing the return type of GetData() to string.
Related
I've added a custom authentification on a WCF service in order to validate all incoming requests using an override of the ServiceAuthenticationManager.
Everything works great on my own developer PC but when deployed to a Windows 2008 R2 webserver the ServiceAuthenticationManager override is never fired. Spend many hours searching for an answer but I'm stuck.
Here is my code:
namespace FDC.IHI.WebServices.VirtualInsuranceCard
{
public class ServiceAuthorization : ServiceAuthorizationManager
{
private bool VerifyAuthorizationHeader(string authorizationHeader, string userName, string password)
{
try
{
var convertedString = Convert.FromBase64String(authorizationHeader);
var svcCredentials = System.Text.Encoding.ASCII
.GetString(convertedString)
.Split(':');
var authorizationHeaderCredentials = new { Name = svcCredentials[0], Password = svcCredentials[1] };
if ((authorizationHeaderCredentials.Name == userName && authorizationHeaderCredentials.Password == password))
return true;
return false;
}
catch (Exception)
{
return false;
}
}
protected override bool CheckAccessCore(OperationContext operationContext)
{
Core.ErrorHandler.ErrorHandler.LogText("ServiceAuthorizationManager triggered", "VIC");
var authHeader = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];
if ((authHeader != null) && (authHeader != string.Empty))
{
var correctCredentials = ConfigurationManager.AppSettings["CredentialsVicService"].Split(';').Where(x => !string.IsNullOrEmpty(x)).ToList();
if (VerifyAuthorizationHeader(authHeader.Substring(6), correctCredentials[0], correctCredentials[1]))
return true;
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
return false;
}
else
{
//No authorization header was provided, so challenge the client to provide before proceeding:
WebOperationContext.Current.OutgoingResponse.Headers.Add("WWW-Authenticate: Basic realm=\"vicService\"");
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
return false;
}
}
}
}
Here is my configuration:
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="BindingServices">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="RestHttp">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="BehaviourServices">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpsGetEnabled="true" />
<serviceAuthorization serviceAuthorizationManagerType="FDC.IHI.WebServices.VirtualInsuranceCard.ServiceAuthorization, FDC.IHI.WebServices" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="VirtualInsuranceCard.VicService" behaviorConfiguration="BehaviourServices">
<endpoint behaviorConfiguration="RestHttp" binding="webHttpBinding" bindingConfiguration="BindingServices" contract="VirtualInsuranceCard.iVicService" />
</service>
</services>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
</system.serviceModel>
It really puzzles me that it works as expected when run through my developer platform but not when running on webserver. The webserver responds with an answer so the web service business code is triggered, but the authentification is ignored i.e. the ServiceAuthenticationManager is never fired.
This makes me think that it may have something to do with IIS settings on the webserver that I deployed the code to but I can't seem to find anything missing here though.
After painstakingly going through every corner of my source code and trying to figure out differences between my local IIS and IIS on the webserver I finally figured it out :)
On the remote webserver the hosts file pointed to a different webserver for the endpoint I was trying to reach thereby executing an older version of my webservice code.
Doh!! A lot of hours lost. Wonder if I learned anything here?
I had no idear the hosts file had been changed but learned that this was because someone else in the organization was testing a new webserver to replace the old 2008 R2 version.
Thanks for your effort jdweng :)
I have a WCF service running under .NET Framework 4.6.2. I have used the web.config before to configure the service with my custom IAuthorizationPolicy like this :
<services>
behaviorConfiguration="MyClientService.CustomValidator_Behavior" name="My.Service.Implementation.Services.MyClientService">
<endpoint binding="netHttpBinding" behaviorConfiguration="protoEndpointBehavior" address="BinaryHttpProto" bindingNamespace="http://My.ServiceContracts/2007/11" contract="My.ServiceContracts.IMyClientService" />
<endpoint binding="netHttpsBinding" behaviorConfiguration="protoEndpointBehavior" address="BinaryHttpsProto" bindingNamespace="http://My.ServiceContracts/2007/11" contract="My.ServiceContracts.IMyClientService" />
bindingConfiguration="netTcpCertificate" behaviorConfiguration="protoEndpointBehavior" bindingNamespace="http://My.ServiceContracts/2007/11" contract="My.ServiceContracts.IMyClientService" address="Sll"/>
<host>
</host>
</service>
</services>
<behavior name="MyClientService.CustomValidator_Behavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
<customBehaviorExtension_ClientService />
<serviceThrottling maxConcurrentCalls="2000" maxConcurrentSessions="2147483647" maxConcurrentInstances="2000" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" />
</clientCertificate>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="My.Service.Implementation.Security.CustomUsernamePasswordValidator, My.Service.Implementation" />
</serviceCredentials>
<serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="My.Service.Implementation.Security.CustomServiceAuthorizationManager, My.Service.Implementation">
<authorizationPolicies>
<add policyType="My.Service.Implementation.Security.CustomAuthorizationPolicy_ClientService, My.Service.Implementation" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
Now I need to swtich to do this in code and this is what that looks like :
var endpoint = new System.ServiceModel.Description.ServiceEndpoint(System.ServiceModel.Description.ContractDescription.GetContract(typeof(IMyClientService)),
binding,
new EndpointAddress(endPointAddress));
endpoint.EndpointBehaviors.Add(new ProtoBuf.ServiceModel.ProtoEndpointBehavior());
serviceHost.AddServiceEndpoint(endpoint);
ServiceAuthorizationBehavior serviceAuthorizationBehavior = serviceHost.Description.Behaviors.Find<ServiceAuthorizationBehavior>();
if (serviceAuthorizationBehavior == null)
{
serviceAuthorizationBehavior = new ServiceAuthorizationBehavior();
serviceHost.Description.Behaviors.Add(serviceAuthorizationBehavior);
}
serviceAuthorizationBehavior.ExternalAuthorizationPolicies = new ReadOnlyCollection<IAuthorizationPolicy>(new IAuthorizationPolicy[] { new CustomAuthorizationPolicy_ClientService() });
((ServiceBehaviorAttribute)serviceHost.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).MaxItemsInObjectGraph = 2147483647;
((ServiceBehaviorAttribute)serviceHost.Description.Behaviors[typeof(ServiceBehaviorAttribute)]).IncludeExceptionDetailInFaults = true;
ServiceThrottlingBehavior throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 200,
MaxConcurrentInstances = 2147483647,
MaxConcurrentSessions = 2000,
};
serviceHost.Description.Behaviors.Add(throttleBehavior);
Console.WriteLine("Starting service...");
serviceHost.Open();
Console.WriteLine("Service started successfully (" + uri + ")");
return serviceHost;
}
catch(Exception ex)
In the IAuthorizationPolicy i set the principla like this just as before and it does break here :
var userContext = new UserContextOnService(new ClientIdentity { AuthenticationType = "regular", IsAuthenticated = true, Name = "username" }, currentAnvandare, LoginType.UsernamePassword);
userContext.OrbitToken = orbitToken;
evaluationContext.Properties["Principal"] = userContext;
SharedContext.Instance.AddUserContext(person.PersonId.ToString(), userContext);
The problem is that when I try to run this :
(UserContextOnService)Thread.CurrentPrincipal;
In the service method I get exception, the CurrentPrincipal is a WindowPrincipal?
I can get the correct Principal by using this code :
OperationContext.Current.ServiceSecurityContext.AuthorizationContext.Properties["Principal"]
But that would mean to change in MANY places where the context is fetched with just Thread.CurrentPrincipal.
I suspect that I have lost something in the configuration?
Edit : Have tried to set the Thread.CurrentPrincipal = userContext; in the Evaluate method but this does not help, the Thread.CurrentPrincipal if still a WindowsPrinciple? I suspect that the servicemethod is ending up on another thread then the one that executes the Evaluate.
When starting the service this needed to be set as well :
serviceAuthorizationBehavior.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
serviceAuthorizationBehavior.ServiceAuthorizationManager = new CustomServiceAuthorizationManager();
This is done right above the following line :
serviceAuthorizationBehavior.ExternalAuthorizationPolicies = new ReadOnlyCollection<IAuthorizationPolicy>(new IAuthorizationPolicy[] { new CustomAuthorizationPolicy_ClientService() });
I have a WCF Service with a SOAP endpoint. I added a REST endpoint and the Get methods are working just fine. I am having trouble with a POST method which takes in an object and returns a different object. When I pass in my object, I get this error back:
"Message":"Object reference not set to an instance of an object."
Here's the code to call the service:
string URL = "http://qa.acct.webservice";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var request = new RequestGetInventory
{
BrandIDs = new string[] { "4", "42" },
AccountID = "9900003"
};
var resp = client.PostAsJsonAsync("/AxaptaService.svc/rest/GetInventory", request);
response = resp.Result;
if (response.IsSuccessStatusCode)
{
var temp = response.Content.ReadAsStringAsync().Result;
MessageBox.Show(temp); //error message received here.
}
The RequestGetInventory object is defined as follows:
[DataContract]
public class RequestGetInventory
{
[DataMember]
public string[] BrandIDs { get; set; }
[DataMember]
public string AccountID { get; set; }
}
The contract for the webservice is defined as follows:
[OperationContract]
[WebInvoke(Method = "POST",
RequestFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json)]
ResponseGetInventory GetInventory(RequestGetInventory Request);
I tried playing around with the WebInvoke parameters, but received the same error message for all viable attempts.
And this is how my web.config is set up:
<system.serviceModel>
<services>
<service behaviorConfiguration="" name="Proj.AxaptaUS.WebService.AxaptaService">
<endpoint address="rest" behaviorConfiguration="webBehavior" binding="webHttpBinding" contract="Proj.Interfaces.Axapta3.IAxaptaService"></endpoint>
<endpoint address="" binding="basicHttpBinding" contract="Proj.Interfaces.Axapta3.IAxaptaService"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp helpEnabled="true" />
<enableWebScript/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
I am not entirely sure what I'm doing wrong because I can access this using SOAP just fine. It seems like it is not getting any values for the object which I passed in, thus causing the object reference error.
Any help would be greatly appreciated! Thanks!
#jstreet posted a comment which ended up working.
I changed BodyStyle = WebMessageBodyStyle.WrappedRequest to BodyStyle = WebMessageBodyStyle.Bare and removed <enableWebScript/> from config file.
After doing those things, it started to work correctly! thanks #jstreet!
I have a problem connecting to my WCF service with clientCredentialType="UserName".
When I run the code below I get an error
FaultException: An error occurred when verifying security for the message.
When playing around with some of the binding values I also get Access is denied..
Fiddler says there is no authorization header and I cannot find the username or password in the request either.
Here are excerpts from my config:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
<services>
<service name="InventoryServices.MobileAPI" behaviorConfiguration="customBehaviour">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="secureHttpBinding"
contract="InventoryServices.IMobileAPI"/>
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="customBehaviour">
<serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" />
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="InventoryLibrary.Helpers.UserAuthentication,InventoryLibrary"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="secureHttpBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="MyRealm"/>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
My username/password validator looks like so:
public class UserAuthentication : UserNamePasswordValidator {
public override void Validate(string userName, string password) {
EntitiesContext db = new EntitiesContext();
db.Logs.Add(new DomainModels.Log() {
DateLogged = DateTime.Now,
Message = "hit auth",
Type = DomainModels.LogType.Info
});
db.SaveChanges();
try {
if (userName == "test" && password == "test123") {
Console.WriteLine("Authentic User");
}
}
catch (Exception ex) {
throw new FaultException("Unknown Username or Incorrect Password");
}
}
}
I have this as a simple test on my service:
[OperationContract]
[XmlSerializerFormat]
void Test();
[PrincipalPermission(SecurityAction.Demand, Name = "test")]
public void Test() {
}
I have a self signed SSL certificate on my server and I can access my service/metadata.
Then I have added a service reference in a console application, and attempt to connect to the service with this code below:
class Program {
static void Main(string[] args) {
Stuff.InitiateSSLTrust();
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.Realm = "MyRealm";
ServiceReference1.MobileAPIClient serviceProxy = new ServiceReference1.MobileAPIClient(binding, new EndpointAddress("https://xx.xx.xx.xx/InventoryServices.MobileApi.svc"));
serviceProxy.ClientCredentials.UserName.UserName = "test";
serviceProxy.ClientCredentials.UserName.Password = "test123";
try {
var a = serviceProxy.Login("a", "b");
}
catch (Exception ex) {
var ex2 = ex;
}
}
}
public class Stuff {
public static void InitiateSSLTrust() {
try {
//Change SSL checks so that all checks pass
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(
delegate { return true; }
);
}
catch (Exception ex) {
}
}
}
I've checked the event viewer on the server and this error appears with each request:
MessageSecurityException: Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.
You are specifying the client side to use BasicHttpSecurityMode.Transport whereas the service is expecting BasicHttpSecurityMode.TransportWithMessageCredential. This is a problem because the service is looking for the client credentials in the SOAP Message Header and the client will not send them with the binding configured this way.
Hence, this is why the username/password pair is not present in the Message Header as you are witnessing. So the event viewer was correct that there was a binding mismatch between the communicating parties.
Also set the ClientCredentialType on the client to BasicHttpMessageCredentialType.UserName for Message level security. By default BasicHttpBinding uses None which are anonymous clients.
Here's a code snippet describing the above changes:
var basicHttpBinding = new BasicHttpBinding(
BasicHttpSecurityMode.TransportWithMessageCredential);
basicHttpBinding.Security.Message.ClientCredentialType =
BasicHttpMessageCredentialType.UserName;
This can also be caused by the time being out of sync between client and server. If a certificate or signed token is invalid based off of time, the same An error occurred when verifying security for the message. message may be returned.
Just edit the .csproj file after adding the service reference and point these dependencies from 4.4.* to 4.6.*
<ItemGroup> <PackageReference Include="System.ServiceModel.Duplex" Version="4.6.*" />
<PackageReference Include="System.ServiceModel.Http" Version="4.6.*" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.6.*" />
<PackageReference Include="System.ServiceModel.Security" Version="4.6.*" />
</ItemGroup>
and add this
binding.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
I have defined an own ServiceCredentials provider:
class PasswordServiceCredentials : ServiceCredentials
{
}
That provider generates a custom SecurityTokenManager in CreateSecurityTokenManager() method when I start my ServiceHost:
public override SecurityTokenManager CreateSecurityTokenManager()
{
if (this.UserNameAuthentication.UserNamePasswordValidationMode == UserNamePasswordValidationMode.Custom)
{
return new PasswordSecurityTokenManager(this);
}
return base.CreateSecurityTokenManager();
}
The PasswordSecurityTokenManager class:
class PasswordSecurityTokenManager : ServiceCredentialsSecurityTokenManager
{
}
The instance generates a custom SecurityTokenAuthenticator in CreateSecurityTokenAuthenticator() method:
public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
{
outOfBandTokenResolver = null;
return new PasswordSecurityTokenAuthenticator(this.ServiceCredentials
.UserNameAuthentication
.CustomUserNamePasswordValidator);
}
The generated instance is a custom CustomUserNameSecurityTokenAuthenticator.
The problem is that the overwritten ValidateUserNamePasswordCore() method is NOT CALLED at any time:
protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateUserNamePasswordCore(String userName, String password)
{
ReadOnlyCollection<IAuthorizationPolicy> currentPolicies = base.ValidateUserNamePasswordCore(userName, password);
List<IAuthorizationPolicy> newPolicies = new List<IAuthorizationPolicy>();
if (currentPolicies != null)
{
newPolicies.AddRange(currentPolicies.OfType<IAuthorizationPolicy>());
}
newPolicies.Add(new PasswordAuthorizationPolicy(userName, password));
return newPolicies.AsReadOnly();
}
In my custom IAuthorizationPolicy provider PasswordAuthorizationPolicy I want to set a custom pricipal for the EvaluationContext in Evaluate() method.
But if the upper method is not called, no additional IAuthorizationPolicy item can be defined.
What wrong or missing here?
I DO NOT use XML to configure my service, I do this 100% in C# code!
EDIT: The code ist based on the following blog article: http://www.neovolve.com/post/2008/04/07/wcf-security-getting-the-password-of-the-user.aspx
OK, I'm only asking because you never mentioned anything about your config file in your post, but are you setting your serviceCredentials type in your serviceBehaviors? Example:
<behaviors>
<serviceBehaviors>
<behavior name="YourCustomBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials type="Your.Namespace.PasswordServiceCredentials, Your.Namespace">
<serviceCertificate findValue="localhost" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" />
</serviceCredentials>
<serviceAuthorization principalPermissionMode="Custom" />
</behavior>
</serviceBehaviors>
</behaviors>
And if you are, are you referencing "YourCustomBehavior" in your behaviorConfiguration on your service node? Example:
<services>
<service behaviorConfiguration="YourCustomBehavior"
name="Your.Service.Namespace.YourService">
<endpoint address="net.tcp://..."
binding="netTcpBinding" bindingConfiguration="netTcpBindingConfig"
contract="Your.Service.Interface.Namespace.IYourService" />
</service>
</services>
It might be as obvious as that.
(source: avivacommunityfund.org)