Skip to content

Commit

Permalink
added untrustedspec
Browse files Browse the repository at this point in the history
  • Loading branch information
maxim.salamatko committed Dec 12, 2015
1 parent 0ffbf80 commit 8daa622
Show file tree
Hide file tree
Showing 10 changed files with 367 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/core/Akka.Remote.Tests/Akka.Remote.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
<Compile Include="Transport\TestTransportSpec.cs" />
<Compile Include="Transport\ThrottleModeSpec.cs" />
<Compile Include="Transport\ThrottlerTransportAdapterSpec.cs" />
<Compile Include="UntrustedSpec.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\contrib\testkits\Akka.TestKit.Xunit2\Akka.TestKit.Xunit2.csproj">
Expand Down
295 changes: 295 additions & 0 deletions src/core/Akka.Remote.Tests/UntrustedSpec.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
//-----------------------------------------------------------------------
// <copyright file="RemoteWatcherSpec.cs" company="Akka.NET Project">
// Copyright (C) 2009-2015 Typesafe Inc. <http://www.typesafe.com>
// Copyright (C) 2013-2015 Akka.NET project <https://github.com/akkadotnet/akka.net>
// </copyright>
//-----------------------------------------------------------------------

using System;
using Akka.Actor;
using Akka.Configuration;
using Akka.Event;
using Akka.TestKit;
using Akka.Util.Internal;
using Xunit;

namespace Akka.Remote.Tests
{
public class UntrustedSpec : AkkaSpec
{
private readonly ActorSystem _client;
private readonly Address _address;
private readonly IActorRef _receptionist;
private readonly Lazy<IActorRef> _remoteDaemon;
private readonly Lazy<IActorRef> _target2;


public UntrustedSpec()
: base(@"
akka.actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
akka.remote.untrusted-mode = on
akka.remote.trusted-selection-paths = [""/user/receptionist"", ]
akka.remote.helios.tcp = {
port = 0
hostname = localhost
}
akka.loglevel = DEBUG
")
{
_client = ActorSystem.Create("UntrustedSpec-client", ConfigurationFactory.ParseString(@"
akka.actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
akka.remote.helios.tcp = {
port = 0
hostname = localhost
}
").WithFallback(Sys.Settings.Config));

_address = Sys.AsInstanceOf<ExtendedActorSystem>().Provider.DefaultAddress;
_receptionist = Sys.ActorOf(Props.Create(() => new Receptionist(TestActor)), "receptionist");

_remoteDaemon = new Lazy<IActorRef>(() =>
{
var p = CreateTestProbe(_client);
_client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements)
.Tell(new IdentifyReq("/remote"), p.Ref);
return p.ExpectMsg<ActorIdentity>().Subject;
});

_target2 = new Lazy<IActorRef>(() =>
{
var p = CreateTestProbe(_client);
_client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements)
.Tell(new IdentifyReq("child2"), p.Ref);

var actorRef = p.ExpectMsg<ActorIdentity>().Subject;
return actorRef;
});


EventFilter.Debug().Mute();
}


protected override void AfterTermination()
{
Shutdown(_client);
}


[Fact]
public void UntrustedModeMustAllowActorSelectionToConfiguredWhiteList()
{
var sel = _client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements);
sel.Tell("hello");
ExpectMsg("hello");
}

[Fact]
public void UntrustedModeMustDiscardHarmfulMessagesToSlashRemote()
{
var logProbe = CreateTestProbe();
// but instead install our own listener
Sys.EventStream.Subscribe(
Sys.ActorOf(Props.Create(() => new DebugSniffer(logProbe)).WithDeploy(Deploy.Local), "debugSniffer"),
typeof (Debug));

_remoteDaemon.Value.Tell("hello");
logProbe.ExpectMsg<Debug>();
}

[Fact]
public void UntrustedModeMustDiscardHarmfulMessagesToTestActor()
{
var target2 = _target2.Value;

target2.Tell(new Terminated(_remoteDaemon.Value, true, false));
target2.Tell(PoisonPill.Instance);
_client.Stop(target2);
target2.Tell("blech");
ExpectMsg("blech");
}

[Fact]
public void UntrustedModeMustDiscardWatchMessages()
{
var target2 = _target2.Value;
_client.ActorOf(Props.Create(() => new Target2Watch(target2, TestActor)).WithDeploy(Deploy.Local));
_receptionist.Tell(new StopChild1("child2"));
ExpectMsg("child2 stopped");
// no Terminated msg, since watch was discarded
ExpectNoMsg(TimeSpan.FromSeconds(1));
}

[Fact]
public void UntrustedModeMustDiscardActorSelection()
{
var sel = _client.ActorSelection(new RootActorPath(_address)/TestActor.Path.Elements);
sel.Tell("hello");
ExpectNoMsg(TimeSpan.FromSeconds(1));
}

[Fact]
public void UntrustedModeMustDiscardActorSelectionToChildOfMatchingWhiteList()
{
var sel = _client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements/"child1");
sel.Tell("hello");
ExpectNoMsg(TimeSpan.FromSeconds(1));
}

[Fact]
public void UntrustedModeMustDiscardActorSelectionWithWildcard()
{
var sel = _client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements/"*");
sel.Tell("hello");
ExpectNoMsg(TimeSpan.FromSeconds(1));
}

[Fact]
public void UntrustedModeMustDiscardActorSelectionContainingHarmfulMessage()
{
var sel = _client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements);
sel.Tell(PoisonPill.Instance);
ExpectNoMsg(TimeSpan.FromSeconds(1));
}


[Fact]
public void UntrustedModeMustDiscardActorSelectionWithNonRootAnchor()
{
var p = CreateTestProbe(_client);
_client.ActorSelection(new RootActorPath(_address)/_receptionist.Path.Elements).Tell(
new Identify(null), p.Ref);
var clientReceptionistRef = p.ExpectMsg<ActorIdentity>().Subject;

var sel = ActorSelection(clientReceptionistRef, _receptionist.Path.ToStringWithoutAddress());
sel.Tell("hello");
ExpectNoMsg(TimeSpan.FromSeconds(1));
}


private class IdentifyReq
{
public IdentifyReq(string path)
{
Path = path;
}

public string Path { get; }
}

private class StopChild1
{
public StopChild1(string name)
{
Name = name;
}

public string Name { get; }
}


private class Receptionist : ActorBase
{
private readonly IActorRef _testActor;

public Receptionist(IActorRef testActor)
{
_testActor = testActor;
Context.ActorOf(Props.Create(() => new Child(testActor)), "child1");
Context.ActorOf(Props.Create(() => new Child(testActor)), "child2");
Context.ActorOf(Props.Create(() => new FakeUser(testActor)), "user");
}


protected override bool Receive(object message)
{
return message.Match().With<IdentifyReq>(req =>
{
var actorSelection = Context.ActorSelection(req.Path);
actorSelection.Tell(new Identify(null), Sender);
})
.With<StopChild1>(child => { Context.Stop(Context.Child(child.Name)); })
.Default(o => { _testActor.Forward(o); })
.WasHandled;
}
}

private class Child : ActorBase
{
private readonly IActorRef _testActor;

public Child(IActorRef testActor)
{
_testActor = testActor;
}

protected override bool Receive(object message)
{
_testActor.Forward(message);
return true;
}

protected override void PostStop()
{
_testActor.Tell(string.Format("{0} stopped", Self.Path.Name));
base.PostStop();
}
}

private class FakeUser : ActorBase
{
private readonly IActorRef _testActor;

public FakeUser(IActorRef testActor)
{
_testActor = testActor;
Context.ActorOf(Props.Create(() => new Child(testActor)), "receptionist");
}

protected override bool Receive(object message)
{
_testActor.Forward(message);
return true;
}
}

private class DebugSniffer : ActorBase
{
private readonly TestProbe _testProbe;

public DebugSniffer(TestProbe testProbe)
{
_testProbe = testProbe;
}

protected override bool Receive(object message)
{
return message.Match().With<Debug>(debug =>
{
if (((string) debug.Message).Contains("dropping"))
{
_testProbe.Ref.Tell(debug);
}
}).WasHandled;
}
}

private class Target2Watch : ActorBase
{
private readonly IActorRef _testActor;


public Target2Watch(IActorRef target2, IActorRef testActor)
{
_testActor = testActor;
Context.Watch(target2);
}

protected override bool Receive(object message)
{
_testActor.Forward(message);
return true;
}
}
}
}
68 changes: 36 additions & 32 deletions src/core/Akka.Remote/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,42 +78,46 @@ public void Dispatch(IInternalActorRef recipient, Address recipientAddress, Seri
else if ((recipient is ILocalRef || recipient is RepointableActorRef) && recipient.IsLocal)
{
if (settings.LogReceive) log.Debug("received local message [{0}]", msgLog);
payload.Match()
.With<ActorSelectionMessage>(sel =>
{
var actorPath = "/" + string.Join("/", sel.Elements.Select(x => x.ToString()));
if (settings.UntrustedMode
&& (!settings.TrustedSelectionPaths.Contains(actorPath)
if (payload is ActorSelectionMessage)
{
var sel = (ActorSelectionMessage) payload;

var actorPath = "/" + string.Join("/", sel.Elements.Select(x => x.ToString()));
if (settings.UntrustedMode
&& (!settings.TrustedSelectionPaths.Contains(actorPath)
|| sel.Message is IPossiblyHarmful
|| recipient != provider.Guardian))
{
log.Debug(
"operating in UntrustedMode, dropping inbound actor selection to [{0}], allow it" +
"by adding the path to 'akka.remote.trusted-selection-paths' in configuration",
actorPath);
}
else
{
//run the receive logic for ActorSelectionMessage here to make sure it is not stuck on busy user actor
ActorSelection.DeliverSelection(recipient, sender, sel);
}
})
.With<IPossiblyHarmful>(msg =>
|| recipient != provider.RootGuardian))
{
if (settings.UntrustedMode)
{
log.Debug("operating in UntrustedMode, dropping inbound IPossiblyHarmful message of type {0}", msg.GetType());
}
})
.With<ISystemMessage>(msg => { recipient.Tell(msg); })
.Default(msg =>
log.Debug(
"operating in UntrustedMode, dropping inbound actor selection to [{0}], allow it" +
"by adding the path to 'akka.remote.trusted-selection-paths' in configuration",
actorPath);
}
else
{
recipient.Tell(msg, sender);
});
//run the receive logic for ActorSelectionMessage here to make sure it is not stuck on busy user actor
ActorSelection.DeliverSelection(recipient, sender, sel);
}
}
else if (payload is IPossiblyHarmful && settings.UntrustedMode)
{
log.Debug("operating in UntrustedMode, dropping inbound IPossiblyHarmful message of type {0}",
payload.GetType());
}
else if (payload is ISystemMessage)
{
recipient.Tell(payload);
}
else
{
recipient.Tell(payload, sender);
}

}

// message is intended for a remote-deployed recipient
else if ((recipient is IRemoteRef || recipient is RepointableActorRef) && !recipient.IsLocal && !settings.UntrustedMode)
else if ((recipient is IRemoteRef || recipient is RepointableActorRef) && !recipient.IsLocal &&
!settings.UntrustedMode)
{
if (settings.LogReceive) log.Debug("received remote-destined message {0}", msgLog);
if (provider.Transport.Addresses.Contains(recipientAddress))
Expand All @@ -131,8 +135,8 @@ public void Dispatch(IInternalActorRef recipient, Address recipientAddress, Seri
else
{
log.Error(
"Dropping message [{0}] for non-local recipient [{1}] arriving at [{2}] inbound addresses [{3}]",
payloadClass, recipient, recipientAddress, string.Join(",", provider.Transport.Addresses));
"Dropping message [{0}] for non-local recipient [{1}] arriving at [{2}] inbound addresses [{3}]",
payloadClass, recipient, recipientAddress, string.Join(",", provider.Transport.Addresses));
}
}
}
Expand Down
Loading

0 comments on commit 8daa622

Please sign in to comment.