-
Notifications
You must be signed in to change notification settings - Fork 5
/
pantheon_secure_login.module
188 lines (174 loc) · 6.34 KB
/
pantheon_secure_login.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<?php
/**
* @file
* Pantheon Secure Login module.
*/
/**
* Implements hook_menu().
*/
function pantheon_secure_login_menu() {
$items = array();
// Configuration.
$items['admin/config/people/pantheon-secure-login'] = array(
'title' => 'Pantheon Secure Login',
'description' => 'Manage your Pantheon Secure Login settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array('pantheon_secure_login_admin_form'),
'access arguments' => array('administer permissions'),
);
return $items;
}
/**
* Implements hook_boot().
*
* Very early check to see if we are on the right/wrong domain.
*/
function pantheon_secure_login_boot() {
if (pantheon_secure_login_is_enabled()) {
# Evaluate environment and redirect to HTTPS if we are logged in.
# Also, if live and not logged-in (or trying to log in), then standardize
# on desired "real" domain if enabled.
global $user;
if (!pantheon_secure_login_is_https()) {
# We are not under HTTPS. It may be time to take action.
if ($user->uid > 0 || (arg(0) == 'user' || arg(0) == 'admin')) {
# Uh-oh, we are logged in, trying to access admin pages, or user pages.
# This is not allowed under HTTP. Go log in on https with gotpantheon.
# TODO: it would be nice to have an interstitial page here rather than
# a blind redirect.
$location = 'https://' . pantheon_secure_login_domain() . '/user/login';
pantheon_secure_login_redirect($location);
}
}
// Now handle normalizing most pages on the "live" domain.
if ($_SERVER['PANTHEON_ENVIRONMENT'] === 'live') {
$live_fqdn = variable_get('pantheon_secure_login_live_domain', '');
# If we have a fqdn, and it doesn't match this one, and we're not logged
# in, or trying to log in, then standardize.
if ($live_fqdn !== '' && $live_fqdn !== $_SERVER['HTTP_HOST'] && $user->uid == 0) {
if (!(arg(0) == 'user' && arg(1) == 'login') && !(arg(0) == 'user' && arg(1) == '')) {
$location = 'http://' . $live_fqdn . $_SERVER['REQUEST_URI'];
pantheon_secure_login_redirect($location, 3600);
}
}
}
}
}
/**
* Implements hook_form_alter().
*
* Set user login form and block action to HTTPS.
*/
function pantheon_secure_login_form_alter(&$form, &$form_state, $form_id) {
if (pantheon_secure_login_is_enabled()) {
if ($form_id == 'user_login' || $form_id == 'user_login_block') {
$form['#action'] = 'https://' . pantheon_secure_login_domain() . $form['#action'];
}
}
}
/**
* Function to deliver the admin form.
*/
function pantheon_secure_login_admin_form($form, &$form_state) {
if (!pantheon_secure_login_is_pantheon()) {
$form['disabled'] = array(
'#type' => 'markup',
'#value' => '<p>'. t('You are not running this module on Pantheon, so it cannot be configured.') .'</p>',
);
return $form;
}
# TODO: warn if enabling this for the first time.
# TODO: check cookie domain and security settings.
$form['pantheon_secure_login_enabled'] = array(
'#type' => 'radios',
'#title' => t('Redirect logins and logged-in traffic to HTTPS.'),
'#options' => array('disabled' => t('Disabled'), 'enabled' => t('Enabled')),
'#default_value' => variable_get('pantheon_secure_login_enabled', 'disabled'),
'#description' => t('Force logins and logged-in users onto HTTPS using the "gotpantheon" domain?'),
);
$form['pantheon_secure_login_live_domain'] = array(
'#title' => t('Standardize my live traffic on a standard domain name.'),
'#type' => 'textfield',
'#description' => t('Fully qualified domain name to standardize on in LIVE for non-logged in users. For google and SEO goodness.'),
'#default_value' => variable_get('pantheon_secure_login_live_domain'),
);
return system_settings_form($form);
}
/**
* Validate the FQDN part so it's not a bunk domain.
*
* Borrowed regex from http://stackoverflow.com/questions/4654453/validating-if-string-is-a-fqdn-codeigniter
*
* TODO: awesomesauce checking if we are on Pantheon.
*/
function pantheon_secure_login_admin_form_validate($form, &$form_state) {
if ($form_state['input']['pantheon_secure_login_live_domain'] != '') {
if (preg_match('/(?=^.{1,254}$)(^(?:(?!\d|-)[a-z0-9\-]{1,63}(?<!-)\.)+(?:[a-z]{2,})$)/i', $form_state['input']['pantheon_secure_login_live_domain']) == 0) {
form_set_error('pantheon_secure_login_live_domain', t('This is not a valid domain name'));
return;
}
# TODO: curl the domain, determine if on Pantheon. For great justice.
}
}
/**
* Helper function to see if we are in fact on the platform or not.
*/
function pantheon_secure_login_is_pantheon() {
return isset($_SERVER['PANTHEON_ENVIRONMENT']);
}
/**
* Helper function to see if we are enabled and ready for action.
*/
function pantheon_secure_login_is_enabled() {
if (pantheon_secure_login_is_pantheon() === FALSE) {
return FALSE;
}
if (variable_get('pantheon_secure_login_enabled', 'disabled') === 'enabled') {
return TRUE;
}
return FALSE;
}
/**
* Helper function to determine if we are under SSL.
*/
function pantheon_secure_login_is_https() {
return (isset($_SERVER['HTTP_X_SSL']) && $_SERVER['HTTP_X_SSL'] == 'ON');
}
/**
* Helper function to do redirects.
*
* This will bail out if we are in PHP CLI mode.
*
* If no TTL, then do a 302. If TTL, do a 301 and cache it.
*/
function pantheon_secure_login_redirect($location, $ttl = FALSE) {
if (!isset($_SERVER['GATEWAY_INTERFACE']) ||
strpos($_SERVER['GATEWAY_INTERFACE'], 'CGI') === FALSE) {
# It appears we are running under the CLI. Don't do anything.
return FALSE;
}
if ($ttl) {
header('Cache-Control: public, max-age=' . $ttl);
header('HTTP/1.0 301 Moved Permanently');
}
else {
header('HTTP/1.0 302 Moved Temporarily');
}
header('Location: ' . $location);
exit();
}
/**
* Helper function for determining the proper domain name.
*
* Will use gotpantheon based on the PANTHEON_SITE_NAME env var.
*
* @TODO: potentially extend this to allow customers to use their prod domain
* name if they have a cert there. This would make it useful to Pro and
* above plans.
*/
function pantheon_secure_login_domain() {
if (isset($_SERVER['PANTHEON_SITE_NAME'] )) {
return $_SERVER['PANTHEON_ENVIRONMENT'] . '-' . $_SERVER['PANTHEON_SITE_NAME'] . '.gotpantheon.com';
}
return $_SERVER['HTTP_HOST'];
}