Is there something like a OnClientConnected event for .NET remoting? - c#

I'm using something like this on my server:
TcpServerChannel channel = new TcpServerChannel(settings.RemotingPort);
ChannelServices.RegisterChannel(channel, true);
RemotingServices.Marshal(myRemoteObject, "myRemoteObject");
I would like to subscribe to some kind of event so that whenever a remote client connects to myRemoteObject, I can check the Thread.CurrentPrincipal.Identity.Name to decide whether to authorize him.
Currently I'm doing the authorizing check in every exposed remote method of myRemoteObject which is a messy...

In my remoting application i defined a special object/interface where clients first need to authorize. The special object then returns, if the client successfully authorized the remote object. So you have the authorization at one place.
It looks something like this.
public interface IPortal
{
object SignIn(string name, string password);
}
public class Portal : MarshalByRefObject, IPortal
{
private object _remoteObject;
public Portal() {
_remoteObject = new RemoteObject();
}
public object SignIn(string name, string password)
{
// Authorization
// return your remote object
return _remoteObject;
}
}
In your application you host the Portal-Object
TcpServerChannel channel = new TcpServerChannel(settings.RemotingPort);
ChannelServices.RegisterChannel(channel, true);
Portal portal = new Portal()
RemotingServices.Marshal(portal , "portal");

You could use something like PostSharp to factor out the check from every method - just do it in the AOP advice. (You apply this to the class which is exposing its methods, not to the client connection.)
This approach is independent of whatever transport you use for remoting - it just factors out the cross-cutting concern of authorization across all the methods in your remoted class.

Related

ASP.NET Web Api Authentication Methods

I am trying to implement authentication for my web api.
I have read about different techniques of api authentication and the token technique is the most reasonable for me.
I read different articles about how to implement token based authentication in asp.net but they all rely on different libraries such as OAuth or Owin which also provide their own method of database interactions.
The thing is that I have already implemented database interaction with abstract repositories and entities and I would like to find out how can I implement api authentication easily and simply without interfering with my current design.
(By the way, my project is built on top of an empty web api project, so it doesn't come with all the bootstrap and authentication classes).
Thank you
One solution I've seen is to use .NET's HttpApplicationState class and store tokens in appstate; this way you're not directly messing with Session (which would be a REST antipattern), but you can still track all currently logged in users and use HttpContext/HttpActionContext to x-ref active tokens in the app. The benefit to using HttpActionContext is that it is thread-safe, whereas HttpContext is not, so you can lock the appstate, mess with the HttpContext of an individual request, and then unlock the appstate to allow other threads in.
Since locking/unlocking appstate does tie up the app, I'm not sure how well this solution scales, but here it is anyway . . .
General outline:
When a user first logs in, a token is generated for him/her and stored in appstate. Then you can tag any API calls that require authentication (or that need other information stored on that user) with a custom attribute that checks for that token in the appstate, sending the token name as a header in the API call (e.g. "{token-name: TOKEN}").
Here's a brief example:
[in Controller method first activated at login:]
CustomUserObject user = new CustomUserObject();
//store user props
string token = Guid.NewGuid().ToString();
//create AppState instance, mine's called _appState
//...
_appState.Lock();
_appState[token] = user;
_appState.UnLock();
//...
[Then in global.asax:]
public class CustomAuthorize : System.Web.Http.AuthorizeAttribute
{
HttpRequestMessage request = actionContext.ControllerContext.Request;
string token = string.Empty;
if (request.Headers.GetValues("token-name") != null)
{
token = request.Headers.GetValues("token-name").FirstOrDefault().ToString();
IAppStateService appService; //<--- I've created a custom service tier class for appstate stuff
//Get appState instance, however makes sense for you.
//I'm using repo pattern with UnitOfWork, so mine looks like this...
//"IContainer ioc = DependencyResolution.IoC.Initialize();"
//"IAppStateService appService = ioc.GetInstance<IAppStateService>();"
appService.SetHttpApplicationState(HttpContext.Current.Application);
bool isAuthorized = appService.CheckTokenAndDoStuff(token);
//inside that method ^^^ you'll do stuff like
//"_appState.Lock();"
//"if (_appState[token] == null) return false" (or whatever)
//"_appState.Unlock();"
}
if (isAuthorized)
{
HttpResponseMessage resp = request.CreateResponse(HttpStatusCode.OK);
resp.Headers.Add("AuthenticationToken", token);
resp.Headers.Add("WWW-Authenticate", "Basic");
resp.Headers.Add("AuthenticationStatus", "Authorized");
}
return isAuthorized;
}
[then in webapi]
[HttpPost]
[CustomAuthorize]
public HttpResponseMessage NameOfMethod(...)...
...and that should x-check your appstate for your user token for you. Just make sure to include your token in your request header, and make sure to include the Basic Auth info in your response header.

Restrict service to internal network BUT load balancer?

In our ServiceStack (v3)-based API, we have some services that are for internal use only, so we've put a [Restrict(InternalOnly = true)] attribute on all of our internal request DTOs.
The problem is that we use load balancing, and the restricted services get publicly accessible to everyone because the IP calling the API is always the load balancer's IP, and therefore an internal IP.
Is there any way to circumvent this, so that the internal services are restricted to internal IPs EXCEPT the load balancer's IP?
I haven't seen a built in way (See [Restrict] tests) to restrict based on specific IPs. However you can trivially filter the requests yourself using a custom attribute:
public class AllowLocalExcludingLBAttribute : RequestFilterAttribute
{
public override void Execute(IHttpRequest req, IHttpResponse res, object requestDto)
{
// If the request is not local or it belongs to the load balancer then throw an exception
if(!req.IsLocal || req.RemoteIp == "10.0.0.1")
throw new HttpError(System.Net.HttpStatusCode.Forbidden, "403", "Service can only be accessed internally");
}
}
Then you simply add [AllowLocalExcludingLB] on your services or action methods where you would have otherwise used the [Restrict] attribute or use it in conjunction with other restrictions. Replace 10.0.0.1 with your load balancer IP.

Dynamically create WCF ServiceHost based on parsing Endpoint Address with NamedNetPipes Binding

Need a way for one service on a well-known Endpoint to return strings which are relative addresses. The client can then connect to Endpoints using these relative addresses.
Clearly this resembles REST in some ways, but in this case running a Windows Service using NetNamedPipeBinding for IPC, so no need for HTTP.
Don't want to create the Endpoint ahead of time since there will be a potentially large number of relative addresses, only some of which the client would be interested in.
All Contracts are known in advance.
Tried to find a solution with AddressFilterMode but wasn't sure how to provision new Binding so that client connected to it, UriTemplate but don't want to use the HTTP framework. Haven't looked into RoutingService because constrained to .Net 3.5.
Pseudocode for client would be something like that below...
namespace Testing
{
class RunTest
{
static void Test()
{
NetNamedPipeBinding namedpipe = new NetNamedPipeBinding();
ChannelFactory<Contracts.IRoot> factoryRoot =
new ChannelFactory<Contracts.IRoot>(
namedpipe
, new EndpointAddress("net.pipe://localhost/root");
);
Contracts.IRoot root = factoryRoot.CreateChannel();
ICommunicationObject commsRoot = root as ICommunicationObject;
commsRoot.Open();
// Service examines address and creates Endpoint dynamically.
string address = root.SomeFunctionWhichGetsARelativeAddress();
// IBar service routes endpoint requests internally based on
// "address" variable.
ChannelFactory<Contracts.IBar> factoryBar =
new ChannelFactory<Contracts.IBar>(
namedpipe
, new EndpointAddress("net.pipe://localhost/root/IBar/" +
address)
);
Contracts.IBar bar = factoryBar.CreateChannel();
bar.DoSomething();
}
} // Ends class RunTest
} // Ends namespace Testing
Message Filters are the way to go. You can use “Prefix” or create a custom.
WCF Addressing In Depth
From the Message Filters section of the article:
...it uses message filters to determine the matching endpoint, if one
exists. You can choose which message filter to use or you can provide
your own. This flexibility allows you to break free from the
traditional dispatching model when using Windows Communication
Foundation to implement things other than traditional SOAP—for
instance, the techniques described here enable you to implement
REST/POX-style services on the Windows Communication Foundation
messaging foundation.
Nice question, by the way. I learned something trying to figure this out.
AddressFilterMode.Prefix might suffice. The actual Endpoint used can be inspected in Service methods via
OperationContext.Current.IncomingMessageHeaders.To
Helper code can parse the endpoint and do any necessary internal processing from there.
Hopefully there's some extensibility on the server side which can simplify that code.
Pseudocode for host:
namespace Services
{
[System.ServiceModel.ServiceBehavior(AddressFilterMode =
System.ServiceModel.AddressFilterMode.Prefix)]
class BarService : Contracts.IBar
{
#region IBar Members
public void DoSomething()
{
System.Uri endpoint = System.ServiceModel.OperationContext.Current.IncomingMessageHeaders.To;
Console.WriteLine("DoSomething endpoint: {0}", endpoint);
}
} // Ends class BarService
} // Ends namespace Services
class RunHost
{
static void HostIBar()
{
System.Uri uriBase = new System.Uri("net.pipe://localhost");
System.ServiceModel.ServiceHost hostBar =
new System.ServiceModel.ServiceHost(
typeof(Services.BarService),
uriBase);
hostBar.AddServiceEndpoint(
typeof(Contracts.IBar) // Type implementedContract
, namedpipeBinding // System.ServiceModel.Channels.Binding binding
, "root/IBar" //string address
);
hostBar.Open();
Console.WriteLine("Press <ENTER> to stop...");
Console.ReadLine();
}
}
Correction: I'd originally said that this wouldn't treat "net.pipe://localhost/root/IBar/1" and "net.pipe://localhost/root/IBar/2" as distinct endpoints, but it does. Each causes its own WCF Service instance to be created and called.
An additional change was to encode the data in URL style query parameters and not embed it in the path. E.g.: "net.pipe://localhost/root/IBar?something=1&somethingelse=11" and "net.pipe://localhost/root/IBar?something=2&somethingelse=22" using HttpUtility.ParseQueryString

WCF REST Service - Replace a string parameter with a class instance on every method?

I'm writing a WCF REST Service that has a mobile client.
The mobile client uses an "authToken" along the lines of OAuth to represent a user's identity.
The authToken is a string parameter which, at the moment, is passed to (almost) every method in the service.
What I'd like to do is write something akin to an MVC ActionFilter -which runs for every method and does the authToken processing: validate the token, lookup the related account and return the Account instance object - a failed lookup means an error is returned and my method isn't even called.
I've found these two questions which are kind of similar to what I want to do, but it would appear the tricky part is introducing the Account instance somehow? I can quite happily create my [AuthOperation] attribute which implements the IOperationBehavior interface, but I can't work out what I need to do in order to introduce my new Account instance one I've looked it up.
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
Account = new Account(_context);
if (!Account.LoadByAuthToken(((string)inputs[0]).FromEncodedString()))
{
outputs = new object[0];
return new ErrorResponse
{
Code = ResponseCode.Exception.ToString(),
DebugMessage = MyStrings.AuthToken_NotFound
};
}
How do I pass my Account instance into the invoked method?
object result = this._originalInvoker.Invoke(instance, IntroduceAccount(inputs,Account), out outputs);
return result;
}
Ultimately what I want is to have
public MyResponse GetContacts(string authToken)
exposed in the service, but
public MyResponse GetContacts(Account acct)
or
public MyResponse GetContacts(Account acct, string authToken)
actually implemented on the server - and have the authToken -> Account conversion handled by the "Action Filter".
I'd even be happy if the answer is "Don't use WCF, do it like this...." as long as whatever else is proposed also fits my other requirements.
Have you looked into using interception? Take a look at this example. There are other interceptor implementations out there. This link has some more options as well.
It turns out that I am just really dumb and (almost) achieving my goal was actually fairly straightforward.
In the (Invoke) method above you have access to the instance that is being invoked....So....
var wcfAccountRequired = instance as IWcfAccountRequired;
if (wcfAccountRequired != null)
{
(wcfAccountRequired).Account = Account;
}
...I just make sure that a particular interface is being implemented by (instance) and assign the Account property on it. If I don't successfully retrieve an Account I can just return the error and not invoke anything.
Not perfect, but solves my problem succinctly.

How to Securely Transmit Data to/from a Public Web Service

An app I'm working on interfaces with an existing application running on a remote box. Communicaitons with the remote app are via its public web services. I've been asked to build an enhancement which will involve a client making use of the web service to handle sensitive data which will need to be transmitted securely.
Could anyone give me some pointers on how best to proceed?
To start, you should be using SSL and reject any requests that are not using it. This will encrypt data as it's being transmitted over the Internet.
If you are using SOAP, you could define a custom header in your service that takes a username / password. Then, for the first line in each public method, validate the username and password against a database. If successful, set the HttpContext.Current.User appropriately, and your service will tie in nicely with the built in Asp.NET infrastructure.
ADDED: Below is a sample SoapHeader that includes a username / password for authentication.
// define the header
public class AuthenticationHeader : SoapHeader
{
public String UserName { get; set; }
public String Password { get; set; }
}
// your service
public class PublicWebService : WebService
{
// defines an instance of the header as part of the service
public AuthenticationHeader Authentication;
private void Authenticate()
{
// validate the username / password against a database
// set the HttpContext.Current.User if successful.
// Maybe throw a SoapException() if authentication fails
}
// Notice the SoapHeader("Authentication") attribute...
// This tells ASP.Net to look for the incoming header for this method...
[WebMethod]
[SoapHeader("Authentication")]
public void PublicMethod1()
{
Authenticate();
// your code goes here
}
// Expose another method with the same authentication mechanism
[WebMethod]
[SoapHeader("Authentication")]
public void PublicMethod2()
{
Authenticate();
// your code goes here
}
}
Now, if you run the wsdl tool, the generated proxy class will include the defined authentication header:
PublicWebService s = new PublicWebService();
s.Authentication = new AuthenticationHeader();
s.Authentication.UserName = "xxxxxxxx";
s.Authentication.Password = "yyyyyyyy";
s.PublicMethod1();
s.PublicMethod2();
DIY route:
Read up on security (start with "Secrets and Lies" and other such general books before moving on to the technicalities)
Perform a risk analysis and thread assessment. Understand what you are protecting and from what, and where threats will come from. You are unlikely to need "High Security"1.
Use TLS (aka SSL).
In the client, verify the server's certificate is correct.
Better route: employ an expert who has an established reputation to help you.
1 Unless you really are building a nuclear weapons plant or similar.

Categories

Resources