Merge pull request #2300 from coreos-inc/openid-connect
OpenID Connect support and OAuth login refactoring
This commit is contained in:
commit
01ec22b362
36 changed files with 1623 additions and 983 deletions
|
@ -11,7 +11,9 @@ from peewee import IntegrityError
|
|||
|
||||
import features
|
||||
|
||||
from app import app, billing as stripe, authentication, avatar, user_analytics, all_queues
|
||||
from app import (app, billing as stripe, authentication, avatar, user_analytics, all_queues,
|
||||
oauth_login)
|
||||
|
||||
from auth import scopes
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth.permissions import (AdministerOrganizationPermission, CreateRepositoryPermission,
|
||||
|
@ -24,11 +26,12 @@ from endpoints.api import (ApiResource, nickname, resource, validate_json_reques
|
|||
query_param, require_scope, format_date, show_if,
|
||||
require_fresh_login, path_param, define_json_response,
|
||||
RepositoryParamResource, page_support)
|
||||
from endpoints.exception import NotFound, InvalidToken
|
||||
from endpoints.exception import NotFound, InvalidToken, InvalidRequest, DownstreamIssue
|
||||
from endpoints.api.subscribe import subscribe
|
||||
from endpoints.common import common_login
|
||||
from endpoints.csrf import generate_csrf_token, OAUTH_CSRF_TOKEN_NAME
|
||||
from endpoints.decorators import anon_allowed
|
||||
from oauth.oidc import DiscoveryFailureException
|
||||
from util.useremails import (send_confirmation_email, send_recovery_email, send_change_email,
|
||||
send_password_changed, send_org_recovery_email)
|
||||
from util.names import parse_single_urn
|
||||
|
@ -692,26 +695,62 @@ class Signout(ApiResource):
|
|||
return {'success': True}
|
||||
|
||||
|
||||
@resource('/v1/externaltoken')
|
||||
@resource('/v1/externallogin/<service_id>')
|
||||
@internal_only
|
||||
class GenerateExternalToken(ApiResource):
|
||||
""" Resource for generating a token for external login. """
|
||||
@nickname('generateExternalLoginToken')
|
||||
def post(self):
|
||||
""" Generates a CSRF token explicitly for OIDC/OAuth-associated login. """
|
||||
return {'token': generate_csrf_token(OAUTH_CSRF_TOKEN_NAME)}
|
||||
class ExternalLoginInformation(ApiResource):
|
||||
""" Resource for both setting a token for external login and returning its authorization
|
||||
url.
|
||||
"""
|
||||
schemas = {
|
||||
'GetLogin': {
|
||||
'type': 'object',
|
||||
'description': 'Information required to an retrieve external login URL.',
|
||||
'required': [
|
||||
'kind',
|
||||
],
|
||||
'properties': {
|
||||
'kind': {
|
||||
'type': 'string',
|
||||
'description': 'The kind of URL',
|
||||
'enum': ['login', 'attach'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@resource('/v1/detachexternal/<servicename>')
|
||||
@nickname('retrieveExternalLoginAuthorizationUrl')
|
||||
@anon_allowed
|
||||
@validate_json_request('GetLogin')
|
||||
def post(self, service_id):
|
||||
""" Generates the auth URL and CSRF token explicitly for OIDC/OAuth-associated login. """
|
||||
login_service = oauth_login.get_service(service_id)
|
||||
if login_service is None:
|
||||
raise InvalidRequest()
|
||||
|
||||
csrf_token = generate_csrf_token(OAUTH_CSRF_TOKEN_NAME)
|
||||
kind = request.get_json()['kind']
|
||||
redirect_suffix = '/attach' if kind == 'attach' else ''
|
||||
|
||||
try:
|
||||
login_scopes = login_service.get_login_scopes()
|
||||
auth_url = login_service.get_auth_url(app.config, redirect_suffix, csrf_token, login_scopes)
|
||||
return {'auth_url': auth_url}
|
||||
except DiscoveryFailureException as dfe:
|
||||
logger.exception('Could not discovery OAuth endpoint information')
|
||||
raise DownstreamIssue(dfe.message)
|
||||
|
||||
|
||||
@resource('/v1/detachexternal/<service_id>')
|
||||
@show_if(features.DIRECT_LOGIN)
|
||||
@internal_only
|
||||
class DetachExternal(ApiResource):
|
||||
""" Resource for detaching an external login. """
|
||||
@require_user_admin
|
||||
@nickname('detachExternalLogin')
|
||||
def post(self, servicename):
|
||||
def post(self, service_id):
|
||||
""" Request that the current user be detached from the external login service. """
|
||||
model.user.detach_external_login(get_authenticated_user(), servicename)
|
||||
model.user.detach_external_login(get_authenticated_user(), service_id)
|
||||
return {'success': True}
|
||||
|
||||
|
||||
|
|
Reference in a new issue