Skip to content

Commit

Permalink
feat(Integrations: Laravel): add login to user login and signup events
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Rulleau <alexandre.rulleau@datadoghq.com>
  • Loading branch information
Leiyks committed Nov 27, 2024
1 parent 76bb60b commit 95dcd66
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 28 deletions.
33 changes: 30 additions & 3 deletions src/DDTrace/Integrations/Laravel/LaravelIntegration.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ public function isArtisanQueueCommand()
]);
}

public function getLoginFromArgs($args): string
{
$allowList = ["email", "username"];

foreach ($allowList as $key) {
if (isset($args[$key])) {
return $args[$key];
}
}

return null;
}

/**
* @return int
*/
Expand Down Expand Up @@ -195,11 +208,13 @@ function ($This, $scope, $args) use ($integration) {
) {
return;
}

$id = null;
if (isset($args[1]['id'])) {
$id = $args[1]['id'];
}
\datadog\appsec\track_user_signup_event($id, [], true);

\datadog\appsec\track_user_signup_event($id, $this->getLoginFromArgs($args[1]), [], true);
}
},
'recurse' => true,
Expand Down Expand Up @@ -344,7 +359,8 @@ function ($This, $scope, $args, $loginSuccess) use ($integration) {
if ($loginSuccess || !function_exists('\datadog\appsec\track_user_login_failure_event')) {
return;
}
\datadog\appsec\track_user_login_failure_event(null, false, [], true);

\datadog\appsec\track_user_login_failure_event(null, $this->getLoginFromArgs($args[0]), false, [], true);
}
);

Expand All @@ -362,15 +378,20 @@ function ($This, $scope, $args) use ($integration) {
) {
return;
}

$metadata = [];

if (isset($args[1]['name'])) {
$metadata['name'] = $args[1]['name'];
}

if (isset($args[1]['email'])) {
$metadata['email'] = $args[1]['email'];
}

\datadog\appsec\track_user_login_success_event(
\method_exists($args[1], 'getAuthIdentifier') ? $args[1]->getAuthIdentifier() : '',
$this->getLoginFromArgs($args[1]),
$metadata,
true
);
Expand All @@ -393,15 +414,18 @@ function ($This, $scope, $args) use ($integration) {
}

$metadata = [];

if (isset($args[0]['name'])) {
$metadata['name'] = $args[0]['name'];
}

if (isset($args[0]['email'])) {
$metadata['email'] = $args[0]['email'];
}

\datadog\appsec\track_user_login_success_event(
\method_exists($args[0], 'getAuthIdentifier') ? $args[0]->getAuthIdentifier() : '',
$this->getLoginFromArgs($args[0]),
$metadata,
true
);
Expand All @@ -417,7 +441,8 @@ function ($This, $scope, $args, $loginSuccess) use ($integration) {
if ($loginSuccess || !function_exists('\datadog\appsec\track_user_login_failure_event')) {
return;
}
\datadog\appsec\track_user_login_failure_event(null, false, [], true);

\datadog\appsec\track_user_login_failure_event(null, $this->getLoginFromArgs($args[0]), false, [], true);
}
);

Expand All @@ -435,8 +460,10 @@ function ($This, $scope, $args) use ($integration) {
) {
return;
}

\datadog\appsec\track_user_signup_event(
\method_exists($args[0], 'getAuthIdentifier') ? $args[0]->getAuthIdentifier() : '',
$this->getLoginFromArgs($args[0]),
[],
true
);
Expand Down
44 changes: 27 additions & 17 deletions tests/Appsec/Mock.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
namespace datadog\appsec;

if (!class_exists('datadog\appsec\AppsecStatus')) {
class AppsecStatus {
class AppsecStatus
{

private static $instance = null;
private $connection;

protected function __construct() {
}
protected function __construct() {}

public static function getInstance()
{
Expand All @@ -31,8 +31,8 @@ protected function getDbPdo()
}

/**
* Not all test are interested on events but frameworks are instrumented so this check is to avoid errors
*/
* Not all test are interested on events but frameworks are instrumented so this check is to avoid errors
*/
private function initiated()
{
return $this->getDbPdo()
Expand Down Expand Up @@ -75,8 +75,10 @@ public function getEvents(array $names = [], array $addresses = [])

foreach ($events as $event) {
$new = json_decode($event['event'], true);
if (empty($names) || in_array($new['eventName'], $names) &&
(empty($addresses) || !empty(array_intersect($addresses, array_keys($new))))) {
if (
empty($names) || in_array($new['eventName'], $names) &&
(empty($addresses) || !empty(array_intersect($addresses, array_keys($new))))
) {
$result[] = $new;
}
}
Expand All @@ -87,7 +89,8 @@ public function getEvents(array $names = [], array $addresses = [])
}

if (!function_exists('datadog\appsec\appsecMockEnabled')) {
function appsecMockEnabled() {
function appsecMockEnabled()
{
return getenv('APPSEC_MOCK_ENABLED') === "true";
}
}
Expand All @@ -96,12 +99,14 @@ function appsecMockEnabled() {
/**
* This function is exposed by appsec but here we are mocking it for tests
*/
function track_user_login_success_event($userId, $metadata, $automated) {
if(!appsecMockEnabled()) {
function track_user_login_success_event($userId, $userLogin, $metadata, $automated)
{
if (!appsecMockEnabled()) {
return;
}
$event = [
'userId' => $userId,
'userLogin' => $userLogin,
'metadata' => $metadata,
'automated' => $automated

Expand All @@ -114,12 +119,14 @@ function track_user_login_success_event($userId, $metadata, $automated) {
/**
* This function is exposed by appsec but here we are mocking it for tests
*/
function track_user_login_failure_event($userId, $exists, $metadata, $automated) {
if(!appsecMockEnabled()) {
function track_user_login_failure_event($userId, $userLogin, $exists, $metadata, $automated)
{
if (!appsecMockEnabled()) {
return;
}
$event = [
'userId' => $userId,
'userLogin' => $userLogin,
'exists' => $exists,
'metadata' => $metadata,
'automated' => $automated
Expand All @@ -133,12 +140,14 @@ function track_user_login_failure_event($userId, $exists, $metadata, $automated)
/**
* This function is exposed by appsec but here we are mocking it for tests
*/
function track_user_signup_event($userId, $metadata, $automated) {
if(!appsecMockEnabled()) {
function track_user_signup_event($userId, $userLogin, $metadata, $automated)
{
if (!appsecMockEnabled()) {
return;
}
$event = [
'userId' => $userId,
'userLogin' => $userLogin,
'metadata' => $metadata,
'automated' => $automated

Expand All @@ -152,9 +161,10 @@ function track_user_signup_event($userId, $metadata, $automated) {
* This function is exposed by appsec but here we are mocking it for tests
* @param array $params
*/
function push_address($key, $value) {
if(!appsecMockEnabled()) {
return;
function push_address($key, $value)
{
if (!appsecMockEnabled()) {
return;
}
AppsecStatus::getInstance()->addEvent([$key => $value], 'push_address');
}
Expand Down
23 changes: 15 additions & 8 deletions tests/Integrations/Laravel/AutomatedLoginEventsTestSuite.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ protected function ddSetUp()
protected function login($email)
{
$this->call(
GetSpec::create('Login success event', '/login/auth?email='.$email)
GetSpec::create('Login success event', '/login/auth?email=' . $email)
);
}

protected function createUser($id, $name, $email) {
protected function createUser($id, $name, $email)
{
//Password is password
$this->connection()->exec("insert into users (id, name, email, password) VALUES (".$id.", '".$name."', '".$email."', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi')");
$this->connection()->exec("insert into users (id, name, email, password) VALUES (" . $id . ", '" . $name . "', '" . $email . "', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi')");
}

public function testUserLoginSuccessEvent()
Expand All @@ -46,6 +47,7 @@ public function testUserLoginSuccessEvent()
$events = AppsecStatus::getInstance()->getEvents(['track_user_login_success_event']);
$this->assertEquals(1, count($events));
$this->assertEquals($id, $events[0]['userId']);
$this->assertEquals($email, $events[0]['userLogin']);
$this->assertEquals($name, $events[0]['metadata']['name']);
$this->assertEquals($email, $events[0]['metadata']['email']);
$this->assertTrue($events[0]['automated']);
Expand All @@ -59,6 +61,7 @@ public function testUserLoginFailureEvent()

$events = AppsecStatus::getInstance()->getEvents(['track_user_login_failure_event']);
$this->assertEquals(1, count($events));
$this->assertEquals($email, $events[0]['userLogin']);
$this->assertTrue($events[0]['automated']);
}

Expand All @@ -68,18 +71,19 @@ public function testUserSignUp()
$name = 'somename';
$password = 'somepassword';

$this->call(
GetSpec::create('Signup', sprintf('/login/signup?email=%s&name=%s&password=%s',$email, $email, $password))
);
$this->call(
GetSpec::create('Signup', sprintf('/login/signup?email=%s&name=%s&password=%s', $email, $name, $password))
);

$users = $this->connection()->query("SELECT * FROM users where email='".$email."'")->fetchAll();
$users = $this->connection()->query("SELECT * FROM users where email='" . $email . "'")->fetchAll();

$this->assertEquals(1, count($users));

$signUpEvent = AppsecStatus::getInstance()->getEvents(['track_user_signup_event']);

$this->assertTrue($signUpEvent[0]['automated']);
$this->assertEquals($users[0]['id'], $signUpEvent[0]['userId']);
$this->assertEquals($users[0]['email'], $signUpEvent[0]['userLogin']);
}

public function testLoggedInCalls()
Expand All @@ -98,7 +102,10 @@ public function testLoggedInCalls()
$this->call(GetSpec::create('Behind auth', '/behind_auth'));

$events = AppsecStatus::getInstance()->getEvents([
'track_user_login_success_event','track_user_login_failure_event', 'track_user_signup_event']);
'track_user_login_success_event',
'track_user_login_failure_event',
'track_user_signup_event'
]);
$this->assertEquals(0, count($events)); //Auth does not generate appsec events
$this->disableSession();
}
Expand Down

0 comments on commit 95dcd66

Please sign in to comment.