Modify request object in Slim framework - request

I am developing a small REST app in slim framework. In that, users password is send as encrypted in the request body as xml or json. I want to de-crypt that password in a callable function and update the request body so that in the actual call back function we can validate the password without de-cryptng. I want to do those steps as follows:
$decrypt = function (\Slim\Route $route) use ($app) {
// Decrypt password and update the request body
};
$update = function() use ($app) {
$body = $app->request()->getBody();
$arr = convert($body);
$consumer = new Consumer($arr);
if ($consumer->validate()) {
$consumer->save();
$app->response()->status(201);
} else {
.....
}
}
$app->put('/:consumer_id', $decrypt, $update);

We can modify the body like following way:
$env = $app->environment;
$env['slim.input_original'] = $env['slim.input'];
$env['slim.input'] = 'your modified content here';
Courtsey: ContentTypes middleware

You say you want decrypt the password and update the request body. If you're encrypt the password at client side, i would rather decrypt the password in a server side layer like API service (or something that consume the business layers like a controller in mvc).
I do believe that this decryption process should belong to your application instead of doing it outside before consuming your code. I don't know how you encrypt but if you use server side programming to generate a new hash in those requests, for me that's even a better reason to do it inside the library.
That's how i handle this type of tasks, i try to use only the frameworks for consuming libraries and not handling any logic.
However if you want to do this, you could transform the request body and save it in a new location for services that need to decrypt the password.
I use Middleware for almost every code i need to write specifically to Slim layers. I only passe functions consuming classes that act as API layers and are abstracted from Slim. For your case, use a Middleware to keep this logic in his own place.
class DecriptPasswordRequest extends \Slim\Middleware
{
public function call()
{
$decriptedRoutes = array('login', 'credentials');
$app=$this->app;
$container = $app->container;
$currentRoute = $app->router()->getCurrentRoute();
if ($app->request->getmethod() == 'POST' && in_array($currentRoute, $decriptedRoutes){
$body = $app->request->post();
if (!isset($body['password'])){
throw new Exception('Password missing');
}
$provider = new ClassThatDecryptPassword();
$body['password'] = $provider->decrypt($body['password']);
}
$container['bodydecripted'] = $body;
$this->next->call();
}
}

Related

Spring React and Sessions.. how to keep session

I have set up my spring to maintain a HTTP session on an object like so:
#Component
#SessionScope
public class Basket { .. }
controller:
#PostMapping(path="/basket/addItem/{user}", consumes = "application/json", produces = "application/json")
public Basket createBasket(#PathVariable String user, #RequestBody Item item) {
System.out.println("POSTING..................................");
return basketService.addItem(user, item);
}
now when i use a REST client, in firefox i can see that the session bean is created and maintained for the duration - multiple calls. I can append to the object. If i try another client, it gets its own session with its own bean. great..
spring logs the following:
Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [269] milliseconds.
However im trying to create a basic front end in react, when react makes a request using axios it gets a new bean every time, which means that the session must be ending after each call. IS that correct? or im not tying it to the react application...
Maybe the approach im taking is not correct, maybe i should use a a different approach, Im trying to learn about spring boot, so its a basic project... and right now i want to maintain user session for a cart. so subsequent calls i can append to the object...
by adding the following to my controller it all began to work.
#CrossOrigin(origins = { "http://localhost:3000" }, allowedHeaders = "*", allowCredentials = "true")

How to use a CookieCollection in multiple functions

I'm setting up a web page using cookies to determine if the user already logged in, using a cookie containing his id. Problem is : The cookie is either not written or the cookie collection is not updated.
I've tried reading the documentation, but it does not define the usage of CookieCollection.
Here's the function where i write my cookie :
function displayData(){
$id = $this->getRequest()->getSession()->read('id');
$cookies = CookieCollection::createFromServerRequest($this->getRequest());
if(!$cookies->has('id')){
$cookie = (new Cookie('id'))
->withValue($id)
->withExpiry(new DateTime('+999 year'))
->withPath('/')
->withDomain('break-first.eu')
->withSecure(true)
->withHttpOnly(true);
$cookies = $cookies->add($cookie);
}
// Other stuff
}
And where I try reading it :
function index(){
$cookies = $this->getRequest()->getCookieCollection();
dd($cookies);
}
I expect having a cookie named "id", but I don't have it. Only CAKEPHP and pll_language are showing up.
First things first, CakePHP provides authentication functionality with cookie authentication, you may want to have a look at that instead of driving a custom solution.
Cookbook > Plugins > Authentication
That being said, what you're doing there will create a cookie collection object, which however is just that, a lone object somewhere in space, it won't affect the state of your application, in order for that to happen you have to actually modify the response object.
However what you're trying to do there doesn't require cookie collections in the first place, you can simply read and write cookies directly via the methods provided by the request and response objects, like:
// will be `null` in case the cookie doesn't exist
$cookie = $this->getRequest()->getCookie('id');
// responses are immutable, they need to be reassinged
this->setResponse(
$this->getResponse()->withCookie(
(new Cookie('id'))
->withValue($id)
->withExpiry(new DateTime('+999 year'))
->withPath('/')
->withDomain('break-first.eu')
->withSecure(true)
->withHttpOnly(true)
)
);
And if you where to use a cookie collection for whatever reason, then you'd use withCookieCollection() to pass it into the response:
$this->setResponse($this->getResponse()->withCookieCollection($cookies));
If you run into strict typing errors, you could for example create a custom reponse class with an overridden Response::convertCookieToArray() method and cast the string to an integer there (make sure that PHP_INT_MAX covers your target date timestamp, 32-Bit incompatibility is why the fix that landed in CakePHP 4.x, probably won't come to 3.x), something like:
src/Http/Response.php
namespace App\Http;
use Cake\Http\Cookie\CookieInterface;
use Cake\Http\Response as CakeResponse;
class Response extends CakeResponse
{
protected function convertCookieToArray(CookieInterface $cookie)
{
$data = parent::convertCookieToArray($cookie);
$data['expire'] = (int)$data['expire'];
return $data;
}
}
You can pass that into the app in your webroot/index.php file, as the second argument of the $server->run() call:
// ...
$server->emit($server->run(null, new \App\Http\Response()));
See also
Cookbook > Request & Response Objects > Request > Cookies
Cookbook > Request & Response Objects > Response > Setting Cookies

CakePHP 3.5 Writing & Encrypting Cookie

Background: I have just upgraded to CakePHP 3.5.17.
I had a code that write cookie. However, it seems that I am missing a few steps to encrypt it. Can somebody shed some lights where are the missing steps? At the moment, the web browser is getting the value of the cookie but it is not encrypted. Note I have also set the cookieKey on my app.php
I've also included this steps in the link provided below
https://book.cakephp.org/3.0/en/development/application.html#adding-http-stack
//In src/Controller/UsersController.php
use Cake\I18n\Time;
use Cake\Http\Cookie\Cookie;
use Cake\Http\Cookie\CookieCollection;
use Cake\Core\Configure;
use App\Application;
use Cake\Error\Middleware\ErrorHandlerMiddleware;
use Cake\Http\MiddlewareQueue;
use Cake\Routing\Middleware\AssetMiddleware;
use Cake\Routing\Middleware\RoutingMiddleware;
use Cake\Http\Middleware\EncryptedCookieMiddleware;
public function writecookie() {
$cookie = new Cookie(
'goodday', // name
'YES', // value
(Time::now())->modify('+1 year'), // expiration time, if applicable
'/', // path, if applicable
'', // domain, if applicable
false, // secure only?
true // http only ?
);
$middlewareQueue = new MiddlewareQueue();
$cookiesEncrypted = new EncryptedCookieMiddleware(
['goodday'],
Configure::read('Security.cookieKey')
);
$cookiesEncrypted = $middlewareQueue->add($cookiesEncrypted);
$this->response = $this->response->withCookie($cookie); //value is still YES in the web browser cookie storage
}
After further debugging, I noticed that in class EncryptedCookieMiddleware. It is stating that Cookies in request data will be decrypted, while cookies in response headers will be encrypted automatically. If the response is a Cake\Http\Response, the cookie data set with withCookie() and `cookie()`` will also be encrypted. But for me it doesn't automatically encrypt?
You may want to make yourself more familiar with how middlewares work, you're not supposed to use them in your controller, they're supposed to be "wrapped around" your application and interact with the requests that are sent to the app, and the responses that the app sends back.
You register them in your applications Application::middleware() method, in the Server.buildMiddleware event, or when connecting routes.
// src/Application.php
// ...
use Cake\Http\Middleware\EncryptedCookieMiddleware;
class Application extends BaseApplication
{
public function middleware($middlewareQueue)
{
// ...
$middlewareQueue->add(new EncryptedCookieMiddleware(/* ... */));
return $middlewareQueue;
}
}
See also
Cookbook > Middleware
Cookbook > Middleware > Using Middleware
Cookbook > Routing > Connecting Scoped Middleware

Encrypting the client side local storage data using Angularjs

I have a client side data storing in the localStorage. For security reasons i want to encrypt the data. Is there any way to encrypt/decrypt the client data(not server data) using Angularjs?
$scope.accountObj = {
isErrorMsg:false,
isReadonly:false,
createAccountErr:false
};
You could use cryptojs library for encrypting/decrypting your data. First you should generate some key to use in encryption process:
var secretKey = 'your-secret-key';
Then you need method to store and claim data:
store : function (key, value) {
var encryptedData = CryptoJS.AES.encrypt(angular.toJson(value), secretKey).toString();
window.localStorage.setItem(key, encryptedData);
},
get : function (key) {
var encryptedData = window.localStorage.getItem(key);
if (!_.isNull(encryptedData))
return angular.fromJson(CryptoJS.AES.decrypt(encryptedValue, secretKey).toString(CryptoJS.enc.Utf8));
return null;
}
The only problem here is that secret key is stored on the client side and it's kind of breaking logics of such encryptions.
These are probably the best out of the box solutions available for cryptography in Javascript until now.
https://www.w3.org/TR/WebCryptoAPI/
https://crypto.stanford.edu/sjcl/
However, you will probably wanna avoid cryptography on the browser if "security" is a concern and seeing as you don't trust the client machine with your localStorage.

AngularJS : How to encode decode JSON data in Services

I have used CakePHP + AngularJS for the application
I have below code in Sevices file
test.factory('Dashboard', function ($http, $q) {
return {
userDirectory: function (){
return $http.get(hostName + 'dashboards/userDirectory.json');
}
}
});
The above code calls dashboards's controllers userDirectory function and return JSON data this is how it's work.
Some one raised one issue, When he hit url "http://hostname/dashboards/userDirectory.json" he can see the response data in browser and that is not authenticated. Is there any way through which I can secure it.
By any encoding/decoding or What you prefer.
Decode/encode doesn't make any sense here if the client can decode it the user can get the data as well.
Just send data the user is allowed to see and use, even if he is authorized for that request, remove everything else that is not needed.
Use a JWT token to authorize them
https://github.com/ADmad/cakephp-jwt-auth
http://www.bravo-kernel.com/2015/04/how-to-add-jwt-authentication-to-a-cakephp-3-rest-api/
http://florian-kraemer.net/2014/07/cakephp-and-token-based-auth-with-angular-js/

Resources