I am trying to setup an Oauth server using the pecl-php oauth library http://php.net/manual/en/book.oauth.php
This code assumes that the client has already received a user verified access token, for simplicity sake I've not included any database calls and have hardcoded matching values into my client and provider.
Class OauthVerify
{
private static $consumer_secret = 'f63ed7f7a8899e59d3848085c9668a0d';
private static $token_secret = '72814e6059441037152eecef2e8559a748b84259';
private $provider;
public function __construct()
{
$this->provider = new OAuthProvider();
$this->provider->consumerHandler(array($this,'consumerHandler'));
$this->provider->timestampNonceHandler(array($this,'timestampNonceHandler'));
$this->provider->tokenHandler(array($this,'checkAccessToken'));
}
//Check the client request
public function checkRequest()
{
try {
$this->provider->checkOAuthRequest();
} catch (Exception $Exception) {
return OAuthProvider::reportProblem($Exception);
}
return true;
}
public static function timestampNonceHandler($Provider)
{
//I'm leaving out this logic now, to keep it simple and for testing purposes
return OAUTH_OK;
}
public static function consumerHandler($Provider)
{
//I'm leaving out this logic now, to keep it simple and for testing purposes
$Provider->consumer_secret = self::$consumer_secret;
return OAUTH_OK;
}
public static function checkAccessToken($Provider)
{
$Provider->token_secret = self::$token_secret;
return OAUTH_OK;
}
}
The above code should give me the barebones I need to authenticate an Oauth request.
Before any particular route is executed I call the $OauthVerify->checkRequest() method which checks if the client request is valid, however the server keeps throwing a 'signatures do not match' error. I don't think that the problem is with the clients as I've tried both postman (for chrome) and a PHP implementation and they both generate the same signature. I have however for interest sake included my client call.
$consumer_key = '87d6d61e87f0e30d8747810ae40041d1';
$consumer_secret = 'f63ed7f7a8899e59d3848085c9668a0d';
$token= 'b9d55b3ec4b755d3fe25d7a781da1dfd044b5155';
$token_secret = '72814e6059441037152eecef2e8559a748b84259';
$timestamp = '1417515075';
$nonce = '9QV4rn';
$version = '1.0';
$method = 'GET';
$url = 'https://localhost/micro/v1/nappi';
try {
$oauth = new OAuth($consumer_key, $consumer_secret, OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_URI);
$oauth->enableDebug();
$oauth->disableSSLChecks();
$oauth->setNonce($nonce);
$oauth->setTimestamp($timestamp);
$oauth->setToken($token, $token_secret);
$oauth->setVersion($version);
$oauth->fetch("$url");
$json = json_decode($oauth->getLastResponse());
print_r($json);
}
catch(OAuthException $E) {
print_r($E);
}
I've burned a good couple of hours trying to figure this out, someone please help!
I finally managed to solve it, my .htaccess file had a rewrite rule that was processing a _url parameter for my framework. This parameter was ofcourse being included in the signature that the server generated. I simply instructed OAuth Provider to ignore the the _url parameter in my constructor:
$this->provider->setParam('_url',NULL);,
that was all it took, everything runs perfectly now.
Related
I am trying to use the Sinch Rest API with PHP to mute and unmute specific participants from Conference calls but have not been able to find an example of how to send an application signed request with PHP. I have been trying to work off of this documentation from Sinch here https://www.sinch.com/docs/voice/rest/index.html#muteunmuteconfparticipant
My initial guesses are that this would require the use of CURL and that I would also need to use similar pieces of this example to sign my application but I"m not sure how to combine the two. https://github.com/sinch/php-auth-ticket
Any help appreciated. Thanks!
edit: #cjensen I added this code snippet I've been working on to try and use as the signed request maker. It's very similar to that github link above
<?php
class SinchTicketGenerator
{
private $applicationKey;
private $applicationSecret;
public function __construct($applicationKey, $applicationSecret)
{
$this->applicationKey = $applicationKey;
$this->applicationSecret = $applicationSecret;
}
public function generateTicket()
{
$request = [
'command' => 'mute',
];
$requestJson = preg_replace('/\s+/', '', json_encode($request));
$requestBase64 = $this->base64Encode($requestJson);
$digest = $this->createDigest($requestJson);
$signature = $this->base64Encode($digest);
$requestSigned = $requestBase64.':'.$signature;
return $requestSigned;
}
private function base64Encode($data)
{
return trim(base64_encode($data));
}
private function createDigest($data)
{
return trim(hash_hmac('sha256', $data, base64_decode($this->applicationSecret), true));
}
}
$generator = new SinchTicketGenerator('app-key', 'app-secret');
$signedrequest = $generator->generateTicket();
echo $signedrequest;
?>
I have a function in my Laravel application that generates TwiML for a holding queue. It seems that when I try to dynamically generate the value for the waitUrl attribute, I end up getting a 500 server error during runtime. Routes are properly established and I'm able to view the correct XML at the waitURL in the browser. However, the error persists.
If I create a static XML file with the same exact content, or use a TwiML Bin, it works like a charm.
Here are the relevant functions:
public function wait() {
return $this->generateWaitTwiml();
}
public function onHold($agentId) {
return $this->generateHoldQueueTwiml($agentId, '/phone/wait');
}
private function generateHoldQueueTwiml($agentId, $waitUrl = null) {
$queue = $agentId . '_hold';
if ($waitUrl === null){
$waitUrl = 'path_to_static.xml';
}
$queue = $agentId . '_hold';
$response = new Twiml();
$response->enqueue(
$queue,
['waitUrl' => $waitUrl]
);
return response($response)->header('Content-Type', 'application/xml');
}
private function generateWaitTwiml() {
$response = new Twiml();
$response
->play('http://path_to_my.mp3');
return response($response)->header('Content-Type', 'application/xml');
}
This was resolved by excluding the URIs from the CSRF verification (in VerifyCsrfToken.php):
class VerifyCsrfToken extends Middleware {
protected $except = [
'uri/',
'uri2/*',
];
}
Using the ci-php-unit-test library to do unit tests for PHP/codeigniter, and unit testing controller methods.
Having trouble working out how to mock an external library that is installed using composer.
my SUT method is:
function twitter()
{
$this->load->model('misc/twitter_model');
$request_token = [];
$request_token['oauth_token'] = $_SESSION['twitter_oauth_token'];
$request_token['oauth_token_secret'] = $_SESSION['twitter_oauth_token_secret'];
if ( (isset($_GET['oauth_token'])
&& ($request_token['oauth_token'] !== $_GET['oauth_token'])))
{
log_message('info','abort something is wrong!');
}
else
{
$connection = new Abraham\TwitterOAuth\TwitterOAuth(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, $request_token['oauth_token'], $request_token['oauth_token_secret']);
$access_token = $connection->oauth("oauth/access_token", array("oauth_verifier" => $_REQUEST['oauth_verifier']));
$this->session->set_userdata('twitter_access_token',$access_token);
redirect(get_session('twitter_callback1'));
}
}
my test method (so far) is:
public function test_twitter()
{
$_SESSION['twitter_oauth_token'] = 'twitter_oauth_token';
$_SESSION['twitter_oauth_token_secret'] = 'twitter_oauth_token_secret';
$this->request->setCallable(
function (& $CI) {
// Get mock object
$twitter_oa = $this->getMockBuilder('TwitterOAuth')
->disableOriginalConstructor()
->setMethods(['oauth'])
->getMock();
$twitter_oa->method('oauth')
->willReturn('access_token');
}
);
$output = $this->request('GET','callbacks/twitter',['oauth_token'=>'twitter_oauth_token']);
var_export($output);
}
But the original library is being executed because it isn't being mocked - the $twitter_oa isn't being attached to the CI instance.
This is because the external library has not been instantiated after the codeigniter controller has been instantiated. (this is was the setCallable method does)
My question is, how can I mock TwitterOAuth after the codeigniter controller is instantiated so it can return set testing text?
(and obviously not instantiate the twitter Oauth library)
ok, so when you see a new Class(); in unit testing, you have to re-work something. This may not be the best option, but this works for me.
in the SUT, the controller code is now:
function twitter()
{
$this->load->model('misc/twitter_model');
$request_token = [];
$request_token['oauth_token'] = $_SESSION['twitter_oauth_token'];
$request_token['oauth_token_secret'] = $_SESSION['twitter_oauth_token_secret'];
if ( (isset($_GET['oauth_token'])
&& ($request_token['oauth_token'] !== $_GET['oauth_token'])))
{
log_message('info','abort something is wrong!');
}
else
{
$connection = $this->twitter_connection($request_token['oauth_token'],$request_token['oauth_token_secret']);
$access_token = $connection->oauth("oauth/access_token", array("oauth_verifier" => $_REQUEST['oauth_verifier']));
$this->session->set_userdata('twitter_access_token',$access_token);
redirect(get_session('twitter_callback1'));
}
}
/**
* #param $token
* #param $secret
* #return \Abraham\TwitterOAuth\TwitterOAuth
*
* #codeCoverageIgnore
*
*/
public function twitter_connection($token, $secret)
{
return new Abraham\TwitterOAuth\TwitterOAuth(
TWITTER_CONSUMER_KEY,
TWITTER_CONSUMER_SECRET,
$token,
$secret);
}
There is a new file in APPPATH.tests/mocks/external_libaries with:
class MockTwitterOAuth
{
public function oauth()
{
return 'access_token';
}
}
and the test code is now:
public function test_twitter()
{
$_SESSION['twitter_oauth_token'] = 'twitter_oauth_token';
$_SESSION['twitter_oauth_token_secret'] = 'twitter_oauth_token_secret';
$_SESSION['twitter_callback1'] = 'cb1';
require_once(APPPATH.'tests/mocks/external_libraries/MockTwitterOauth.php');
$twitter_connection = new MockTwitterOAuth();
MonkeyPatch::patchMethod('Callbacks',[
'twitter_connection'=>$twitter_connection
]);
$output = $this->request('GET','callbacks/twitter',['oauth_token'=>'twitter_oauth_token']);
$this->assertNull($output);
$this->assertResponseCode(HTTP_FOUND);
$this->assertRedirect(base_url('cb1'));
$this->assertEquals('access_token',$_SESSION['twitter_access_token']);
}
The trick is to have twitter connection return a new TwitterOAuth class normally, but when the system is unit testing, return the MockTwitterOAuth class that only has one method instead. This can be accomplished by monkeypatching the controller code.
Hope this answer is useful for others, and if you haven't used it already the https://github.com/kenjis/ci-phpunit-test is pretty good, even though it is hard to get started. Purchasing the companion book is recommended!
I am creating web service. So I created this soapcall:
public function GetLogon($uzivatel, $heslo){
$soap = new SoapClient('http://www.softhouse.cz/ezopconnector2/ezopconnector.asmx?wsdl');
$params = array('uzivatel'=>$uzivatel, 'password'=>$heslo);
$response = $soap->__soapCall("EzopLogon", array($params));
var_dump($response);
}
call it in presenter like this, but it's not relevant I think:
$this->me->GetLogon("administrator", "a");
my problem is that this function should return me a session (of user).. does anybody know how can I get this session for future use? (for example for logout)
thanks a lot I am a novice, so dont yel at me :D
Update:
code for login:
public function GetLogon($uzivatel, $heslo){
$soapClient = new SoapClient('http://www.softhouse.cz/ezopconnector2/ezopconnector.asmx?wsdl');
$params = array('uzivatel'=>$uzivatel, 'heslo'=>$heslo);
$this->session = $soapClient->__soapCall("EzopLogon", array($params));
var_dump($this->session);
}
session saved as public variable in class:
public $session;
Code of function where session si required:
public function GetCtiSezSdruzAdd2(){
$soapClient = new SoapClient('http://www.softhouse.cz/ezopconnector2/ezopconnector.asmx?wsdl');
$params = array('Session'=>$this->session);
return $soapClient->__soapCall("EzopCtiSeznamSdruzenychAdresaru", array($params));
}
and call in presenter:
$this->me->GetCtiSezSdruzAdd2();
searching for a good authentication method for my rest api i came a cross this :
"What is stateless authentication?
Again, stateless means without state. But, how can we identify a user from a token without having any state on the server? Surprisingly, it’s very easy! just send all the data to the client.
So what would you store/send (send to client/network)? The most trivial example is an access token. Access tokens usually have a unique ID, an expiration date and the ID of the client that created it. To store this, you would just put this data into a JSON object, and encode it using base64."
Now, having a self-contained token, you will need to make sure that nobody can manipulate the data. For this you should sign it using MAC algorithm or any other digital signature method available.
This is a little confusing for me , how can i validate the access token when the request comes(nothing stored to match it), but i find it a good idea and i want to implement it, any advice will be very helpful.
My rest api is very simple I receive every request to index.php , then i create new object with the request class to analyze every element of the request.
request class looks like this :
<?php
class Request {
public $url_elements;
public $verb;
public $parameters;
public function __construct() {
$this->verb = $_SERVER['REQUEST_METHOD'];
$this->url_elements = explode('/', $_SERVER['PATH_INFO']);
$this->parseIncomingParams();
$this->format = 'json';
if(isset($this->parameters['format'])) {
$this->format = $this->parameters['format'];
}
return true;
}
public function parseIncomingParams() {
$parameters = array();
if (isset($_SERVER['QUERY_STRING'])) {
parse_str($_SERVER['QUERY_STRING'], $parameters);
}
$body = file_get_contents("php://input");
$content_type = false;
if(isset($_SERVER['CONTENT_TYPE'])) {
$content_type = $_SERVER['CONTENT_TYPE'];
}
switch($content_type) {
case "application/json":
$body_params = json_decode($body);
if($body_params) {
foreach($body_params as $param_name => $param_value) {
$parameters[$param_name] = $param_value;
}
}
$this->format = "json";
break;
case "application/x-www-form-urlencoded":
parse_str($body, $postvars);
foreach($postvars as $field => $value) {
$parameters[$field] = $value;
}
$this->format = "html";
break;
default:
break;
}
$this->parameters = $parameters;
}
}
?>
After this i proceed with the proper controller that is the first element after index.php/
Thank you very much for your time and sorry if the question is not very clear as i am new to rest :/