def oauth_authorize(): """ OAuth2 server -- authorization endpoint """ form = AuthorizeForm() response_type = request.args.get('response_type') client_id = request.args.get('client_id') redirect_uri = request.args.get('redirect_uri') scope = request.args.get('scope', u'').split(u' ') state = request.args.get('state') # Validation 1.1: Client_id present if not client_id: if redirect_uri: return oauth_auth_error(redirect_uri, state, 'invalid_request', "client_id missing") else: return oauth_auth_403("Missing client_id") # Validation 1.2: Client exists client = Client.query.filter_by(key=client_id).first() if not client: if redirect_uri: return oauth_auth_error(redirect_uri, state, 'unauthorized_client') else: return oauth_auth_403("Unknown client_id") # Validation 1.2.1: Client allows login for this user if not client.allow_any_login: print "Checking for permissions" permissions = UserClientPermissions.query.filter_by(user=g.user, client=client).first() print permissions if not permissions: return oauth_auth_error(redirect_uri, state, 'invalid_scope', "You do not have access to this application") # Validation 1.3: Is the client active? if not client.active: return oauth_auth_error(redirect_uri, state, 'unauthorized_client') # Validation 1.4: Cross-check redirection_uri if not redirect_uri: redirect_uri = client.redirect_uri elif redirect_uri != client.redirect_uri: if urlparse.urlsplit(redirect_uri).hostname != urlparse.urlsplit(client.redirect_uri).hostname: return oauth_auth_error(redirect_uri, state, 'invalid_request', "Redirect URI hostname doesn't match") # Validation 2.1: Is response_type present? if not response_type: return oauth_auth_error(redirect_uri, state, 'invalid_request', "response_type missing") # Validation 2.2: Is response_type acceptable? if response_type not in [u'code']: return oauth_auth_error(redirect_uri, state, 'unsupported_response_type') # Validation 3.1: Scope present? if not scope: return oauth_auth_error(redirect_uri, state, 'invalid_request', "Scope not specified") resources = {} # resource_object: [action_object, ...] # Validation 3.2: Scope valid? for item in scope: if item not in [u'id', u'email']: # Validation 3.2.1: resource/action is properly formatted if '/' in item: parts = item.split('/') if len(parts) != 2: return oauth_auth_error(redirect_uri, state, 'invalid_scope', "Too many / characters in %s in scope" % item) resource_name, action_name = parts else: resource_name = item action_name = None resource = Resource.query.filter_by(name=resource_name).first() # Validation 3.2.2: Resource exists if not resource: return oauth_auth_error(redirect_uri, state, 'invalid_scope', "Unknown resource '%s' in scope" % resource_name) # Validation 3.2.3: Client has access to resource if resource.trusted and not client.trusted: return oauth_auth_error(redirect_uri, state, 'invalid_scope', "This application does not have access to resource '%s' in scope" % resource_name) # Validation 3.2.4: If action is specified, it exists for this resource if action_name: action = ResourceAction.query.filter_by(name=action_name, resource=resource).first() if not action: return oauth_auth_error(redirect_uri, state, 'invalid_scope', "Unknown action '%s' on resource '%s' in scope" % (action_name, resource_name)) resources.setdefault(resource, []).append(action) else: action = None resources.setdefault(resource, []) # Validations complete. Now ask user for permission # If the client is trusted (LastUser feature, not in OAuth2 spec), don't ask user. # The client does not get access to any data here -- they still have to authenticate to /token. if request.method == 'GET' and client.trusted: # Return auth token. No need for user confirmation return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) # If there is an existing auth token with the same or greater scope, don't ask user again; authorise silently existing_token = AuthToken.query.filter_by(user=g.user, client=client).first() if existing_token and set(scope).issubset(set(existing_token.scope)): return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) # First request. Ask user. if form.validate_on_submit(): if 'accept' in request.form: # User said yes. Return an auth code to the client return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) elif 'deny' in request.form: # User said no. Return "access_denied" error (OAuth2 spec) return oauth_auth_error(redirect_uri, state, 'access_denied') # else: shouldn't happen, so just show the form again # GET request or POST with invalid CSRF return render_template('authorize.html', form=form, client=client, redirect_uri=redirect_uri, scope=scope, resources=resources, )
def oauth_authorize(): """ OAuth2 server -- authorization endpoint """ form = AuthorizeForm() response_type = request.args.get('response_type') client_id = request.args.get('client_id') redirect_uri = request.args.get('redirect_uri') scope = request.args.get('scope', u'').split(u' ') state = request.args.get('state') # Validation 1.1: Client_id present if not client_id: return oauth_auth_403(u"Missing client_id") # Validation 1.2: Client exists client = Client.query.filter_by(key=client_id).first() if not client: return oauth_auth_403(u"Unknown client_id") # Validation 1.2.1: Is the client active? if not client.active: return oauth_auth_error(client.redirect_uri, state, 'unauthorized_client') # Validation 1.3: Cross-check redirect_uri if not redirect_uri: redirect_uri = client.redirect_uri if not redirect_uri: # Validation 1.3.1: No redirect_uri specified return oauth_auth_403(u"No redirect URI specified") elif redirect_uri != client.redirect_uri: if urlparse.urlsplit(redirect_uri).hostname != urlparse.urlsplit(client.redirect_uri).hostname: return oauth_auth_error(client.redirect_uri, state, 'invalid_request', u"Redirect URI hostname doesn't match") # Validation 1.4: Client allows login for this user if not client.allow_any_login: if client.user: permissions = UserClientPermissions.query.filter_by(user=g.user, client=client).first() else: permissions = TeamClientPermissions.query.filter_by(client=client).filter( TeamClientPermissions.team_id.in_([team.id for team in g.user.teams])).first() if not permissions: return oauth_auth_error(client.redirect_uri, state, 'invalid_scope', u"You do not have access to this application") # Validation 2.1: Is response_type present? if not response_type: return oauth_auth_error(redirect_uri, state, 'invalid_request', "response_type missing") # Validation 2.2: Is response_type acceptable? if response_type not in [u'code']: return oauth_auth_error(redirect_uri, state, 'unsupported_response_type') # Validation 3.1: Is scope present? if not scope: return oauth_auth_error(redirect_uri, state, 'invalid_request', "Scope not specified") # Validation 3.2: Is scope valid? try: resources = verifyscope(scope, client) except ScopeException as scopeex: return oauth_auth_error(redirect_uri, state, 'invalid_scope', unicode(scopeex)) # Validations complete. Now ask user for permission # If the client is trusted (LastUser feature, not in OAuth2 spec), don't ask user. # The client does not get access to any data here -- they still have to authenticate to /token. if request.method == 'GET' and client.trusted: # Return auth token. No need for user confirmation return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) # If there is an existing auth token with the same or greater scope, don't ask user again; authorise silently existing_token = AuthToken.query.filter_by(user=g.user, client=client).first() if existing_token and set(scope).issubset(set(existing_token.scope)): return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) # First request. Ask user. if form.validate_on_submit(): if 'accept' in request.form: # User said yes. Return an auth code to the client return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) elif 'deny' in request.form: # User said no. Return "access_denied" error (OAuth2 spec) return oauth_auth_error(redirect_uri, state, 'access_denied') # else: shouldn't happen, so just show the form again # GET request or POST with invalid CSRF return render_template('authorize.html', form=form, client=client, redirect_uri=redirect_uri, scope=scope, resources=resources, )
def oauth_authorize(): """ OAuth2 server -- authorization endpoint """ form = AuthorizeForm() response_type = request.args.get('response_type') client_id = request.args.get('client_id') redirect_uri = request.args.get('redirect_uri') scope = request.args.get('scope', u'').split(u' ') state = request.args.get('state') # Validation 1.1: Client_id present if not client_id: return oauth_auth_403(u"Missing client_id") # Validation 1.2: Client exists client = Client.query.filter_by(key=client_id).first() if not client: return oauth_auth_403(u"Unknown client_id") # Validation 1.2.1: Is the client active? if not client.active: return oauth_auth_error(client.redirect_uri, state, 'unauthorized_client') # Validation 1.3: Cross-check redirect_uri if not redirect_uri: redirect_uri = client.redirect_uri if not redirect_uri: # Validation 1.3.1: No redirect_uri specified return oauth_auth_403(u"No redirect URI specified") elif redirect_uri != client.redirect_uri: if urlparse.urlsplit(redirect_uri).hostname != urlparse.urlsplit(client.redirect_uri).hostname: return oauth_auth_error(client.redirect_uri, state, 'invalid_request', u"Redirect URI hostname doesn't match") # Validation 1.4: Client allows login for this user if not client.allow_any_login: if client.user: perms = UserClientPermissions.query.filter_by(user=g.user, client=client).first() else: perms = TeamClientPermissions.query.filter_by(client=client).filter( TeamClientPermissions.team_id.in_([team.id for team in g.user.teams])).first() if not perms: return oauth_auth_error(client.redirect_uri, state, 'invalid_scope', u"You do not have access to this application") # Validation 2.1: Is response_type present? if not response_type: return oauth_auth_error(redirect_uri, state, 'invalid_request', "response_type missing") # Validation 2.2: Is response_type acceptable? if response_type not in [u'code']: return oauth_auth_error(redirect_uri, state, 'unsupported_response_type') # Validation 3.1: Is scope present? if not scope: return oauth_auth_error(redirect_uri, state, 'invalid_request', "Scope not specified") # Validation 3.2: Is scope valid? try: resources = verifyscope(scope, client) except ScopeException as scopeex: return oauth_auth_error(redirect_uri, state, 'invalid_scope', unicode(scopeex)) # Validations complete. Now ask user for permission # If the client is trusted (Lastuser feature, not in OAuth2 spec), don't ask user. # The client does not get access to any data here -- they still have to authenticate to /token. if request.method == 'GET' and client.trusted: # Return auth token. No need for user confirmation return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) # If there is an existing auth token with the same or greater scope, don't ask user again; authorise silently existing_token = AuthToken.query.filter_by(user=g.user, client=client).first() if existing_token and set(scope).issubset(set(existing_token.scope)): return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) # First request. Ask user. if form.validate_on_submit(): if 'accept' in request.form: # User said yes. Return an auth code to the client return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) elif 'deny' in request.form: # User said no. Return "access_denied" error (OAuth2 spec) return oauth_auth_error(redirect_uri, state, 'access_denied') # else: shouldn't happen, so just show the form again # GET request or POST with invalid CSRF return render_template('authorize.html', form=form, client=client, redirect_uri=redirect_uri, scope=scope, resources=resources, registry=registry, )