Slide 1

Slide 1 text

Decoupling your application …with SSO, OAuth & more

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

/me Matthieu Moquet @MattKetmo Developer at …for almost 3 years

Slide 5

Slide 5 text

Back to 2011…

Slide 6

Slide 6 text

Covoiturage.fr 1 monolithic PHP app o Core website o Web mobile o B2B platform o Backoffice tools o Web views (mobile apps) o External widgets

Slide 7

Slide 7 text

Plain Old PHP No Dependency Injection No functional tests High coupling …hard to maintain

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

# wc -l lib.trip.php 3678 …longest method: 1000+ lines

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

Get rid of the Technical Debt

Slide 12

Slide 12 text

Since 2012 Start from scratch

Slide 13

Slide 13 text

2.0

Slide 14

Slide 14 text

NEW ORGANISATION NEW FRAMEWORK

Slide 15

Slide 15 text

Let’s embrace best practices

Slide 16

Slide 16 text

1 bundle BlablacarWebBundle BlablacarBlogBundle BlablacarFaqBundle BlablacarTripBundle BlablacarUserBundle ... N bundles OR

Slide 17

Slide 17 text

Services & Controllers §  Should controllers access the repository? §  How should I split my services? §  Is ContainerAware that bad? §  How to organize my Business Layer?

Slide 18

Slide 18 text

Where should I put my Model & Doctrine entities?

Slide 19

Slide 19 text

Forms Should I map my entities with my forms?

Slide 20

Slide 20 text

Validation §  Should I map validation with entities? §  Should I use groups?

Slide 21

Slide 21 text

Translations §  Catalogue message? §  Should I use key identifiers or phrases? §  How to name the keys?

Slide 22

Slide 22 text

Route naming homepage blablacar_homepage blablacar_main_homepage

Slide 23

Slide 23 text

Events §  Listen on Doctrine events? §  Create your own? ACTION / PRE_ACTION / POST_ACTION ? §  Subscribers VS. Listeners

Slide 24

Slide 24 text

Design When you don’t have full-time designer, then Bootstrap(2) FTW

Slide 25

Slide 25 text

With a few developers… At the beginning, you need to start quickly, (but you take time to write conventions). Legacy App New App

Slide 26

Slide 26 text

Then you hire new people

Slide 27

Slide 27 text

How many developers to be more efficient?

Slide 28

Slide 28 text

More code means…

Slide 29

Slide 29 text

Heavy Container

Slide 30

Slide 30 text

$ app/console cache:warmup Warming up the cache for the dev env with debug true

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

$ app/console assetic:dump Dumping all dev assets. Debug mode is on. 23:00:32 [file+] /path/to/web/css/0e781b6.css 23:00:35 [file+] /path/to/web/css/0e781b6_part_1_bootstrap_1.css 23:00:35 [file+] /path/to/web/css/0e781b6_part_2_buttons_1.css 23:00:35 [file+] /path/to/web/css/0e781b6_part_2_card_2.css 23:00:35 [file+] /path/to/web/css/0e781b6_part_2_form_3.css 23:00:35 [file+] /path/to/web/css/0e781b6_part_2_grid_4.css 23:00:36 [file+] /path/to/web/css/0e781b6_part_2_list_5.css 23:00:36 [file+] /path/to/web/css/0e781b6_part_2_navbar_6.css 23:00:36 [file+] /path/to/web/css/0e781b6_part_2_panel_7.css 23:00:37 [file+] /path/to/web/css/0e781b6_part_2_vcard_9.css 23:00:37 [file+] /path/to/web/js/e66598b.js 23:00:37 [file+] /path/to/web/js/e66598b_jquery_1.js 23:00:37 [file+] /path/to/web/js/e66598b_bootstrap_2.js 23:00:37 [file+] /path/to/web/js/e66598b_script_3.js

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

$ phpunit -c app ........................... .............. (63/975) .......................... ............... (126/975) .............. ........................... (189/975) .......F................ ................. (252/975) .............F....

Slide 35

Slide 35 text

Changed few lines of code? Run the full test suite!

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Optimize test execution time Invest in parallelization processes Split TestSuite in VMs (on AWS) Run 1h tests in 10min

Slide 38

Slide 38 text

One big projet makes your team less reactive How often do you deploy your main project?

Slide 39

Slide 39 text

https://code.facebook.com/posts/218678814984400/scaling-mercurial-at-facebook/

Slide 40

Slide 40 text

Changing foundations is expensive What if we want to change…

Slide 41

Slide 41 text

What if we want to change The backend framework? We don’t plan to change it, and we couldn’t

Slide 42

Slide 42 text

What if we want to change The testing framework? We won’t rewrite the whole test suite. But we can use several frameworks at the same time (eg. Behat)

Slide 43

Slide 43 text

What if we want to change The frontend framework? Well, we are stuck with Bootstrap2. Updating to Bootstrap3 or rewriting our own will take time.

Slide 44

Slide 44 text

What if we want to change The assets builder? Assetic took too long to compile all assets. We moved to asset management with Grunt.

Slide 45

Slide 45 text

What if we want to change The data layer? Actually frontend servers make MySQL queries. But in the long term, it’s not a good practice (see coming slides).

Slide 46

Slide 46 text

We’ll ALWAYS have technical debt. We must LIMIT it as much as possible.

Slide 47

Slide 47 text

Think as small as possible Microservices The secret to building large apps is never build large apps. Break your application into small pieces. Then, assemble those testable, bite-sized pieces into your big application — Justin Meyer

Slide 48

Slide 48 text

3 patterns to build a better software architecture…

Slide 49

Slide 49 text

Request-Response

Slide 50

Slide 50 text

Request-Response GET your resources synchronously Data Layer

Slide 51

Slide 51 text

Request-Response $user = $this ->get('my.repository.user') ->find(1337);

Slide 52

Slide 52 text

Request-Response mysql_query('...')

Slide 53

Slide 53 text

Request-Response Id   Firstname   Lastname   Pseudo   Email   Birthday   1337   Ma'hieu   Moquet   Ma'Ketmo   ma'[email protected]   1988-­‐12-­‐17  

Slide 54

Slide 54 text

Request-Response However front-end servers should NOT access the database directly It should fetch normalized data from an internal service API for the win!

Slide 55

Slide 55 text

Request-Response GET /users/123 Do you speak REST ? Better versioning & normalization

Slide 56

Slide 56 text

Request-Response …or you may speak: § SOAP § XML-RPC § Protobuffer § Thrift § etc.

Slide 57

Slide 57 text

Request-Response Even RabbitMQ can be used for synchronous requests scrutinizer-ci/rabbitmq src/Scrutinizer/RabbitMQ/Rpc http://www.rabbitmq.com/tutorials/tutorial-six-python.html

Slide 58

Slide 58 text

Request-Response

Slide 59

Slide 59 text

Command(Handler)

Slide 60

Slide 60 text

Command $cmd = FooCommand('bar'); $handler = FooCommandHandler(); $handler->execute($cmd); Do not expect a return value

Slide 61

Slide 61 text

Command Perfect for asynchronous jobs §  Send e-mails / SMS / PUSH notifications §  Image processing §  Data indexation §  Saving complex data §  etc.

Slide 62

Slide 62 text

Command publish consume RabbitMQ   DIRECT  rou

Slide 63

Slide 63 text

Command publish consume Easy  scaling  

Slide 64

Slide 64 text

Command Service is accessible via a queueing system only (not REST) §  RabbitMQ §  ActiveMQ §  Beanstalkd §  Gearman §  … More at http://queues.io

Slide 65

Slide 65 text

Sending Newsletters publish 100k messages Create an army of workers in AWS consume send mails message payload = emails address + content App Scheduler (Java + Quartz) Worker NL @10am segment X Get users of segment X (Scroll ElasticSearch)

Slide 66

Slide 66 text

PubSub Obverser / Event Dispatcher

Slide 67

Slide 67 text

PubSub $dispatcher = new EventDispatcher();! ! // Listen using an object or a callback! $listener = new AcmeListener();! $dispatcher->addListener('foobar', array($listener, 'onFoobar'));! ! $dispatcher->addListener('foobar', function (Event $event) {! // do something else with the events! });! ! // Dispatch event! $dispatcher->dispatch('foobar', $event);! Example with the Symfony EventDispatcher

Slide 68

Slide 68 text

PubSub Notify your infrastructure of every business events Publish events without knowing who is listening Create services without any core changes

Slide 69

Slide 69 text

PubSub pub RabbitMQ   TOPIC  rou

Slide 70

Slide 70 text

PubSub Use Case BI

Slide 71

Slide 71 text

user.register user.edit_bio user.left_rating user.post_trip ... Data WareHouse Log every business events in Hadoop

Slide 72

Slide 72 text

user.register user.edit_bio user.left_rating user.post_trip ... user.register user.post_trip ... Meanwhile… RealTime Dashboard Log every business events in ElasticSearch

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

ReqRes — Command — PubSub Message Broker RabbitMQ removes hard link between services

Slide 75

Slide 75 text

Now we have the keys to start a distributed architecture let’s start decoupling our application… Front-end desktop + mobile Hard to split in several projects (need to delegate jobs) API For mobile apps & partners Backoffice Set of administration tools Workers Already decoupled from the core app

Slide 76

Slide 76 text

Backoffice A set of independent tools Easy to split

Slide 77

Slide 77 text

Backoffice — CRUD Some tools are just data manipulation: – User Management – Blog – FAQ GET /users PUT /users/123 Data Layer

Slide 78

Slide 78 text

Backoffice — Moderation Manage user « data » which need to be moderated user.upload_avatar user.edit_bio user.left_rating UI to check data manually Auto detect spam & non compliant data Machine Learning data.received data.treated send mails

Slide 79

Slide 79 text

Backoffice — URL Shortener Some tools are completely independent https://www.blablacar.com/register SHORTEN No data shared with core business

Slide 80

Slide 80 text

Authentication Splitting our backoffice in many apps should not be a pain for the UX

Slide 81

Slide 81 text

Let’s build a Single Sign-On service

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

« OAuth is an open standard for authorization […] to access server resources on behalf of a resource owner » — Wikipedia

Slide 84

Slide 84 text

OAuth2 Grant Types Authorization Code Connect-like workflow Implicit Grant (Direct Token) Usefull for JS app Password flow Trusted app (client credentials) Client Credentials Basic (use of client id + secret)

Slide 85

Slide 85 text

OAuth2 Client App Use token to call API Server App

Slide 86

Slide 86 text

Do It Yourself

Slide 87

Slide 87 text

From LDAP to OAuth Given I am on the login page Then I should login with my LDAP credentials App LDAP Login

Slide 88

Slide 88 text

THERE IS A BUNDLE FOR THAT!

Slide 89

Slide 89 text

FR3DLdapBundle

Slide 90

Slide 90 text

FR3DLdapBundle/config.yml # LDAP Configuration! fr3d_ldap:! driver:! host: "%ldap_host%"! username: "%ldap_username%"! password: "%ldap_password%"! baseDn: "%ldap_username%"! user:! baseDn: "%ldap_user_dn%"! filter: "%ldap_user_filter%"! attributes:! - { ldap_attr: "uid", user_method: "setUsername" }! - { ldap_attr: "cn", user_method: "setName" }! - { ldap_attr: "mail", user_method: "setEmail" }! service:! user_manager: "acme.user_manager"!

Slide 91

Slide 91 text

From LDAP to OAuth Given I am on "/me" with "user" access token Then I should get "user" resources in JSON App LDAP OAuth2 API

Slide 92

Slide 92 text

THERE IS A BUNDLE FOR THAT!

Slide 93

Slide 93 text

FOSOAuthServerBundle

Slide 94

Slide 94 text

FOSOAuthServerBundle/security.yml firewalls:! api:! pattern: ^/api! fos_oauth: true! stateless: true  

Slide 95

Slide 95 text

From LDAP to OAuth App LDAP OAuth2 API Login

Slide 96

Slide 96 text

Enforce security PO said, this SSO entry-point should be a top-notch secure app

Slide 97

Slide 97 text

THERE ARE BUNDLES FOR THAT!

Slide 98

Slide 98 text

SchebTwoFactorBundle SpomkyIpFilterBundle CCDNUserSecurityBundle NelmioSecurityBundle …

Slide 99

Slide 99 text

App LDAP OAuth2 2FA FW

Slide 100

Slide 100 text

What about the client?

Slide 101

Slide 101 text

THERE IS A BUNDLE FOR THAT!

Slide 102

Slide 102 text

HWIOAuthBundle

Slide 103

Slide 103 text

No content

Slide 104

Slide 104 text

# HWI OAuth Configuration! hwi_oauth:! firewall_name: "main"! resource_owners:! acme_sso:! type: "oauth2"! client_id: "%client_id%"! client_secret: "%client_secret%"! access_token_url: "%base_url%/oauth/v2/token"! authorization_url: "%base_url%/oauth/v2/auth"! infos_url: "%base_url%/api/me”! paths:! identifier: "id"! nickname: "username"! realname: "name"! email: "email"!

Slide 105

Slide 105 text

UX — We don’t really need this login form

Slide 106

Slide 106 text

UX — We don’t really need a one-button page

Slide 107

Slide 107 text

302 Found UX — Get transparent login process

Slide 108

Slide 108 text

OAuth is all about authorization, not authentication Watch out for weaknesses & attacks

Slide 109

Slide 109 text

GET /api/me {! "id": 1337,! "firstname": "Matthieu",! "lastname": "Moquet",! "nickname": "MattKetmo"! }! (the cheat)

Slide 110

Slide 110 text

CSRF http://example.org?redirect_uri=xxxx&state=yyyy session[state] === params[state]. http://tools.ietf.org/html/draft-ietf-oauth-v2-27#section-10.12

Slide 111

Slide 111 text

id_token Multiple Response Type Encoding Practices. Provides an assertion of the identity of the Resource Owner. http://openid.bitbucket.org/oauth-v2-multiple-response-types-1_0.html

Slide 112

Slide 112 text

However if OAuth is not designed to be an SSO protocol, what should I use?

Slide 113

Slide 113 text

SAML (Security Assertion Markup Language) SAML is an XML-based protocol that uses security tokens containing assertions to pass information about a principal between an identity provider, and a consumer. There are bundles/lib for that (but not maintained, see impl.) §  pdias/FOSSamlBundle §  aerialship/SamlSPBundle §  chtitux/sfSAMLPlugin (symfony1)

Slide 114

Slide 114 text

JWT (JSON Web Token) Payload signed server-side with a JSON Web Signature (JWS). auth.   signed token request

Slide 115

Slide 115 text

JWT (JSON Web Token) Sign payload using a secret key auth.   signed token request

Slide 116

Slide 116 text

firebase/php-jwt curl –H "Authorization: Bearer eyJ0eXAiOiJKV..." example.org $key = "s3cr3t_key"; $token = array( "sub" => "mattketmo", "aud" => "http://example.com", "exp" => 1356999524, ); $jwt = JWT::encode($token, $key);  // eyJ0eXAiOiJKV...

Slide 117

Slide 117 text

namshi/jose OpenSSL + cookies // Auth (SSO) $privateKey = openssl_pkey_get_private("file://private.key"); $jws = new JWS('RS256'); $jws->setPayload([$userId]); $jws->sign($privateKey) setcookie('identity', $jws->getTokenString()); // Client App $jws = JWS::load($_COOKIE['identity']); $publicKey = openssl_pkey_get_public("/public.key"); if ($jws->isValid($publicKey)) { $payload = $jws->getPayload(); $userId = $payload['id']; }

Slide 118

Slide 118 text

OAuth2 + JWT http://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-08

Slide 119

Slide 119 text

Of course, there are Symfony bundles: –  formapro/FpOpenIdBundle –  KainHaart/OpenIDAuthBundle –  etc.

Slide 120

Slide 120 text

Hawk Shared secret between client & server by Eran Hammer Read more at http://alexbilbie.com/2012/11/hawk-a-new-http-authentication-scheme/

Slide 121

Slide 121 text

CAS (Central Authentication Service) Example of client implementation BeSimple/BeSimpleSsoAuthBundle

Slide 122

Slide 122 text

h"ps://github.com/BeSimple/BeSimpleSsoAuthBundle/blob/master/Resources/doc/protocols.md  

Slide 123

Slide 123 text

No content

Slide 124

Slide 124 text

Core app is now lightweight Tiny container (less services/listeners) Test suite is smaller

Slide 125

Slide 125 text

Choose the right tools for the task Backend / Frontend / Datastore / …

Slide 126

Slide 126 text

Make experiments

Slide 127

Slide 127 text

Work faster No more bottleneck & dependencies with other dev teams

Slide 128

Slide 128 text

BE EFFICIENT AVOID REPETITIVE PROCESSES

Slide 129

Slide 129 text

Install dev environment in less than 1h

Slide 130

Slide 130 text

Bootstrap everything composer create-project blablacar/backoffice-app git clone [email protected]/worker-skeleton.git via git or via composer

Slide 131

Slide 131 text

Enforce reusable components { "require": { "blablacar/monolog": "~1.0", "blablacar/scheduler-client": "~1.1", "blablacar/redis-client": "~1.2", "blablacar/rabbit-mq-admin-toolkit": "dev-master" } }

Slide 132

Slide 132 text

Be ready for production Don’t loose time in configuration setup Parameters for $ENV Config template for $PROJECT Config file for $PROJECT/$ENV Centralized build tool to generate a project configuration file for any environment (local / dev / staging / prod)

Slide 133

Slide 133 text

Never miss a log

Slide 134

Slide 134 text

Don’t be lost in translations Open-sourced a tool to manage your projects’ translations easily

Slide 135

Slide 135 text

More information at openl10n.io

Slide 136

Slide 136 text

Thank you Slides available at moquet.net/talks/symfony-live-2014 Leave feedbacks @MattKetmo we’re hiring!