I am implementing a basic auth with Slim and REST. I have installed the basic auth via Composer and used the below code.
<?php
require 'confing.php';
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim;
$app->add(new \Slim\Middleware\HttpBasicAuthentication([
"path" => "/admin", /* or ["/admin", "/api"] */
"realm" => "Protected",
"users" => [
"root" => "t00r",
"user" => "passw0rd"
],
"callback" => function ($request, $response, $arguments) {
print_r($arguments);
}
]));
$app->get('/getLaboorState/:laboor_id', function($laboor_id) use ($app) {
$db =getDB();
$sql="SELECT status FROM laboor WHERE laboor_id='".$laboor_id."'";
$stmt = $db->query($sql);
$items = $stmt->fetchAll();
echo json_encode($items);
});
$app->run();
?>
When I am trying now to connect the /getLaboorState with Postman it returns nothing. I used same username and password in postman and nothing shows, but when I take the basic auth it works fine.
Other questions is, after implement the basic auth, how can I restrict all slim api to go throw each api before run the query?
This is a pic from Postman:
Note: then I want to use the API with AJAX.
you need to use $authenticate($app) to restrict all slim api to go throw each api before run the query
$app->get('/profile(/)(:id)', $authenticate($app), function($laboor_id) use ($app) {
//Your logic here
})->name('profile');
$authenticate = function ($app) {
return function () use ($app) {
//your logic here
if (!isset($_SESSION['ID'])) {
$app->redirect($app->urlFor('loginpage'));
}
};
};
Use bellow code to display the exact error coming while calling Ajax request
header('Access-Control-Allow-Origin: *');
ini_set('display_errors', 1);
error_reporting(E_ALL);
Hope this helps, Accept the answer if it works.. or comment
You have configured two users:
Username root with password t00r
Username user with password passw0rd
According to your screenshot you are trying to use username t00r with password passw0rd. This does not exist in your configuration. Use one of the username password combinations mentioned above.
Related
I'm trying to verify the idToken provided from firebase javascript sdk with the Tuupola Jwt middleware for slim 4 but I always get a 401 error. This is the client code I'm using to get the token:
const provider = new firebase.auth.GoogleAuthProvider();
provider.addScope("profile");
provider.addScope("email");
firebase.auth().signInWithPopup(provider).then( (result) => {
console.log(result);
});
The auth flow will work correctly as expected and I'm able to pass the token into the Authorization header but I'm not able to verify it on the server where I'm using slim 4 for a Restful api.
I've read different question about this problem but none of this have helped me to solve this problem.
here is my middleware implementation:
use Tuupola\Middleware\CorsMiddleware;
use Tuupola\Middleware\JwtAuthentication;
use Slim\App as App;
return function(App $app) {
$app->add(new Tuupola\Middleware\CorsMiddleware([
"origin" => ["chrome-extension://oegddbimpfdpbojkmfibkebnagidflfc"],
"methods" => ["GET", "POST", "OPTIONS"],
"headers.allow" => ["Authorization"],
"headers.expose" => [],
"credentials" => true,
"cache" => 86400
]));
// $rawPublicKeys = file_get_contents('https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com');
// $keys = json_decode($rawPublicKeys, true);
$keys = file_get_contents('https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com');
$app->add(new Tuupola\Middleware\JwtAuthentication([
"algorithm" => ["RS256"],
"header" => "X-Authorization",
"regexp" => "/Bearer\s+(.*)$/i",
"secret" => $keys,
"secure" => false,
"after" => function ($response, $arguments) {
return $response->withHeader("X-Brawndo", "plants crave"); //this is only for test
}
]));
};
and this is what I have inside my index.php file where slim app is running
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Routing\RouteCollectorProxy;
use Slim\Routing\RouteContext;
use Slim\Factory\AppFactory;
use Tuupola\Middleware\CorsMiddleware;
require_once __DIR__.'/vendor/autoload.php';
$app = AppFactory::create();
$authMiddleware = require_once __DIR__.'/middleware.php';
$authMiddleware($app);
$app->get('/keygen', function(Request $request, Response $response, $args){
$password = bin2hex(random_bytes(3));
$response->getBody()->write( json_encode(['generated_password' => $password]) );
return $response->withHeader('Content-Type','application/json');
});
$app->add(new Tuupola\Middleware\CorsMiddleware([
"origin" => ["*"],
"methods" => ["GET", "POST", "OPTIONS"],
"headers.allow" => ["Authorization"],
"headers.expose" => [],
"credentials" => true,
"cache" => 86400
]));
$app->run();
What I want to achive is to authenticate each request made from the client to the api using the firebase idToken provided after client login. When a request is made, the middleware will verify the token and then authorize the user or not to use the endpoint.
Is possible to fix this?
After a lot of debug I've found and solved the problem. In my client code I was using the wrong idToken as Authorization: Bearer and also the header sended to the server was mismatching the middelware configuration, in my axios requests I was sending the X-Authorization header instead of Authorization. To get the correct token to use I've called firebase.auth().onAuthStateChanged( (user) =>{...}) method and when the user object become available I've called the getIdToken() method. This operation return the correct JWT token to use with the middleware to authenticate the requests.
So, I'm using Laravel+Passport and so far is working fine.
But, I would like to made a small change to the passport code(well, not in the vendor folder, I hope), once that I would request the User to change it's password in case that he is doing the first login.
So, what I would need is two things (I believe):
1 - How can I add one more info to the oauth/token response? Together with the access_token, I would like to add one column from the DB that is needsNewPassword=true/false.
2 - In case that needsNewPassword is true, then, the app will redirect to another screen, where the user will set a new password. I would set the new password, remove the flag for needsNewPassword and send back a new access_token to the user. The user then, would use only that access_token. How can I regenerate a new access_token?
Thanks for you help! João
Right,
I answering my own question, in case someone needs to do the same. Maybe is not the best way, but is working.What I did is:
Create a new route, like /api/login that points to a method (be sure that is Outside of your middleware "auth", once that it's not sending the token in thi call). E.g: Route::post('/login', 'Auth\LoginController#apiLogin');
in the method, you do a request to the oauth/token and, with the result, you add the fields that you want.
test
function apiLogin(Request $request) {
$tokenRequest = $request->create('/oauth/token', 'POST', $request->all());
$request->request->add([
"client_id" => 'your_client_id',
"client_secret" => 'your_client_secret',
"grant_type" => 'password',
"code" => '*',
]);
$response = Route::dispatch($tokenRequest);
$json = (array) json_decode($response->getContent());
$json['new_value'] = '123456';
$response->setContent(json_encode($json));
return $response
}
This is working for me. In my case, I also have just one app so, my client_id, client_secret, grant_type and code is added in the server side. The client only need to pass username(or email, depends of what you are using) and password and then it will get the access_token and the other info that I want to send as well.
Hope that this helps someone else too.
Cheers,
joao
#joao.sauer
Your own answer is working like a charm, but if you wan't a bit more freedom, you could extend Passport's own AccessTokenController.
A simple example:
use App\Models\User;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Psr\Http\Message\ServerRequestInterface;
use Response;
class AccessTokenController extends \Laravel\Passport\Http\Controllers\AccessTokenController
{
public function issueToken(ServerRequestInterface $request)
{
try {
//get username (default is :email)
$username = $request->getParsedBody()['username'];
//get user
$user = User::where('email', '=', $username)->firstOrFail();
//issuetoken
$tokenResponse = parent::issueToken($request);
//convert response to json string
$content = $tokenResponse->getBody()->__toString();
//convert json to array
$data = json_decode($content, true);
if(isset($data["error"]))
throw new OAuthServerException('The user credentials were incorrect.', 6, 'invalid_credentials', 401);
//add access token to user
$user = collect($user);
$user->put('access_token', $data['access_token']);
return Response::json(array($user));
}
catch (ModelNotFoundException $e) { // email notfound
//return error message
}
catch (OAuthServerException $e) { //password not correct..token not granted
//return error message
}
catch (Exception $e) {
////return error message
}
}
}
credits to Messi89:
Laravel Passport - Customize The Token Response
I found a simple solution without need new request, controller or extends, just add parameters to request and call issueToken via app, it can useful for starter:
// in routes/api.php
Route::post('/token',function(Request $request){
$request->request->add([
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
]);
return app()->call('\Laravel\Passport\Http\Controllers\AccessTokenController#issueToken');
});
Also can add try...catch block to handle exceptions or add parameters to response before send to client
Route::post('/token',function(Request $request){
$request->request->add([
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
]);
try {
$response = app()->call('\Laravel\Passport\Http\Controllers\AccessTokenController#issueToken');
$newResponse = json_decode($response->content());
// Add parameters to response here
$newResponse->user = ['user'=>'user','pass'=>'pass'];
return Response()->json($newResponse);
}catch (Laravel\Passport\Exceptions\OAuthServerException $e) {
if ($e->statusCode() == 400) {
return response()->json(['message' => 'Invalid request. Please enter username and password.'], $e->statusCode());
} else if ($e->statusCode() == 401) {
return response()->json(['message' => 'Your credentials are incorrect. Please try again.'], $e->statusCode());
}
return response()->json('Something went wrong on the server. Please try later.', $e->statusCode());
}
});
I'm integrating Laravel with GoCardless to allow my users to take card payments however I'm struggling installing the GoCardless php wrapper.
I've followed the following doc:
https://developer.gocardless.com/getting-started/partners/building-an-authorisation-link/
It says to use the following, am I right in saying this will go in my controller? surely with Laravel I wouldnt need to require the vendor/autoload?
<?php
require 'vendor/autoload.php';
// You should store your client ID and secret in environment variables rather than
// committing them with your code
$client = new OAuth2\Client(getenv('GOCARDLESS_CLIENT_ID'), getenv('GOCARDLESS_CLIENT_SECRET'));
$authorizeUrl = $client->getAuthenticationUrl(
// Once you go live, this should be set to https://connect.gocardless.com. You'll also
// need to create a live app and update your client ID and secret.
'https://connect-sandbox.gocardless.com/oauth/authorize',
'https://acme.enterprises/redirect',
['scope' => 'read_write', 'initial_view' => 'login']
);
// You'll now want to direct your user to the URL - you could redirect them or display it
// as a link on the page
header("Location: " . $authorizeUrl);
Apologies, if someone can point me in the right direction I would appreciate.
My controller currently looks like.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
class goCardlessController extends Controller
{
public function index()
{
$client = new OAuth2\Client(env('GOCARDLESS_CLIENT_ID'), env('GOCARDLESS_CLIENT_SECRET'));
$authorizeUrl = $client->getAuthenticationUrl(
'https://connect-sandbox.gocardless.com/oauth/authorize',
'REDIRECT_URL',
['scope' => 'read_write', 'initial_view' => 'login']
);
header("Location: " . $authorizeUrl);
}
}
but I get the error:
Class 'App\Http\Controllers\OAuth2\Client' not found
Which makes sense because I haven't defined it in my controller but Im wondering how I would do this?
Try this in your controller:
use Oauth2;
Or alternatively, $client = new \OAuth2\Client(.... Do note the \ before Oauth2
I am working on a laravel App. a part of that is written pure php that is a html form and form submission script that stores data to Database.
Suppose form.php page is like :
<?php
require('config.php');
?>
<form action="process.php" method="post">
<input type="text" name="username">
<input type="submit" value="Send">
</form>
And process.php page is :
<?php
require ('config.php');
?>
if (isset($_POST['submit_edu'])) {
$username = trim($_POST['username']);
// other codes to store data to DB
}
Now I want just Authenticated Users in main laravel app can access to those pages and send their info.
To access Auth laravel Object, I added below codes to beginning of config.php file that holds connection settings and required by those two page:
require __DIR__ . '/../../bootstrap/autoload.php';
$app = require_once __DIR__ . '/../../bootstrap/app.php';
$app->make('Illuminate\Contracts\Http\Kernel')->handle(Illuminate\Http\Request::capture());
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
if (!Auth::check()) {
exit('Only authorized Users can access to this page');
}
As you can see if an unAuthorized user want to pages Encounters an error.
Now when an Authenticated user want to open form.php page (in face via GET method) Auth::check() works correctly but when clicks on submit form button and data sent to process.php (via POST method) , it always returns false.
While if I open same process.php via GET method Auth::check() works correctly again.
Means in this case Auth::check() can not work properly.
What is problem in your idea. can anyone help me to solve this problem?
Update :
Even I used EventServiceProvider and authentication events to create a session. first I added this to provider :
'Illuminate\Auth\Events\Login' => [
'App\Listeners\SessionLoginEnable',
],
And in SessionLoginEnable:
public function handle (Login $event)
{
session(['user_is_logged_in' => true]);
}
then I added:
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\SessionLoginDisable',
],
And in that :
public function handle (Logout $event)
{
session(['user_is_logged_in' => false]);
}
And in the other hand to check and user created session first I tried in config.php :
require __DIR__ . '/../../bootstrap/autoload.php';
$app = require_once __DIR__ . '/../../bootstrap/app.php';
$app->make('Illuminate\Contracts\Http\Kernel')->handle(Illuminate\Http\Request::capture());
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
$is_logged = session('user_is_logged_in');*
if ( !is_logged ) {
exit('Only authorized Users can access to this page');
}
This solution did not work.
Then I tried this :
session_start();
if ( !isset($_SESSION['user_is_logged_in']) or $_SESSION['user_is_logged_in'] != true) {
exit('Only authorized Users can access to this page');
}
But in this case again, the answer not receive and It seems $_SESSION['user_is_logged_in'] could not be recognized.
Another solution remains?
I have already written an application in a procedural way and am trying to move into into a Laravel framework. I'm having trouble with the SOAP exchange section as I am getting an ID value that authenticates the user but cannot access that value (as a cookie) later in the program to authenticate the search.
Here is my code so far:
<?php namespace App;
use Artisaninweb\SoapWrapper\Facades\SoapWrapper;
use Illuminate\Http\RedirectResponse;
class SoapController {
private $auth_response;
private $cookie;
private $search_client;
private $search_response;
public function soapExchange() {
// create SOAP client and add service details
SoapWrapper::add(function ($service) {
$service
->name('WoSAuthenticate')
->wsdl('http://search.webofknowledge.com/esti/wokmws/ws/WOKMWSAuthenticate?wsdl')
->trace(true)
->cache(WSDL_CACHE_NONE);
});
SoapWrapper::service('WoSAuthenticate', function($service) {
// call authenticate() method to get SID cookie
$auth_response = $service->call('authenticate', []);
$cookie = $auth_response->return;
// test for cookie return
// print($cookie);
});
// create SOAP client and add service details
$search_client = new SoapWrapper;
$search_client::add(function ($service) {
$service
->name('WoSSearch')
->wsdl('http://search.webofknowledge.com/esti/wokmws/ws/WokSearch?wsdl')
->trace(true)
->cache(WSDL_CACHE_NONE);
});
if (isset($auth_response->return)) {
// if there is an SID returned then add it to the cookie attribute of the search client
$search_client->__setCookie('SID', $cookie);
} else {
// route to relevant view to display throttle error
return redirect('throttle');
}
}
}
I am successfully retrieving the response from the Web API call and getting a code to authenticate the user, saved as $cookie. However, I need then to create another SoapWrapper for performing the search and this needs the ID code attached by using the __setCookie method. If nothing is returned by the authenticate call then it redirects to an error message via throttle.blade.php elsewhere.
Surely there is a way to return a value created from a function so that it can be used elsewhere?
** EDIT **
Looked into employing SoapClient instead and including all operations within a single function. It all relates to a specific Web API anyway so I guess separation of concerns is not so much of an issue. FYI the new class I am trying is this:
<?php namespace App\Models;
use SoapClient;
use Illuminate\Http\RedirectResponse;
class SoapWrapper {
public function soapExchange() {
// set WSDL for authentication and create new SOAP client
$auth_url = "http://search.webofknowledge.com/esti/wokmws/ws/WOKMWSAuthenticate?wsdl";
// array options are temporary and used to track request & response data
$auth_client = #new SoapClient($auth_url);
// set WSDL for search and create new SOAP client
$search_url = "http://search.webofknowledge.com/esti/wokmws/ws/WokSearch?wsdl";
// array options are temporary and used to track request & response data
$search_client = #new SoapClient($search_url);
// run 'authenticate' method and store as variable
$auth_response = $auth_client->authenticate();
// call 'setCookie' method on '$search_client' storing SID (Session ID) as the response (value) given from the 'authenticate' method
// check if an SID has been set, if not it means Throttle server has stopped the query, therefore display error message
if (isset($auth_response->return)) {
$search_client->__setCookie('SID',$auth_response->return);
} else {
return Redirect::route('throttle');
}
}
}
Maybe try $GLOBALS?
<?php
$GLOBALS[data] = "something";
function abc(){
echo $GLOBALS[data];
}
?>
use Artisaninweb\SoapWrapper\Facades\SoapWrapper;
class SoapController extends Controller {
public $resultSoapStatus;
public $resultSoapAuthority;
public function heySoap{
SoapWrapper::add(function ($service) ...
$data = [
'MerchantID' => $MerchantID,
'Amount' => $Amount,
'Description' => $Description,
'Email' => $Email,
'Mobile' => $Mobile,
'CallbackURL' => $CallbackURL
];
SoapWrapper::service('test', function ($service) use ($data) {
$resultSoap = $service->call('PaymentRequest', [$data]);
$this->resultSoapStatus = $resultSoap->Status;
$this->resultSoapAuthority = $resultSoap->Authority;
});
if($this->resultSoapStatus == 100 && strlen($this->resultSoapAuthority) == 36)
{
//Do Something
}
else
{
return Redirect::back();
}
}
}
Enjoy bro