From 492d039fc9564795b15f2a4d4a0bc388e9690fa1 Mon Sep 17 00:00:00 2001 From: stickevi Date: Mon, 28 Aug 2017 09:30:39 -0700 Subject: [PATCH 1/3] Functional Validations for differing message format. --- tests/FunctionalValidationsTest.php | 148 ++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 tests/FunctionalValidationsTest.php diff --git a/tests/FunctionalValidationsTest.php b/tests/FunctionalValidationsTest.php new file mode 100644 index 0000000..1cb34ab --- /dev/null +++ b/tests/FunctionalValidationsTest.php @@ -0,0 +1,148 @@ + "Notification", + 'MessageId' => "9438aee6-d476-5e20-ba25-ff24bf09d6ce", + 'TopicArn' => "arn:aws:sns:us-west-2:604091128280:testing1", + 'Subject' => "A subject", + 'Message' => "A message", + 'Timestamp' => "2017-06-20T00:15:59.380Z", + 'SignatureVersion' => "1", + 'Signature' => "WT7qMHW+jPdj/brSAX7M1jbP5OoPjn9pYmGQqrWeQgbMyVvz3D2sV72ldhCxQLqj/3TLtcTyErVqzT3AfQ8Vk55Rzxd1xnBufJ+0vIyH98b82pKOqRHOqlB72la5nY9/GF/p71BXmIChQpfv/CEZumexgLWnweJsqSMe82I6/eMmrhVZdKpBvz4Sqj+wNQW+0eYEc9bdZmEKuYIvrvTGm1MWkXmqUGuCGj5o3vFFn1GTtM895B3MyMgaSeDHI08CVfs9y1nLcrxwMvqpkHZmIwTi1jzSipYMRD8FVF6Wvq0Scy+FoYSnOWHpEsELI0SGddSqYgli9ROYiqi3DQhvHw==", + 'SigningCertURL' => "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem", + 'UnsubscribeURL' => "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:b061e4fd-c468-458d-9736-91c8c0c18e29", + ] + ], + [ + [ + 'Type' => "Notification", + 'MessageId' => "7317aaf2-e97a-5cf3-8123-fb3a48fabd2a", + 'TopicArn' => "arn:aws:sns:us-west-2:604091128280:testing1", + 'Message' => "A subject-less message", + 'Timestamp' => "2017-06-24T17:20:00.581Z", + 'SignatureVersion' => "1", + 'Signature' => "Lvtgxo8P2C3XUKT8fC7sfMRhxoK6dn/ed9B1DClmJ9GNuFF73G27lhKUsKWrLReawa+v7C1UY49qQb+lSMsBiTV0Hx7L2OKJjzll4fx+G09h2P8OK43Jk6/W05+xU0uvch6Ktp3XrBcI6KNyGFio5GAR2rCBHjdh8MsEYAWRtaVCBqJTLqnHscivOJD8u/m807wDbDhh9cQ5WnvjerUjtrDAfQJN5vHLjEPbL1owtu2FzC3rOHUL9j4TGOdZi2jhUYv8jwzNnJ05bhbtKd6HxKcTcv1JCp/4NLPa8LWYnbLRvWooDQdF2hr56EF6EKDzTtAWagoNYztwSvosQXNK+Q==", + 'SigningCertURL' => "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem", + 'UnsubscribeURL' => "https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:f0dd49ac-c33d-471e-812d-1f0e5116c711", + ] + ], + ]; + } + + public function getLambdaFixtures() + { + return [ + [ + [ + 'Type' => 'Notification', + 'MessageId' => '9438aee6-d476-5e20-ba25-ff24bf09d6ce', + 'TopicArn' => 'arn:aws:sns:us-west-2:604091128280:testing1', + 'Subject' => 'A subject', + 'Message' => 'A message', + 'Timestamp' => '2017-06-20T00:15:59.380Z', + 'SignatureVersion' => '1', + 'Signature' => 'WT7qMHW+jPdj/brSAX7M1jbP5OoPjn9pYmGQqrWeQgbMyVvz3D2sV72ldhCxQLqj/3TLtcTyErVqzT3AfQ8Vk55Rzxd1xnBufJ+0vIyH98b82pKOqRHOqlB72la5nY9/GF/p71BXmIChQpfv/CEZumexgLWnweJsqSMe82I6/eMmrhVZdKpBvz4Sqj+wNQW+0eYEc9bdZmEKuYIvrvTGm1MWkXmqUGuCGj5o3vFFn1GTtM895B3MyMgaSeDHI08CVfs9y1nLcrxwMvqpkHZmIwTi1jzSipYMRD8FVF6Wvq0Scy+FoYSnOWHpEsELI0SGddSqYgli9ROYiqi3DQhvHw==', + 'SigningCertUrl' => 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem', + 'UnsubscribeUrl' => 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:7118d01a-202e-4a65-a372-f46b0994bdae', + ] + ], + [ + [ + 'Type' => 'Notification', + 'MessageId' => '7317aaf2-e97a-5cf3-8123-fb3a48fabd2a', + 'TopicArn' => 'arn:aws:sns:us-west-2:604091128280:testing1', + 'Subject' => null, + 'Message' => 'A subject-less message', + 'Timestamp' => '2017-06-24T17:20:00.581Z', + 'SignatureVersion' => '1', + 'Signature' => 'Lvtgxo8P2C3XUKT8fC7sfMRhxoK6dn/ed9B1DClmJ9GNuFF73G27lhKUsKWrLReawa+v7C1UY49qQb+lSMsBiTV0Hx7L2OKJjzll4fx+G09h2P8OK43Jk6/W05+xU0uvch6Ktp3XrBcI6KNyGFio5GAR2rCBHjdh8MsEYAWRtaVCBqJTLqnHscivOJD8u/m807wDbDhh9cQ5WnvjerUjtrDAfQJN5vHLjEPbL1owtu2FzC3rOHUL9j4TGOdZi2jhUYv8jwzNnJ05bhbtKd6HxKcTcv1JCp/4NLPa8LWYnbLRvWooDQdF2hr56EF6EKDzTtAWagoNYztwSvosQXNK+Q==', + 'SigningCertUrl' => 'https://sns.us-west-2.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem', + 'UnsubscribeUrl' => 'https://sns.us-west-2.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:us-west-2:604091128280:testing1:7118d01a-202e-4a65-a372-f46b0994bdae', + ] + ], + ]; + } + + private function getMockCertServerClient() + { + return function () { + return self::$certificate; + }; + } + + /** + * @dataProvider getHttpFixtures + * + * @param array $messageData + */ + public function testValidatesHttpFixtures($messageData) + { + $validator = new MessageValidator($this->getMockCertServerClient()); + $message = new Message($messageData); + + $this->assertTrue($validator->isValid($message)); + $this->assertNotEmpty($message['SigningCertURL']); + } + + /** + * @dataProvider getLambdaFixtures + * + * @param array $messageData + */ + public function testValidatesLambdaFixtures($messageData) + { + $validator = new MessageValidator($this->getMockCertServerClient()); + $message = new Message($messageData); + + $this->assertTrue($validator->isValid($message)); + $this->assertNotEmpty($message['SigningCertUrl']); + } +} From 87706c393ec1cbcc3a5a54cf377deaa64e6791d9 Mon Sep 17 00:00:00 2001 From: stickevi Date: Mon, 28 Aug 2017 13:01:23 -0700 Subject: [PATCH 2/3] Make *URL or *Url a valid key suffix when constructing a Message --- src/Message.php | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Message.php b/src/Message.php index 890b780..5c8ec26 100644 --- a/src/Message.php +++ b/src/Message.php @@ -15,10 +15,15 @@ class Message implements \ArrayAccess, \IteratorAggregate 'TopicArn', 'Type', 'Signature', - 'SigningCertURL', + ['SigningCertURL', 'SigningCertUrl'], 'SignatureVersion', ]; + private static $subscribeKeys = [ + ['SubscribeURL', 'SubscribeUrl'], + 'Token' + ]; + /** @var array The message data */ private $data; @@ -81,7 +86,7 @@ public function __construct(array $data) if ($data['Type'] === 'SubscriptionConfirmation' || $data['Type'] === 'UnsubscribeConfirmation' ) { - $this->validateRequiredKeys($data, ['SubscribeURL', 'Token']); + $this->validateRequiredKeys($data, self::$subscribeKeys); } $this->data = $data; @@ -125,7 +130,23 @@ public function toArray() private function validateRequiredKeys(array $data, array $keys) { foreach ($keys as $key) { - if (!isset($data[$key])) { + $keyIsArray = is_array($key); + if (!$keyIsArray) { + $found = isset($data[$key]); + } else { + $found = false; + foreach ($key as $keyOption) { + if (isset($data[$keyOption])) { + $found = true; + break; + } + } + } + + if (!$found) { + if ($keyIsArray) { + $key = $key[0]; + } throw new \InvalidArgumentException( "\"{$key}\" is required to verify the SNS Message." ); From a51483fa5f5fe1f361870df86e38278ccfe27c16 Mon Sep 17 00:00:00 2001 From: stickevi Date: Mon, 28 Aug 2017 13:02:35 -0700 Subject: [PATCH 3/3] Create a standard Message object from a Lambda style Message when validating. --- src/MessageValidator.php | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/MessageValidator.php b/src/MessageValidator.php index dd4c24c..e84a917 100644 --- a/src/MessageValidator.php +++ b/src/MessageValidator.php @@ -27,6 +27,30 @@ class MessageValidator private static $defaultHostPattern = '/^sns\.[a-zA-Z0-9\-]{3,}\.amazonaws\.com(\.cn)?$/'; + private static function isLambdaStyle(Message $message) + { + return isset($message['SigningCertUrl']); + } + + private static function convertLambdaMessage(Message $lambdaMessage) + { + $keyReplacements = [ + 'SigningCertUrl' => 'SigningCertURL', + 'SubscribeUrl' => 'SubscribeURL', + 'UnsubscribeUrl' => 'UnsubscribeURL', + ]; + + $message = clone $lambdaMessage; + foreach ($keyReplacements as $lambdaKey => $canonicalKey) { + if (isset($message[$lambdaKey])) { + $message[$canonicalKey] = $message[$lambdaKey]; + unset($message[$lambdaKey]); + } + } + + return $message; + } + /** * Constructs the Message Validator object and ensures that openssl is * installed. @@ -55,6 +79,10 @@ public function __construct( */ public function validate(Message $message) { + if (self::isLambdaStyle($message)) { + $message = self::convertLambdaMessage($message); + } + // Get the certificate. $this->validateUrl($message['SigningCertURL']); $certificate = call_user_func($this->certClient, $message['SigningCertURL']);