Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DPC 2015 - Implement Single Sign On easily with Symfony

DPC 2015 - Implement Single Sign On easily with Symfony

We'll first make a round trip to the Security world of Symfony2 : understanding what is a provider, a firewall, the two very important services "security.token_storage" and "security.authorization_checker" and of course how the user object is important in Symfony.
Then we'll see how to authenticate a user through a OAuth2 server (like facebook) very easily.

With few lines of code, we'll be able to go further and see how we can make sure that a user stay logged in from application to another.

Sarah KHALIL

June 27, 2015
Tweet

More Decks by Sarah KHALIL

Other Decks in Technology

Transcript

  1. IMPLEMENT SINGLE SIGN ON EASILY WITH SYMFONY
    Sarah Khalil - @saro0h

    View Slide

  2. IMPLEMENT SINGLE SIGN ON EASILY WITH SYMFONY
    Sarah Khalil - @saro0h
    Disclaimer you need to have
    some experience with security
    in Symfony.

    View Slide

  3. WHO AM I?
    • Head of
    • Trainer & Developer
    • Enjoying sharer
    • Contributor to

    View Slide

  4. View Slide

  5. WHAT’S THE PLAN?
    1. Security in Symfony
    2. Let’s implement authentication with Github (without any
    third party library)
    3. Authenticate apps in the SOA context
    4. Advices

    View Slide

  6. I. SECURITY IN SYMFONY

    View Slide

  7. Security Component

    View Slide

  8. Security Bundle

    View Slide

  9. 2 MAIN PARTS
    •Authentication
    •Authorization
    We won’t talk
    about that today.
    OK, just
    a little.

    View Slide

  10. LET’S TALK ABOUT
    AUTHENTICATION

    View Slide

  11. AUTHENTICATION
    Ensures that the user
    is who he claims to
    be.

    View Slide

  12. WHAT DO WE HAVE TO
    WRITE?
    Most of the time, it’s all about
    configuration.

    View Slide

  13. WHAT DO WE HAVE TO WRITE?

    View Slide

  14. WHAT DO WE HAVE TO WRITE?
    security:
    encoders:
    Symfony\Component\Security\Core\User\User: bcrypt
    providers:
    in_memory:
    memory:
    users:
    sarah:
    password: $2a$12$LCY0M…
    roles: 'ROLE_USER'
    firewalls:
    admin:
    provider: in_memory
    pattern: /^admin
    form_login:
    login_path: /login
    check_path: /login_check

    View Slide

  15. WHAT DO WE HAVE TO WRITE?
    security:
    encoders:
    Symfony\Component\Security\Core\User\User: bcrypt
    providers:
    in_memory:
    memory:
    users:
    sarah:
    password: $2a$12$LCY0M…
    roles: 'ROLE_USER'
    firewalls:
    admin:
    provider: in_memory
    pattern: /^admin
    form_login:
    login_path: /login
    check_path: /login_check

    View Slide

  16. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    $encoder-­‐>isPasswordValid('mypwd');
    Encoder
    true
    authenticated
    false
    |
    401: Unauthorized
    /admin/myprofile
    or

    View Slide

  17. CONFIGURATION
    • Firewall
    • Encoder
    • Provider

    View Slide

  18. FIREWALL

    View Slide

  19. Determines whether or
    not the user needs to be
    authenticated.
    AUTHENTICATION: FIREWALL

    View Slide

  20. Your application

    View Slide

  21. Your application
    all routes beginning
    with /shop

    View Slide

  22. Your application
    all routes begin
    with /admin
    all routes beginning
    with /shop

    View Slide

  23. Your application
    all routes begin
    with /admin
    all routes beginning
    with /shop all routes beginning
    with /blog

    View Slide

  24. Your application
    all routes begin
    with /admin
    all routes beginning
    with /shop all routes beginning
    with /blog
    all other routes…

    View Slide

  25. Your application
    all routes begin
    with /admin
    all routes beginning
    with /shop all routes beginning
    with /blog
    all other routes…
    The user needs to be authenticated
    to access that part of the app

    View Slide

  26. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    authenticated
    401: Unauthorized
    or
    /admin/myprofile

    View Slide

  27. WHAT DO WE HAVE TO WRITE?
    security:
    firewalls:
    admin:
    provider: in_memory
    pattern: /^admin
    form_login:
    login_path: /login
    check_path: /login_check

    View Slide

  28. BUILT-IN WAYS OF AUTHENTICATING A USER

    View Slide

  29. http-basic
    http-digest
    BUILT-IN WAYS OF AUTHENTICATING A USER

    View Slide

  30. http-basic
    http-digest
    form-based
    BUILT-IN WAYS OF AUTHENTICATING A USER

    View Slide

  31. http-basic
    http-digest
    form-based
    x.509 certificate
    BUILT-IN WAYS OF AUTHENTICATING A USER

    View Slide

  32. PROVIDER

    View Slide

  33. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  34. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  35. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  36. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  37. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  38. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  39. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  40. Finds and/or creates users
    AUTHENTICATION: PROVIDER

    View Slide

  41. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    authenticated
    401: Unauthorized
    /admin/myprofile
    or

    View Slide

  42. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    authenticated
    401: Unauthorized
    /admin/myprofile
    or

    View Slide

  43. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    authenticated
    401: Unauthorized
    /admin/myprofile
    or

    View Slide

  44. security:
    providers:
    in_memory:
    memory:
    users:
    sarah:
    password: $2a$12$LCY0M…
    roles: 'ROLE_USER'

    View Slide

  45. interface UserProviderInterface
    {
    /**
    * Loads the user for the given username.
    *
    * This method must throw UsernameNotFoundException if the user is not
    * found.
    */
    public function loadUserByUsername($username);
    /**
    * Refreshes the user for the account interface.
    *
    * It is up to the implementation to decide if the user data should be
    * totally reloaded (e.g. from the database), or if the UserInterface
    * object can just be merged into some internal array of users /
    identity
    * map.
    */
    public function refreshUser(UserInterface $user);
    /**
    * Whether this provider supports the given user class.
    */
    public function supportsClass($class);
    }

    View Slide

  46. ENCODER

    View Slide

  47. AUTHENTICATION: ENCODER
    Used for hashing and
    comparing a password.

    View Slide

  48. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    authenticated
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  49. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    authenticated
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  50. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    authenticated
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  51. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    authenticated
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  52. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    authenticated
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  53. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    authenticated
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  54. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    authenticated
    true
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  55. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    authenticated
    true
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile
    false
    |
    401: Unauthorized
    or

    View Slide

  56. CONFIGURATION
    security:
    encoders:
    Symfony\Component\Security\Core\User\User: bcrypt
    SecurityBundle

    View Slide

  57. interface PasswordEncoderInterface
    {
    /**
    * Encodes the raw password.
    */
    public function encodePassword($raw, $salt);
    /**
    * Checks a raw password against an encoded password.
    */
    public function isPasswordValid($encoded, $raw, $salt);
    }

    View Slide

  58. ALL TOGETHER NOW!

    View Slide

  59. security:
    encoders:
    Symfony\Component\Security\Core\User\User: bcrypt
    providers:
    in_memory:
    memory:
    users:
    sarah:
    password: $2a$12$LCY0M…
    roles: 'ROLE_USER'
    firewalls:
    admin:
    provider: in_memory
    pattern: /^admin
    form_login:
    login_path: /login
    check_path: /login_check

    View Slide

  60. AUTHENTICATION FLOW
    backend

    View Slide

  61. AUTHENTICATION FLOW
    backend
    /admin/myprofile

    View Slide

  62. AUTHENTICATION FLOW
    Firewall
    backend
    /admin/myprofile

    View Slide

  63. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    /admin/myprofile

    View Slide

  64. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    /admin/myprofile

    View Slide

  65. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    /admin/myprofile

    View Slide

  66. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    /admin/myprofile

    View Slide

  67. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    /admin/myprofile

    View Slide

  68. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    /admin/myprofile

    View Slide

  69. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    /admin/myprofile

    View Slide

  70. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    /admin/myprofile

    View Slide

  71. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    /admin/myprofile

    View Slide

  72. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    /admin/myprofile

    View Slide

  73. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    true
    /admin/myprofile

    View Slide

  74. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    true
    authenticated
    /admin/myprofile

    View Slide

  75. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    true
    authenticated
    /admin/myprofile
    or

    View Slide

  76. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    true
    authenticated
    false
    |
    /admin/myprofile
    or

    View Slide

  77. AUTHENTICATION FLOW
    Firewall
    backend
    username = ‘sarah.khalil’
    password = ‘mypwd’
    Provider
    $provider-­‐>loadUserByUsername('sarah.khalil');
    $user  =  new  User(‘sarah.khalil’);
    Encoder
    Factory
    $factory-­‐>getEncoder($user);
    $encoder
    Encoder
    $encoder-­‐>isPasswordValid('mypwd');
    true
    authenticated
    false
    |
    401: Unauthorized
    /admin/myprofile
    or

    View Slide

  78. WHAT IS A USER?
    The object stores:
    • credentials
    • associated roles

    View Slide

  79. WHAT IS A USER?
    Symfony\Component\Security\Core\User\UserInterface
    Symfony\Component\Security\Core\User\AdvancedUserInterface

    View Slide

  80. WHAT DO WE HAVE MORE?
    Authorization

    View Slide

  81. SERVICES
    No more security.context!

    View Slide

  82. View Slide

  83. $this->get('security.context')->getToken()->getUser();
    Before 2.6

    View Slide

  84. After
    $this->get('security.token_storage')->getToken()->getUser();
    $this->get('security.context')->getToken()->getUser();
    Before 2.6

    View Slide

  85. After
    $this->get('security.token_storage')->getToken()->getUser();
    $this->get('security.context')->getToken()->getUser();
    Before 2.6
    Before 2.6
    $this->get('security.context')->isGranted(‘ROLE_USER’);

    View Slide

  86. After
    $this->get('security.token_storage')->getToken()->getUser();
    $this->get('security.context')->getToken()->getUser();
    Before 2.6
    Before 2.6
    $this->get('security.context')->isGranted(‘ROLE_USER’);
    After
    $this->get('security.authorization_checker')->isGranted(‘ROLE_USER’);

    View Slide

  87. II. AUTHENTICATION WITH
    GITHUB

    View Slide

  88. VERY FIRST STEPS
    • http://symfony.com/doc/current/cookbook/security/
    api_key_authentication.html
    • https://developer.github.com/v3/oauth/
    • https://github.com/settings/applications/new
    • https://github.com/csarrazi/CsaGuzzleBundle
    • [supports last version of Guzzle]

    View Slide

  89. OAUTH
    • Protocol
    • 2 versions
    • Read the documentation of the
    service you need to use

    View Slide

  90. View Slide

  91. View Slide

  92. View Slide

  93. IMPLEMENTATION

    View Slide

  94. CREATE THE USER CLASS
    Stores all information coming from the provider.

    View Slide

  95. CREATE THE TEMPLATES

    View Slide

  96. CREATE THE TEMPLATES
    {% extends 'base.html.twig' %}
    {% block body %}
    Homepage !
    This application shows how to implement an authentication with Github
    with Symfony.
    {% endblock %}
    {% extends 'base.html.twig' %}
    {% block body %}
    Administration
    If you can access this page, it's because you are authenticated.

    Actually you are!


    Your login: {{ app.user.username }}


    Your name (in case you forgot…): {{ app.user.name }}


    Aaaaand your email address: {{ app.user.email }}


    Your FACE:
    {% endblock %}
    admin.html.twig
    index.html.twig

    View Slide

  97. CONFIGURE THE
    SecurityBundle

    View Slide

  98. View Slide

  99. security:
    firewalls:
    secured_area:
    pattern: ^/admin
    stateless: false
    simple_preauth:
    authenticator: github_authenticator
    provider: github_user_provider
    logout:
    path: /admin/logout
    target: /

    View Slide

  100. security:
    firewalls:
    secured_area:
    pattern: ^/admin
    stateless: false
    simple_preauth:
    authenticator: github_authenticator
    provider: github_user_provider
    logout:
    path: /admin/logout
    target: /
    Trigger authentication!

    View Slide

  101. security:
    firewalls:
    secured_area:
    pattern: ^/admin
    stateless: false
    simple_preauth:
    authenticator: github_authenticator
    provider: github_user_provider
    logout:
    path: /admin/logout
    target: /
    Create that
    authenticator
    Trigger authentication!

    View Slide

  102. security:
    firewalls:
    secured_area:
    pattern: ^/admin
    stateless: false
    simple_preauth:
    authenticator: github_authenticator
    provider: github_user_provider
    logout:
    path: /admin/logout
    target: /
    Create that
    authenticator
    Create that provider
    Trigger authentication!

    View Slide

  103. AUTHENTICATOR

    View Slide

  104. class
    GithubAuthenticator implements SimplePreAuthenticatorInterface, AuthenticationFailureHandlerInterface
    {
    public function createToken(Request $request, $providerKey)
    {
    // This method is called first.
    // Get an access token to be able to use the API of Github
    // return a PreAuthenticatedToken storing this access token. No user yet!
    }
    public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
    {
    // This method is called secondly.
    // Call the loadUserByUsername from the provider, responsible of getting the
    user through the API thanks to the access token
    // return a PreAuthenticatedToken storing the user and its roles.
    }
    public function supportsToken(TokenInterface $token, $providerKey)
    {
    // Make sure that the token is an instance of PreAuthenticatedToken
    // and that it stores the provider key
    }
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
    return new Response("Authentication Failed :(", 401);
    }
    }

    View Slide

  105. Make it a service.
    id => github_authenticator

    View Slide

  106. PROVIDER

    View Slide

  107. security:
    firewalls:
    #…
    providers:
    github_user_provider:
    id: github_user_provider

    View Slide

  108. class GithubUserProvider implements UserProviderInterface
    {
    public function loadUserByUsername($username)
    {
    // Calls the Github API to get the user info.
    // Creates the User object with all of the info.
    }
    public function refreshUser(UserInterface $user)
    {
    // Called at each request.
    // Returns the object user coming from the session.
    }
    public function supportsClass($class)
    {
    return 'AppBundle\Model\User' === $class;
    }
    }

    View Slide

  109. Make it a service.
    id => github_user_provider

    View Slide

  110. View Slide

  111. View Slide

  112. III. AUTHENTICATE WITH ALL
    APPS

    View Slide

  113. OAuth server
    app 1 app 2
    app 3 app n

    View Slide

  114. OAuth server
    ecommerce API Blog API
    Frontend Backend

    View Slide

  115. OAuth server
    ecommerce API Blog API
    Frontend Backend
    http://e-commerce.api.domain.name/ http://blog.api.domain.name/
    http://domain.name/ http://domain.name/

    View Slide

  116. • UserAPI
    • Contacts the Oauth server;
    • Is your own Oauth server;
    • Authenticates each request.
    • Each app must have its OAUTH
    application credentials registered to have
    the right settings for each micro service.

    View Slide

  117. OAuth server
    Frontend
    blog API

    View Slide

  118. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me

    View Slide

  119. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me

    View Slide

  120. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate

    View Slide

  121. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate
    returns access
    token

    View Slide

  122. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate
    returns access
    token
    with access token

    View Slide

  123. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate
    returns access
    token
    validate access
    token
    with access token

    View Slide

  124. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate
    returns access
    token
    validate access
    token
    validated
    with access token

    View Slide

  125. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate
    returns access
    token
    validate access
    token
    validated
    get articles
    with access token

    View Slide

  126. OAuth server
    Frontend
    blog API
    http://domain.name/articles
    http://api-blog.domain.name/articles
    http://api-user.domain.name/me
    authenticate
    returns access
    token
    validate access
    token
    validated
    get articles
    with access token

    View Slide

  127. EXCHANGE TOKEN
    BETWEEN APPLICATIONS

    View Slide

  128. Front 1
    Front 2
    GET / HTTP/1.1
    Host: backend.domain.name
    Authorization: bearer xxxx-xxxx
    GET /#xxxx-xxxx HTTP/1.1
    Host: domain.name

    View Slide

  129. Front 1
    Front 2
    GET / HTTP/1.1
    Host: backend.domain.name
    Authorization: bearer xxxx-xxxx
    GET /#xxxx-xxxx HTTP/1.1
    Host: domain.name
    Event[Listener|Subscriber] =>
    kernel.request to extract the token:
    1. Validate the token;
    2. Call the API to get the user info
    from the Oauth server;
    3. User authenticated.

    View Slide

  130. Front 1
    Front 2
    GET / HTTP/1.1
    Host: backend.domain.name
    Authorization: bearer xxxx-xxxx
    GET /#xxxx-xxxx HTTP/1.1
    Host: domain.name
    Event[Listener|Subscriber] =>
    kernel.request to extract the token:
    1. Validate the token;
    2. Call the API to get the user info
    from the Oauth server;
    3. User authenticated.
    Is he/she?
    For Symfony,
    nope.

    View Slide

  131. Front 1
    Front 2
    GET / HTTP/1.1
    Host: backend.domain.name
    Authorization: bearer xxxx-xxxx
    GET /#xxxx-xxxx HTTP/1.1
    Host: domain.name

    View Slide

  132. Front 1
    Front 2
    GET / HTTP/1.1
    Host: backend.domain.name
    Authorization: bearer xxxx-xxxx
    GET /#xxxx-xxxx HTTP/1.1
    Host: domain.name
    In the application you are redirecting
    your user, make sure that the firewall
    triggers authentication when the user
    comes from another application
    (another firewall for another pattern
    for instance).
    And in your authenticator extract the
    access token from your header/URI to
    finally do your business with the Oauth
    server to get the user’s info.

    View Slide

  133. Front 1
    Front 2
    GET / HTTP/1.1
    Host: backend.domain.name
    Authorization: bearer xxxx-xxxx
    GET /#xxxx-xxxx HTTP/1.1
    Host: domain.name
    In the application you are redirecting
    your user, make sure that the firewall
    triggers authentication when the user
    comes from another application
    (another firewall for another pattern
    for instance).
    And in your authenticator extract the
    access token from your header/URI to
    finally do your business with the Oauth
    server to get the user’s info.
    Now you’re using the
    security process of
    Symfony.

    View Slide

  134. IF MULTIPLE FRONTENDS
    • Send the access token from fronts to fronts.
    • Use:
    • either the « # » as it is not logged anywhere
    • and / or the access token in the header.
    • Use a special listener to get it and have it in the request

    View Slide

  135. IV. ADVICES

    View Slide

  136. • To mutualise the code to access to the Oauth
    server
    • Authenticator, Provider and User class can be in a
    shared bundle.
    • To avoid to much connections to the Oauth
    server (performances)
    • Cache strategy!

    View Slide

  137. View Slide

  138. CACHE STRATEGY
    In the micro service in charge of the authentication :
    • When getting back the access token, from the URL or the
    header
    • check that the Doctrine cache has the access token and
    until when the token is valid;
    • if not:
    • call the Oauth server, get a new access token;
    • save the access token, when it expires and the user info.

    View Slide

  139. CACHE STRATEGY
    Store those tokens anywhere you want: Redis,
    MongoDB…
    Be careful: once logout, the access token needs
    to be revoked everywhere.

    View Slide

  140. View Slide

  141. View Slide

  142. Need training? Come see us
    at the SensioLabs booth!

    View Slide

  143. Thank you!
    @saro0h
    speakerdeck.com/saro0h/
    saro0h
    This is a
    zero guys!
    github.com/saro0h/oauth-github

    View Slide