CheckAccessCore not being called in custom ServiceAuthorizationManager - wcf

I am working on a WCF REST service that will be hosted within Azure and want to check the user id. To this end I have created a custom ServiceAuthorizationManager.
namespace SecureService
{
public class AccessControlServiceAuthorizationManager : ServiceAuthorizationManager
{
String serviceNamespace = String.Empty;
String acsHostname = String.Empty;
String trustedTokenPolicyKey = String.Empty;
String trustedAudience = String.Empty;
public AccessControlServiceAuthorizationManager()
{
try
{
serviceNamespace = RoleEnvironment.GetConfigurationSettingValue("serviceNamespace");
acsHostname = RoleEnvironment.GetConfigurationSettingValue("acsHostname");
trustedTokenPolicyKey = RoleEnvironment.GetConfigurationSettingValue("trustedTokenPolicyKey");
trustedAudience = RoleEnvironment.GetConfigurationSettingValue("trustedAudience");
}
catch
{
GenerateErrorResponse();
}
finally
{
}
} // end AccessControlServiceAuthorizationManager() Constructor
protected override bool CheckAccessCore(OperationContext operationContext)
{
String headerValue = WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Authorization];
String token = String.Empty;
string[] nameValuePair = null;
TokenValidator validator = null;
if (String.IsNullOrEmpty(headerValue))
{
GenerateErrorResponse();
return false;
}
if (!headerValue.StartsWith("WRAP "))
{
GenerateErrorResponse();
return false;
}
nameValuePair = headerValue.Substring("WRAP ".Length).Split(new char[] { '=' }, 2);
if (nameValuePair.Length != 2 ||
nameValuePair[0] != "access_token" ||
!nameValuePair[1].StartsWith("\"") ||
!nameValuePair[1].EndsWith("\""))
{
GenerateErrorResponse();
return false;
}
token = nameValuePair[1].Substring(1, nameValuePair[1].Length - 2);
validator = new TokenValidator(acsHostname, serviceNamespace, trustedAudience, trustedTokenPolicyKey);
if (!validator.Validate(token))
{
GenerateErrorResponse();
return false;
}
return true;
}
public void GenerateErrorResponse()
{
}
}
}
My Web.config is as follows;
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="Secure">
<serviceAuthorization serviceAuthorizationManagerType="SecureService.AccessControlServiceAuthorizationManager" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="SecureService.Demo">
<endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="SecureService.IDemo" />
<endpoint address="rest" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="SecureService.IDemo" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
However the CheckAccessCore() method does not seem to be called when I call the service via IE. So the question is how can I ensure it is called and therefore ensure that my users are validated.
I have put a break point in the CheckAccessCore and it never seems to get hit.
And just to make things really interesting - I will need to call this webservice from within Silverlight.
Thanks in advance

Ignore your 'services' section in config. Try:
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint crossDomainScriptAccessEnabled="True" automaticFormatSelectionEnabled="true" helpEnabled="True"/>
</webHttpEndpoint>
</standardEndpoints>

Following the configuration pasted above, I see that service behavior "Secure" is missed to apply on Service. Please check it, if it's not a typo...

Related

SwaggerWCF configuration for self hosted WCF library

I'm having some difficulties getting SwaggerWCF to load my documentation page, and I'm not sure why. I get no errors, but I also get no Swagger docs either, just a 404 when I visit http://localhost:8733/docs per the endpoint configuration. What am I doing wrong here? I have everything decorated up, using Framework 4.8. Service works fine and the mex and js endpoints will return data, just no swaggerUI.
Here is my App.Config:
<system.serviceModel>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" contentTypeMapper="Microsoft.Samples.WebContentTypeMapper.JsonContentTypeMapper, JsonContentTypeMapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</webHttpEndpoint>
</standardEndpoints>
<services>
<service name="AutodeskVaultAPI.VaultWorker">
<endpoint address="" binding="basicHttpBinding" contract="AutodeskVaultAPI.IVaultServices">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="js" behaviorConfiguration="jsonEP" binding="webHttpBinding"
name="jsonEP" contract="AutodeskVaultAPI.IVaultServices" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/AutodeskVaultAPI/" />
</baseAddresses>
</host>
</service>
<service name="SwaggerWcf.SwaggerWcfEndpoint">
<endpoint address="http://localhost:8733/docs" binding="webHttpBinding" contract="SwaggerWcf.ISwaggerWcfEndpoint" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="jsonEP">
<webHttp helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Here is my service implementation:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[SwaggerWcf("/AutodeskVaultAPI/js")]
public class VaultWorker : IVaultServices
{
...[redacted]...
[SwaggerWcfTag("AutodeskVaultAPI")]
public AutodeskVaultFolder GetRootFolder(string vaultServerName = "", string currentUserLogin = "false")
{
try
{
Folder rootFolder = VaultConnection.WebServiceManager.DocumentService.GetFolderRoot();
if (null == rootFolder)
return null;
else
{
var toReturn = new AutodeskVaultFolder()
{
Created = rootFolder.CreateDate,
Category = (null == rootFolder.Cat) ? "No Category" : rootFolder.Cat.CatName,
CreatedByUserID = rootFolder.CreateUserId,
CreatedByUserName = rootFolder.CreateUserName,
EntityMasterID = rootFolder.Id,
FolderEntityName = rootFolder.Name,
FolderFullPath = rootFolder.FullName,
IsVaultRoot = true,
NumberOfChildren = rootFolder.NumClds,
ParentID = rootFolder.ParId
};
return toReturn;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return null;
}
}
[SwaggerWcfTag("AutodeskVaultAPI")]
public AutodeskVaultSearchResponse SearchVault(AutodeskVaultSearchRequest request)
{
try
{
string bookMark = string.Empty;
var parameters = getSearchParametersFromRequest(request);
SrchStatus srchStatus = null;
List<File> foundFiles = new List<File>();
if (null != parameters && parameters.Length > 0)
{
while (null == srchStatus || foundFiles.Count < srchStatus.TotalHits)
{
File[] srcResults = VaultConnection.WebServiceManager.DocumentService.FindFilesBySearchConditions(parameters, null, null, true, false, ref bookMark, out srchStatus);
if (null != srcResults)
foundFiles.AddRange(srcResults);
else
break;
}
}
return mapResultsToResponse(request, foundFiles);
}
catch (Exception ex)
{
Debug.Write(ex);
return null;
}
}
...[redacted]...
[DataContract(Name = "AutodeskVaultSearchRequest")]
public class AutodeskVaultSearchRequest
{
[DataMember]
public bool OR_Search = false;
[DataMember]
public List<AutodeskVaultProperty> properties;
}
[DataContract(Name = "AutodeskVaultSearchResponse")]
public class AutodeskVaultSearchResponse
{
[DataMember]
public AutodeskVaultSearchRequest Request;
[DataMember]
public List<AutodeskVaultFile> Files;
[DataMember]
public string Message;
and here is my service interface:
[ServiceContract]
public interface IVaultServices
{
[SwaggerWcfPath("GetRootFolder", #"Test the default configured server to see if we can get back the root folder")]
[OperationContract]
[WebInvoke(UriTemplate = "GetRootfolder/{vaultServerName}/{currentUserLogin}", Method = "GET", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[Description(#"Test the default configured server to see if we can get back the root folder")]
AutodeskVaultFolder GetRootFolder(string vaultServerName = "", string currentUserLogin = "false");
[SwaggerWcfPath("GetAsbuiltDrawingsByNumber", #"Given an Autodesk Search Request, search through Vault to find File information using the supplied properties.")]
[OperationContract]
[WebInvoke(UriTemplate = "SearchVault", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
[Description(#"Given an Autodesk Search Request, search through Vault to find File information using the supplied properties.")]
AutodeskVaultSearchResponse SearchVault(AutodeskVaultSearchRequest request);
}
Add an endpoint to your App.config file.
<services>
<service name="SwaggerWcf.SwaggerWcfEndpoint">
<endpoint address="http://localhost/docs" binding="webHttpBinding" contract="SwaggerWcf.ISwaggerWcfEndpoint" />
</service>
</services>
Create a WebServiceHost
var swaggerHost = new WebServiceHost(typeof(SwaggerWcfEndpoint));
swaggerHost.Open();
You can refer to the steps provided in the link for details.
https://github.com/abelsilva/swaggerwcf
How do I view my Swagger docs when using SwaggerWcf?

Implementation the basic authenication in WCF using webHttpBinding

I'm going to implement basic authentication in WCF. I'm very new in all this stuff and my program is based on this series of articles http://leastprivilege.com/2008/01/11/http-basic-authentication-against-non-windows-accounts-in-iisasp-net-part-0-intro/ I do use webHttpBinding and HTTPS is on.
So the main idea is implementation of IHttpModule in this way:
When user requests some resource a module checks if Authorization header is present.
In case of Authorization is present, the module extracts the header's value, decodes and checks login and pass
In the other case the module sends a response with 401 code and a header "WWW-Authenticate".
Here is my implementation of the module:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Management;
using System.Text;
namespace MyProj_A
{
public class MyHTTPModule : IHttpModule
{
void IHttpModule.Dispose()
{
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += Context_BeginRequest;
context.AuthenticateRequest += OnEnter;
context.EndRequest += OnLeave;
}
private void Context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
context.Response.Write("BeginRequest");
}
void OnEnter(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (IsHeaderPresent())
{
if (!AuthenticateUser())
{
DenyAccess();
}
}
else
{
// if anonymous requests are not allowed - end the request
DenyAccess();
}
}
bool IsHeaderPresent()
{
return HttpContext.Current.Request.Headers["Authorization"] != null;
}
bool AuthenticateUser()
{
string username = "", password = "";
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic"))
{
// extract credentials from header
string[] credentials = ExtractCredentials(authHeader);
username = credentials[0];
password = credentials[1];
if (username.CompareTo("tikskit") == 0 && password.CompareTo("") == 0)
{
return true;
} else
{
return false;
}
}
else
{
return false;
}
}
private static void DenyAccess()
{
HttpContext context = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.End();
}
void OnLeave(object sender, EventArgs e)
{
// check if module is enabled
if (HttpContext.Current.Response.StatusCode == 401)
{
SendAuthenticationHeader();
}
}
private void SendAuthenticationHeader()
{
HttpContext context = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.AddHeader(
"WWW-Authenticate",
"Basic realm=\"yo-ho-ho\""
);
}
}
}
I publish it under IIS 7.5 on remote computer and connect to it with remote debugger from my Visual Studio. I set breakpoints at Context_BeginRequest, OnEnter and OnLeave.
Then I access to my WCF from a browser using URL and here is what happens:
After I inputted an URL and pressed the Enter Context_BeginRequest is fired
In VS I can see that the Authorization header isn't present
OnEnter is fired and eventually it assigns 401 code to the response
OnLeave is executed as well and it sets WWW-Authenticate to the response header
In the browser the standart login dialog is shown
I input the user name and password and press OK
Now Context_BeginRequest is fired again and I can see that Authorization header is present and consists a value like "Basic ", which is right
OnEnter isn't executed at all this time
OnLeave is fired but a value of HttpContext.Current.Response.StatusCode is 401 by some reason
Here is my Web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
<customErrors mode="Off" />
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp automaticFormatSelectionEnabled="false"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Default" >
<serviceMetadata httpGetEnabled="false" />
<serviceMetadata httpsGetEnabled="false"/>
<serviceAuthenticationManager authenticationSchemes="Basic"/>
<serviceCredentials>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="MyBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="MyProj_A.Service1">
<endpoint address="" binding="webHttpBinding" contract="MyProj_A.IService1"
behaviorConfiguration="webBehavior"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost/" />
</baseAddresses>
</host>
</service>
</services>
<diagnostics>
<endToEndTracing activityTracing="false" messageFlowTracing="true" propagateActivity="true"></endToEndTracing>
</diagnostics>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyHTTPModule"
type="MyProj_A.MyHTTPModule,MyProj-A"/>
</modules>
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>
So my questions are
1. Why OnEnter isn't fired second time, in 8, and how is 401 assigned in an item 9?
2. How to work around this behaviour, I mean do I need to move all the authentication processing from AuthenticateRequest (OnLeave) to BeginRequest (Context_BeginRequest) for example? Or maybe there is a better place for such processing?
Thanks!
Case is closed
I've forgotten to refer to binding configuration in endpoint configuration:
<endpoint address="" binding="webHttpBinding"
contract="MyProj_A.IService1"
behaviorConfiguration="webBehavior"
**bindingConfiguration="MyBinding"**/>

WCF Service receives null request

var dataToSend = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(mi));
var req = HttpWebRequest.Create("http://localhost/Service1.svc/json/MethodName");
req.ContentType = "application/json";
req.ContentLength = dataToSend.Length;
req.Method = "POST";
req.GetRequestStream().Write(dataToSend, 0, dataToSend.Length);
var response = req.GetResponse();
Here "/json" is my endpoint address and my service is configured with multiple endpoints. As per image here, request i sent is recieving null at server.
If my request format is not proper then suggest proper way to call this service.
// Service inter face
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method="POST")]
Response MethodName(Request request);
}
// Service1
public class Service1 : IService
{
public Response MethodName(Request request)
{
some logical operation....
}
}
// End point configuration (Web config)
<endpoint address="json" behaviorConfiguration="jsonBehavior"
binding="webHttpBinding" bindingConfiguration="webHttpBindingJson"
name="jsonn" contract="Service1.IService" />
<endpoint address="xml" behaviorConfiguration="poxBehavior" binding="webHttpBinding"
bindingConfiguration="webHttpBindingXml" name="xmll" contract="Service1.IService" />
<endpointBehaviors>
<behavior name="jsonBehavior">
<enableWebScript />
</behavior>
<behavior name="poxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
<webHttpBinding>
<binding name="webHttpBindingJson">
<security mode="None" />
</binding>
<binding name="webHttpBindingXml">
<security mode="None" />
</binding>
</webHttpBinding>
// Request class
[DataContract]
public class Request
{
string userMobile;
string otp;
[DataMember]
public string UserMobile
{
get { return userMobile; }
set { userMobile = value; }
}
[DataMember]
public string OTP
{
get { return otp; }
set { otp = value; }
}
}
Finally i found for this.
I modified endpoint of json behaviour configuration to this,
<behavior name="jsonBehavior">
<webHttp defaultBodyStyle ="Bare"/>
<!--<enableWebScript />-->
</behavior>
and removed enableWebScript. Finally my code working.

The caller was not authenticated by the service

I have build a simple WCF service using wsDualHttpBinding. It is working fine at local end but it throws a error when I publish the service on a different server and try to consume that service in a WPF project.
Error:
System.ServiceModel.SecurityNegotiationException "The caller was not authenticated by the service."
InnerException:
System.ServiceModel.FaultException "The caller was not authenticated by the service."
Server Config:
<system.serviceModel>
<services>
<service name="VetChat.Service.VetChatService" behaviorConfiguration="wsDualHttpBinding.SampleServiceBehavior">
<!-- Service Endpoints -->
<host>
<baseAddresses>
<add baseAddress="http://service.softprodigy.com:8090/VetChatService.svc"/>
</baseAddresses>
</host>
<endpoint address="" binding="wsDualHttpBinding" contract="VetChat.Service.IVetChatService">
<!--
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="VPS" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="wsDualHttpBinding.SampleServiceBehavior">
<!-- 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"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="VetChat.Service.UserNamePassValidator, VetChat.Service" />
<serviceCertificate findValue="MyName" storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Client Config:
<system.serviceModel>
<bindings>
<wsDualHttpBinding>
<binding name="WSDualHttpBinding_IVetChatService" />
</wsDualHttpBinding>
</bindings>
<client>
<endpoint address="http://service.softprodigy.com:8090/VetChatService.svc"
binding="wsDualHttpBinding" bindingConfiguration="WSDualHttpBinding_IVetChatService"
contract="ServiceReference1.IVetChatService" name="WSDualHttpBinding_IVetChatService">
<identity>
<dns value="VPS" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="CustomBehavior">
<clientCredentials>
<clientCertificate findValue="MyName" x509FindType="FindBySubjectName"
storeLocation="CurrentUser" storeName="TrustedPeople" />
<serviceCertificate>
<defaultCertificate findValue="MyName" storeLocation="CurrentUser" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
<authentication certificateValidationMode="PeerTrust" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Interface:
[ServiceContract(CallbackContract = typeof(ICallback), SessionMode = SessionMode.Required)]
public interface IVetChatService
{
[OperationContract(IsOneWay = true)]
void DoWork();
}
public interface ICallback
{
[OperationContract(IsOneWay = true)]
void Notify(string value);
}
Interface Implementation:
public class VetChatService : IVetChatService
{
public void DoWork()
{
//Thread.Sleep(5000);
OperationContext.Current.GetCallbackChannel<ICallback>().Notify("Hello");
}
}
Validte username password service class:
namespace VetChat.Service
{
class UserNamePassValidator :
System.IdentityModel.Selectors.UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName == null || password == null)
{
throw new ArgumentNullException();
}
if (!(userName == UserName && password == Password))
{
//throw new FaultException("Incorrect Username or Password");
}
}
}
public class Service
{
}
}
Call method:
InstanceContext instanceContext = new InstanceContext(new SampleServiceCallback());
ServiceReference1.VetChatServiceClient sampleServiceClient = new ServiceReference1.VetChatServiceClient(instanceContext);
sampleServiceClient.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.CurrentUser,
StoreName.TrustedPeople,
X509FindType.FindBySubjectName,
"MyName");
sampleServiceClient.ClientCredentials.UserName.UserName = UserName;
sampleServiceClient.ClientCredentials.UserName.Password = Password;
//sampleServiceClient.Open();
sampleServiceClient.DoWork();
Response Callback:
public class SampleServiceCallback : ServiceReference1.IVetChatServiceCallback
{
#region ISampleServiceCallback Members
public void Notify(string value)
{
MessageBox.Show(value);
}
#endregion
}
Thanks

WCF windows service, Service metadata may not be accessible

Hi a have WCF service libary with this configuration:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="Default" name="ComDocs.ControlServerServiceLibary.Concrete.TokenService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/TokenService" />
</baseAddresses>
</host>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="basic" binding="basicHttpBinding" contract="ComDocs.ControlServerServiceLibary.Abstract.ITokenService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
If I build it in debug, everything works fine on localhost. But if I make a Windows Service library with the same configuration:
public partial class TokenService : ServiceBase
{
ServiceHost _host = null;
public TokenService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Trace.WriteLine("Starting Token Service...");
_host = new ServiceHost(typeof(TokenService));
_host.Open();
}
protected override void OnStop()
{
Trace.WriteLine("Shutting down Token Service...");
if (_host != null)
{
_host.Close();
_host = null;
}
}
}
Install it with InstallUtil and start it:
but error:
I suspect this line is the culprit.
_host = new ServiceHost(typeof(TokenService));
TokenService is your Windows service class, not your WCF service class.