I have developed an ASP.NET Web Service that performs queries to a database. Now I am developing a PHP Web site that consumes the Web Service for anything that requires access to the database. I have written the following function which creates a new SoapClient to consume the Web Service:
function get_soap_client()
{
if (!file_exists('wsdl_path.txt')
return NULL;
if (!$file = fopen('wsdl_path.txt', 'r'))
return NULL;
$path = fgets($file);
fclose($file);
return new SoapClient($path);
}
I have already tested this function as means to get a client to a stateless Web Service, and it does work. For example, this is my Web site's login function (whose control flow is not affected by state):
function try_login($user, $pass)
{
$client = get_soap_client();
// ASP.NET Web Services encapsulate all inputs in a single object.
$param = new stdClass();
$param->user = $user;
$param->pass = $pass;
// Execute the WebMethod TryLogin and return its result.
// ASP.NET Web Services encapsulate all outputs in a single object.
return $client->TryLogin($param)->TryLoginResult;
}
Which in turn calls the following WebMethod:
[WebMethod(EnableSession = true)]
public bool TryLogin(string user, string pass)
{
SqlParameter[] pars = new SqlParameter[2];
pars[0] = new SqlParameter("#User", SqlDbType.VarChar, 20);
pars[0].Value = user;
pars[1] = new SqlParameter("#Pass", SqlDbType.VarChar, 20);
pars[1].Value = pass;
// The Stored Procedure returns a row if the user and password are OK.
// Otherwise, it returns an empty recordset.
DataTable dt = Utilities.RetrieveFromStoredProcedure('[dbo].[sp_TryLogin]', pars);
if (dt.Rows.Count == 0) // Wrong user and/or password
{
Context.Session.Abandon();
return false;
}
else
return true;
}
However, I don't know whether the Web Service's Context.Session data is preserved between consecutive requests made from SoapClient objects retrieved by get_soap_client(). So I have the following questions:
Is the Web Service's Context.Session data preserved between consecutive requests made from a SoapClient object retrieved by get_soap_client()?
Is the Web Service's Context.Session data preserved between consecutive requests made from different SoapClient objects retrieved on the fly as I need them?
If the answer to the previous question is "no", is there any way to serialize the SoapClient's session data into a PHP state variable?
Ah, you mean is it sending the SESSION ID. I imagine you'll need to call __setCookie manually to set a cookie with the SESSION ID to your web service.
http://php.net/manual/en/soapclient.setcookie.php
Related
I use external libraries to communicate with external systems. Communication is via Soap.
I provide the library with a set of data in a simple way. She checks the data, sends the request, and receives the reply. Converts the response to its object and returns.
How can I access the SoapClient object without making changes to the external library?
For this object, I need the original data. Request, response, headers.
Is it possible to do?
EDIT:
A simple example of using one of the many external libraries:
class fedex {
public function trackShipment($number)
{
$trackRequest = new TrackServiceTrackRequest();
$trackRequest->WebAuthenticationDetail->UserCredential->Key = $this->getAccessNumber();
$trackRequest->WebAuthenticationDetail->UserCredential->Password = $this->getAccountPassword();
$trackRequest->ClientDetail->AccountNumber = $this->getAccountNumber();
$trackRequest->ClientDetail->MeterNumber = $this->getMeterNumber();
$trackRequest->SelectionDetails[0]->PackageIdentifier->Value = $number;
$request = new TrackServiceRequest();
return $request->getTrackReply($trackRequest);
}
}
$fedex = new fedex();
$result = $fedex->trackShipment('123456789');
How to get original xml with request and header that was sent by library without modifying it?
The TrackServiceRequest() object does not access the SoapClient() object.
I'm developing REST API server in PHP, which I plan to call by client application, but I want to prevent direct API accesss via browser.
E.g. say I have GET call on "HOST/api/article/id" which would return article with given id to the client application. But when I type "HOST/api/article/id" in my browser, the article shouldn't be returned - I want nothing to happen (for example just return empty page or 403).
Is this possible?
If yes, is it common practice? (I mean is it something one would normally want to do or is it obscure and/or violates HTTP/REST principles and should be avoided?)
If yes, how do I do it? (in PHP/.htaccess/etc.)
I know I could implement some kind of authorization (like API key) instead which would allow API execution only for the client applications, which I plan to do anyway.
(I'm kind of new to this so maybe my question doesn't make sense. Maybe I misunderstood something very basic about how REST/HTTP/whatever works. If so, please tell me.)
The normal approach would be:
Your client (using a public key), requests token from the server, token checks if key is valid and not blacklisted (you can expire/blacklist old keys if they are compromised)
Token is sent every time
Server only responds if there is a token
Depending what your requirements, there is a hacky way to implement this.
Have a variable, called "my_client" with value true
On each request from your application sent the variable in your headers.
Server only servers information if "my_client" variable is in the headers
The cons with this approach is, that is not really secure, because each person can see the requests they make. Therefor can notice this extra information.
Its so simple that you can write it for a minute, just as a test.
<?php
if(!$_SERVER['HTTP_MY_CLIENT']){
header("HTTP/1.1 403 FORBIDEN");
}
Extending on the concept of using a header variable, we can use it as "semi token", which will mean we will populate the value with a random value that only we can read.
So the concept is this:
Client -> Request random value
Client /sets value in each request header/
Client -> makes requests to the server.
<?php
/* A basic API token and authentication class. */
class SimpleToken
{
/* Creates a salt based on the passed key that is good for the current day */
public static function generateSalt($key)
{
return md5($key . date('Y-m-d'));
}
/* Crytographically combine the key and the salt to produce a token */
public static function generateToken($key, $content)
{
$package = $content . $key;
return crypt($package);
}
/* Generate a relatively strong SSL key */
public static function generateKey()
{
$config = array(
"digest_alg" => "sha512",
"private_key_bits" => 4096,
"private_key_type" => OPENSSL_KEYTYPE_RSA,
);
//Create a private key
$res = openssl_pkey_new($config);
//Extract the private part of the key
openssl_pkey_export($res, $private_key);
//Shorten it up for use in an API
return md5($private_key);
}
/* Verify the authenticity of the passed key/token pair */
public static function isAuthentic($key, $content, $token)
{
$package = $content . $key;
if(crypt($package, $token) == $token)
{
return true;
}
else
{
return false;
}
}
}
Background: I've been drafted to maintain and update a flash/flex/as3 front-end to website using php on the backend. I'm getting better at it, but I'm still new to the environment.
I need some processed information received back in the return handler of a POST. I thought it would be clever to do the next POST within the return handler. In other words, I've got something like this:
private function finishThis():void
{
var s:HTTPService = new HTTPService();
rq.action = "do_something";
s.url = "inc/php/test.php";
s.method = "POST";
s.request = rq;
s.requestTimeout = 120000;
s.addEventListener(ResultEvent.RESULT, doSomethingRH);
s.send();
s.disconnect(); // That's a test, it didn't help
}
and then in doSomethingRH(), I've got
private function doSomethingRH(event:ResultEvent):void
{
doSomethingElse();
}
private function doSomethingElse():void
{
var s:HTTPService = new HTTPService();
rq.action = "do_something_else";
s.url = "inc/php/test.php";
s.method = "POST";
s.request = rq;
s.requestTimeout = 120000;
s.addEventListener(ResultEvent.RESULT, doSomethingElseRH);
s.send();
s.disconnect(); // That's new, it wasn't there before
}
All of this works as expected using http://localhost (WAMP). But online, though I have backend indications that function do_something_else runs (so far), but function doSomethingElseRH() never gets called. Instead, I get the error I've seen from several posts :
[RPC Fault faultString="HTTP request error" faultCode="Server.Error.Request" faultDetail="Error: [IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2032: Stream Error. URL: http://test.net/inc/php/test.php"]. URL: http://test.net/inc/php/test.php"]
The problem pointed out most often is too many simultaneous connections. I don't need to do multiple connections, but thought perhaps I had them since I was starting the new POST in the previous POST return handler. Instead of calling doSomethingElse() directly, I added an event and did a dispatchEvent() to call it, but at least according to the call stack shown in FlashDevelop, the eventual call to doSomethingElse() was under the doSomethingRH() function (still learning this stuff). And all of that is conjecture based on a post I saw about getting the HTTPService instance from within event delivered to the return handler.
My ultimate question is, how can I achieve sequential POSTs like this without the error?
And if I'm getting the error because of the way I'm chaining them together, is there a clean-up function I can do so that when the return handler is called, the connection can be fully closed?
Update - it's fine
A pdf engine was being called within both functions, one to create a base file, the other to append some pages. It was working fine, but was updated recently. Blocking those activities allowed the http flow to work as expected, no disconnect() needed.
The best I can say for this is it's an example of chaining calls together that I haven't seen online, I suppose that's something.
It's possible that you s.disconnect(); too soon (hence PHP file is not found). Why disconnect immediately after .send before that even gets a chance to do anything? File access on hard drive is faster than between web server. If still failing then try adding a delay (ie: disconnect, then start a timer that counts to 3 seconds) before attempting to do doSomethingElse();...
Untested but try :
public var s:HTTPService; //make one and re-use
private function finishThis():void
{
s = new HTTPService();
rq.action = "do_something";
s.url = "inc/php/test.php";
s.method = "POST";
s.request = rq;
s.requestTimeout = 120000;
s.addEventListener(ResultEvent.RESULT, doSomethingRH);
s.send();
}
...then in doSomethingRH() :
private function doSomethingRH(event:ResultEvent):void
{
s.disconnect(); //is now finished so disconnect before re-use
doSomethingElse();
}
private function doSomethingElse():void
{
s = new HTTPService();
rq.action = "do_something_else";
s.url = "inc/php/test.php";
s.method = "POST";
s.request = rq;
s.requestTimeout = 120000;
s.addEventListener(ResultEvent.RESULT, doSomethingElseRH);
s.send();
}
h t t p should be http
relative urls are relative to where the swf is loaded from... i would have a baseUrl variable that you want to be the relative url
I'm creating a project which uses CakePHP framework, and the PHP OAuth module.
The reason I'm using the module over a Vendor plugin is because the APIs need to have data/custom headers sent to them or else they generate 500s, and I know the standard PHP module does this well.
The issue is that when I use OAuth->fetch("http://www.example.com" ...), CakePHP redirects the external fetch request to my localhost (which I'm developing on), thus resulting in no data being generated.
It looks like the only way I can get external data is by using CakePHP's HTTPSocket class, but that doesn't allow me to send that data I need to send to the OAuth provider.
Does anyone know how to turn off this routing, or if I should be doing something differently?
UPDATE : Currently code is as follows:
public function createClient() {
$client = new OAuth(
'key',
'secret'
);
$client->disableSSLChecks();
if ($accessToken = $this->getAccessToken() !== false) {
$client->setToken(
$accessToken[$this->accessTokenKeyKeyname],
$accessToken[$this->accessTokenSecretKeyname]
);
}
return $client;
}
$url = 'http://example.com';
$client = $this->createClient();
$client->fetch($url, null, OAUTH_HTTP_METHOD_GET);
The request/access tokens are generated successfully, but the fetch continues to redirect to localhost, instead of example.com (example.com being used as an example URL).
EDIT Originally I thought Oauth2 is the way to go but maybe it is not. I'll leave that out of this question for now as it is confusing things.
I'm creating a mobile app (Android/iOS). I'd like the user to enter their credentials (user/pass) in the mobile device which would then get sent to my server (Joomla CMS) to verify the credentials and create/send a token. I don't want to store the user/pass on the device just the token.
In addition this token needs to have a timeout to be refreshed when needed. Such as credentials have changed.
At this point I'm trying to figure out what the architecture of this will look like.
Are there any tutorials on how you can achieve this (ideally with Joomla)? Anything that someone could point me to?
You should post the username and password from the mobile app and from there on you should follow the solution provided in this question:
https://stackoverflow.com/a/2188969/900617
The end solution is to create my own Joomla component. Pretty much everything is in my controller. Not the final code but something like this will work.
defined('_JEXEC') or die;
jimport('joomla.application.component.controller');
class FooauthController extends JController
{
function __construct() {
// params
$jinput = JFactory::getApplication()->input;
$this->username = $jinput->get('user', '', 'STRING');
$this->password = $jinput->get('password', '', 'STRING');
$this->checkParameters();
}
private function checkParameters() {
// datatype checks
if ($this->username == '' || $this->password == '') {
header('HTTP/1.1 400 Bad Request', true, 400);
}
}
private function createToken() {
// token generation - what Joomla does (just an example)
jimport('joomla.user.helper');
$salt = JUserHelper::genRandomPassword(32);
$crypted = JUserHelper::getCryptedPassword($password, $salt);
$cpassword = $crypted.':'.$salt;
return $cpassword;
}
function execute() {
// Get the global JAuthentication object
jimport( 'joomla.user.authentication');
$auth = & JAuthentication::getInstance();
$credentials = array( 'username' => $this->username, 'password' => $this->password );
$options = array();
$response = $auth->authenticate($credentials, $options);
// success
if ($response->status === JAUTHENTICATE_STATUS_SUCCESS) {
$response->status = true;
echo json_encode($this->createToken());
} else {
// failed
$response->status = false;
echo json_encode($response);
}
}
}
This represents a component called com_fooauth. Now the native app will send a query like this:
http://www.myhost.com/index.php?option=com_fooauth&user=username&password=pass&format=raw
Kind of a short cut to put everything in the controller, but hopefully you get the idea.
I hope that I understand correctly your use case.
If you want to use oAuth, then your mobile apps are considered as the oAuth-client.
Your "server" holds the "protected resources", and it can be used only with oAuth access-token, so it is called "resource server". Now you want something to supply this access-token, so this is the identity-provider, AKA authentication server, e.g. Facebook, Google, (or implement one by your own).
The flow is (generally): the user (mobile app) tries to reach a protected resource; since it has no token, he is being redirected to the auth-server. the latter is responsible for the user/password login page, and creating the token.
If it is true - you still can implement everything by your own, without using Facebook/Google APIs, because oAuth has SPECs. However, it can be easier for you to use the providers' packages.
EDIT: reconsider the usage of oAuth
You use oAuth only if you want your webapp to support oAuth SPEC. There are several benefits, one of them is that you can use 3rd party identity provider, e.g. Yahoo! and use their identities without managing them. So if I have a user in Yahoo!, I can use your app without additional registrations (your app will have to support access-tokens from Yahoo!). But in your case, you are about to implement all the logic of identity-provider (forgot password, change password, registration, etc) plus supporting oAuth - and all of this without enjoying the benefits of oAuth at all! So - you have to reconsider the usage of oAuth...
You need to use their APIs as a base. They aren't going to just let you build your own API that connects to their database, that to them would look more like a password cracker than an API.
This isn't Joomla or a tutorial, (and I'm very rusty in php) that said...
First a few caveats:
* memcache isn't secure & this implementation has you putting username / password in: Be sure that it is safely behind a firewall, or else encrypt it first. Happy to give some pointers on that if you need it.
* memcache isn't guaranteed not to drop data if it runs out of memory. In practice it is reliable, but your app should handle that gracefully. If you don't want to lose data like that, just substitute something like couchbase for memcache.
* just returning a token in response to a login probably isn't super useful. I'd json-ize the token along with stuff like the user name, and any other info to get the app up and running without needing to make a second API call.
* the code below doesn't handle error cases, I can call them all out in more detail if that isn't obvious to you.
If it were me, I'd just use memcache to persist the tokens & map that token to the username & password that was originally passed. You can use the memcache time to live to get your expiration for free.
Send username / password to the server (ideally over https).
Create a random string or guid (eg: http://php.net/manual/en/function.uniqid.php or http://www.lateralcode.com/creating-a-random-string-with-php/) , this is your token
Store the username / password in memcache with that token as a key
Set a timeout
$token = createToken("user1234", "pass2324");
print "Token: $token \n\n";
$credentials = credtialsFromToken($token);
print "Credentials from the token: ";
var_dump($credentials);
print "\n\n";
function setup() {
$memcache = new Memcache;
$memcache->connect('localhost', 11211) or die ("Could not connect");
}
function createToken($user, $pass) {
$TOKEN_EXPIRE_TIME=60 * 60 * 24 * 30;
$credentials = array(
"user" => $user,
"pass" => $pass,
);
$token = uniqid( );
memcache_set($token, credentials, 'some variable', 0, 30);
return $token;
}
function credtialsFromToken($token) {
$credentials = memcache_get($token);
return $credentials;
}
If the token is incorrect or expired, they get an null credentials back and have to login.
Edit: cleaned it up into functions that appear to work in php...