Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

Commit

Permalink
feat: add ability to use openid-connect flow for other providers
Browse files Browse the repository at this point in the history
  • Loading branch information
max-wittig committed Jul 16, 2018
1 parent 578432d commit 25ae598
Show file tree
Hide file tree
Showing 13 changed files with 191 additions and 157 deletions.
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
include setup.py package.json webpack.config.js README.rst MANIFEST.in LICENSE AUTHORS
recursive-include sentry_auth_google/templates *
recursive-include sentry_auth_openid_connect/templates *
global-exclude *~
20 changes: 16 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,32 @@ Install

$ pip install https://github.com/getsentry/sentry-auth-google/archive/master.zip

Setup
-----
Example Setup for Google
------------------------

Start by `creating a project in the Google Developers Console <https://console.developers.google.com>`_.

In the **Authorized redirect URIs** add the SSO endpoint for your installation::

https://sentry.example.com/auth/sso/

Naturally other providers, that are supporting OpenID-Connect can also be used (like GitLab).
To get the OpenID-Configuration of your favorite provider, just go to **PROVIDER_URL**/.well-known/openid-configuration

Finally, obtain the API keys and plug them into your ``sentry.conf.py``:

.. code-block:: python
GOOGLE_CLIENT_ID = ""
OPENID_CONNECT_CLIENT_ID = ""
OPENID_CONNECT_CLIENT_SECRET = ""
OPENID_CONNECT_AUTHORIZATION_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth" # e.g. for Google
OPENID_CONNECT_TOKEN_ENDPOINT = "https://www.googleapis.com/oauth2/v4/token" # e.g. for Google
OPENID_CONNECT_USERINFO_ENDPOINT = "https://www.googleapis.com/oauth2/v3/userinfo" # e.g. for Google
GOOGLE_CLIENT_SECRET = ""
OPENID_CONNECT_SCOPE = "openid email"
OPENID_CONNECT_PROVIDER_NAME = "Google"
7 changes: 0 additions & 7 deletions sentry_auth_google/__init__.py

This file was deleted.

22 changes: 0 additions & 22 deletions sentry_auth_google/constants.py

This file was deleted.

81 changes: 0 additions & 81 deletions sentry_auth_google/views.py

This file was deleted.

7 changes: 7 additions & 0 deletions sentry_auth_openid_connect/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from __future__ import absolute_import

from sentry.auth import register

from .provider import OpenIDConnectOAuth2Provider

register('openid_connect', OpenIDConnectOAuth2Provider)
33 changes: 33 additions & 0 deletions sentry_auth_openid_connect/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from __future__ import absolute_import, print_function

from django.conf import settings


AUTHORIZE_URL = getattr(settings, 'OPENID_CONNECT_AUTHORIZATION_ENDPOINT',
'https://accounts.google.com/o/oauth2/v2/auth')

ACCESS_TOKEN_URL = getattr(settings, 'OPENID_CONNECT_TOKEN_ENDPOINT',
'https://www.googleapis.com/oauth2/v4/token')

CLIENT_ID = getattr(settings, 'OPENID_CONNECT_CLIENT_ID', None)
if not CLIENT_ID:
"""Try Google backwards compability"""
CLIENT_ID = getattr(settings, 'GOOGLE_CLIENT_ID', None)

CLIENT_SECRET = getattr(settings, 'OPENID_CONNECT_CLIENT_SECRET', None)
if not CLIENT_SECRET:
"""Try Google backwards compability"""
CLIENT_SECRET = getattr(settings, 'GOOGLE_CLIENT_SECRET', None)

API_URL = getattr(settings, 'OPENID_CONNECT_USERINFO_ENDPOINT',
'https://www.googleapis.com/oauth2/v3/userinfo')

SCOPE = getattr(settings, 'OPENID_CONNECT_SCOPE', 'openid email')

PROVIDER_NAME = getattr(settings, 'OPENID_CONNECT_PROVIDER_NAME', 'Google')

ERR_INVALID_DOMAIN = 'The domain for your account (%s) is not allowed to authenticate with this provider.'

ERR_INVALID_RESPONSE = 'Unable to fetch user information from Provider. Please check the log.'

DATA_VERSION = '1'
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
from __future__ import absolute_import, print_function

from sentry.auth.provider import MigratingIdentityId
import requests

from sentry.auth.providers.oauth2 import (
OAuth2Callback, OAuth2Provider, OAuth2Login
)

from .constants import (
AUTHORIZE_URL, ACCESS_TOKEN_URL, CLIENT_ID, CLIENT_SECRET, DATA_VERSION,
SCOPE
SCOPE, API_URL, PROVIDER_NAME,
)
from .views import FetchUser, GoogleConfigureView
from .views import FetchUser, OpenIDConnectConfigureView


class GoogleOAuth2Login(OAuth2Login):
class OpenIDConnectOAuth2Login(OAuth2Login):
authorize_url = AUTHORIZE_URL
client_id = CLIENT_ID
scope = SCOPE

def __init__(self, domains=None):
self.domains = domains
super(GoogleOAuth2Login, self).__init__()
super(OpenIDConnectOAuth2Login, self).__init__()

def get_authorize_params(self, state, redirect_uri):
params = super(GoogleOAuth2Login, self).get_authorize_params(
params = super(OpenIDConnectOAuth2Login, self).get_authorize_params(
state, redirect_uri
)
# TODO(dcramer): ideally we could look at the current resulting state
Expand All @@ -33,8 +33,8 @@ def get_authorize_params(self, state, redirect_uri):
return params


class GoogleOAuth2Provider(OAuth2Provider):
name = 'Google'
class OpenIDConnectOAuth2Provider(OAuth2Provider):
name = PROVIDER_NAME
client_id = CLIENT_ID
client_secret = CLIENT_SECRET

Expand All @@ -54,14 +54,14 @@ def __init__(self, domain=None, domains=None, version=None, **config):
else:
version = None
self.version = version
super(GoogleOAuth2Provider, self).__init__(**config)
super(OpenIDConnectOAuth2Provider, self).__init__(**config)

def get_configure_view(self):
return GoogleConfigureView.as_view()
return OpenIDConnectConfigureView.as_view()

def get_auth_pipeline(self):
return [
GoogleOAuth2Login(domains=self.domains),
OpenIDConnectOAuth2Login(domains=self.domains),
OAuth2Callback(
access_token_url=ACCESS_TOKEN_URL,
client_id=self.client_id,
Expand All @@ -82,32 +82,22 @@ def build_config(self, state):
'version': DATA_VERSION,
}

def get_user_info(self, bearer_token):
endpoint = API_URL
bearer_auth = 'Bearer ' + bearer_token
return requests.get(endpoint + "?schema=openid",
headers={'Authorization': bearer_auth}).json()

def build_identity(self, state):
# https://developers.google.com/identity/protocols/OpenIDConnect#server-flow
# data.user => {
# "iss":"accounts.google.com",
# "at_hash":"HK6E_P6Dh8Y93mRNtsDB1Q",
# "email_verified":"true",
# "sub":"10769150350006150715113082367",
# "azp":"1234987819200.apps.googleusercontent.com",
# "email":"jsmith@example.com",
# "aud":"1234987819200.apps.googleusercontent.com",
# "iat":1353601026,
# "exp":1353604926,
# "hd":"example.com"
# }
data = state['data']
bearer_token = data['access_token']
user_info = self.get_user_info(bearer_token)
user_data = state['user']

# XXX(epurkhiser): We initially were using the email as the id key.
# This caused account dupes on domain changes. Migrate to the
# account-unique sub key.
user_id = MigratingIdentityId(id=user_data['sub'], legacy_id=user_data['email'])

return {
'id': user_id,
'email': user_data['email'],
'name': user_data['email'],
'id': user_data.get('sub'),
'email': user_info.get('email'),
'email_verified': user_info.get('email_verified'),
'nickname': user_info.get('nickname'),
'name': user_info.get('name'),
'data': self.get_oauth_data(data),
'email_verified': user_data['email_verified'],
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<h3>Domain</h3>

<p>Users will be allowed to authenticate if they have an account under the Google Apps domain <strong>{{ domains|join:" or " }}</strong>.</p>
<p>Users will be allowed to authenticate if they have an account under the domain <strong>{{ domains|join:" or " }}</strong>.</p>
File renamed without changes.
Loading

0 comments on commit 25ae598

Please sign in to comment.