I have a SqlMembershipProvider store with Roles enabled. This is configured and has the user "devtest" in the roles "xxUser" and "xxAdmin".
I also have a WCF service, which I want to authenticate and authorize against. My problem is that:
the authorisation is not
happening, code just executes
despite the policy attribute
I don't get any identity or security
context so do not know who is
calling the service
I need:
to know which user is calling the
method
some degree of rejecting
users if permissions don't match up
(ideally this should be performed
within the
RoleProvider/MembershipProvider/WCF
but can do it myself if I have to)
SSL in transport
I have my service contract set up thus:
[ServiceContract]
public interface ISupportService
{
[OperationContract]
[PrincipalPermission(SecurityAction.Demand, Role = "ThisRoleDoesNotExist")]
List<BaseInterestRate> GetAllBaseInterestRates();
}
the code is simple enough:
public class SupportService : ISupportService
{
public List<BaseInterestRate> GetAllBaseInterestRates()
{
OperationContext operationContext = OperationContext.Current;
ServiceSecurityContext serviceSecurityContext = ServiceSecurityContext.Current; // is always null
using (xxxEntities entities = new xxxEntities())
{
return new List<BaseInterestRate>(entities.BaseInterestRates);
}
}}
My service configuration is thus:
-->
<behaviors>
<serviceBehaviors>
<behavior name="SupportServiceBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="AspNetSqlRoleProvider" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="SqlMembershipProvider" />
</serviceCredentials>
</behavior>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
Having already configured the MembershipProvider:
<membership defaultProvider="SqlMembershipProvider" >
<providers>
<clear/>
<add name="SqlMembershipProvider"
connectionStringName="SqlMembershipProvider"
applicationName="xxx"
type="System.Web.Security.SqlMembershipProvider" />
</providers>
</membership>
<roleManager enabled="true">
<providers>
<clear />
<add connectionStringName="SqlMembershipProvider" applicationName="xxx"
name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
<add applicationName="xxx" name="AspNetWindowsTokenRoleProvider"
type="System.Web.Security.WindowsTokenRoleProvider" />
</providers>
</roleManager>
I have followed the instructions at these pages to the letter:
How to: Use the SQL Server Role Provider with Windows Authentication in WCF Calling from Windows Forms (MSDN)
How to: Create and Install Temporary Client Certificates in WCF During Development (MSDN)
How to: Use wsHttpBinding with Username Authentication and TransportWithMessageCredentials in WCF Calling from Windows Forms (MSDN)
Also quite useful found via SO: Use Asp.Net Membership provider with a WCF .svc service (Alkampfer's Place)
I would at lest expect an issue with certificates/transport/etc. to fail with exceptions, but I can debug right in and over the WCF call. I have no security context/ user context available to me and when I use a user not in the two mentioned roles (which I do in the code example above), I don't get "kicked out".
My client app is currently a Web App, but will ultimately also serve a Windows Forms app and Test suite. I'm currently using the ASP.NET WebDev server and am running .NET 4.0.
Am I missing something?
I'm a little new to WCF Rest services, but during my own testing I ran into a similar problem to this. I came across this video, which helped a bit (even if it wasn't quite what I was trying to do):
http://channel9.msdn.com/blogs/rojacobs/endpointtv-securing-restful-services-with-aspnet-membership
Essentially the problem was that under the asp.net configuration I had to disable anonymous access in order for it to use the MembershipProvider authentication:
system.web>
<authorization>
<deny users="?" />
</authorization>
...
I don't think you can set the principal permission on the interface.
I bet if you move it onto the service implementation method it will work
or at least start breaking for a different reason (I am currently stuck at that point - I get access denied exceptions - hopefully you dont!)
(I first tried to put them on the contract interface also)
this is the correct configuration for wcf service self-hosted with SSL:
<?xml version="1.0"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
<connectionStrings>
<add name="mySqlConnection" connectionString="Data Source=.\SQLEXPRESS2012;Integrated Security=SSPI;Initial Catalog=aspnetdb;"/>
</connectionStrings>
<system.web>
<compilation debug="true"/>
<!-- Configure the Sql Membership Provider -->
<membership defaultProvider="MySqlMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear/>
<add name="MySqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="mySqlConnection" applicationName="UsersManagementNavigationApplication" enablePasswordRetrieval="false" enablePasswordReset="false" requiresQuestionAndAnswer="false" requiresUniqueEmail="true" passwordFormat="Hashed"/>
</providers>
</membership>
<!-- Configure the Sql Role Provider -->
<roleManager enabled="true" defaultProvider="MySqlRoleProvider">
<providers>
<clear/>
<add name="MySqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="mySqlConnection" applicationName="UsersManagementNavigationApplication"/>
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="webBinding">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</webHttpBinding>
<basicHttpBinding>
<binding name="basicBindingConfiguration">
<security mode="Transport">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="webEndpointBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="webServiceBehavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceThrottling/>
<serviceDebug/>
</behavior>
<behavior name="myServiceBehavior">
<!-- Configure role based authorization to use the Role Provider -->
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="MySqlRoleProvider">
</serviceAuthorization>
<serviceCredentials>
<!-- Configure user name authentication to use the Membership Provider -->
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfServiceHTTPSSelfHosted.MyCustomValidator, WcfServiceHTTPSSelfHosted" />
</serviceCredentials>
<!-- To avoid disclosing metadata information, set the value below to false 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="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="myServiceBehavior" name="WcfServiceHTTPSSelfHosted.WcfServiceHTTPSSelfHosted">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicBindingConfiguration" contract="WcfServiceHTTPSSelfHosted.IWcfServiceHTTPSSelfHosted"/>
<endpoint address="web" behaviorConfiguration="webEndpointBehavior" binding="webHttpBinding" bindingConfiguration="webBinding" contract="WcfServiceHTTPSSelfHosted.IWcfServiceHTTPSSelfHosted"/>
<endpoint address="mex" binding="mexHttpsBinding" bindingConfiguration="" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="https://localhost:50001/WcfServiceHTTPSSelfHosted/"/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
if you want more info take a look this:
http://www.albertoschiassi.it/Home/tabid/55/EntryId/94/Use-ASP-NET-SqlMemberShipProvider-in-WCF-self-hosted-service.aspx
and
http://www.albertoschiassi.it/Home/tabid/55/EntryId/95/Use-ASP-NET-SqlMemberShipProvider-in-WCF-self-hosted-service-with-SSL.aspx
Related
I try to implement a WCF service that is hosted on IIS, the users ask for some templates files transformation and it return them the processed file (If they are authorized for the template they asked for).
I selected the visual studio project template "WCF Service Application" and got a project with aspNetCompatibilityEnabled set to true etc.
I thought on implementing my need using AzMan authorization since I am fimiliar with that mechanism and did similiar things with it.
However, I can't debug the service since I get 401 unauthorized.
I assume the user token is not being sent.
1. How can I enable Azman usage for WCF, IIS hosted service?
2. Is there similiar mechanism embedded in WCF that can assist checking if a user belongs to a group that allowed to access some site folder?
Confiuration:
<configuration>
<connectionStrings>
<add name="LocalPolicyStore"connectionString="msxml://c:/RolesData/azmanstore.xml" /> </connectionStrings>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
<authentication mode="Windows" />
<authorization>
<deny users="?" />
</authorization>
<roleManager enabled="true" cacheRolesInCookie="true" defaultProvider="RoleManagerAzManProvider" cookieName=".ASPXROLES" cookiePath="/" cookieTimeout="30" cookieRequireSSL="true" cookieSlidingExpiration="true" createPersistentCookie="false" cookieProtection="All">
<providers>
<add name="RoleManagerAzManProvider" type="System.Web.Security.AuthorizationStoreRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, publicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalPolicyStore" applicationName="DRP" />
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<!-- 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"/>
<serviceAuthorization principalPermissionMode="UseAspNetRoles"
roleProviderName="RoleManagerAzManProvider" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="ExcelGeneratingService.ExcelGeneratorService" behaviorConfiguration="metadataBehavior">
<endpoint
address=""
binding="basicHttpBinding" bindingConfiguration="excelGeneratorServiceBinding"
contract="ExcelGeneratingService.IExcelGeneratorService"/>
<endpoint
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="excelGeneratorServiceBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Code:
//Check if the user is allowed to access this path
if (!UrlAuthorizationModule.CheckUrlAccessForPrincipal(virtPath, user, "GET"))
{
return false;
}
I have solved it. I hope it will help someone.
Some fixes to the configuration (Attached). All users allowed but filtered at lower level folders.
Installing missing authorization handlers at the IIS on the OS (Turn windows features on...)
Use the local IIS and not IIS Express from the visual studio
Clean the IIS Express configurations at the user data folder (C:\Users\\Documents\IISExpress\config) if the IIS visrtual folder creation fails
Give my azman store a reader security privilege (at the azman console) for the service application pool user (from the IIS).
Configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<connectionStrings>
<add name="LocalPolicyStore" connectionString="msxml://c:/RolesData/ExcelGeneration.xml" />
</connectionStrings>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Windows" />
<authorization>
<allow users="*" />
</authorization>
<identity impersonate="false" />
<roleManager enabled="true" cacheRolesInCookie="true" defaultProvider="RoleManagerAzManProvider" cookieName=".ASPXROLES" cookiePath="/" cookieTimeout="30" cookieRequireSSL="true" cookieSlidingExpiration="true" createPersistentCookie="false" cookieProtection="All">
<providers>
<add name="RoleManagerAzManProvider" type="System.Web.Security.AuthorizationStoreRoleProvider, System.Web, Version=4.0.0.0, Culture=neutral, publicKeyToken=b03f5f7f11d50a3a" connectionStringName="LocalPolicyStore" applicationName="ExcelGeneration" />
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="UseAspNetRoles"
roleProviderName="RoleManagerAzManProvider" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="ExcelGeneratingService.ExcelGeneratorService" behaviorConfiguration="metadataBehavior">
<endpoint address="" bindingConfiguration="excelGeneratorServiceBinding" binding="basicHttpBinding" contract="ExcelGeneratingService.IExcelGeneratorService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="excelGeneratorServiceBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true" />
</system.webServer>
I have created an amazon EC2 instance and hosted my .net web application on port 80 and WCF service on port 1212 port.
Locally on the remote session I am able to browse both application and service and able to make ajax request calls.
Only when I try doing same functionality over the internet(not on same remote session) which makes ajax call to wcf service on port 1212 ``gives access denied error. I have added $.support.cors = true; while making request.
Web application web.config:
<configuration>
<system.web>
<connectionStrings>
<add name="ApplicationServices"
connectionString="Server=somedbinstance.asdkfjlksd.us-west-2.rds.amazonaws.com;Initial Catalog=xed; user id=user ;password=pwd"
providerName="System.Data.SqlClient" />
</connectionStrings>
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webEndpoint">
<webHttp defaultBodyStyle="Wrapped"
defaultOutgoingResponseFormat="Xml" helpEnabled="true" />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="webHttpBinding" />
</webHttpBinding>
</bindings>
<client>
<endpoint name="BasicHttpBinding_ICustomerRequestService"
address="http://10.90.12.121:1212/myservice.svc"
binding="webHttpBinding" bindingConfiguration="webHttpBinding"
behaviorConfiguration="webEndpoint"
contract="CustomerRequestService.ICustomerRequestService" />
</client>
<serviceHostingEnvironment
aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<defaultDocument>
<files>
<add value="index.aspx" />
</files>
</defaultDocument>
</system.webServer>
</configuration>
WCF Service web.config:
<system.serviceModel>
<services>
<service name="iHandyService.CustomerRequestService">
<endpoint
address=""
behaviorConfiguration="restfulBehavior"
binding="webHttpBinding" bindingConfiguration=""
contract="Interfac.ICustomerRequestService" />
<host>
<baseAddresses>
<add baseAddress="http://10.90.12.121:1212/myservice.svc" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="restfulBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true">
</serviceHostingEnvironment>
</system.serviceModel>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
Ajax call:
error function gives access denied error.
Please guide me on this error and how to resolve it.
You need to add this port to AWS console->EC2-->Security group-->Inbound rules-->Port. This link will be helpful. You need to select security group corresponding to your instance, and this is also visible in instances link.
LINK1 , LINK2
Also make sure, you have added this port to windows firewall inbound rule. - http://technet.microsoft.com/en-us/library/cc947789(v=ws.10).aspx
Note: You might need to configure WCF service to be CORS ready, follow this link - WCF REST Service Template 40(CS) Cross domain error, i have answered there how to make it CORS enabled.
I've written a WCF service application.
When the project is generated, visual studio creates 3 web config files.
I've finished the project and to date I've been using a hard coded connection string within my GetOpenConnection() function, so I now want to move the connection string to the web.config files.
The following call returns null.
ConnectionStringSettings csSettings = ConfigurationManager.ConnectionStrings["PulseWcfConnectionString"];
When I run the following code it doesn't return the string set in my web.debug.config file.
for(int idx = 0; idx < ConfigurationManager.ConnectionStrings.Count; idx++)
Debug.WriteLine(ConfigurationManager.ConnectionStrings[idx].ConnectionString);
it returns the following 2 items, 2nd one is an empty string. I don't recognise the first line, maybe it's a default one?
data source=.\SQLEXPRESS;Integrated Security=SSPI; AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true
""
What am I missing please?
My web.debug.config contains the following which should be for a local sql server instance
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add
name="PulseWcfConnectionString"
connectionString="Data Source=WIN8-CLAIRE\SQLSRVDEV2008;Initial
Catalog=gcll;Persist Security Info=True;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
</configuration>
For now my web.release.config contains the same thing (it's being published to it's destination tomorrow so I'll change the details for it then)
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<connectionStrings>
<add
name="PulseWcfConnectionString"
connectionString="Data Source=WIN8-CLAIRE\SQLSRVDEV2008;Initial
Catalog=gcll;Persist Security Info=True;Integrated Security=True"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
</system.web>
</configuration>
web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Windows" />
</system.web>
<system.serviceModel>
<services>
<service name ="pulse.smartcentre.wcf.service.app.PulseWebService"
behaviorConfiguration="ServiceBehavior">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:52478/Design_Time_Addresses/pulse.smartcentre.wcf.service.app/PulseWebService/" />
</baseAddresses>
</host>
<endpoint address="" binding="wsHttpBinding"
bindingConfiguration="wsHttpBinding"
contract="pulse.smartcentre.wcf.service.app.IPulseWebService">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<!-- CNH -->
<bindings>
<!-- Secure binding (to use) -->
<wsHttpBinding>
<binding name="wsHttpBinding" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8"
useDefaultWebProxy="true" transactionFlow="true">
<readerQuotas
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxDepth="2147483647"
maxNameTableCharCount="2147483647"
maxStringContentLength="2147483647" />
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="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"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="Behaviors.EndpointBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
If you use the transformation files, you need to add the transformation property, and specify what you would like to do, Insert, Remove, Replace...
I use to put the local connection in the master web.config and then transform it in the Release configuration, by Replacing the attributes of the defined connection string.
Check this article: Web.config Transformation Syntax for Web Project Deployment Using Visual Studio
If you want to use your way, just add xdt:Transform="Insert" in the <add> node.
You can test your transformation using this web tester: Web.config Transformation Tester
I feel like I'm close but I'm a newbie at WCF and can't figure out why this is not working. I've tried searching, but I couldn't find an example of using aspnet membership without using message level security. I am trying to authenticate over https from Android to a WCF service. It works just fine until I change the clientCredentialType from 'None' to 'Basic'. I have to authenticate via username and password. When I try to update my proxy by running slsvcutil.exe against the https://myPublicWebsite/ABCService/ABC.svc it gives the following error:
The authentication schemes configured on the host ('IntegratedWindowsAuthentication, Anonymous') do not allow those configured on the binding 'BasicHttpBinding' ('Basic'). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly. Additionally, this may be resolved by changing the authentication schemes for this application through the IIS management tool, through the ServiceHost.Authentication.AuthenticationSchemes property, in the application configuration file at the element, by updating the ClientCredentialType property on the binding, or by adjusting the AuthenticationScheme property on the HttpTransportBindingElement.
Here is my web.config of the service. Thanks for any help you can give me.
<system.web>
<compilation debug="false" strict="false" explicit="true" targetFramework="4.0" />
<customErrors mode="Off" />
<membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<remove name="AspNetSqlMembershipProvider" />
<clear />
<add
name="AspNetSqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="LocalSqlServer"
applicationName="ABC"
enablePasswordRetrieval="false"
enablePasswordReset="false"
requiresQuestionAndAnswer="false"
minRequiredPasswordLength="8"
requiresUniqueEmail="true"
passwordFormat="Hashed" />
</providers>
</membership>
</system.web>
<system.serviceModel>
<services>
<service name="ABCService.ABC" behaviorConfiguration="metadataBehavior">
<endpoint
address=""
binding="basicHttpBinding"
bindingConfiguration="ABCBinding"
contract="ABCService.IService1"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="MembershipProvider"
membershipProviderName="AspNetSqlMembershipProvider" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="ABCBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="false"/>
</system.webServer>
Also, what do I put in the code of service to run the validation check? I have this:
Public Class MyCustomUserNameValidator
Inherits IdentityModel.Selectors.UserNamePasswordValidator
' This method validates users. It allows two users, test1 and test2
' with passwords 1tset and 2tset respectively.
' This code is for illustration purposes only and
' MUST NOT be used in a production environment because it is NOT secure.
Public Overrides Sub Validate(ByVal userName As String, ByVal password As String)
If Nothing = userName OrElse Nothing = password Then
Throw New ArgumentNullException()
End If
If Not (userName = "test1" AndAlso password = "1tset") AndAlso Not (userName = "test2" AndAlso password = "2tset") Then
Throw New IdentityModel.Tokens.SecurityTokenException("Unknown Username or Password")
End If
End Sub
End Class
But I don't really understand how it works because I never call it, and I would rather use a default one than a custom one. I'm sure this is simple, but all the examples I could find by searching are for 'custom' validators. Does this get called automatically? or do I even need it if I just want the default?
Are you using IIS? you need to install and enable basic authentication in IIS.
To install: Turn On or Off Windows Components, and enable Basic
Authentication under IIS.
To enable:
http://technet.microsoft.com/en-us/library/cc772009(v=ws.10).aspx
However, even if you enabled basic auth, you can only use membership providers and custom validators in message based security and when clientCredentialType set to UserName. Pure transport based security mode like TransportCredentialOnly and Transport will not work.
Reference - go to the Authentication section
This should work for wsHttpBinding
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
Another possibility for wsHttpBinding and basicHttpBinding
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
I have a client and application which are set up to use the ClientFormAuthenticationMembershipProvider for authentication. On the client side, when the application boots up the system prompts for a username and password. The server is set up to accept this, and a Web Application is supposed to permit the application to work. We are in the midst of setting up a new environment, and something is not working on the server side (if we point the client at another server, it works fine). We've painstakingly gone over every detail we can think of, and the result is the same: The call to ValidateUser() throws an exception. I have downloaded a network sniffer, and under the hood I can see that a 302 message is being returned when I try to call Authentication_JSON_AppService.axd. On the server side, ProcMon registers attempts to read the Authentication_JSON_AppService.axd file from within the wwwroot/../Authentication_JSON_AppService.axd, which obviously does not exist.
Client Side Configuration:
From our FormMain.cs (which attempts to call the provider)
if (!System.Web.Security.Membership.ValidateUser(null, null))
System.Windows.Forms.Application.Exit();
else
{
DoStartUp();
....
}
From Our FormLogin.cs (which prompts for UserName and Pass) Note: class inherits
IClientFormsAuthenticationCredentialsProvider
public System.Web.ClientServices.Providers.ClientFormsAuthenticationCredentials GetCredentials()
{
if (this.ShowDialog() == DialogResult.OK)
{
return new ClientFormsAuthenticationCredentials(
textEditUsername.Text, textEditPassword.Text,
false);
}
else
{
return null;
}
}
From the app.config:
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<clear />
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="http://SERVERNAME/APPNAME/Authentication_JSON_AppService.axd" credentialsProvider="APPNAME.Windows.FormLogin, APPNAME.Windows" savePasswordHashLocally="False" />
</providers>
</membership>
On the server side:
IIS has been configured for this application for anonymous authentication and forms authentication. (we're running IIS 7.5, .NET 4.0, Windows Server 2008 R2). We have the WCF Activation and HTTP Activation features installed on the server. The ApplicationPool is set to v4.0 Framework, 32-bit Applications not enabled, Integrated PipelineMode, most other values set to default.
The web.config file:
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true" />
<roleService enabled="true" />
</webServices>
</scripting>
</system.web.extensions>
<authentication mode="Forms">
<forms name=".MDPSApp" loginUrl="~/Connect/Login.aspx" slidingExpiration="true" timeout="600000">
</forms>
</authentication>
<authorization>
<deny users="?" />
</authorization>
<membership defaultProvider="XYZ">
<providers>
<add name="XYZ" type="APPNAME.Web.Providers.MembershipProvider, APPNAME.Web" />
</providers>
</membership>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="DisableAutoCookieManagement" maxReceivedMessageSize="2147483647" allowCookies="false">
<readerQuotas maxDepth="64" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None" />
</binding>
</wsHttpBinding>
<behaviors>
<serviceBehaviors>
<behavior name="APPNAME.Application.Web.Services.AgenceMaster.ServiceAgenceMasterBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceAuthorization principalPermissionMode="None">
</serviceAuthorization>
</behavior>
<behavior name="APPNAME.Application.Web.Services.Agence.ServiceAgenceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="APPNAME.Application.Web.Services.AgenceMaster.ServiceAgenceMasterBehavior" name="APPNAME.Application.Web.Services.AgenceMaster.ServiceAgenceMaster">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="DisableAutoCookieManagement" contract="APPNAME.Services.AgenceMaster.IServiceAgenceMaster">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
<service behaviorConfiguration="APPNAME.Application.Web.Services.Agence.ServiceAgenceBehavior" name="APPNAME.Application.Web.Services.Agence.ServiceAgence">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="DisableAutoCookieManagement" contract="APPNAME.Services.Agence.IServiceAgence">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
The APPNAME.Web.Providers.MembershipProvider class extends System.Web.Security.MembershipProvider and overrides ValidateUser(string username, string password) with custom code. This class is not getting instantiated or called during the scenario.
Something isn't configured properly on the server side, or else the server would know how to resolve the Authentication_JSON_AppService.axd call properly (and it seems to me like it's not). Any thoughts or help are appreciated!
This was driving me bonkers. In FireFox - if I entered the URL for my *.aspx page that invoked my WCF REST call - everything worked fine. If I then did a shift-reload - I would get a 302 which redirected me to a non-existent forms login page.
In Safari and Chrome - no shift-reloaded needed. It would fail with the 302 on the first load.
I found the basic answer in the Alex on ASP.NET blog
Short answer: change the web.config to remove forms authentication:
<modules runAllManagedModulesForAllRequests="true">
<remove name="FormsAuthentication" />
</modules>