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

OAuth 2.0 and Django, What you should know

Jharrod LaFon
September 03, 2014

OAuth 2.0 and Django, What you should know

OAuth 2.0 is the current version of OAuth, a hotly debated open standard for authorization. Implementing it allows your users to grant access to their data to other services, turning your collection of services into a platform. In this talk I will discuss the options you have for creating your own OAuth 2.0 components with Django, how to use them, and common implementation mistakes.

Jharrod LaFon

September 03, 2014
Tweet

Other Decks in Technology

Transcript

  1. about(self) •  OpenEye Scientific Software –  We make scientific software

    for drug discovery –  Corporate member of the Django Software Foundation •  I create web services with Django •  Los Alamos National Laboratory –  High Performance Computing
  2. What you should know •  How it works •  How

    to use it with Django •  What common mistakes to avoid
  3. Enter OAuth •  Authorization for web services without disclosing a

    password •  The ‘valet key for the web’ •  OAuth 1.0 (RFC 5849) - April, 2010
  4. OAuth 2.0 •  “the next evolution of the OAuth protocol”

    •  A framework, not a protocol •  RFC 6749 http://tools.ietf.org/html/rfc6749 •  Added TLS, removed complexity
  5. OAuth 2.0 Vocabulary •  Resource Owner – The user • 

    Resource Server – A service hosting data •  Client – An application that accesses data residing on the resource server and belonging to the resource owner •  Authorization Server – Authenticates the user, grants tokens •  Token - Credential
  6. OAuth 2.0 Vocabulary Cloud   Storage   Alice   3D

      Prin4ng   Service   Resource  Owner   Resource  Server   Client   Authoriza4on   Server  
  7. OAuth 2 Grants •  A grant is a way for

    a client to get a token Grant Types •  Authorization Code •  Implicit •  Resource Owner Password Credentials •  Client Credentials
  8. OAuth 2 Flows •  A flow is the sequence of

    steps necessary to obtain a grant •  Authorization code flow –  ‘optimized for confidential clients’
  9. Before the flow •  The user has an account on

    the authorization server •  The client has registered with the authorization server and has its own client_id and client_secret (credentials), and redirect_uris
  10. Client to Auth. Server Redirect Cloud   Storage   Alice

      3D   Prin4ng   Service   GET  /login   redirect  to  auth.  server  /authorize   GET  /authorize  
  11. Client to Auth. Server Redirect hAps://www.example.com/auth/?    client_id=42    &scope=read+write

       &state=041b48ea    &redirect_uri=  hAps://evilclient.com/auth/callback   hAps://clientapp.com/auth/callback  
  12. Authorization Code Flow •  The authorization server has validated the

    redirect URI, client_id, and scope •  The user has approved or denied the authorization request
  13. Redirect back to client Cloud   Storage   Alice  

    3D   Prin4ng   Service   GET  /authorize   redirect  to  client  /callback     GET  /callback  
  14. Redirect back to client https://www.clientapp.com/auth/callback/? state=041b48ea& code=4275c127d799 If  state  is

     not  checked,  an  a"acker’s  account   on  the  authoriza4on  server  can  be  linked  to   the  user’s  account  on  the  client  
  15. Finally, a token •  The client exchanges the authorization code

    for a token –  The code expires in 10 minutes or less, –  The code can be used only once •  Requires both the authorization code and the client’s credentials •  Tokens expire, but there are refresh tokens
  16. What do I do with a token? •  Access the

    user’s data –  Include token in request header •  Authorization: Bearer token_value! •  Create a linked account (in our case, a new Django user)
  17. Failures by role (client vs. auth server) •  Not using

    TLS (either) •  Not validating the redirect URI (auth. server) •  Not using the state parameter (either) •  Not authenticating the client (auth. server) •  Not expiring authorization codes (auth. server)
  18. Integrating OAuth 2 Consumer     Role   •  Client

          Requirements   •  Register  with  authoriza4on  servers   •  Redirect  users  to  authoriza4on   endpoint   •  Must  provide  callback  URIs   •  Deal  with  inconsistent   implementa4ons     Provider     Role   •  Authoriza4on  Server   •  Resource  Server     Requirements   •  URLs  for  authoriza4on  and   tokens   •  Client  registra4on   •  User  registra4on   •  Make  your  own  inconsistent   implementa4on  
  19. Consistently Inconsistent All OAuth 2.0 implementations are consistent in the

    same way that all Unicode strings are UTF-8. Token  Endpoints   •  Google:  hAps://accounts.google.com/o/oauth2/auth   •  FB:  hAps://www.facebook.com/dialog/oauth   •  Github:  hAps://github.com/login/oauth/authorize   •  Foursquare:   hAps://foursquare.com/oauth2/authen4cate    
  20. What the spec. doesn’t say $ grep –c ‘beyond the

    scope’ rfc-5949.txt! ! 5! ! ! ! $ grep –c ‘beyond the scope’ rfc-6749.txt! ! 9! OAuth  1.0   OAuth  2.0  
  21. Left up to you •  ‘...methods used to access protected

    resources...’ •  ‘...interaction between the authorization server and resource server...’ •  ‘...location of the authorization endpoint...’ •  ‘...location of the token endpoint...’ •  ‘...methods used to validate the access token...’
  22.             OAuth 2 Packages for

    Django Package Consumer Provider Python 3 Coverage Downloads python-social-auth ✔ ✖ ✔ 88% 44k django-allauth ✔ ✖ ✔ 37% 14k django-oauth2-provider ✖ ✔ ✔ 89% 8k django-oauth-toolkit ✔ ✔ ✔ 100% 4k django-allaccess ✔ ✖ ✔ 83% 1k django-oauthost ✔ ✔ ✔ 79% < 1k django-oauth2-consumer ✔ ✖ ✖ 95% < 1k djoauth2 ✔ ✔ ✖ 95% < 1k oauthlib ✔ ✔ ✔  97% 161k
  23. Django Authentication (django.contrib.auth) •  Middleware   –  Authen4cates  user  

    –  Sets  request.user  to  the  authen4cated  (or  anonymous)   user   ! ! Class ModelBackend(object):! def authenticate(username, password):! ! ...! ! if user.check_password(password):! ! ! return user!
  24. Python Social Auth http://psa.matiasaguirre.net/ •  Supports several frameworks, providers • 

    An authorization backend for each provider •  Has a ‘pipeline’ mechanism with code for association, disassociation
  25. Python Social Auth •  Implements state parameter J –  But

    not for every provider (it’s configurable) L •  Sometimes incorrectly L –  spotify.com –  angel.co –  https://github.com/omab/python-social-auth/issues/367 –  Use the example app to try out the providers and verify settings
  26. Python Social Auth Django Support •  Does things the Django

    way –  @login_required still works –  Works with session, authentication middleware •  Deals with all of those inconsistent provider implementations for you
  27. Python Social Auth Cloud   Storage   Resource  Owner  

    Resource  Server   Client   Alice   3D   Prin4ng   Service  
  28. Python Social Auth Summary •  If you only need an

    OAuth 2.0 consumer, start with PSA •  Carefully choose your backends, and verify their settings
  29. Django OAuth Toolkit https://github.com/evonove/django-oauth-toolkit •  oauthlib + Django Models, Views,

    and URLs •  RFC 6749 Compliant –  Supports the different flow types –  Uses the state parameter J –  Validates the redirect URI J •  “OAuth2 goodies for Djangonauts!”
  30. Django OAuth Toolkit Cloud   Storage   Resource  Owner  

    Resource  Server   Client   Alice   3D   Prin4ng   Service   Authoriza4on   Server  
  31. Django OAuth Toolkit Views •  For managing clients (Applications) • 

    For managing tokens •  Mixins for protecting resources (by requiring tokens)
  32. Django OAuth Toolkit (Res. Server) from oauth2_provider.views.generic import ProtectedResourceView! !

    class ApiEndpoint(ProtectedResourceView):! def get(self, request):! return HttpResponse(‘data’)! ! !
  33. Django OAuth Toolkit with DRF •  Built  in  support  for

     Django  Rest  Framework     ! class UserViewSet(viewsets.ModelViewSet):! permission_classes = [! ! IsAuthenticated,! ! TokenHasScope! ]! required_scopes = [‘read_users’]! model = User! ! !
  34. Django OAuth Toolkit •  Both a Resource Server and an

    Authorization Server –  “The methods used by the resource server to validate the access token (as well as any error responses) are beyond the scope...” token = AccessToken.objects.get(token=value)! if access_token.is_valid(scopes):! !# success!
  35. Django OAuth Toolkit •  Separate resource server(s) from the authorization

    server –  “The authorization server may be the same server as the resource server or a separate entity. A single authorization server may issue access tokens accepted by multiple resource servers” •  DOT doesn’t immediately allow this separation –  Every resource server has to use the authorization server’s DB to access tokens
  36. Database   Authoriza4on   &  Resource   Server   Database

      Authoriza4on   Server   Database   Resource   Server   Client   vs.  
  37. Separate Django Resource Server •  Has a separate database – 

    Create linked accounts locally for each account on the authorization server •  Can no longer use Django OAuth Toolkit authorization backend or middleware •  Needs a way to validate tokens “The methods used by the resource server to validate the access token are beyond the scope of this specification but generally involve an interaction or coordination between the resource server and the authorization server.”
  38. Solution 1: Token validation view class TokenInfoView(ProtectedResourceView):! def get(self, request):!

    token_data = {! ! "scope": request.access_token.scope,! ! ! “expires”: request.access_token.expires,! ! ! !...! }! return HttpResponse(token_data)! ! •  S+ll  RFC  6749  compliant!   •  Google  does  it  (hAps://www.googleapis.com/oauth2/v1/ tokeninfo)  
  39. Solution 2: Out of band storage with Django Signals post_save.connect(!

    !sync_token_func, ! !AccessToken, !! !dispatch_uid="sync_token”! )! ! post_delete.connect(! !delete_token_func, ! !AccessToken, ! !dispatch_uid="delete_token”! )!
  40. Django Resource Server •  Now tokens can be verified • 

    Without DOT, no OAuth2TokenMiddleware •  Need to roll your own authentication backend –  Retrieve token from request –  Verify token –  Set request.user (create local account if necessary) –  oauthlib has nice examples in their documentation
  41. •  You’ve seen –  Django as a consumer with Python

    Social Auth –  Django as a provider with Django OAuth Toolkit •  Avoid common client mistakes –  Use the state parameter •  Avoid common auth. server mistakes –  Use the state parameter –  Validate the redirect URI –  Expire authorization codes •  Use TLS •  Don’t just take my word for it, read the spec.