How to allow path without login on ApiPlatform? - api-platform.com

I have the following path:
api_inventories_create_inventory_listing_collection POST ANY ANY /api/inventory/{type}
Its defined in my entity as follows:
#ApiResource(
* attributes={"security"="is_granted('ROLE_ADMIN')"},
* collectionOperations={
* "get"={"security"="is_granted('ROLE_ADMIN')"},
* "create_inventory_listing"={
* "method"="POST",
* "path"="/inventory/{type}",
* "controller"=CreateSingleDeviceTypeController::class,
* },
* "post"
* },
* itemOperations={
* "get"={"security"="is_granted('ROLE_ADMIN')"},
* "delete"={"security"="is_granted('ROLE_ADMIN')"},
* "put"={"security"="is_granted('ROLE_ADMIN') or object.owner == user"},
* }
* )
As you can see, in the ApiResource, that controller has no security.
And in security.yml I allowed the path:
access_control:
- { path: ^/api/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Allows accessing the Swagger UI
- { path: ^/api/inventory, roles: IS_AUTHENTICATED_ANONYMOUSLY } # Allows accessing the Swagger UI
- { path: ^/authentication_token, roles: IS_AUTHENTICATED_ANONYMOUSLY }
Attached is the request via curl
curl -X POST 'https://127.0.0.1:8000/api/inventory/water' \
-H 'Accept: application/json, text/plain, */*' \
-H 'Content-Type: application/json;charset=utf-8' \
--data '{"deviceType":"/api/device_types/2","serial":"provision"}'
and the response
{"code":401,"message":"JWT Token not found"}

you specified security attributes on the ressource level in your entity :
attributes={"security"="is_granted('ROLE_ADMIN')"},
That means their is a security, so the system will try to find a user.

Related

How to send file with curl to a spring-boot-starter-webflux app?

I'm trying to send a file to a spring-boot-starter-webflux application.
This is my controller:
#RestController
#RequestMapping("/fplan")
public class FplanController {
private final FplanService fplanService;
public FplanController(FplanService fplanService) {
this.fplanService = fplanService;
}
#PostMapping(value = "/file")
public Flux<Boolean> handleFileUpload(#RequestPart("file") MultipartFile file) throws IOException {
LOGGER.info(file.getOriginalFilename());
return fplanService.newFplan(file.getInputStream());
}
}
And this is my curl command line:
curl -v -F 'file=#fplan.txt' 'http://localhost:8082/fplan/file'
And this is the error output:
* Trying 127.0.0.1:8082...
* Connected to localhost (127.0.0.1) port 8082 (#0)
> POST /fplan/file HTTP/1.1
> Host: localhost:8082
> User-Agent: curl/7.79.1
> Accept: */*
> Content-Length: 16985001
> Content-Type: multipart/form-data; boundary=------------------------76d46a224dfc0ceb
> Expect: 100-continue
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 100 Continue
* We are completely uploaded and fine
* Mark bundle as not supporting multiuse
< HTTP/1.1 415 Unsupported Media Type
< Content-Type: application/json
< Content-Length: 137
<
{"timestamp":"2022-03-07T15:30:53.056+00:00","path":"/fplan/file","status":415,"error":"Unsupported Media Type","requestId":"936a38c5-5"}
I already tried:
#PostMapping(value = "/file", consumes = MediaType.ALL_VALUE)
or
#PostMapping(value = "/file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
or
curl -v -X POST -H "Content-Type: multipart/form-data" -F 'file=#./fplandb_fv.txt;type=text/plain' "http://localhost:8082/fplan/file"
without success.
Any ideas whats missing?
After all I found this post POST binary file with cmd line curl using headers contained in the file.
If I change the controller method like this
#PostMapping(value = "/file", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public Flux<Boolean> handleFileUpload(#RequestBody byte[] bytes) throws IOException {
LOGGER.info("Received {} bytes", bytes.length);
return fplanService.newFplan(new ByteArrayInputStream(bytes));
}
then this curl line sends the file:
curl -v --header "Content-Type:application/octet-stream" --data-binary #fplandb_fv.txt 'http://localhost:8082/fplan/file'
Feel free to post an answer that explains how to send a file for the controller implementation in the question.

api platform.com - Unsuported Media Type

I just added API platform to existing Symfony 4.4 project
$ composer require api
but can't get any response in Supported Media Type from it. Documentation says it should work out of the box but I'm out of luck. Probably something is missing in my setup although it looks just like in examples:
config/packages/api_platform.yaml
api_platform:
mapping:
paths: ['%kernel.project_dir%/src/Entity']
patch_formats:
json: ['application/merge-patch+json']
swagger:
versions: [3]
Entity/Main/ContentProviders.php
/**
* ContentProviders
*
* #ORM\Table(name="content_providers", indexes={
* #ORM\Index(name="title", columns={"title"}),
* })
* #ApiResource(
* collectionOperations={"post"},
* itemOperations={
* "get"={},
* "put"
* },
* shortName="content_providers",
* normalizationContext={"groups"={"content_providers:read"}, "swagger_definition_name"="Read"},
* denormalizationContext={"groups"={"content_providers:write"}, "swagger_definition_name"="Write"}
* )
* #ORM\Entity
*/
...
And if I call
curl -X GET "https://127.0.0.1:8000/api/content_providers/1" -H
"accept: application/ld+json"
It says
{"#context":"\/api\/contexts\/Error","#type":"hydra:Error","hydra:title":"An error occurred","hydra:description":"Format \u0027jsonld\u0027 not supported, handler must be implemented"
By default, JSON-LD format should be enabled https://api-platform.com/docs/core/content-negotiation/ but I also tried to add formats lines to
config/packages/api_platform.yaml
api_platform:
mapping:
paths: ['%kernel.project_dir%/src/Entity']
formats:
jsonld: ['application/ld+json']
jsonhal: ['application/hal+json']
jsonapi: ['application/vnd.api+json']
json: ['application/json']
xml: ['application/xml', 'text/xml']
yaml: ['application/x-yaml']
csv: ['text/csv']
html: ['text/html']
patch_formats:
json: ['application/merge-patch+json']
swagger:
versions: [3]
however this not helped.

playframework - Can't read cookie from request

How can I get the cookie from a request in playframework?
I have the following test endpoint
def home = Action.async { implicit request =>
println(request)
println(request.session)
println(request.flash)
request.session.get("session") match {
case Some(cookie) => Future(Ok(cookie))
case None =>
Future(BadRequest(Json.obj("message" -> "missing session cookie")))
}
}
When submitting the following request:
curl 'http://local.example.com:9000/home' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Connection: keep-alive' -H 'Cookie: session=eyJhbGciOiJSUzI1NiIsImtpZCI...' -H 'Upgrade-Insecure-Requests: 1' -H 'Cache-Control: max-age=0'
I unfortunately get the "missing session cookie" response. and the following printout on the console
GET /home
Session(Map())
Flash(Map())
I don't know what I'm doing wrong. Any help is much appreciated.
Edit: I set the cookie using the following method:
def tokenLogin = Action(parse.json).async { implicit request =>
val loginRequest = request.body.validate[LoginRequest]
loginRequest.fold(
errors =>
{
println(errors)
Future(BadRequest(Json.obj("message" -> JsError.toJson(errors))))
},
request => {
println("in success")
firebaseAdminService
.createSessionCookie(request.idToken)
.map(sessionCookie =>
Ok("success")
.withNewSession
.withCookies(Cookie(name = "session", value = sessionCookie))
)
}
)
}
By default, the session cookie in Play is called "PLAY_SESSION" (configuration play.http.session.cookieName).
So, you would need to use -H "Cookie: PLAY_SESSION=..." with curl.
But note, this won't work with arbitrary data since Play uses JWT and signs the information contained in the session cookie using its crypto secret.
The only thing expected to work is using a session cookie received in a Set-Cookie header from your Play service in another request to the same service (having the same secret).
update after your edit:
When using request.session, you are accessing the session cookie, which is called PLAY_SESSION and the information stored inside it.
But, you are setting a cookie of your own. This is something else.
You can access "normal" cookies with
request.cookies.get("session")
Oh, and in case you really wanted to make use of the session cookie, you can set it like this:
Ok("success").withSession("session" -> sessionCookie)

How to get OKTA implicit response without callback (Desktop app)

Can i get okta authentication worked in Desktop applications ? Where i just want to hit okta api to get access token and other details in response ?
As per my understanding it looks for some redirect_uri which i do not have in case of desktop application. Any recommendation ?
I tried it with my web application that works fine.
with following parameters
const openIdConnectUrl = 'https://xxxx.okta.com/oauth2/default';
const clientId = 'xxxxxxxxxxxxxxxxxxx';
const redirectUri = 'http://xxxx.com/yyy/zzz';
Reqeust
curl -v -X POST \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"username": "xxxx#example.com",
"password": "xxxxxx",
"relayState": "/myapp/some/deep/link/i/want/to/return/to",
"options": {
"multiOptionalFactorEnroll": false,
"warnBeforePasswordExpired": false
}
}' "https://${yourOktaDomain}/api/v1/authn"
provides response like
{"expiresAt":"2019-11-13T06:27:03.000Z","status":"SUCCESS","sessionToken":"20111PJIKs504fXVoLs-9zf4t8YoVzMCEvlUbcnjDnPhqSk7C-YPzCL","_embedded":{"user":{"id":"xxxxxxxxxxxxxxx","passwordChanged":"2019-11-13T03:20:33.000Z","profile":{"login":"xxxxxx#gmail.com","firstName":"xxxx","lastName":"xxxx","locale":"en","timeZone":"America/Los_Angeles"}}},"_links":{"cancel":{"href":"https://dev-924234.okta.com/api/v1/authn/cancel","hints":{"allow":["POST"]}}}}
Refer the below documentation if needed.
https://developer.okta.com/docs/reference/api/authn
Although it did not serve my purpose completely. But it can help you.

Error Symfony 3 with Monolog & swift mailer

I have a problem with swift mailer and monolog on Symfony 3.0.2:
FatalThrowableError in appDevDebugProjectContainer.php line 4963:
Type error: Argument 1 passed to SymfonyBundleMonologBundleSwiftMailerMessageFactory_0000000079e53f2b00000001716bb61a50d0bc982eb9e83148fbcc469ab36a58::__construct() must be an instance of Swift_Mailer, instance of Closure given, called in /Users/Romain/Sites/var/cache/dev/appDevDebugProjectContainer.php on line 4043
# Swiftmailer Configuration config.yml
swiftmailer:
transport: "%mailer_transport%"
host: "%mailer_host%"
username: "%mailer_user%"
password: "%mailer_password%"
spool: { type: memory }
#Monolog config_prod.yml
monolog:
handlers:
main:
type: fingers_crossed
action_level: critical
handler: grouped
grouped:
type: group
members: [streamed, buffered]
streamed:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
buffered:
type: buffer
handler: swift
swift:
type: swift_mailer
from_email: no-reply#email.com
to_email: email#email.com
subject: "Subject"
level: debug
An extract appDevDebugProjectContainer.php on line 4963
/**
* {#inheritDoc}
*/
public function __construct(\Swift_Mailer $mailer, $fromEmail, $toEmail, $subject, $contentType = null)
{
static $reflection;
if (! $this->valueHolder56d41e956b1f5441039037) {
$reflection = $reflection ?: new \ReflectionClass('Symfony\\Bundle\\MonologBundle\\SwiftMailer\\MessageFactory');
$this->valueHolder56d41e956b1f5441039037 = $reflection->newInstanceWithoutConstructor();
\Closure::bind(function (\Symfony\Bundle\MonologBundle\SwiftMailer\MessageFactory $this) {
unset($this->mailer, $this->fromEmail, $this->toEmail, $this->subject, $this->contentType);
}, $this, 'Symfony\\Bundle\\MonologBundle\\SwiftMailer\\MessageFactory')->__invoke($this);
}
$this->valueHolder56d41e956b1f5441039037->__construct($mailer, $fromEmail, $toEmail, $subject, $contentType);
}
An extract appDevDebugProjectContainer.php on line 4043
/**
* Gets the 'monolog.handler.swift.mail_message_factory' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* This service is private.
* If you want to be able to request this service from the container directly,
* make it public, otherwise you might end up with broken code.
*
* #param bool $lazyLoad whether to try lazy-loading the service with a proxy
*
* #return \Symfony\Bundle\MonologBundle\SwiftMailer\MessageFactory A Symfony\Bundle\MonologBundle\SwiftMailer\MessageFactory instance.
*/
public function getMonolog_Handler_Swift_MailMessageFactoryService($lazyLoad = true)
{
if ($lazyLoad) {
return $this->services['monolog.handler.swift.mail_message_factory'] = new SymfonyBundleMonologBundleSwiftMailerMessageFactory_0000000057f95edf000000015dd8d44e50d0bc982eb9e83148fbcc469ab36a58(
function (&$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface $proxy) {
$wrappedInstance = $this->getMonolog_Handler_Swift_MailMessageFactoryService(false);
$proxy->setProxyInitializer(null);
return true;
}
);
}
return new \Symfony\Bundle\MonologBundle\SwiftMailer\MessageFactory($this->get('swiftmailer.mailer.default'), 'contact#domaine.com', array(0 => 'error#domaine.com'), 'Une erreur critique est survenue', NULL);
}
Sends him of e-mail with swiftmailer only work.
I already have this configuration with the same environment but symfony 2.7 and that works.
And this configuration works on a wamp (php7) but not on my environement OSX and server Linux ...
Thank you for your help
fix with symfony 3.0.3 and monolog 1.18

Resources