Allow to get POST data from outter server YII2 - yii2

i want to make a yii2 route which can receive POST data from other server (of course i know about all risk).
I tried to just send it like usual but i got this error message.
Error 400
Unable to verify your data submission.
more or less is just like this...
public function actionWriteSession()
{
if (isset($_POST))
{
print_r($_POST);
...
write to session
...
}
...
}
Any Advice?
Thanks..

You should disbale csrf verification E.g:
$this->enableCsrfValidation=false;//In your controller context
// Or if you only use this action for sending post from outer server
// you can disbalecsrf token verification only this action. So, in your controller
public function beforeAction($action)
{
if ($action->id == 'writeSession') {
Yii::$app->controller->enableCsrfValidation = false;
}
return parent::beforeAction($action);
}

Related

How to redirect to a client callback page after a successful authentication via Identityserver4?

I am creating a login server using Identityserver4. I am using ASP.net core 3.1 for functionality, and angular 9 project for serving static files for login/registeration screens. The angular project is being served from within the .netcore project's wwwroot folder.
My flow goes like this
javascript client calls OIDC user manager's signInRedirect() method with following configurations
This sends a call to my Login method to render the angular's login component. Once the user fills in credentials, a second call is sent to my Login method return this.http.post('Account/Login', {UserName, Password, ReturnUrl}, {headers, responseType:'text'});
On successfull login, I do a return Redirect(model.returnUrl);
[HttpGet]
public IActionResult Login(string returnUrl)
{
return Redirect("/login?ReturnUrl=" + WebUtility.UrlEncode(returnUrl));
}
[HttpPost]
public IActionResult Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = _userManager.FindByNameAsync(model.UserName).Result;
var result = _signInManager.PasswordSignInAsync(model.UserName, model.Password, false, false).Result;
if(result.Succeeded)
{
return Redirect(model.ReturnUrl);
}
return Ok(new Error { ErrorMessage = "Invalid credentials" });
}
return Ok(new Error { ErrorMessage = "Some error" });
}
In my network tab, I can see that the return Url which is a call to IdentityServer's authorization endpoint /connect/authorize/callbackis successfull.
It has also made a second call to the actual javascript client in point 1 with the authentication successfull.
However, the problem arises here. This request is returning the HTML as string of the JS clients callback.html instead of actually redirecting to that URL(http://localhost:5003/callback.html)
I don't even have any way to access the URL of the returned HTML, otherwise I would have done a window.location.href. How do I capture the URL of the callback page in angular and redirect to it ?
I would need a few more details to remedy this particular situation. However, I did want to offer my expertise in the form of explaining how this is supposed to work. I have an NPM library imng-auth0-oidc that does this very thing, except that it uses NGRX.
Your callback.html should be a static (non-Angular) HTML page. You can find a copy here callback.html. The purpose of this page is to receive the OAUTH2 response and store the token in localStorage, then redirect the response to your Angular application. Once the application is loaded, you'll now have access to your token that is waiting in localStorage.
-Isaac

Yii2 beginner. Display REST exception handling

In my controller, I extend the Controller class instead of ActiveController
I have a simple actionIndex() method:
public function actionIndex(){
return json_encode(["text" => "some text"]);
}
When I access the certain route in browser, in the debugger, I see that this function is executing (the breakpoint stops inside the function), but I get 500 status code (Internal server error). How can I find the cause of the error? I have implemented the actionError() method, but it is not executing.
public function actionError() {
$exception = Yii::$app->errorHandler->exception;
if ($exception !== null) {
return $this->render('error', ['exception' => $exception]);
}
}
If I put the logic of the actionError() method in the actionIndex(), the $exception variable is null
The only output I get is:
{
name: "PHP Warning",
message: "Expected array for frame 0",
code: 2,
type: "yii\base\ErrorException",
file: "Unknown",
line: 0,
stack-trace: []
}
but it's warning, not error. May this cause the status code 500?
How can I get the error? Thanks!
According to this thread https://github.com/yiisoft/yii2/issues/11120 this is related to Xdebug for Yii 2 < 2.0.9.
When handling an exception, XDebug modifies the exception and Yii2 was not able to handle it correctly.
So several possible solutions here
The best idea is to update Yii2 to a version >= 2.0.9
Also you sould correct the source of the exception (the warning). It is never a good idea to have warnings. It can hide some more issues.
And as a workaround, you can disable XDebug. It is very useful during development but must be disabled in production in all cases.
Don't know about your error, but there is generally no need to return a response as json encoded. Yii checks the Accept-header of the request and adjust output accordingly. In your case I would just use:
public function actionIndex()
{
return ["text" => "some text"];
}
Possibly it might also solve your error...

Getting data from Android device in laravel

I am trying to get data from android in server in laravel. What I did till now is :
here in my route:
Route::any('jsondata','JsonController#jsonFunction');
And in my controller:
public function jsonFunction()
{
$jsonPostedData = Input::all();
return response(['jsonobjtest'=>$jsonPostedData]);
}
}
What it gives in browser is:
{"jsonobjtest":[]}
Actually i want to do is i want to send a success message to android device when it sends data. And get data here in server.
You can write like this
In your Controller
public function jsonFunction()
{
$jsonPostedData = Input::all();
// do something with your data insert or update or anything
if(count($jsonPostedData) > 0) // here you might write any of your condition.
{
return response()->json(['success'=>true]);
}
return response()->json(['success'=>false,'error'=>'your error message']);
}
You can try following code
public function jsonFunction(){
$requestObj=Input::all();
return response()->json(['success'=>true,'request_param'=>$requestObj]);
}
You can check whether
$jsonPostedData = Input::all();
input contain data or not by by simply
die and dumping $jsonPostedData variable
example
dd($jsonPostedData);

Calling Jersey from Angular2

I'm beggining to play with Angular2. I have developed a basic RESTful API using Jersey. I tested it and it works fine (with browser and SOAP UI). This is the code:
#GET
#Produces(MediaType.APPLICATION_JSON)
public TwoWordsMessage getMessage() {
TwoWordsMessage message = new TwoWordsMessage();
message.setFirstWord("hello");
message.setSecondWord("world");
return message;
}
I'm tryng to call the service from an Angular2 app:
this.http.request(this.url).subscribe((res: Response) => {
this.message = res.json();
});
I can see (debbuging) that "getMessage" method is called and it returns the TwoWordsMessage object but the Angular2 application never gets it. The same code with the url http://jsonplaceholder.typicode.com/posts/1 works fine.
What I'm doing wrong?
Thanks!
Are you calling the http request inside a component or a service? Does a function or method fire off the http request?
Also, can you see if there are errors coming back from the response? The subscribe method can take three functions as parameters, first one being on success, second on error, third on completion. If there's an error in the AJAX call (400s, 500s, etc), your code would never be able to handle it. Try this:
this.http.request(this.url).subscribe((res: Response) => {
this.message = res.json();
}, (error) => {
console.warn(error)
});
and see what is spit out. To further debug, you can even use the .do() method on the Observable:
this.http.request(this.url)
.do((res: Response) => console.log(res)) // or other stuff
.subscribe((res: Response) => {
this.message = res.json();
});
The .do() method will execute an arbitrary function with the response without actually affecting it.
If not, you could also try changing the http call to http.get(). I don't think that's the problem, but the Angular docs do not state what method is defaulted to with http.request() (although I would be almost certain it's a GET).
I finally got it working. It's a CORS problem.
The console showed the error:
"No 'Access-Control-Allow-Origin' header is present on the requested
resource"
I changed the resource method like this:
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getMessage() {
TwoWordsMessage message = new TwoWordsMessage();
message.setFirstWord("hello");
message.setSecondWord("world");
return Response.status(200).header("Access-Control-Allow-Origin", "*").entity(message).build();
}
You can find useful information here:
http://www.codingpedia.org/ama/how-to-add-cors-support-on-the-server-side-in-java-with-jersey/

Capturing the login failed event in Symfony3

I have this set up in security.yml;
failure_path: /login
This redirects a user to the log in page if they are not authenticated when trying to access specific URLs set in access_control e.g.
access_control:
- { path: ^/admin, role: ROLE_ADMIN }
But I cannot seem to capture this redirect.
I have tried to use a service for the security.authentication.failure event but this does not work
app.security.authentication_failure_event_listener:
class: MemberBundle\Event\AuthenticationListener
tags:
- { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }
The redirect still occurs and the onAuthenticationFailure is never called. Presumably because authentication has not explicitly failed. The user just isn't logged in and is redirected.
The reason is because I want to give different response based on the expected format. For example I want html requests to go to the login page, but JSON requests should return valid JSON - and not the HTML login form page.
I feel like the FOSRestBundle may handle this, but it seems overkill for this relatively simple need. And its not a RESTFul web site so I shouldn't need that bundle to do this?
I also tried a service to listen for Exceptions but this did not work either. I guess the redirect that occurs doesn't throw an Exception?
app.exception_listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }
So how can I always capture the redirect event that occurs when failure_path is set in security.yml?
My Tip (also for the future) is to "Create a Custom Authentication System with Guard. Much More simple and more flexible/customizable to handle that stuff (specially if a bit complicated with many authenticators like facebook, twitter, etc... and with a remember me option activated...).
But... as showed in the SecurityBundle Configuration ("security") you can set a failure_handler parameter for each login system in that firewall:
security:
firewalls:
your_firewall_name:
form_login:
failure_handler: your_custom_failure_handler_service_name <-- THIS ONE
Then you can create a service injecting the needed dependencies to handle the stuff you need and to return a different response based on the request format.
NOTE: I'm not sure if you can achieve this also creating a listener for the Security authentication event failure, but you can give it a try.
So the answer to this lay in a subtle thing about Symfony and the AccessDeniedException.
In that the Exception is only thrown based on your access controls if the current user is not allowed access. It is not thrown if you are not authenticated at all.
The same is true for any sort of authentication failure hook. Its only called with some sort of auth fails, not if you're simply not logged in and therefore not allowed.
So its done via two new services
app.exception_listener:
class: AppBundle\EventListener\ExceptionListener
tags:
- { name: kernel.event_listener, event: kernel.exception }
app.entry_point:
class: AppBundle\EventListener\EntryPoint
arguments: ["#router"]
The first does capture the AccessDeniedException as you would expect when you're denied access to a resource.
class ExceptionListener
{
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
do {
if ($exception instanceof AccessDeniedException) {
$request = $event->getRequest();
if ('json' == $request->get("format") || $request->isXmlHttpRequest()) {
$json = new JsonResponse(["status" => 0, 'not_logged_in' => true, "msg" => "You must be logged in"]);
$event->setResponse($json);
}
}
} while (null !== $exception = $exception->getPrevious());
}
}
The entry point service needs to be set in security.yml like to
security
firewalls:
main:
entry_point: app.entry_point
This class handles the start of the firewall and handles the redirection to authenticate. I check for the Exception is present and then test for XHR and json format and handle accordingly.
/**
* Returns a response that directs the user to authenticate.
*
* This is called when an anonymous request accesses a resource that
* requires authentication. The job of this method is to return some
* response that "helps" the user start into the authentication process.
*
* Examples:
* A) For a form login, you might redirect to the login page
* return new RedirectResponse('/login');
* B) For an API token authentication system, you return a 401 response
* return new Response('Auth header required', 401);
*
* #param Request $request The request that resulted in an AuthenticationException
* #param AuthenticationException $authException The exception that started the authentication process
*
* #return Response
*/
class EntryPoint implements AuthenticationEntryPointInterface
{
/** #var Router */
protected $router;
public function __construct(Router $router)
{
$this->router = $router;
}
public function start(Request $request, AuthenticationException $authException = null) {
if($authException) {
if('json' == $request->get("format") || $request->isXmlHttpRequest()) {
return new JsonResponse(["status" => 0, 'not_logged_in' => true, "msg" => "You must be logged in"]);
}
}
return new RedirectResponse($this->router->generate("fos_user_security_login"));
}
}