Require inbox requests to be signed by the activity actor

This commit is contained in:
Jeremy Dormitzer 2019-01-25 21:15:13 -05:00
parent 3c5dfa9a3d
commit feeea74aea
2 changed files with 51 additions and 18 deletions

View File

@ -51,17 +51,21 @@ class PostController
$object = $results[0]; $object = $results[0];
$inboxField = $object->getReferencingField( 'inbox' ); $inboxField = $object->getReferencingField( 'inbox' );
if ( $inboxField ) { if ( $inboxField ) {
$actorWithInbox = $inboxField->getObject(); $activity = json_decode( $request->getContent(), true );
if ( ! $activity || ! array_key_exists( 'actor', $activity ) ) {
throw new BadRequestHttpException();
}
$activityActor = $this->getActivityActor( $activity );
if ( ! $activityActor) {
throw new BadRequestHttpException();
}
if ( ! $request->attributes->has( 'signed' ) || if ( ! $request->attributes->has( 'signed' ) ||
! $this->authorized( $request, $actorWithInbox ) ) { ! $this->authorized( $request, $activityActor ) ) {
throw new UnauthorizedHttpException( throw new UnauthorizedHttpException(
'Signature realm="ActivityPub",headers="(request-target) host date"' 'Signature realm="ActivityPub",headers="(request-target) host date"'
); );
} }
$activity = json_decode( $request->getContent(), true ); $actorWithInbox = $inboxField->getObject();
if ( ! $activity ) {
throw new BadRequestHttpException();
}
$event = new InboxActivityEvent( $activity, $actorWithInbox, $request ); $event = new InboxActivityEvent( $activity, $actorWithInbox, $request );
$this->eventDispatcher->dispatch( InboxActivityEvent::NAME, $event ); $this->eventDispatcher->dispatch( InboxActivityEvent::NAME, $event );
return; return;
@ -85,6 +89,17 @@ class PostController
throw new MethodNotAllowedHttpException( array( Request::METHOD_GET ) ); throw new MethodNotAllowedHttpException( array( Request::METHOD_GET ) );
} }
private function getActivityActor( array $activity )
{
xdebug_break();
$actor = $activity['actor'];
if ( is_array( $actor ) && array_key_exists( 'id', $actor ) ) {
return $this->objectsService->dereference( $actor['id'] );
} else if ( is_string( $actor ) ) {
return $this->objectsService->dereference( $actor );
}
}
private function authorized( Request $request, ActivityPubObject $activityActor ) private function authorized( Request $request, ActivityPubObject $activityActor )
{ {
if ( ! $request->attributes->has( 'actor' ) ) { if ( ! $request->attributes->has( 'actor' ) ) {

View File

@ -31,6 +31,9 @@ class PostControllerTest extends TestCase
'id' => 'https://example.com/actor/1/outbox', 'id' => 'https://example.com/actor/1/outbox',
), ),
), ),
'https://elsewhere.com/actor/1' => array(
'id' => 'https://elsewhere.com/actor/1',
),
); );
const REFS = array( const REFS = array(
'https://example.com/actor/1/inbox' => array( 'https://example.com/actor/1/inbox' => array(
@ -67,34 +70,46 @@ class PostControllerTest extends TestCase
} }
} ) } )
); );
$objectsService->method( 'dereference' )->will(
$this->returnCallback( function( $id ) {
if ( array_key_exists( $id, self::OBJECTS ) ) {
return TestActivityPubObject::fromArray( self::OBJECTS[$id] );
} else {
return null;
}
} )
);
$testCases = array( $testCases = array(
array( array(
'id' => 'basicInboxTest', 'id' => 'basicInboxTest',
'request' => $this->makeRequest( 'request' => $this->makeRequest(
'https://example.com/actor/1/inbox', 'https://example.com/actor/1/inbox',
Request::METHOD_POST, Request::METHOD_POST,
'{"type": "Create"}', '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}',
array( array(
'signed' => true, 'signed' => true,
'actor' => TestActivityPubObject::fromArray( 'actor' => TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://elsewhere.com/actor/1']
), ),
) )
), ),
'expectedEventName' => InboxActivityEvent::NAME, 'expectedEventName' => InboxActivityEvent::NAME,
'expectedEvent' => new InboxActivityEvent( 'expectedEvent' => new InboxActivityEvent(
array( 'type' => 'Create' ), array(
'type' => 'Create',
'actor' => 'https://elsewhere.com/actor/1'
),
TestActivityPubObject::fromArray( TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://example.com/actor/1']
), ),
$this->makeRequest( $this->makeRequest(
'https://example.com/actor/1/inbox', 'https://example.com/actor/1/inbox',
Request::METHOD_POST, Request::METHOD_POST,
'{"type": "Create"}', '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}',
array( array(
'signed' => true, 'signed' => true,
'actor' => TestActivityPubObject::fromArray( 'actor' => TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://elsewhere.com/actor/1']
), ),
) )
) )
@ -135,10 +150,10 @@ class PostControllerTest extends TestCase
'request' => $this->makeRequest( 'request' => $this->makeRequest(
'https://example.com/actor/1/inbox', 'https://example.com/actor/1/inbox',
Request::METHOD_POST, Request::METHOD_POST,
'{"type": "Create"}', '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}',
array( array(
'actor' => TestActivityPubObject::fromArray( 'actor' => TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://elsewhere.com/actor/1']
), ),
) )
), ),
@ -149,7 +164,7 @@ class PostControllerTest extends TestCase
'request' => $this->makeRequest( 'request' => $this->makeRequest(
'https://example.com/actor/1/inbox', 'https://example.com/actor/1/inbox',
Request::METHOD_POST, Request::METHOD_POST,
'{"type": "Create"}', '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}',
array() array()
), ),
'expectedException' => UnauthorizedHttpException::class, 'expectedException' => UnauthorizedHttpException::class,
@ -159,10 +174,11 @@ class PostControllerTest extends TestCase
'request' => $this->makeRequest( 'request' => $this->makeRequest(
'https://example.com/actor/notreal/inbox', 'https://example.com/actor/notreal/inbox',
Request::METHOD_POST, Request::METHOD_POST,
'{"type": "Create"}', '{"type": "Create", "actor": "https://elsewhere.com/actor/1"}',
array( array(
'signed' => true,
'actor' => TestActivityPubObject::fromArray( 'actor' => TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://elsewhere.com/actor/1']
), ),
) )
), ),
@ -175,8 +191,9 @@ class PostControllerTest extends TestCase
Request::METHOD_POST, Request::METHOD_POST,
'', '',
array( array(
'signed' => true,
'actor' => TestActivityPubObject::fromArray( 'actor' => TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://elsewhere.com/actor/1']
), ),
) )
), ),
@ -189,8 +206,9 @@ class PostControllerTest extends TestCase
Request::METHOD_POST, Request::METHOD_POST,
'this is not JSON', 'this is not JSON',
array( array(
'signed' => 'true',
'actor' => TestActivityPubObject::fromArray( 'actor' => TestActivityPubObject::fromArray(
self::OBJECTS['https://example.com/actor/1'] self::OBJECTS['https://elsewhere.com/actor/1']
), ),
) )
), ),