Laravel payum and paypal rest - paypal

I have setup the payum Paypal Rest. Credit card purchase into my laravel app for payment using credit card, everything is set but it's given me exception like:
A storage for model Payum\Paypal\Rest\Model\PaymentDetails was not
registered. There are storages for next models:
Payum\Core\Model\Payment, Payum\Core\Model\ArrayObject,
Payum\Core\Model\Payout.
AppServiceProvider.php
//For payment gateway...
$this->app->resolving('payum.builder', function(\Payum\Core\PayumBuilder $payumBuilder) {
$payumBuilder
// this method registers filesystem storages, consider to change them to something more
// sophisticated, like eloquent storage
->addDefaultStorages()
//->getPayum();
->addGateway('paypal_ec', [
'factory' => 'paypal_express_checkout',
'username' => config('payment.paypalusername'),
'password' => config('payment.paypalpassword'),
'signature' => config('payment.paypalsignature'),
'sandbox' => true
])
->addGateway('paypalRest', [
'factory' => 'paypal_rest',
'client_id' => config('payment.paypalclientid'),
'client_secret' => config('payment.paypalsecret'),
'config_path' => '%kernel.root_dir%/config/sdk_config.ini'
]);
});
prepare.php
$storage = $this->getPayum()->getStorage('Payum\Paypal\Rest\Model\PaymentDetails');
$payment = $storage->create();
.
.
.
Where I need to register storage for model Payum\Paypal\Rest\Model\PaymentDetails?

Payum Paypal Rest extension uses a model from the official Paypal's SDK lib. There is no storage for it by default and you provide one:
<?php
/** #var \Payum\Core\Storage\StorageInterface $storage */
$storage;
$payumBuilder->addStorage('Payum\Paypal\Rest\Model\PaymentDetails', $storage);
What you could also do is to create your own capture action that supports array and ArrayObject model from the Payum core and in that action, you get data from the array and set it to Paypal Rest model and do subrequest with it. Then set data back from the model to the array.
I must admit that the extension was created a long time ago as a proof of concept and haven't been updated for a long time. For example, it would be good to use basic models (from Payum core) in it.

Related

What is the best way to connect TYPO3 fe_users from an Azure AD with SAML 2?

I need to implement SSO on a TYPO3 intranet, where the fe_users are synchronized from an Azure AD. the platform will be in V9.
Is there a compatible extension that I haven't found yet ?
If no, what would be the best way to implement the automatic authentication with SAML 2.0 ?
thanks in advance,
Rachel
Thanks to #Rakel (and others) I managed to finally solve my SAML authentication requirement. Still I used a slightly different and more direct approach then described in her solution.
I used an Authentication Service to implement the SAML Login Process.
For handling the SAML login itself I used the library SimpleSamlPHP, which I can truly recommend. Its really simple and the provided frontend to test the SAML configuration comes really handy to test the Identity Provider (Idp) configuration without dealing with TYPO3.
For details please look into this: https://docs.typo3.org/m/typo3/reference-coreapi/master/en-us/ApiOverview/Authentication/Index.html
First you need to create a class which extends TYPO3\CMS\Core\Authentication\AuthenticationService. This class must implement the methods "getUser" and "authUser".
namespace Vendor\Extension\Service;
use SimpleSAML\Auth\Simple;
use TYPO3\CMS\Core\Authentication\AuthenticationService;
class SamlAuth extends AuthenticationService
{
public function getUser() {
// Create new Simple Auth with SimpleSamlPHP
$as = new Simple($config['sp']);
// Require authentication, this redirects you to the Idp and then comes back
$as->requireAuth();
// Get the attributes provides by your Idp
$attributes = $as->getAttributes();
// Please consult the API for details on fetchUserRecord
// Also the SAML attributes may vary depending on your Idp implementation
$user = $this->fetchUserRecord($attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'];
}
public function authUser(array $user): int {
return is_array($user) ? 200 : 0;
}
}
Then you need to register the service in your extensions "ext_localconf.php".
...
TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addService(
'my_extension',
'auth',
Vendor\Extension\Service\SamlAuth::class,
[
'title' => 'Saml Authentication for Frontend Users',
'description' => 'Authenticates FeUsers via Saml',
'subtype' => 'authUserFE,getUserFE',
'available' => true,
'priority' => 80,
'quality' => 80,
'os' => '',
'exec' => '',
'className' => Vendor\Extension\Service\SamlAuth::class
]
);
...
Please note:
This is just a over simplified version of my final code. Just to get you started on the idea.
Also you need to configure SimpleSamlPHP correctly. Please look at their documentation for details.
The method "getUser" is supposed to return an array holding the to be logged in FeUser with all its parameters.
The method "authUser" is only to return 200 or 0. Take a look at this link to understand which number are there to return: https://docs.typo3.org/m/typo3/reference-services/7.6/en-us/Authentication/Index.html#authentication-service-chain
After returning "200" the FeUser object is created and the user is logged in. No need to fiddle around with $GLOBALS['TSFE'] by yourself. This is a huge benefit, as it makes your code shorter and easier to read.
Nethertheless I learned a lot from reading through all the documentations and responses here and on Slacks TYPO3 channel.
Thanks to everybody who helped me. Greatly appreciated.
Yes we solved that requirements. We used SimpleSAMLphp to implement the authentication, following this great tutorial :
https://www.lewisroberts.com/2015/09/05/single-sign-on-to-azure-ad-using-simplesamlphp/.
When you are able to connect then you just have to implement a process to auto connect a fe_user when you get the saml user attributes.
Here is a simplified summary of the process:
if we reach a TYPO3 site url without being authenticated then redirection to a script like this :
// SimpleSamlPHP library
require_once (dirname(__FILE__) . /../../../../../../simplesamlphp/lib/_autoload.php');
//instanciation of a simple authentication
$as = new SimpleSAML_Auth_Simple('default-sp');
//requires authentication from Office 365
$as->requireAuth();
//retrieving information from the logged-in user
$attributes = $as->getAttributes();
//retrieve original url
$returnURL = $_GET['returnURL'];
//if a user is well connected
if($attributes){
//redirection to the TYPO3 site with the username
header('Location: /auth/?samlUident='.$attributes['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name'][0].'&recupURL='.$returnURL);
}
and here's a simplified summary of what the auth page does:
//if a get saml is in the url
if(\TYPO3\CMS\Core\Utility\GeneralUtility::_GP('samlUident')){
//recovering username for TYPO3 authentication
$loginData = array(
'uname' => \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('samlUident'), //username
'status' => 'login'
);
//TYPO3 session creation
$frontendUserAuthentication = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Authentication\\FrontendUserAuthentication');
$frontendUserAuthentication->checkPid = false;
$info = $frontendUserAuthentication->getAuthInfoArray();
$user_db = $frontendUserAuthentication->fetchUserRecord($info['db_user'], $loginData['uname']);
//if a user exists
if ($user_db){
//authentication
$GLOBALS['TSFE']->fe_user->forceSetCookie = TRUE;
$GLOBALS['TSFE']->fe_user->dontSetCookie = false;
$GLOBALS['TSFE']->fe_user->start();
$GLOBALS['TSFE']->fe_user->createUserSession($user_db);
$GLOBALS['TSFE']->fe_user->user = $user_db;
$GLOBALS['TSFE']->fe_user->setAndSaveSessionData('dummy', TRUE);
$GLOBALS['TSFE']->fe_user->loginUser = 1;
}
}
Cheers,
Rachel

Writing API best practice in Cakephp

i am creating a web application in cakephp 2.9. it has two use,
To provide API access to android and Ios devices
To serve Web pages(Normal web applicaiton)
currently i am developing the api part , i create a webserviceController.php file and write all the Api , Now i feel like the controller is too fatty,
i dont know which is the best practice to manage API's. now my webservice controllerhave more than 2000 lines of code..
now iam planning to seperate the each api's in different controller
can anyone suggest me a good practice for writing apis in cakephp
currently my code look like
class WebServicesController extends Controller
{
public $uses = null;
public $components = array('RequestHandler', 'Verification', 'AppContstant','PushNotification');
public function users()
{
//code to get users
//
$this->set(array(
'result' => $result,
'_serialize' => 'result'
));
}
and in my route.php
Router::mapResources('WebServices');
Router::parseExtensions();
Router::resourceMap(array(
array('action' => 'users', 'method' => 'GET', 'id' => false),
i have more around 43 api's in webserviceController,
How to manage API's cakephp
What is the best practice?
_serialize vs json_encode() which is fast?
How to versioning my API url ?
The simplest way of making an API in cakephp is print the a JSON directly from the controller and stop the rendering by die().
Official document suggests you to have an API view for the output, which is a standard MVC way and is a good practice. You can check out more here: https://book.cakephp.org/2.0/en/views/json-and-xml-views.html
Maybe you can reference how Croogo implemented it, this is a Cakephp based CMS.
They make API as a component to manage version and methods: https://github.com/croogo/croogo/blob/master/Croogo/Controller/Component/BaseApiComponent.php
This is an example of its URL routing in format /$version/$model/$method.$format/?$parameters
http://www.example.com/croogo-2.2.2/api/v1.0/nodes/lookup.json?type=page&title=how
Sibin Francis, You can use rest api class and include in you api controller
add following line at top
App::import('Vendor', 'REST', array('file' => 'Rest.inc.php'));
Public function yourFunctionName() {
if ($this->request->is("post")) { // Use your method name put/post/get/etc
$rest = new REST();
// Your logic here
return $rest->response(json_encode($data), response_code);
}
}
Its very easy and simple. Only you need to call vendor Rest Api class.

Looking for a start-to-finish how-to on Laravel 5.2 OAuth2 implementation

Quick background: I'm fairly experienced with PHP, but needed to build my first RESTful API. I figured I'd try Laravel (5.2) and am starting to feel pretty comfortable with it.
I started adding auth to my project over the weekend and I am really struggling to get it working. I got the basic Laravel Auth middleware working quickly, but I think I need to be using OAuth2 for production (I will be building a mobile app that will connect up to this server). I'm using the Luca Degasperi OAuth2 package, which seems to be pretty popular.
I reviewed the actual documentation: https://github.com/lucadegasperi/oauth2-server-laravel/tree/master/docs#readme)
I also went through this tutorial: https://medium.com/#mshanak/laravel-5-token-based-authentication-ae258c12cfea#.5lszb67xb
And, most recently, I found this thread about the need to seed the OAuth tables before anything will work: https://github.com/lucadegasperi/oauth2-server-laravel/issues/56
That's all great, but there are some minor differences in the most recent distribution of Laravel. For example, /app/Http/Kernel.php is slightly different from what's shown in some of the examples I found because it now uses middleware groups. I thought I handled those differences correctly (I added the OAuthExceptionHandlerMiddleware class to the 'web' section of $middlewareGroups instead of $middleware). I got my seeder working (the current oauth_scopes table only allows you to supply a description, so I had to slim down what was provided in the third link above).
If I put a test route in my 'web' group in routes.php, I would have thought this would require OAuth because I added OAuth to the 'web' middleware group in Kernel.php. That's not the case. My route works with no authentication if I do that.
I then explicitly added the OAuth middleware to my test route as follows:
Route::get('tests/events', ['middleware' => 'oauth', function() {
$events = App\Event::get();
return response()->json($events);
}]);
That causes a 500 error ("ErrorException in OAuth2ServerServiceProvider.php line 126: explode() expects parameter 2 to be string, object given").
I'm to feel pretty lost. Each of these packages seems to be shifting so quickly that there's no complete documentation on how to get this up and running.
What else do I need to do to get this functioning?
The following link is what finally got me un-stuck:
https://github.com/lucadegasperi/oauth2-server-laravel/blob/master/docs/authorization-server/password.md
Now that I have it working, I'll try and make this a complete how-to FOR PASSWORD GRANT TYPES ONLY. I didn't play with other grant types. So this assumes you're building something like a RESTful API where users will connect to it with a client app that you're going to build. So users will create a user account in your system and then when they send a REST request, the OAuth2 package will authenticate them and send them a token to stay logged in.
I'm using Laravel 5.2 and already had the basic Auth package up and running. Be advised that a lot of these steps seem to change even with incremental releases of Laravel or the OAuth2 package.
The first part of getting this working is fairly well documented already (https://github.com/lucadegasperi/oauth2-server-laravel/tree/master/docs#readme), but here's a summary just in case...
Edit the require section of your composer.json file to look something like this:
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.*",
"lucadegasperi/oauth2-server-laravel": "5.1.*"
},
Run composer update to download the package.
Open your config/app.php file and add the following two lines to the end of the providers section:
LucaDegasperi\OAuth2Server\Storage\FluentStorageServiceProvider::class,
LucaDegasperi\OAuth2Server\OAuth2ServerServiceProvider::class,
Also in config/app.php, add this line to the aliases array:
'Authorizer' => LucaDegasperi\OAuth2Server\Facades\Authorizer::class,
Now we start to do things a little differently from the documentation to accommodate the current version of Laravel...
Open app/Http/Kernel.php. Laravel now uses groups and it didn't used to. Update your $middlewareGroups to look like this:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
//Added for OAuth2 Server
\LucaDegasperi\OAuth2Server\Middleware\OAuthExceptionHandlerMiddleware::class,
//Commented out for OAuth2 Server
//\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
Also in app/Http/kernel.php, update $routeMiddleware to look like this:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Http\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
//Added for OAuth2 Server
'oauth' => \LucaDegasperi\OAuth2Server\Middleware\OAuthMiddleware::class,
'oauth-user' => \LucaDegasperi\OAuth2Server\Middleware\OAuthUserOwnerMiddleware::class,
'oauth-client' => \LucaDegasperi\OAuth2Server\Middleware\OAuthClientOwnerMiddleware::class,
'check-authorization-params' => \LucaDegasperi\OAuth2Server\Middleware\CheckAuthCodeRequestMiddleware::class,
'csrf' => App\Http\Middleware\VerifyCsrfToken::class,
];
You now have to set up your grant types. You used to do this all in one place in config\oauth2.php using an array with a closure for callback. With the most recent version of the OAuth2 server package, you can't use a closure for callback anymore. It has to be a string. So your grant_types should look something like this:
'grant_types' => [
'password' => [
'class' => '\League\OAuth2\Server\Grant\PasswordGrant',
'callback' => '\App\PasswordGrantVerifier#verify',
'access_token_ttl' => 3600
]
]
access_token_ttl is the duration that an auth token will be good for (in seconds). The main package documentation uses 3600 (1 hour) by default. You might want to try 604800 (1 week) instead -- at least during testing.
You now need to create the PasswordGrantVerifier class and verify method that you just called in the code section above. So you create a file App/PasswordGrantVerifier.php and use the following code (which is basically what used to go in the closure for callback).
<?php
namespace App;
use Illuminate\Support\Facades\Auth;
class PasswordGrantVerifier
{
public function verify($username, $password)
{
$credentials = [
'email' => $username,
'password' => $password,
];
if (Auth::once($credentials)) {
return Auth::user()->id;
}
return false;
}
}
You will need at least one row in the oauth_clients table before OAuth2 will work. You can insert something manually or create a seeder. To create a seeder, modify database/seeds/DatabaseSeeder.php and add the following to the end of the run() method:
$this->call(OAuthClientsTableSeeder::class);
Now create a file called database/seeds/OAuthClientsTableSeeder.php and enter something like this:
<?php
use Illuminate\Database\Seeder;
class OAuthClientsTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
//Add sample users
$oAuthClients = array(
array(
'id' => 'TEST_ENVIRONMENT',
'secret' => 'b17b0ec30dbb6e1726a17972afad008be6a3e4a5',
'name' => 'TEST_ENVIRONMENT'
)
);
foreach ($oAuthClients as $oAuthClient) {
App\OAuthClient::create($oAuthClient);
}
}
}
Run php artisan vendor:publish to publish the package configuration and migrations. Run php artisan migrate to set up the billion-or-so new tables for OAuth. Run php artisan db:seed to seed your database.
You can now set up some test routes in app\Http\routes.php. They should look something like this:
Route::post('oauth/access_token', function() {
return Response::json(Authorizer::issueAccessToken());
});
Route::group(['middleware' => 'oauth'], function () {
Route::get('authroute', function() {
//OAuth will be required to access this route
});
Route::post('postwithauth', function(Request $request) {
$userID = Authorizer::getResourceOwnerId();
$input = $request->input();
return response()->json(array('userID' => $userID, 'input' => $input));
});
});
Route::get('noauthroute', function () {
//No authorization will be required to access this route
});
Pay close attention to the postwithauth route I included above. The OAuth2 package recently changed how you access the user's ID and it took me quite a while to figure out how to get it.
Now that it's time for testing, point your browser to localhost:8000 (or whatever the path is for your test environment) and create a user account for yourself (this step just uses the standard Laravel Auth package).
Go into your HTTP client (I'm currently using Paw and I like it). Go to request->authorization->OAuth2 to set up authorization for the route you're going to test. For Grant Type, select Resource Owner Password Credentials. If you used the seed example I provided above, the Client ID is TEST_ENVIRONMENT, the Client Secret is b17b0ec30dbb6e1726a17972afad008be6a3e4a5, enter the username (email) and password you created through the web Auth interface, your Access Toekn URL will be something like localhost:8000/oauth/access_token (depending on how you set up your test environment), leave Scope blank, and Token should say Bearer. Click on Get Access Token then say Use Access Token when prompted.
That should be it!

PayPal NVP API - BMUpdateButton

I have a hosted subscribe button with PayPal, which I want to have an unlimited number of billing cycles. This is easy enough to set up through the PayPal web interface, by setting 'After how many cycles should billing stop?' to 'Never'. However, when I then update that button through the PayPal NVP API BMUpdateButton, the number of billing cycles shows to the user as '$25.00 AUD for one month' instead of '$25.00 AUD for each month'. The button still shows 'Never' as the value in the web interface, but when it is used, the button is set to complete after 1 month.
I have tried variations of L_OPTIONnTOTALBILLINGCYCLESx API parameter, but with no success. Any help or thoughts would be appreciated. For all I know, this is a subtle bug in PayPal itself. If anyone has reason to believe that if I switch from NVP to SOAP it will work, then that would also count as a solution.
Here is a sample of the parameters that I send through. I don't get any API errors, and the button updates correctly except for the total billing cycles.
'METHOD' => BMUpdateButton
'VERSION' => 117
'USER' => ...
'PWD' => ...
'SIGNATURE' => ...
'L_OPTION0SELECT0' => First Tier
'L_OPTION0PRICE0' => 25.00
'L_OPTION0BILLINGPERIOD0' => Month
'L_OPTION0BILLINGFREQUENCY0' => 1
'L_OPTION0TOTALBILLINGCYCLES0' => 0
'L_OPTION0SELECT1' => Second Tier
'L_OPTION0PRICE1' => 30.00
'L_OPTION0BILLINGPERIOD1' => Month
'L_OPTION0BILLINGFREQUENCY1' => 1
'L_OPTION0TOTALBILLINGCYCLES1' => 0
'HOSTEDBUTTONID' => ...
'BUTTONTYPE' => SUBSCRIBE
'OPTION0NAME' => Payment Scheme
'L_BUTTONVAR0' => currency_code=AUD
'L_BUTTONVAR1' => no_shipping=1
'L_BUTTONVAR2' => cancel_return=...
'L_BUTTONVAR3' => return=...
Thanks very much for any thoughts.
The below two parameters in your API call is related to the installment buttons and if you pass them with the subscription type button they will be ignored.
L_OPTION0BILLINGFREQUENCY0
L_OPTION0TOTALBILLINGCYCLES0
If you are looking to update the subscription billing cycles you need to pass these two parameters :
L_BUTTONVARn="src=1"
L_BUTTONVARn="srt=12"
If the above src=1 means profile is set to be recurring and srt=12 will set the billing cycle to 12 .
If you don't pass any of the parameter in the API call then by default "src" will be set to "0" meaning no recurrence which is similar to your case .

drupal, rules, flag, date

I am using drupal 6. I have a node called [classroom]. I would like to have a [vacancy register] associated with each classroom.
vacancy register is a cck type with:
- uid
- nid
- join date
I would like for each user to [register] for a vacancy. I think I can use flag for this.
When a user joins, I can use rules to action an email to be sent to the user and the [classroom]->cck_email field.
I would like a rule schedule to also run every 30 days ( configurable ) to alert the user to confirm their [registration].
1a. If no registration is confirmed, then 14 days later, the user is [unregistered] from the classroom.
1b. If user confirms registration ( by clicking on a button or url ). then the rule 1 runs again.
I would like to confirms if my approach to this is correct.
Update:
I have been playing around with signup, but there are the rules schedule aspect of it that I find hard customising to my liking.
I'm trying to write a rules event for signup_signup and signup_cancel, then action it through rules schedule. But there a bit of existing signup code I have to look through.
Have to do too much custom work to signup, so I thought, its easier to just do it with rules and flags. The downside is having to also create the UI for it.
For the signup module,
I have the following rules event.
Could this be reviewed please?
<http://drupal.org/node/298549>
function signup_rules_event_info() {
return array(
'signup_signup' => array(
'label' => t('User signups to classroom'),
'module' => 'Signup',
'arguments' => array(
'userA' => array('type' => 'user', 'label' => t('UserA, which adds userB.')),
'userB' => array('type' => 'user', 'label' => t('UserB, which is added to UserA\'s list.')),
),
),
);
}
I don't know what to do with the arguments list.
I haven't looked at the signup module for some time, but I think that might be a better module for your case. The flag module is a good choice too, but the signup module is more geared towards what you are doing. Users signing up for content like a classroom.