Logins on my sites are very infrequent and are normally done by myself. I would like a way of getting email notification when someone logs in. This way I might be able to spot someone hacking into the site early on.
I am using Drupal 7.
Logins on my sites are very infrequent and are normally done by myself. I would like a way of getting email notification when someone logs in. This way I might be able to spot someone hacking into the site early on.
I am using Drupal 7.
A possible solution is to use the Rules module and create a custom rule like so:
That's really it (a kind of Rules 101 also if you want ...).
Here is a rule (in Rules import format) that should answer your question:
{ "rules_notify_about_login" : {
"LABEL" : "Notify admin about login",
"PLUGIN" : "reaction rule",
"ACTIVE" : false,
"OWNER" : "rules",
"REQUIRES" : [ "rules" ],
"ON" : { "user_login" : [] },
"IF" : [
{ "NOT user_has_role" : { "account" : [ "account" ], "roles" : { "value" : { "3" : "3" } } } }
],
"DO" : [
{ "mail" : {
"to" : "[site:mail]",
"subject" : "New login",
"message" : "Some user just completed a login to [site:name], located at [site:url].",
"language" : [ "" ]
}
}
]
}
}
The rule will be triggered (Rules Event) right after login was completed. For any user who does not have the role that matches "role id = 3
" (= Rules Condition), aka for any user who is not an administrator, it will send an appropriate eMail to the admin user of the site.
If you have the Rules UI enabled, you can just import the above rule. As an alternative just use the Rules UI to create a similar rule from scratch.
Some further refinements you may want to apply to the above sample rule:
Adapt the value (=3) of the role id to fit your needs or just omit the Rules Condition if you want to perform the Rules Action for any role.
Include relevant info about the user who performed a login (using available tokens about that user).
Adapt the eMail subject and content to fit your needs.
PS: This answer applies to D7, though for D8 it should be similar.
Sending eMails to be informed about such logins is perfectly possible, as explained in my prior answer. However, eMails may get lost, or may not ever arrive at its destination. So therefor, as an alternative (or supplement?), you might also want to create a "custom log" using the Message module, as further detailed below.
Use the Message module and create a custom Message Type for creating custom log records whenever a user performs a login. Here is a sample of such message type (in export format, which you should be able to import in your own site also):
{
"name" : "users_performing_login",
"description" : "Users performing login",
"argument_keys" : [ "@login_user_name", "@login_user_id" ],
"argument" : [],
"category" : "message_type",
"data" : {
"token options" : { "clear" : 0 },
"purge" : { "override" : 0, "enabled" : 0, "quota" : "", "days" : "" }
},
"language" : "",
"arguments" : null,
"message_text" : { "und" : [
{
"value" : "\u003Cp\u003EUser with name =\u0026nbsp;@login_user_name and uid =\u0026nbsp;@login_user_id just performed a login.\u003C\/p\u003E\r\n",
"format" : "filtered_html",
"safe_value" : "\u003Cp\u003EUser with name =\u00a0@login_user_name and uid =\u00a0@login_user_id just performed a login.\u003C\/p\u003E\n"
}
]
},
"rdf_mapping" : []
}
Some details about this Message Type:
Users performing login
User with name = @login_user_name and uid = @login_user_id just performed a login.
@login_user_name, @login_user_id
(*): The usage of these "Replacement tokens" is crucial here. For way more details about this (amazing) feature, refer to What's the purpose of "Replacement tokens" of a Message type?.
Create a rule with a Rules Action "Create entity" (of type "Message", and with Message Type the one created in the previous step). Here is a sample of such rule you could use (in Rules export format, which you should be able to import in your own site also if you have the Rules UI enabled):
{ "rules_logging_about_logins" : {
"LABEL" : "Custom logging about logins",
"PLUGIN" : "reaction rule",
"OWNER" : "rules",
"REQUIRES" : [ "rules" ],
"ON" : { "user_login" : [] },
"IF" : [
{ "NOT user_has_role" : { "account" : [ "account" ], "roles" : { "value" : { "3" : "3" } } } }
],
"DO" : [
{ "entity_create" : {
"USING" : {
"type" : "message",
"param_type" : "users_performing_login",
"param_user" : [ "account" ]
},
"PROVIDE" : { "entity_created" : { "log_record_created" : "Created log record" } }
}
},
{ "data_set" : {
"data" : [ "log-record-created:arguments:login-user-name" ],
"value" : [ "account:name" ]
}
},
{ "data_set" : {
"data" : [ "log-record-created:arguments:login-user-id" ],
"value" : [ "account:uid" ]
}
}
]
}
}
The Rules Event and Rules Conditions are similar to the rule in my prior answer. While the Rules Actions will take care of creating an appropriate Message. Also note the last 2 Rules Actions: these are to assign the appropriate values to the "Replacement tokens" used in the Message type.
The rule in the previous step will create a message (with a Message Type "Users performing login"). What is left is to create an appropriate view to browse these messages that get created.
Here is a (rather basic) view to "Show all existing messages." (in Views export format, which you should be able to import in your own site also if you have the Views UI enabled):
$view = new view();
$view->name = 'message';
$view->description = 'Show all existing messages.';
$view->tag = 'Message';
$view->base_table = 'message';
$view->human_name = 'Message';
$view->core = 7;
$view->api_version = '3.0';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
/* Display: Defaults */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->display->display_options['use_more_always'] = FALSE;
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'administer message types';
$handler->display->display_options['cache']['type'] = 'none';
$handler->display->display_options['query']['type'] = 'views_query';
$handler->display->display_options['query']['options']['query_comment'] = FALSE;
$handler->display->display_options['exposed_form']['type'] = 'basic';
$handler->display->display_options['pager']['type'] = 'full';
$handler->display->display_options['pager']['options']['items_per_page'] = '30';
$handler->display->display_options['pager']['options']['offset'] = '0';
$handler->display->display_options['pager']['options']['id'] = '0';
$handler->display->display_options['style_plugin'] = 'table';
$handler->display->display_options['style_options']['columns'] = array(
'timestamp' => 'timestamp',
'message_render' => 'message_render',
'name' => 'name',
);
$handler->display->display_options['style_options']['default'] = '-1';
$handler->display->display_options['style_options']['info'] = array(
'timestamp' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
),
'message_render' => array(
'align' => '',
'separator' => '',
),
'name' => array(
'sortable' => 1,
'default_sort_order' => 'asc',
'align' => '',
'separator' => '',
),
);
$handler->display->display_options['style_options']['sticky'] = TRUE;
/* No results behavior: Global: Text area */
$handler->display->display_options['empty']['area']['id'] = 'area';
$handler->display->display_options['empty']['area']['table'] = 'views';
$handler->display->display_options['empty']['area']['field'] = 'area';
$handler->display->display_options['empty']['area']['content'] = 'No messages created yet.';
$handler->display->display_options['empty']['area']['format'] = 'filtered_html';
/* Relationship: Message: User uid */
$handler->display->display_options['relationships']['user']['id'] = 'user';
$handler->display->display_options['relationships']['user']['table'] = 'message';
$handler->display->display_options['relationships']['user']['field'] = 'user';
/* Field: Message: Timestamp */
$handler->display->display_options['fields']['timestamp']['id'] = 'timestamp';
$handler->display->display_options['fields']['timestamp']['table'] = 'message';
$handler->display->display_options['fields']['timestamp']['field'] = 'timestamp';
$handler->display->display_options['fields']['timestamp']['date_format'] = 'short';
/* Field: Message: Render message (Get text) */
$handler->display->display_options['fields']['message_render']['id'] = 'message_render';
$handler->display->display_options['fields']['message_render']['table'] = 'message';
$handler->display->display_options['fields']['message_render']['field'] = 'message_render';
$handler->display->display_options['fields']['message_render']['label'] = 'Text';
$handler->display->display_options['fields']['message_render']['element_label_colon'] = FALSE;
$handler->display->display_options['fields']['message_render']['hide_alter_empty'] = FALSE;
/* Field: User: Name */
$handler->display->display_options['fields']['name']['id'] = 'name';
$handler->display->display_options['fields']['name']['table'] = 'users';
$handler->display->display_options['fields']['name']['field'] = 'name';
$handler->display->display_options['fields']['name']['relationship'] = 'user';
$handler->display->display_options['fields']['name']['label'] = 'User';
/* Sort criterion: Message: Timestamp */
$handler->display->display_options['sorts']['timestamp']['id'] = 'timestamp';
$handler->display->display_options['sorts']['timestamp']['table'] = 'message';
$handler->display->display_options['sorts']['timestamp']['field'] = 'timestamp';
$handler->display->display_options['sorts']['timestamp']['order'] = 'DESC';
/* Filter criterion: Message: Type */
$handler->display->display_options['filters']['type']['id'] = 'type';
$handler->display->display_options['filters']['type']['table'] = 'message';
$handler->display->display_options['filters']['type']['field'] = 'type';
$handler->display->display_options['filters']['type']['exposed'] = TRUE;
$handler->display->display_options['filters']['type']['expose']['operator_id'] = 'type_op';
$handler->display->display_options['filters']['type']['expose']['label'] = 'Message type';
$handler->display->display_options['filters']['type']['expose']['operator'] = 'type_op';
$handler->display->display_options['filters']['type']['expose']['identifier'] = 'type';
/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page_1');
$handler->display->display_options['path'] = 'admin/content/message';
$handler->display->display_options['menu']['type'] = 'tab';
$handler->display->display_options['menu']['title'] = 'Messages';
$handler->display->display_options['menu']['description'] = 'A list of all messages.';
$handler->display->display_options['menu']['weight'] = '0';
$handler->display->display_options['menu']['name'] = 'management';
After you enabled the view, you should navigate to /admin/content/message
in your site, where you should see some views result similar to this one (assuming some users performed a login after you enabled the view):
Timestamp Text
08/03/2017 - 11:21 User with name = Pierre.Vriens and uid = 3 just performed a login.
08/03/2017 - 10:03 User with name = Dries.Buytaert and uid = 4 just performed a login.
08/02/2017 - 19:17 User with name = Hillary.Trump and uid = 911 just performed a login.
08/01/2017 - 11:55 User with name = Donald.Clinton and uid = 7 just performed a login.
So with this Views result, you have a permanent (custom) log, without the risk of eMails getting lost, or eMails that never arrive. Especially at times when you want to investigate possible hacking, this is IMO a much more solid solution as compared to just "sending an eMail" ... Which IT auditors must love also.
a) Tuning the layout of the custom log records
The Message Text in the above scenario is rather basic (apart from some fixed text, it only includes the user's name and user's id). However, the real magic is in the "Replacement tokens": virtually any token that you have available in the custom rule, can be passed along to the Message text to be created. Combined with the zillion of tokens already made available via the Message module, it implies that you can make your Message Text to be whatever you want.
b) Receiving eMail notifications
By using the Message module, you may also combine it with using the Message Notify module. Some details about it (from its project page):
... provides a method for sending a message via a notifier plugin. Message Notify comes with plugins for email and SMS and may be extended to other transport mechanisms as required.
Message Notify is part of the message stack, a suite of modules that provide a framework for messaging and notifications.
There is not a lot of documentation available about the Message module, which is what makes it a hidden Drupal gem. A possible way to get started with it, and to get an idea of the kind of things it can be used for, is to also have a look at these tutorials:
PS: This answer applies to D7.