Swagger-php with Swagger-ui not working with Basic Authentication - php

I use swagger-ui and swagger-json generated with swagger-php. I m not able to do a basic auth to use my endpoint. I m able to get the swagger json file from my application but not to use exposed endpoint. I don't see what i m misunderstanding. If someone could show me a full example with basic auth in swagger 2.0 ?
CORS is enabled and totally working. Swagger-ui is running on localhost:3000 with nodejs and my application is running php with nginx on localhost:80.
I use swagger-ui-dist 3.14.1 that is compatible with swagger 2.0 (swagger-php is 2.0)
3.14.1 | 2018-05-04 | 2.0, 3.0 | tag v3.14.1
I m using theses SWG comments in my controllers to use basicAuth, (server-side)
/**
* #SWG\SecurityScheme(
* securityDefinition="basicAuth",
* name="authorization",
* type="basic",
* scheme="http"
* )
*/
and this comments
/**
* #SWG\Get(
* description="Get all catalog",
* path="/ott/catalogs",
* produces={"application/json"},
* security = {"basicAuth"},
* #SWG\Response(response="200", description="Get all catalogs"),
* #SWG\Response(response="401",description="You are not authorized")
* )
* )
*/
Here is my client-side code:
window.onload = function() {
// Build a system
const ui = SwaggerUIBundle({
url: "http://ott/ott/tools/swagger",
host: 'ott',
basePath: 'ott/',
schemes: 'http',
enableCORS: true,
dom_id: '#swagger-ui',
deepLinking: true,
validatorUrl:null,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout",
requestInterceptor: (req) => {
if (req.loadSpec) {
let hash = btoa("*******" + ":" + "********");
req.headers.Authorization = "Basic " + hash;
}
return req
},
onComplete : () => {
ui.preauthorizeBasic("basicAuth","*******","*******")
}
});
window.ui = ui
When i click to the lock, i have the first error in my console and then when i try to get my catalogs i get a 401 - not authorized because the Basic Authentication header is not sent.

Annotations do not look right. Change #SWG\SecurityScheme to:
/**
* #SWG\SecurityScheme(
* securityDefinition="basicAuth",
* type="basic"
* )
*/
(without the name and scheme attributes), and change the security in #SWG\Get as follows:
/**
* #SWG\Get(
* ...
* security = {{"basicAuth": {}}},
* ...

Related

StackDriver in PHP / How to setup the LoggingClient for Google AppEngine PHP/Flex

I'm switching to the Google LoggingClient to log to StackDriver.
It's working, I've managed to switch the "resource->type" from global to gae_app (since my PHP App is running in Google App Engine Flex), but in the label section, I can't set the the module_id and version_id.
Ideally, I would see the GAE logs with the PHP logs of my application.
The code
In SlimFramework dependency, I've setup the logger as follow :
/**
* #property PsrLogger $logger
* #param \Slim\Container $c
* #return PsrLogger
*/
$container['logger'] = function (\Slim\Container $c)
{
$settings = $c->get('settings')['logger'];
$logger = LoggingClient::psrBatchLogger(
$settings['name'], [
'resource'=>[
'type'=>'gae_app'
],
'labels' =>['module_id=>'default', 'version_id'=>'XXXXX']
]);
return $logger;
};
What I'm currently getting:
resource: {
labels: {
module_id: ""
project_id: "redcrossquest-fr-dev"
version_id: ""
}
type: "gae_app"
}
Ideally, I would like to fill the module_id & version_id with the values from GoogleAppEngine instance.

Symfony 2 - Allow OPTIONS requests

I have a symfony 2 backend and I have installed it on a server. My frontend is an ionic PWA, so it runs in browser and it is also installed on that server, but with an other subdomain. When I send a request from the web app to the backend, I'm getting this error:
OPTIONS https://api.example.com/api/login.json
XMLHttpRequest cannot load https://api.example.com/api/login.json. Response
for preflight has invalid HTTP status code 405
This is my code for the login action:
/**
* Login via username and password or via API key
*
* #Doc\ApiDoc(
* section="Security",
* description="Login",
* views={"default", "security"}
* )
*
* #param ParamFetcher $params
*
* #Rest\RequestParam(name="username", nullable=true, description="Username")
* #Rest\RequestParam(name="password", nullable=true, description="Password")
* #Rest\RequestParam(name="apikey", nullable=true, description="API key (alternative to username + password)")
*
* #Rest\Post("/login", name="api_security_login", options={"method_prefix" = false})
*
* #return Response
*/
public function loginAction(ParamFetcher $params)
{
//...do some stuff here...//
$data = array(
'user' => $userValue,
'apikey' => $user->getApiKey(),
);
$groups = array('default', 'private');
return $this->createAPIResponse(self::STATUS_OK, $data, $groups);
}
This is header from the response:
Access-Control-Allow-Methods:GET,POST,OPTIONS,DELETE,PUT
Access-Control-Allow-Origin:*
Allow:POST
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:54
Content-Type:application/json
Date:Tue, 29 Aug 2017 08:33:26 GMT
Keep-Alive:timeout=5, max=100
Server:Apache
This is the error message in the prod.log file:
request.ERROR: Uncaught PHP Exception
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException:
"No route found for "OPTIONS /api/login.json": Method Not Allowed
(Allow: POST)" at
/var/www/example.com/api/htdocs/symfony/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php
line 163 {"exception":"[object]
(Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException(code:
0): No route found for \"OPTIONS /api/login.json\": Method Not Allowed
(Allow: POST) at
/var/www/example.com/api/htdocs/symfony/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php:163,
Symfony\Component\Routing\Exception\MethodNotAllowedException(code:
0): at
/var/www/example.com/api/htdocs/symfony/app/cache/prod/appProdUrlMatcher.php:855)"}
[]
So it seems like the OPTIONS request, which is send because CORS, is not allowed, because of the "Allow" header, where only "POST" is allowed. So what is the best way to fix that for all routes?
You only have a route on your action for the POST method:
#Rest\Post("/login", name="api_security_login", options={"method_prefix" = false})
If you want to answer OPTIONS requests, you have to define an Options route using the #Rest\Options annotation.
You can either have several annotations on the same action and test the method inside the action (typically the case with GET and POST for a form action), or define two distinct actions with the same path but different methods.
http://symfony.com/doc/master/bundles/FOSRestBundle/7-manual-route-definition.html
There is no route that accepts the options http method.
No route found for "OPTIONS /api/login.json"
You need to define it first:
/**
* #Rest\Route(
* "/login",
* name="api_security_login",
* methods = {
* Request::METHOD_POST,
* Request::METHOD_OPTIONS,
* }
* )
*/
Clear your cache afterwards and verify that the route is active i.e. using:
bin/console debug:router | grep -i api_security_login

Swagger doctrine/zircote bearer Authorization code

i'm trying to use swagger zircote to create the swagger ui json.
for my application i use JWT and i need the following swagger code in my json:
"securityDefinitions": {
"Bearer": {
"in": "header",
"type": "accessToken",
"name": "Authorization"
}
},
But i dont know how i create that code with swaggers zircote. I've tried the following code:
* #SWG\Swagger(
* schemes={"https"},
* #SWG\SecurityDefinitions(
* bearer={
* type="apiKey",
* name="Authorization",
* in="header"
* }
* ),
but this results in the following error:
The annotation "#Swagger\Annotations\SecurityDefinitions" in
.\index.php on line 2 does not exist, or could not be auto-loaded.
Can someone help me, i cant find any good documentation about this, maybe its to specific, but i hope someone can help me.
Thanks!
Issued this also on the github... https://github.com/zircote/swagger-php/issues/366
Use #SWG\SecurityScheme instead of #SWG\SecurityDefinitions.
* #SWG\Swagger(
* schemes={"https"},
* #SWG\SecurityScheme(
* securityDefinition="Bearer",
* type="apiKey",
* name="Authorization",
* in="header"
* ),
A list of available annotations can be found list in vendor/zircote/swagger-php/src/Annotations
In my case worked as follows:
In the src dir a following class (some general settings):
#[OA\Info(version: "0.1", title: "My First API")]
#[OA\Server(url: 'http://localhost:8080/api')]
#[OA\SecurityScheme(
securityScheme: 'bearerAuth',
type: 'http',
in: 'header',
scheme: 'bearer',
)]
class OpenApi
{
}
and endpoint:
#[OA\Get(
path: '/someUrl',
summary: 'some description',
security: [['bearerAuth' => []]],
tags: ['some tag'],
)
]
#[OA\Response(response: '200', description: 'The data 1')]
#[OA\Response(response: '401', description: 'Unauthorized')]
public function getSomeData($request, $response, $args)

ClankBundle - WebSocket in Symfony

I try to use webscoket in my symfony project. I found this bundle, but i can't setup it.
https://github.com/JDare/ClankBundle
My ChatTopic.php
<?php
namespace My\ChatBundle\Topic;
use JDare\ClankBundle\Topic\TopicInterface;
use Ratchet\ConnectionInterface as Conn;
class ChatTopic implements TopicInterface
{
/**
* This will receive any Subscription requests for this topic.
*
* #param \Ratchet\ConnectionInterface $conn
* #param $topic
* #return void
*/
public function onSubscribe(Conn $conn, $topic)
{
//this will broadcast the message to ALL subscribers of this topic.
$topic->broadcast($conn->resourceId . " has joined " . $topic->getId());
}
/**
* This will receive any UnSubscription requests for this topic.
*
* #param \Ratchet\ConnectionInterface $conn
* #param $topic
* #return void
*/
public function onUnSubscribe(Conn $conn, $topic)
{
//this will broadcast the message to ALL subscribers of this topic.
$topic->broadcast($conn->resourceId . " has left " . $topic->getId());
}
/**
* This will receive any Publish requests for this topic.
*
* #param \Ratchet\ConnectionInterface $conn
* #param $topic
* #param $event
* #param array $exclude
* #param array $eligible
* #return mixed|void
*/
public function onPublish(Conn $conn, $topic, $event, array $exclude, array $eligible)
{
/*
$topic->getId() will contain the FULL requested uri, so you can proceed based on that
e.g.
if ($topic->getId() == "acme/channel/shout")
//shout something to all subs.
*/
$topic->broadcast(array(
"sender" => $conn->resourceId,
"topic" => $topic->getId(),
"event" => $event
));
}
}
Now my services
my_chat.chat_topic_handle:
class: My\ChatBundle\Topic\ChatTopic
config
# Clank Configuration
clank:
web_socket_server:
port: 8080 #The port the socket server will listen on
host: 127.0.0.1 #(optional) The host ip to bind to
topic:
-
name: "chat"
service: "my_chat.chat_topic_handle"
This is my js code:
var myClank = Clank.connect("ws://localhost:8080");
myClank.on("socket/connect", function(session){
session.publish("chat/channel", {msg: "This is a message!"});
//the callback function in "subscribe" is called everytime an event is published in that channel.
session.subscribe("chat/channel", function(uri, payload){
console.log("Received message", payload.msg);
});
session.unsubscribe("chat/channel");
session.publish("chat/channel", {msg: "I won't see this"});
})
myClank.on("socket/disconnect", function(error){
//error provides us with some insight into the disconnection: error.reason and error.code
console.log("Disconnected for " + error.reason + " with code " + error.code);
})
After refreshing page i have nothing from websocket in my console. Webscoket connects with server, but I think that my ChatTopic.php doesn't work, and I don't know why. Thanks for help.
I think the problem is in your js code.
You connect to socket, subscribe to "chat/channel" and immediately unsubscribe. This prevents you from receiving any message.
You should, in order:
subscribe
publish
never unsubscribe (or at least, I still did not find a reason to do so)
By the way, you do not have to "refresh the page", you should open two browser pages on the same url: when the second loads you should see a message in the other one too.

Symfony2 FOS RestBundle Test

I`m trying to write some functional tests for a REST API, created using FOS Rest Bundle.
The problem is that when I use the Symfony\Component\BrowserKit, symfony throws me the following error:
{"message":"Unable to find template \"AccountBundle:Account:list.html.twig\". .. }
The code that I run is:
$client = static::createClient();
$client->request('GET','/account');
When I run the request from the browser, it works fine.
Here is the controller:
/**
* Get channel by ID
* #Secure(roles="ROLE_USER")
* #RestView()
* #ApiDoc(
* resource=true,
* description="Get channel by id",
* section="Channel",
* output="Channel"
* )
*/
public function getAction(Channel $channel)
{
return array('channel' => $channel);
}
So when in test scenario, instead of returning the JSON tries to load the template.
You should use the $server parameter of the $client-request() method to set the Accept header to application/json. FOSRestBundle has a listener that returns JSON only if the corresponding Accept header is received, otherwise it will search for the template corresponding to the controller.
$client->request('GET', '/account', array(), array(), array('HTTP_ACCEPT' => 'application/json'));

Categories