Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth GitHub support #320

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [Unreleased]

### Added

- Support for GitHub OAuth authorization ([#320](https://github.com/src-d/sourced-ui/issues/320))

## [v0.8.1](https://github.com/src-d/sourced-ui/releases/tag/v0.8.1) - 2019-10-28

### Fixed
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ You can configure the Docker image using the following environment variables:
| `METADATA_USER` | Username for metadata DB (when `SYNC_MODE` is set to `true`) |
| `METADATA_PASSWORD` | Password for metadata DB (when `SYNC_MODE` is set to `true`) |
| `METADATA_DB` | Database name for metadata (when `SYNC_MODE` is set to `true`) |
| `OAUTH_PROVIDER` | Use OAuth provider for authorization. Currently only `google` |
| `OAUTH_CONSUMER_KEY` | OAuth provider consumer key (aka client_id) |
| `OAUTH_CONSUMER_SECRET` | OAuth provider consumer secret (aka client_secret) |
| `OAUTH_ENABLED_PROVIDERS` | Comma separated list of available OAuth providers (eg: `github,google`) |
| `OAUTH_REGISTRATION_ROLE` | The role for newly registered users using OAuth `Admin`/`Alpha`/`Gamma` |
| `OAUTH_GITHUB_CONSUMER_KEY` | GitHub OAuth provider consumer key (aka client_id) |
| `OAUTH_GITHUB_CONSUMER_SECRET` | GitHub OAuth provider consumer secret (aka client_secret) |
| `OAUTH_GOOGLE_CONSUMER_KEY` | Google OAuth provider consumer key (aka client_id) |
| `OAUTH_GOOGLE_CONSUMER_SECRET` | Google OAuth provider consumer secret (aka client_secret) |

To see the differences between roles in `OAUTH_REGISTRATION_ROLE` variable consult [official superset documentation](https://superset.incubator.apache.org/security.html#provided-roles).

Expand Down
2 changes: 2 additions & 0 deletions srcd/contrib/docker/docker-compose.override.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ services:
- ${SOURCED_UI_ABS_PATH}/superset/dashboards:/home/superset/dashboards
- ${SOURCED_UI_ABS_PATH}/superset/contrib/docker/superset_config.py:/home/superset/superset/superset_config.py
- ${SOURCED_UI_ABS_PATH}/superset/contrib/docker/docker-entrypoint.sh:/entrypoint.sh
- ${SOURCED_UI_ABS_PATH}/superset/contrib/docker/bootstrap.py:/home/superset/bootstrap.py
- type: volume
source: node_modules
target: /home/superset/superset/assets/node_modules
Expand All @@ -21,6 +22,7 @@ services:

sourced-ui-celery:
# disable separate celery container
restart: \"no\"
image: tianon/true
entrypoint: /true

Expand Down
3 changes: 2 additions & 1 deletion superset/contrib/docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ if [ "`whoami`" = "root" ] && [ -n "$LOCAL_USER" ]; then
# It will grant write access to the data from the volumes,
# inside of the container and on host file system (see #221)
find . -group superset -exec chgrp $LOCAL_USER '{}' \;
find . -group root -exec chgrp $LOCAL_USER '{}' \;
groupmod -g $LOCAL_USER superset
usermod -u $LOCAL_USER superset
chown -R superset superset/assets/node_modules
Expand All @@ -44,7 +45,7 @@ elif [ "$SUPERSET_ENV" = "development" ]; then
# non-asset requests to `Flask`, wich is listening at the port 8081
# Doing so, updates to asset sources will be reflected in-browser without a refresh.
(cd superset/assets/ && npm install)
(cd superset/assets/ && npm run dev-server -- --host=0.0.0.0 --port=8088 --supersetPort=8081) &
(cd superset/assets/ && npm run dev-server -- --host=0.0.0.0 --port=8088 --supersetPort=8081 --disable-host-check) &
FLASK_ENV=development FLASK_APP=superset:app flask run -p 8081 --with-threads --reload --debugger --host=0.0.0.0
elif [ "$SUPERSET_ENV" = "production" ]; then
exec gunicorn --bind 0.0.0.0:8088 \
Expand Down
78 changes: 55 additions & 23 deletions superset/contrib/docker/superset_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,31 +154,63 @@ def mutator(f):
SUPERSET_WEBSERVER_TIMEOUT = 300

# Authorization configuration

OAUTH_PROVIDER = get_env_variable('OAUTH_PROVIDER', False)
if OAUTH_PROVIDER:
OAUTH_PROVIDERS = [
{
'name': 'google',
'icon': 'fa-google',
'token_key': 'access_token',
'remote_app': {
'consumer_key': get_env_variable('OAUTH_CONSUMER_KEY'),
'consumer_secret': get_env_variable('OAUTH_CONSUMER_SECRET'),
'base_url': 'https://www.googleapis.com/oauth2/v2/',
'request_token_params': {
'scope': 'email profile'
},
'request_token_url': None,
'access_token_url': 'https://accounts.google.com/o/oauth2/token',
'authorize_url': 'https://accounts.google.com/o/oauth2/auth'
}
OAUTH_ENABLED_PROVIDERS = get_env_variable('OAUTH_ENABLED_PROVIDERS', False)
OAUTH_GOOGLE_CONSUMER_KEY = get_env_variable('OAUTH_GOOGLE_CONSUMER_KEY', False)
OAUTH_GOOGLE_CONSUMER_SECRET = get_env_variable('OAUTH_GOOGLE_CONSUMER_SECRET', False)
OAUTH_GITHUB_CONSUMER_KEY = get_env_variable('OAUTH_GITHUB_CONSUMER_KEY', False)
OAUTH_GITHUB_CONSUMER_SECRET = get_env_variable('OAUTH_GITHUB_CONSUMER_SECRET', False)

OAUTH_AVAILABLE_CONFIGS = {
'google': {
'name': 'google',
'icon': 'fa-google',
'token_key': 'access_token',
'remote_app': {
'consumer_key': OAUTH_GOOGLE_CONSUMER_KEY,
'consumer_secret': OAUTH_GOOGLE_CONSUMER_SECRET,
'base_url': 'https://www.googleapis.com/oauth2/v2/',
'request_token_params': {
'scope': 'email profile'
},
'request_token_url': None,
'access_token_url': 'https://accounts.google.com/o/oauth2/token',
'authorize_url': 'https://accounts.google.com/o/oauth2/auth'
}
},
'github': {
'name': 'github',
'icon': 'fa-github',
'token_key': 'access_token',
'remote_app': {
'consumer_key': OAUTH_GITHUB_CONSUMER_KEY,
'consumer_secret': OAUTH_GITHUB_CONSUMER_SECRET,
'base_url': 'https://api.github.com/',
'request_token_params': {
'scope': 'user' # read:user
},
'request_token_url': None,
'access_token_method': 'POST',
'access_token_url': 'https://github.com/login/oauth/access_token',
'authorize_url': 'https://github.com/login/oauth/authorize'
}
]
}
}

if OAUTH_ENABLED_PROVIDERS:
providers = []
provider_names = OAUTH_ENABLED_PROVIDERS.split(',')
for provider in provider_names:
if provider in OAUTH_AVAILABLE_CONFIGS:
if not OAUTH_AVAILABLE_CONFIGS[provider]['remote_app']['consumer_key']:
raise EnvironmentError('Not valid OAuth consumer_key provided for {}'.format(provider))
if not OAUTH_AVAILABLE_CONFIGS[provider]['remote_app']['consumer_secret']:
raise EnvironmentError('Not valid OAuth consumer_secret provided for {}'.format(provider))
else:
raise EnvironmentError('Unknown OAuth provider {}'.format(provider))

providers.append(OAUTH_AVAILABLE_CONFIGS[provider])

if OAUTH_PROVIDER not in [p['name'] for p in OAUTH_PROVIDERS]:
raise EnvironmentError(
'Unknown OAuth provider {}'.format(OAUTH_PROVIDER))
OAUTH_PROVIDERS = providers

from flask_appbuilder.security.manager import AUTH_OAUTH

Expand Down
47 changes: 38 additions & 9 deletions watcher
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,45 @@ function ctrl_c {
}

function watch_inotify {
inotifywait --recursive \
--event modify,move,create,delete \
$DIRECTORY_TO_OBSERVE
inotifywait --recursive --monitor --quiet \
--event modify,move,create,delete,attrib \
${DIRECTORY_TO_OBSERVE} | awk -v SRCD="^srcd" -v SUPERSET="$(pwd)/superset" '{ \
print $0; \
if ($2 ~ "DELETE" || $2 ~ "MOVED_FROM") { \
print "[deleted]: " $1$3; \
print "rm -rf " gensub(SRCD, SUPERSET, 1, $1$3); \
system("rm -rf " gensub(SRCD, SUPERSET, 1, $1$3)); \
} else if ($1$3 ~ "docker-compose.override.yml") { \
print "[docker-compose.override]: updated " $1$3; \
system("cp -rf " $1$3 " ~/.sourced/compose-files/__active__/docker-compose.override.yml"); \
} \
else { \
print "[modified]: " $1$3; \
system("make --no-print-directory apply-patch"); \
} \
}';
}

function watch_fswatch {
fswatch --recursive --one-event \
--event Created --event Updated --event Removed \
${DIRECTORY_TO_OBSERVE}
fswatch --recursive --event-flags \
--event Created --event Updated --event Removed --event Renamed \
--event MovedFrom --event MovedTo \
--event OwnerModified --event AttributeModified \
${DIRECTORY_TO_OBSERVE} | awk -v SRCD="$(pwd)/srcd" -v SUPERSET="$(pwd)/superset" '{ \
print $0; \
if ($2 ~ "Removed") { \
print "[deleted]: " $1; \
print "rm -rf " gensub(SRCD, SUPERSET, 1, $1); \
system("rm -rf " gensub(SRCD, SUPERSET, 1, $1)); \
} else if ($1 ~ "docker-compose.override.yml") { \
print "[docker-compose.override]: updated " $1; \
system("cp -rf " $1 " ~/.sourced/compose-files/__active__/docker-compose.override.yml"); \
} \
else { \
print "[modified]: " $1; \
system("make --no-print-directory apply-patch"); \
} \
}';
}


Expand All @@ -43,6 +73,5 @@ fi

make --no-print-directory apply-patch
echo -e "\033[1;92mWatching for changes in 'srcd'; using '${whichWatcher}' ...\033[0m"
while watcher; do
make --no-print-directory apply-patch
done

watcher