Using symonfy as a REST API, I would like the server not to send such headers on a 401 :
WWW-Authenticate : Basic realm=XXX
but something like
WWW-Authenticate : myOwnBasic realm=XXX
How can I overload the BasicAuthenticationEntryPoint class or make my own entry point class for basic auth ?
I finally found the solution :
You need to override this paramater in parameters.yml :
security.authentication.basic_entry_point.class: NAMESAPCE\YOURCUSTOM_CLASS
And create a file where you prefer (I made it in MyBundle\Security\Http\EntryPoint) looking like :
<?php
namespace NAMESAPCE;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint;
class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint
{
private $realmName;
public function __construct($realmName)
{
$this->realmName = 'XXX';
}
/**
* {#inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$response = new Response();
$response->headers->set('WWW-Authenticate', sprintf('myOwnBasic realm="%s"', $this->realmName));
$response->setStatusCode(401);
return $response;
}
}
Related
I am creating a custom API for SuiteCRM. When I attempt to run the new API from {CRM Home}/custom/service/v4_1_custom I receive an 'HTTP ERROR 500'. There are not errors in the error_log file or the SuiteCRM.log file.
I have followed the method in the following two url's
https://fayebsg.com/2013/05/extending-the-sugarcrm-api-updating-dropdowns/
https://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_10.0/Integration/Web_Services/Legacy_API/Extending_Web_Services/
registry.php
<?php
require_once('service/v4_1/registry.php');
class registry_v4_1_custom extends registry_v4_1
{
protected function registerFunction()
{
parent::registerFunction();
$this->serviceClass->registerFunction('test', array(), array());
}
}
SugarWebServicesImplv4_1_custom.php
<?php
if(!defined('sugarEntry'))define('sugarEntry', true);
require_once('service/v4_1/SugarWebServiceImplv4_1.php');
class SugarWebServiceImplv4_1_custom extends SugarWebServiceImplv4_1
{
/**
* #return string
*/
public function test()
{
LoggerManager::getLogger()->warn('SugerWebServiceImplv4_1_custom test()');
return ("Test Worked");
} // test
} // SugarWebServiceImplv4_1_custom
I found the answer to this issue.
In the file {SuiteCRM}/include/entryPoint.php there are many files that are included thru require_once. In this list of require_once files, there were 4 files that were set as require not require_once. These were classes and therefore could not be included a second time. I changed these to require_once and the HTTP Error 500 went away and the custom APIs started working.
I want use a route to get the complete collection and, if available, a filtered collection.
so my route:
$app->get("/companies", \App\Handler\CompanyPageHandler::class, 'companies');
My Handler for this route:
use App\Entity\Company;
use App\Entity\ExposeableCollection;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class CompanyPageHandler extends AbstractHandler
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
$categories = new ExposeableCollection();
foreach (['test', 'test1', 'test3'] as $name) {
$category = new Company();
$category->setName($name);
$categories->addToCollection($category);
}
return $this->publish($categories);
}
}
When getting this route /companies, i get the expected collection
[{"name":"test"},{"name":"test1"},{"name":"test3"}]
So now i change the route
$app->get("/companies[/:search]", \App\Handler\CompanyPageHandler::class, 'companies');
It's all fine when i'm browsing to /companies.
But if i try the optional parameter /companies/test1 then i got an error
Cannot GET http://localhost:8080/companies/test1
my composer require section:
"require": {
"php": "^7.1",
"zendframework/zend-component-installer": "^2.1.1",
"zendframework/zend-config-aggregator": "^1.0",
"zendframework/zend-diactoros": "^1.7.1 || ^2.0",
"zendframework/zend-expressive": "^3.0.1",
"zendframework/zend-expressive-helpers": "^5.0",
"zendframework/zend-stdlib": "^3.1",
"zendframework/zend-servicemanager": "^3.3",
"zendframework/zend-expressive-fastroute": "^3.0"
},
In Zend Framework 2 and Symfony4 this route definition works fine. So im confused.
Why my optional parameter doesn't work?
That's because you are using https://github.com/nikic/FastRoute router and correct syntax would be:
$app->get("/companies[/{search}]", \App\Handler\CompanyPageHandler::class, 'companies');
or be more strict and validate search param something like this:
$app->get("/companies[/{search:[\w\d]+}]", \App\Handler\CompanyPageHandler::class, 'companies');
My challenge here is to find the best way to test a Symfony (3.4) API application using Behat/Mink for functionnal test, in my CICD platform.
Because my testing processes must be called in a shell script, all the tests must be very linear. I have no way to start a standalone webserver like Apache or the PHP/Symfony webserver. Also, Docker is not an option.
For the moment, I can successfully test the GET verbs of the API using the Mink syntax :
-- file test.feature
#function1
Scenario Outline: Test my api
When I go to "/api/v1/hello"
Then the response is JSON
The "I go to" instruction is implemented by Mink (http://docs.behat.org/en/v2.5/cookbook/behat_and_mink.html) and it emulates a GET request only. When this instruction is called by BeHat, the app Symfony kernel is "spawned" and the "api/v1/hello" method is called internally : there is no network trafic, no TCP connection, there is no need for a dedicated webserver (apache, or the symfony standalone server). It looks like Behat is emulating a webserver and start by itself the Symfony app it its own user space.
Now I want to test the POST verbs of my API, with a json payload, but unfortunally Mink do not have other verbs than GET.
I have read some articles over the web (keyword : behat test post api) but all I have seen is based on a Guzzl/Curl client. So a real client-to-server connection is made to http://localhost and a real webserver have to respond to the request.
I want the Symfony API to be called internally without using an other webserver.
Is there a way to do that ? How to test a Symfony REST API and specially the POST verb without needing a standalone server to reply ?
Thank you.
Here is how I do a functional test of a POST API, with BeHat, without a local running webserver :
test.feature :
#function1
Scenario Outline: Test my api
Given I have the payload
"""
{ "data":"object"}
"""
When I request "POST /api/v1/post"
Then the response is JSON
The featureContext file implement two functions :
"I Have The Payload" : See here https://github.com/philsturgeon/build-apis-you-wont-hate/blob/master/chapter8/app/tests/behat/features/bootstrap/FeatureContext.php
"I request" : based on code provided by philsturgeon just above, I modify it to have something like that :
/**
* #When /^I request "(GET|PUT|POST|DELETE|PATCH) ([^"]*)"$/
*/
public function iRequest($httpMethod, $resource)
{
$this->lastResponse = $this->lastRequest = null;
$this->iAmOnHomepage();
$method = strtoupper($httpMethod);
$components = parse_url($this->getSession()->getCurrentUrl());
$baseUrl = $components['scheme'].'://'.$components['host'];
$this->requestUrl = $baseUrl.$resource;
$formParams = json_decode($this->requestPayload, true);
$formParamsList = [];
foreach($formParams as $param => $value) {
$formParamsList[$param] = json_encode($value);
}
// Construct request
$headers = [
'Accept'=>'application/json',
'Content-Type'=>'application/x-www-form-urlencoded'
];
try {
// Magic is here : allow to simulate any HTTP verb
$client = $this->getSession()->getDriver()->getClient();
$client->request(
$method,
$this->requestUrl,
$formParamsList,
[],
$headers,
null);
} catch (BadResponseException $e) {
$response = $e->getResponse();
// Sometimes the request will fail, at which point we have
// no response at all. Let Guzzle give an error here, it's
// pretty self-explanatory.
if (null === $response) {
throw $e;
}
$this->lastResponse = $e->getResponse();
throw new \Exception('Bad response.');
}
}
If you use Mink then it is quite easy
class FeatureContext extends RawMinkContext
{
/**
* #When make POST request to some Uri
*/
public function makePostRequestToSomeUri(): void
{
$uri = '/some-end-point';
/** #var \Symfony\Component\BrowserKit\Client $client */
$client = $this->getSession()->getDriver()->getClient();
$postParams = [];
$files = [];
$serverParams = [];
$rawContent = '';
$client->request(
\Symfony\Component\HttpFoundation\Request::METHOD_POST,
$uri,
$postParams,
$files,
$serverParams,
$rawContent
);
/** #var \Symfony\Component\HttpFoundation\Response $response */
$response = $client->getResponse();
//...
}
}
I installed Symfony4 using the following steps.
step1: composer create-project "Symfony/skeleton:^4.0” symfony4
step2: git status
step3: git add.
step4: git commit
step5: composer require annotations
step6: create a controller named ArticleController
<?php
namespace App\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Component\HttpFoundation\Response;
class ArticleController
{
/**
* #Route("/")
*/
public function indexAction()
{
return new Response('OMG! My first page already! Wooooo!');
}
/**
* #Route("/{id}", requirements={"id" = "\d+"}, defaults={"id" = 1})
*/
public function showAction($id)
{
echo 123;die;
}
/**
* #Route("/news/{$slug}")
* #Method({"GET", "POST"})
*/
public function news($slug)
{
return new Response(sprintf('Today new is "%s"', $slug));
}
}
Step7: access http://127.0.0.1:8000
You can view 'OMG! My first page already! Wooooo!'.
But http://127.0.0.1:8000/123 and http://127.0.0.1:8000/news/test do not work. Who can tell me why? And please help me to fix it.
Just find the solution.
composer require symfony/apache-pack
It will automatically generate .htaccess.
the right namespace is :
use Symfony\Component\Routing\Annotation\Route;
thanks
The follwing below is an controller for an template i am making in codeignither HMVC. I am trying to load this template module in my task modules but for some reason it wont load in the template modules but the data loads in my task controller.
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class templates extends MX_Controller
{
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* #see https://codeigniter.com/user_guide/general/urls.html
*/
public function one_col($data)
{
$this->load->view('one_col',$data);
}
public function two_col($data)
{
$this->load->view('two_col',$data);
}
public function admin($data)
{
$this->load->view('admin', $data);
}
public function index()
{
echo "Hello world";
}
}
this code below is my task controller and it works fine when i run it in the link http://localhost:81/hmvc/index.php/tasks however when i try to run the template view "two_col" http://localhost:81/hmvc/index.php/templates/two_col
using this code in the template
<?php $this->load->view($module.'/'.$view_file); ?>
i get this error :
task module controller below
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class tasks extends MX_Controller
{
/**
* Index Page for this controller.
*
* Maps to the following URL
* http://example.com/index.php/welcome
* - or -
* http://example.com/index.php/welcome/index
* - or -
* Since this controller is set as the default controller in
* config/routes.php, it's displayed at http://example.com/
*
* So any other public methods not prefixed with an underscore will
* map to /index.php/welcome/<method_name>
* #see https://codeigniter.com/user_guide/general/urls.html
*/
public function index()
{
$this->load->model('mdl_tasks');
$data['query'] = $this->mdl_tasks->get('priority');
#$this->load->view('display', $data);
$data['view_file'] = "display";
$data['module'] = "tasks";
echo Modules::run('templates/two_col', $data);
#$this->load->module('templates');
#$this->templates->two_col($data);
}
}
echo Modules::run('templates/two_col', $data);
#$this->load->module('templates');
I'm pretty sure replacement these codes together will work.
Because php is an interpreted programming language. PHP loads every line one by one if deteced an error for ex. on 5Th line it doesnt compile the rest of lines. More information for interpreted lang. and also in your code you implementing the lib function before loading lib