diff -r 000000000000 -r 9d2c4f04a0d0 plugins/yubikey/corelib.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/yubikey/corelib.php Thu Feb 26 01:08:22 2009 -0500 @@ -0,0 +1,178 @@ +'; + if ( $value ) + { + $html .= '' . $lang->get('yubiauth_ctl_status_enrolled') . ''; + $atext = $lang->get('yubiauth_ctl_btn_change_key'); + $classadd = ' abutton_green'; + } + else + { + $html .= '' . $lang->get('yubiauth_ctl_status_empty') . ''; + $atext = $lang->get('yubiauth_ctl_btn_enroll'); + $classadd = ''; + } + $html .= ' ' . $atext . ''; + if ( $value ) + { + $html .= ' ' + . $lang->get('yubiauth_ctl_btn_clear') . + ''; + } + $html = '' + . $html; // ''; + return $html; +} + +function yubikey_validate_otp($otp) +{ + $api_key = getConfig('yubikey_api_key'); + $api_id = getConfig('yubikey_api_key_id'); + if ( !$api_key || !$api_id ) + { + return array( + 'success' => false, + 'error' => 'missing_api_key' + ); + } + if ( !preg_match('/^[cbdefghijklnrtuv]{44}$/', $otp) ) + { + return array( + 'success' => false, + 'error' => 'otp_invalid_chars' + ); + } + // make HTTP request + require_once( ENANO_ROOT . '/includes/http.php' ); + $auth_url = getConfig('yubikey_auth_server', YK_DEFAULT_VERIFY_URL); + $auth_url = preg_replace('#^https?://#i', '', $auth_url); + if ( !preg_match('#^(\[?[a-z0-9-:]+(?:\.[a-z0-9-:]+\]?)*)(/.*)$#', $auth_url, $match) ) + { + return array( + 'success' => false, + 'error' => 'invalid_auth_url' + ); + } + $auth_server =& $match[1]; + $auth_uri =& $match[2]; + $req = new Request_HTTP($auth_server, $auth_uri); + $req->add_get('id', strval($api_id)); + $req->add_get('otp', $otp); + $req->add_get('h', yubikey_sign($req->parms_get)); + + $response = $req->get_response_body(); + + if ( $req->response_code != HTTP_OK ) + { + return array( + 'success' => false, + 'error' => 'http_response_error' + ); + } + $response = trim($response); + $response_nosig = preg_replace('/^h=(.+?)$/m', '', $response); + if ( !preg_match_all('/^([a-z0-9_]+)=(.*?)$/m', $response, $matches) ) + { + return array( + 'success' => false, + 'error' => 'malformed_response' + ); + } + $response = array(); + foreach ( $matches[0] as $i => $_ ) + { + $response[$matches[1][$i]] = $matches[2][$i]; + } + // make sure we have a status + if ( !isset($response['status']) ) + { + return array( + 'success' => false, + 'error' => 'response_missing_status' + ); + } + // verify response signature + // MISSING_PARAMETER is the ONLY situation under which an unsigned response is acceptable + if ( $response['status'] !== 'MISSING_PARAMETER' ) + { + if ( !isset($response['h']) ) + { + return array( + 'success' => false, + 'error' => 'response_missing_sig' + ); + } + if ( yubikey_sign($response) !== $response['h'] ) + { + return array( + 'success' => false, + 'error' => 'response_invalid_sig' + ); + } + } + if ( $response['status'] === 'OK' ) + { + return array( + 'success' => true + ); + } + else + { + return array( + 'success' => false, + 'error' => strtolower("response_{$response['status']}") + ); + } +} + +function yubikey_sign($arr) +{ + static $api_key = false; + + ksort($arr); + if ( isset($arr['h']) ) + unset($arr['h']); + + if ( !$api_key ) + { + $api_key = getConfig('yubikey_api_key'); + $api_key = hexencode(base64_decode($api_key), '', ''); + } + + $req = array(); + foreach ( $arr as $key => $val ) + { + $req[] = "$key=$val"; + } + $req = implode('&', $req); + + $sig = hmac_sha1($req, $api_key); + $sig = hexdecode($sig); + $sig = base64_encode($sig); + + return $sig; +} + +$plugins->attachHook('compile_template', 'yubikey_attach_headers($this);'); + +function yubikey_attach_headers(&$template) +{ + $template->add_header(''); + $template->add_header(''); +} +