'checkbox',
'#title' => t('Use keys'),
'#default_value' => variable_get('services_use_key', TRUE),
'#description' => t('When enabled all method calls need to provide a validation token to autheciate themselves with the server.'),
);
$form['security']['options']['services_key_expiry'] = array(
'#type' => 'textfield',
'#prefix' => "
",
'#suffix' => "
",
'#title' => t('Token expiry time'),
'#default_value' => variable_get('services_key_expiry', 30),
'#description' => t('The time frame for which the token will be valid. Default is 30 secs'),
);
$form['security']['options']['services_use_sessid'] = array(
'#type' => 'checkbox',
'#title' => t('Use sessid'),
'#default_value' => variable_get('services_use_sessid', TRUE),
'#description' => t('When enabled, all method calls must include a valid sessid. Only disable this setting if the application will user browser-based cookies.')
);
return $form;
}
function _services_keyauth_security_settings_validate($form_state) {
if (isset($form_state['input']['services_key_expiry']) && !preg_match('/^\d+$/', $form_state['input']['services_key_expiry'])) {
form_set_error('services_key_expiry', t('The token expiry time must specified in whole seconds as a number'));
}
}
function _services_keyauth_security_settings_submit($form_state) {
// Store all values from "our" form as variables.
$options = _services_keyauth_security_settings();
foreach ($options['security']['options'] as $key => $field) {
$value = isset($form_state['input'][$key]) ? $form_state['input'][$key] : 0;
variable_set($key, $value);
}
}
function _services_keyauth_alter_methods(&$methods) {
// Skip this if no services have been activated
if (!is_array($methods) || empty($methods)) {
return;
}
// sessid arg
$arg_sessid = array(
'#name' => 'sessid',
'#type' => 'string',
'#description' => t('A valid sessid.'),
);
$arg_domain_time_stamp = array(
'#name' => 'domain_time_stamp',
'#type' => 'string',
'#description' => t('Time stamp used to hash key.'),
);
$arg_nonce = array(
'#name' => 'nonce',
'#type' => 'string',
'#description' => t('One time use nonce also used hash key.'),
);
// domain arg
$arg_domain_name = array(
'#name' => 'domain_name',
'#type' => 'string',
'#description' => t('A valid domain for the API key.'),
);
// api_key arg
$arg_api_key = array(
'#name' => 'hash',
'#type' => 'string',
'#description' => t('A valid API key.'),
);
foreach ($methods as $key => &$method) {
// set method defaults
switch ($method['#method']) {
case 'system.connect':
$method['#key'] = FALSE;
$method['#auth'] = FALSE;
break;
default:
$method['#key'] = TRUE;
$method['#auth'] = TRUE;
}
if ($method['#auth'] && variable_get('services_use_sessid', TRUE)) {
array_unshift($method['#args'], $arg_sessid);
}
if ($method['#key'] && variable_get('services_use_key', TRUE)) {
array_unshift($method['#args'], $arg_nonce);
array_unshift($method['#args'], $arg_domain_time_stamp);
array_unshift($method['#args'], $arg_domain_name);
array_unshift($method['#args'], $arg_api_key);
}
}
}
function _services_keyauth_alter_browse_form(&$form, $method) {
foreach ($method['#args'] as $key => $arg) {
switch ($arg['#name']) {
case 'hash':
$form['arg'][$key] = array(
'#title' => 'Hash',
'#type' => 'textfield',
'#value' => t('Gets generated after form submission'),
'#disabled' => TRUE,
);
break;
case 'sessid':
$form['arg'][$key]['#default_value'] = session_id();
break;
case 'domain_name':
$form['arg'][$key]['#default_value'] = $_SERVER['HTTP_HOST'];
break;
case 'domain_time_stamp':
$form['arg'][$key] = array(
'#title' => 'Timestamp',
'#type' => 'textfield',
'#value' => t('Gets generated after form submission'),
'#disabled' => TRUE,
);
break;
case 'nonce':
$form['arg'][$key]['#default_value'] = user_password();
break;
}
}
}
function _services_keyauth_authenticate_call($method, $method_name, &$args) {
if ($method['#key'] && variable_get('services_use_key', TRUE)) {
$hash = array_shift($args);
$domain = array_shift($args);
$timestamp = array_shift($args);
$nonce = array_shift($args);
$expiry_time = $timestamp + variable_get('services_key_expiry', 30);
if ($expiry_time < REQUEST_TIME) {
return services_error(t('Token has expired.'), 401);
}
$has_rows = (bool) db_query_range("SELECT 1 FROM {services_timestamp_nonce} WHERE domain = :domain AND nonce = :nonce", 0, 1, array(':domain' => $domain, ':nonce' => $nonce))->fetchField();
// Still in time but has it been used before
if ($has_rows) {
return services_error(t('Token has been used previously for a request. Re-try with another nonce key.', 401));
}
else{
db_insert('services_timestamp_nonce')
->fields(array('domain', 'timestamp', 'nonce'))
->values(array(
'domain' => $domain,
'timestamp' => $timestamp,
'nonce' => $nonce,
))
->execute();
}
$api_key = db_query("SELECT kid FROM {services_keys} WHERE domain = :key", array(':key' => $domain))->fetchField('kid');
//if (!services_keyauth_validate_key($api_key, $timestamp, $domain, $nonce, $method_name, $hash_parameters, $hash)) {
if ($hash != services_get_hash($timestamp, $domain, $nonce, $method, $args)) {
return services_error(t('Invalid API key.'), 401);
}
$has_rows = (bool) db_query_range("SELECT 1 FROM {services_key_permissions} WHERE kid = :kid AND method = :method", 0, 1, array(':kid' => $api_key, ':method' => $method_name))->fetchField();
if (!$has_rows) {
return services_error(t('Access denied.'), 401);
}
}
// Add additonal processing for methods requiring session
$session_backup = NULL;
if ($method['#auth'] && variable_get('services_use_sessid', TRUE)) {
$sessid = array_shift($args);
if (empty($sessid)) {
return t('Invalid sessid.');
}
$session_backup = services_session_load($sessid);
}
}
function _services_keyauth_alter_browse_form_submit($method, &$args) {
if ($method['#key'] && variable_get('services_use_key', TRUE)) {
$args_stripped = $args;
for ($i = 1; $i <= 4; $i++) {
array_shift($args_stripped);
}
$args[2] = time();
$args[0] = services_get_hash($args[2], $args[1], $args[3], $method, $args_stripped);
}
}