Using PrincipalPermissionAttribute with Custom role provider - wcf-security

I'm working on a new security infrastracture for my organization. Since we develop systems for the inside organization use I'd like to use Windows Authentication, but for the authorization we manage a separate Oracle DB (for historical reasons). My idea was to use PrincipalPermissionAttribute defining
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
in Global::Application_Start
and
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authorization>
<deny users="?"/>
</authorization>
<roleManager **defaultProvider="MyRoleProvider"**
enabled="true"
cacheRolesInCookie="true"
cookieName=".ASPROLES"
cookieTimeout="30"
cookiePath="/"
cookieRequireSSL="false"
cookieSlidingExpiration="true"
cookieProtection="All" >
<providers>
<clear />
<add
name="MyRoleProvider"
type="WcfServiceLibrary1.MyRoleProvider"
connectionStringName="Service1"
applicationName="InfraTest"
writeExceptionsToEventLog="true" />
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpointBinding">
<security mode="TransportCredentialOnly">
<transport **clientCredentialType="Windows"** />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WcfService1.Service1">
<endpoint address="WcfAuthenticationTest" binding="basicHttpBinding"
bindingConfiguration="BasicHttpEndpointBinding" name="BasicHttpEndpoint"
contract="WcfService1.IService1">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<host>
<baseAddresses>
<add baseAddress="http://localhost/WcfAuthentication"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceAuthorization **principalPermissionMode="UseAspNetRoles"**/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
in my Web.config using my custom role provider that should access the Oracle DB to check the role. But I can not make it work. Is there any way to make the PrincipalPermissionAttribute work in this way or may be the entire concept is wrong? I thought of implementing my custom CodeAccessSecurityAttribute but it is not that simple so I prefer not to do it
Does anybody have any idea of the issue? I'll be glad to get some answers

There are two things that I've learned lately. First af all my concept was right, I can use PrinciplePermissionAttribute with costom role provider, the second is that I was totaly confused with the web.config tags. tag is used for the asp .net settings, while is used for WCF settings. So a liitle bit configuration solved the entire problem. Here is the right configuration
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" defaultLanguage="c#" targetFramework="4.0" />
<roleManager enabled="true" cacheRolesInCookie="true" cookieName=".ASPROLES"
defaultProvider="MyRoleProvider">
<providers>
<clear />
<add connectionStringName="Service1" applicationName="InfraTest"
writeExceptionsToEventLog="false" name="MyRoleProvider" type="SecLib.MyRoleProvider" />
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBindingConfiguration" closeTimeout="00:01:00"
sendTimeout="00:10:00" maxBufferSize="524288" maxReceivedMessageSize="524288">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WcfRoleProviderTestService.Service1"
behaviorConfiguration="BasicHttpServiceBehavior" >
<endpoint name="BasicHttpEndpoint"
contract="WcfRoleProviderTestService.IService1"
address="WcfAuthenticationTest"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBindingConfiguration" />
<host>
<baseAddresses>
<add baseAddress="http://localhost/WcfRoleProviderTestService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="BasicHttpServiceBehavior">
<serviceAuthorization principalPermissionMode="UseAspNetRoles"
roleProviderName="MyRoleProvider" impersonateCallerForAllOperations="true" />
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>

You need not include impersonateCallerForAllOperations="true" unless you need impersonation

Related

WCF Web Deploy HTTP Error 404 - Not Found

I have created a REST WCF web service in vb.net and published it to 1&1 Host Server using Web Deploy. When trying to call one of the services, I keep receiving:
HTTP Error 404 - Not Found.
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
I have looked at the wwwroot directory and I can find the .svc files and web.config, so I can't figure out why it can not find it. The call I am making is: http://localhost/Service1.svc/GetTimesheetDetails/1/1/11256/2017-8-9
<OperationContract()>
<WebInvoke(Method:="GET", ResponseFormat:=WebMessageFormat.Json, BodyStyle:=WebMessageBodyStyle.Wrapped, UriTemplate:="GetTimesheetDetails/{userid}/{organisationid}/{jobid}/{sdate}")>
Function GetTimesheetDetails(ByVal userid As String, ByVal organisationid As String, ByVal jobid As String, ByVal sdate As String) As List(Of JobEngineerTime)
I have tested these calls running them on Visual Studio and it works fine, unfortunately I am unable to get it to run through the 1&1 server.
This is my web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<!--Disabled custom errors to allow display of detailed errors.-->
<!--<customErrors mode="Off"/>-->
<customErrors mode="RemoteOnly" defaultRedirect="~/Errors/500.htm">
<error statusCode="404" redirect="~/Errors/404.htm"/>
</customErrors>
<compilation debug="true" strict="false" explicit="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webBehaviour">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="metadataBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="metadataBehavior" name="WCFTimesheetWebService.Service1">
<endpoint address="" behaviorConfiguration="webBehaviour"
binding="webHttpBinding" contract="WCFTimesheetWebService.IService1" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
<service behaviorConfiguration="metadataBehavior" name="WCFTimesheetWebService.Service2">
<endpoint address="" behaviorConfiguration="webBehaviour"
binding="webHttpBinding" contract="WCFTimesheetWebService.IService2" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
<service behaviorConfiguration="metadataBehavior" name="WCFTimesheetWebService.Service3">
<endpoint address="" behaviorConfiguration="webBehaviour"
binding="webHttpBinding" contract="WCFTimesheetWebService.IService3" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<!-- Allowing Cross-Origin Resource Sharing (CORS) - The httpProtocol settings allow web services to be called from external domains using JavaScript-->
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
</customHeaders>
</httpProtocol>
<modules runAllManagedModulesForAllRequests="true"/>
<httpErrors errorMode="Detailed" />
<validation validateIntegratedModeConfiguration="false"/>
<!--
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>
A couple of mappings were missing in IIS "Handler Mappings". To sort out the problem, all I had to do was click on "Revert to Parent" inside "Handler Mappings" which restored the missing mappings and it started working.

WCF Service wsHttpBinding

I'm getting error while creating wcf service using wsHtpBinding help page is getting error and services also not working
Help Page Error:
The resource cannot be found. Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
http://localhost:80/Service1.svc/help
My old working wsHttpbinding project web.config but it's not working now:
web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" executionTimeout="3600" maxRequestLength="10000000"/>
<customErrors mode="Off" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
</behavior>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding >
<binding name="MyBasicwsHttpBinding">
<security mode="None">
<transport clientCredentialType="None" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="MyServiceTypeBehaviors" name="WcfService1.Service1">
<endpoint address="mex" binding="wsHttpBinding" bindingConfiguration="MyBasicwsHttpBinding" name="WcfService1.Service1" contract="WcfService1.IService1"/>
</service>
</services>
<serviceHostingEnvironment minFreeMemoryPercentageToActivateService="0" aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
In my case, I found out that a Microsoft IIS filtering module Url Scan 3.1 was installed on IIS/website, which have it's own limit to reject incoming requests based on content size and return "404 Not found page".
It's limit can be updated in %windir%\System32\inetsrv\urlscan\UrlScan.ini file by setting MaxAllowedContentLength to the required value.
For eg. following will allow upto 300 mb requests
MaxAllowedContentLength=314572800

WCF is showing development machine path on production server

I have deployed a wcf service app which I made on vs 2013, I published the project to a file system and moved the published version on production server. Now when I am accessing the service from production server it tries to connect to the local development machine where it says an exception
The server encountered an error processing the request. The exception message is 'Unable to connect to the remote server'.
<?xml version="1.0"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=169433
-->
<configuration>
<!--
For a description of web.config changes see http://go.microsoft.com/fwlink/?LinkId=235367.
The following attributes can be set on the <httpRuntime> tag.
<system.Web>
<httpRuntime targetFramework="4.5" />
</system.Web>
-->
<system.web>
<compilation targetFramework="4.5"/>
<httpRuntime/>
<pages controlRenderingCompatibilityVersion="4.0"/>
<customErrors mode="Off"/>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*"/>
<add name="Access-Control-Allow-Headers" value="Content-Type, x-requested-with, origin, authorization, accept, client-security, X-PINGOTHER"/>
<add name="Access-Control-Allow-Methods" value="GET, PUT, OPTIONS "/>
<add name="Access-Control-Max-Age" value="3600"/>
<add name="Access-Control-Allow-Credentials" value="true"/>
<add name="Access-Control-Expose-Headers" value="DAV, content-length, Allow"/>
</customHeaders>
</httpProtocol>
</system.webServer>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="EndpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceBehavior" name="ServiceWebApp.Service1">
<endpoint address="" binding="webHttpBinding" contract="ServiceWebApp.IService1" behaviorConfiguration="EndpBehavior" />
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="secureHttpBinding">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint crossDomainScriptAccessEnabled="true"/>
</webScriptEndpoint>
</standardEndpoints>
</system.serviceModel>
</configuration>

Implemeneting IIS hosted WCF service with AzMan role provider

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>

Requests to wcf service are unauthorized

I want to use a wcf service in my asp.net application that uses integrated windows-authentication however all the requests to my Model.svc are 401 Unauthorized.
If I change clientCredentialType="Windows" to clientCredentialType="Ntlm" every request is Unauthorized 2 times and the 3rd one is successful.
Here is my web.config:
<configuration>
<appSettings>
</appSettings>
<connectionStrings/>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Windows" />
</system.web>
<!--WCF Configuration-->
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true"/>
<bindings>
<webHttpBinding>
<binding name="WebHttpBinding_IModel">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<client />
<services>
<service behaviorConfiguration="ServiceBehavior" name="Model">
<endpoint address="" behaviorConfiguration="JsonBehavior" binding="webHttpBinding" bindingConfiguration="WebHttpBinding_IModel" contract="IModel">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="JsonBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
2 times unauthorized and third working is a part of the protocol. That is the way NTLM authentication works. Is this posing a problem? WCF is made to handle such scenarios, and so your WCF authentication call will work fine.

Resources