Introduction
In 2013 I got
some free time and provided a bootstrap project for people who wanted
to create a website with a Rest API based on Symfony 2 and
AngularJS. Back in the day, the project attracted some
attention and some contributors begun to work on it too. It was more
and more forked. But, for lack of time, I couldn’t
maintain the project and upgrade to the new software versions. So it got
very outdated.
The good thing is
that I took a moment to upgrade the
project recently to Symfony 4 and Angular 8. So yes it was a
very big gap between the software but because of the very limited
size of the project it wasn’t so much of a pain. In the process
I’ve learned some tricks that I wanted to share with you.
In order to make
things clear I want to remember that the project use Web Service
Security standard for API communication and use the REST protocol.
You might want to have the
project opened in another window in order to fully follow the steps to upgrade :
https://github.com/FlyersWeb/angular-symfony.
Preamble
The project use a
technique called WS-Security UserToken in order to authenticate the
connected user. You can have a detailed explanation by going to OASIS
specifications :
https://www.oasis-open.org/committees/download.php/13392/wss-v1.1-spec-pr-UsernameTokenProfile-01.htm.
The simplified
process is as follow :
- client access the shared secret by authenticating with the server
- client generate a user token by using a nonce (random string), a created (date time) and a secret (shared with the server)
- client send a token with a different nonce for each subsequent query
The server knows at
which date time the token was created, it also can detect replay
attack if the nonce is sent twice and it can authenticate the client
through the shared secret.
Now that we had a
quick refresh let’s dive in the upgrade process.
Upgrade Node
The project was
using NodeJS 5 and we upgraded it to NodeJS 12. Because it is a big
gap, we better started a new Angular 8 project from
scratch based on webpack.
Upgrade PHP
The project was
using PHP 5 and we upgraded it to PHP 7. There were a lot of breaking
changes and some real improvements between these two versions so we
also started a new project from scratch using Symfony 4.
Upgrade Angular
Between AngularJS
and Angular 8 there is an abyss. The frameworks are so different that
it was easier to start over a new project by copy/pasting the
important parts of the algorithm. It was also a good exercise to add
some improvements to the existing code.
This is how we
removed a useless custom Base64 encoding function and preferred the
CryptoJS version.
I’ve been
searching online and didn’t get any direct usage of a Base64
encoding using CryptoJS, this is how I did it :
CryptoJS.enc.Utf8.parse(nonce).toString(CryptoJS.enc.Base64);
You first need to
parse your string using the correct encoding then use the toString
function specifying the Base64 output.
We also removed the
custom random string function and added the ‘random-string’
dependency. FYI there is a ‘randomstring’ dependency but it
didn’t work on my laptop saying that there is no global defined,
maybe the NodeJS version break something for that dependency.
The Angular
structure totally changed but you can find all the interesting parts
in the ‘token.service.ts’ file.
Upgrade Symfony
Same as before, the
gap between Symfony 2 and Symfony 4, was so big that we just started
a new project from scratch. The implementation of the WS-Security
UserToken is available in the official Symfony documentation
https://symfony.com/doc/4.4/security/custom_authentication_provider.html.
The implementation
we used is exactly the same. FYI, the regular expression to parse the
X-WSSE header wasn’t working because of escaped double quote coming
from Symfony request headers. Besides that it’s all the same.
It was also a good
excuse for some improvements, so we preferred the use of Nelmio/CORS
in lieu of a custom request listener for Cross Origin Request. We added FOS/FOSRestBundle to
manage the REST API part more easily and upgraded the
FOS/FOSUserBundle dependency.
Thing is, this last dependency is not
fully compatible with Symfony 4 so we had to use some tricks
to make it work. So while you’re installing the dependency by
following the instructions you might have to.
First, move the
configuration to ‘config/packages/fos_user.yaml’. Second, add the FOSUserBundle routes
definitions to ‘config/routes/fos_user.yaml’.
Finally, we
generated a migration and created the User entity in database using
the following command :
bin/console doctrine:migrations:diff &&
bin/console doctrine:schema:update –force’
Additionally we
decided to set logs to stderr because the project is dockerized. This
way you can have logs in real time in your docker daemon. To do that
it was necessary to update ‘monolog.yaml’ configurations to use
‘php://stderr’.
Upgrade database
While working on the
project I decided to migrate the existing MySQL database to
PostgreSQL. Because PostgreSQL is such an amazing project, being so
powerful and well maintained. I do think that MySQL might have reached this quality without all the commercial fuzz around it, but that is another story.
So moving from MySQL
to PostgreSQL was actually really easy on this project, we just had
to install the correct database, add pdo_psql to PHP and update the
connection URL in ‘.env’. I really loved the new way to configure
Symfony 4 it make it a breeze.
We also decided to
improve a little the project by adding doctrine fixture for the
sample user for the demo.
Staying connected
To be able to stay
connected after a page refresh, we had to use the localStorage to
store the token generation data. This way we can come back to our
client and still be connected. Tokens have a lifetime of 5 minutes.
You can change this
lifetime in the ‘WsseProvider.php’ file if necessary.
Update docker configuration
By upgrading so much
of the project, we could actually make some significant improvements
to docker configuration. On the Angular part, the building and watch
mode process is now natively supported. On the Symfony part, the NGINX configuration through PHP-FPM was also much easier without necessity for
custom configuration anymore. You can have a look to it in the
dockerify folder containing the ‘docker-compose.yml’
infrastructure and the nginx configuration files.
Please be aware that
the project is in development mode with watch mode activated, it is
not suited for production deployment as is. The idea is more to offer
a bootstrap project for developers to begin working on their project
with authentication out of the box. You might have to configure your own Continuous Delivery System for deployments.
Update License
To finish the License was also upgraded to MIT License. So you're free to use, modify and/or redistribute this software. The README was also upgraded with latest installation instructions.
Conclusion
Thanks for reading,
I hope that the project will be useful to you. You should have a look
to the README at https://github.com/FlyersWeb/angular-symfony
for more details.
No comments:
Post a Comment
Merci de votre commentaire. Celui-ci est en cours de modération.