def logout_client(): """ Client-initiated logout """ cred = ClientCredential.get(request.args['client_id']) client = cred.client if cred else None if client is None or not request.referrer or not client.host_matches( request.referrer): # No referrer or such client, or request didn't come from the client website. # Possible CSRF. Don't logout and don't send them back flash( current_app.config.get('LOGOUT_UNAUTHORIZED_MESSAGE') or logout_errormsg, 'danger') return redirect(url_for('index')) # If there is a next destination, is it in the same domain as the client? if 'next' in request.args: if not client.host_matches(request.args['next']): # Host doesn't match. Assume CSRF and redirect to index without logout flash( current_app.config.get('LOGOUT_UNAUTHORIZED_MESSAGE') or logout_errormsg, 'danger') return redirect(url_for('index')) # All good. Log them out and send them back logout_internal() db.session.commit() return redirect(get_next_url(external=True))
def _client_login_inner(): if request.authorization is None or not request.authorization.username: return Response("Client credentials required", 401, {"WWW-Authenticate": 'Basic realm="Client credentials"'}) credential = ClientCredential.get(name=request.authorization.username) if credential is None or not credential.secret_is(request.authorization.password): return Response("Invalid client credentials", 401, {"WWW-Authenticate": 'Basic realm="Client credentials"'}) if credential: credential.accessed_at = datetime.utcnow() db.session.commit() g.client = credential.client
def login_beacon_iframe(client_id, login_url): cred = ClientCredential.get(client_id) client = cred.client if cred else None if client is None: abort(404) if not client.host_matches(login_url): abort(400) return render_template('login_beacon.html', client=client, login_url=login_url), 200, { 'Expires': 'Fri, 01 Jan 1990 00:00:00 GMT', 'Cache-Control': 'private, max-age=86400' }
def client_cred_new(client): form = ClientCredentialForm() if request.method == 'GET' and not client.credentials: form.title.data = _("Default") if form.validate_on_submit(): cred, secret = ClientCredential.new(client) cred.title = form.title.data db.session.commit() return render_template('client_cred.html.jinja2', name=cred.name, secret=secret, cred=cred) return render_form(form=form, title=_("New access key"), formid='client_cred', submit=_("Create"), ajax=False)
def _client_login_inner(): if request.authorization is None or not request.authorization.username: return Response('Client credentials required', 401, {'WWW-Authenticate': 'Basic realm="Client credentials"'}) credential = ClientCredential.get(name=request.authorization.username) if credential is None or not credential.secret_is(request.authorization.password): return Response('Invalid client credentials', 401, {'WWW-Authenticate': 'Basic realm="Client credentials"'}) if credential: credential.accessed_at = db.func.utcnow() db.session.commit() add_auth_attribute('client', credential.client, actor=True)
def login_beacon_json(client_id): cred = ClientCredential.get(client_id) client = cred.client if cred else None if client is None: abort(404) if g.user: token = client.authtoken_for(g.user) else: token = None response = jsonify({'hastoken': True if token else False}) response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT' response.headers['Cache-Control'] = 'private, max-age=300' return response
def login_beacon_json(client_id): cred = ClientCredential.get(client_id) client = cred.client if cred else None if client is None: abort(404) if g.user: token = client.authtoken_for(g.user) else: token = None response = jsonify({ 'hastoken': True if token else False }) response.headers['Expires'] = 'Fri, 01 Jan 1990 00:00:00 GMT' response.headers['Cache-Control'] = 'private, max-age=300' return response
def decorated_function(*args, **kwargs): g.login_required = True # Check if http referrer and given client id match a registered client if 'client_id' in request.values and 'session' in request.values and request.referrer: client_cred = ClientCredential.get(request.values['client_id']) if client_cred is not None and get_scheme_netloc(client_cred.client.website) == get_scheme_netloc(request.referrer): if UserSession.authenticate(buid=request.values['session']) is not None: return f(*args, **kwargs) # If we didn't get a valid client_id and session, maybe there's a user? if g.user is not None: return f(*args, **kwargs) # If user is not logged in, check for client credentials in the request authorization header. # If no error reported, call the function, else return error. result = _client_login_inner() if result is None: return f(*args, **kwargs) else: return result
def decorated_function(*args, **kwargs): add_auth_attribute('login_required', True) # Check if http referrer and given client id match a registered client if 'client_id' in request.values and 'session' in request.values and request.referrer: client_cred = ClientCredential.get(request.values['client_id']) if client_cred is not None and get_scheme_netloc(client_cred.client.website) == get_scheme_netloc(request.referrer): if UserSession.authenticate(buid=request.values['session']) is not None: return f(*args, **kwargs) # If we didn't get a valid client_id and session, maybe there's a user? if current_auth.is_authenticated: return f(*args, **kwargs) # If user is not logged in, check for client credentials in the request authorization header. # If no error reported, call the function, else return error. result = _client_login_inner() if result is None: return f(*args, **kwargs) else: return result
def logout_client(): """ Client-initiated logout """ cred = ClientCredential.get(request.args['client_id']) client = cred.client if cred else None if client is None or not request.referrer or not client.host_matches(request.referrer): # No referrer or such client, or request didn't come from the client website. # Possible CSRF. Don't logout and don't send them back flash(current_app.config.get('LOGOUT_UNAUTHORIZED_MESSAGE') or logout_errormsg, 'danger') return redirect(url_for('index')) # If there is a next destination, is it in the same domain as the client? if 'next' in request.args: if not client.host_matches(request.args['next']): # Host doesn't match. Assume CSRF and redirect to index without logout flash(current_app.config.get('LOGOUT_UNAUTHORIZED_MESSAGE') or logout_errormsg, 'danger') return redirect(url_for('index')) # All good. Log them out and send them back logout_internal() db.session.commit() return redirect(get_next_url(external=True))
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(_("Missing client_id")) # Validation 1.2: Client exists credential = ClientCredential.get(client_id) if credential: client = credential.client else: return oauth_auth_403(_("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(_("No redirect URI specified")) elif redirect_uri != client.redirect_uri: if not client.host_matches(redirect_uri): 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', u'token']: 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: internal_resources, external_resources, full_client_access = 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 if response_type == 'code': return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) else: return oauth_auth_success(client, redirect_uri, state, code=None, token=oauth_make_token(g.user, client, scope, g.usersession)) # If there is an existing auth token with the same or greater scope, don't ask user again; authorise silently if client.confidential: existing_token = AuthToken.query.filter_by(user=g.user, client=client).first() else: existing_token = AuthToken.query.filter_by(user_session=g.usersession, client=client).first() if existing_token and set(scope).issubset(set(existing_token.scope)): if response_type == 'code': return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) else: return oauth_auth_success(client, redirect_uri, state, code=None, token=oauth_make_token(g.user, client, scope, g.usersession)) # First request. Ask user. if form.validate_on_submit(): if 'accept' in request.form: # User said yes. Return an auth code to the client if response_type == 'code': return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) else: return oauth_auth_success(client, redirect_uri, state, code=None, token=oauth_make_token(g.user, client, scope, g.usersession)) 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, internal_resources=internal_resources, external_resources=external_resources, full_client_access=full_client_access, resource_registry=resource_registry, ), 200, {'X-Frame-Options': 'SAMEORIGIN'}
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(_("Missing client_id")) # Validation 1.2: Client exists credential = ClientCredential.get(client_id) if credential: client = credential.client else: return oauth_auth_403(_("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(_("No redirect URI specified")) elif redirect_uri != client.redirect_uri: if not client.host_matches(redirect_uri): 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', u'token']: 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: internal_resources, external_resources, full_client_access = 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 if response_type == 'code': return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) else: return oauth_auth_success(client, redirect_uri, state, code=None, token=oauth_make_token(g.user, client, scope, g.usersession)) # If there is an existing auth token with the same or greater scope, don't ask user again; authorise silently if client.confidential: existing_token = AuthToken.query.filter_by(user=g.user, client=client).first() else: existing_token = AuthToken.query.filter_by(user_session=g.usersession, client=client).first() if existing_token and set(scope).issubset(set(existing_token.effective_scope)): if response_type == 'code': return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) else: return oauth_auth_success(client, redirect_uri, state, code=None, token=oauth_make_token(g.user, client, scope, g.usersession)) # First request. Ask user. if form.validate_on_submit(): if 'accept' in request.form: # User said yes. Return an auth code to the client if response_type == 'code': return oauth_auth_success(client, redirect_uri, state, oauth_make_auth_code(client, scope, redirect_uri)) else: return oauth_auth_success(client, redirect_uri, state, code=None, token=oauth_make_token(g.user, client, scope, g.usersession)) 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.jinja2', form=form, client=client, redirect_uri=redirect_uri, internal_resources=internal_resources, external_resources=external_resources, full_client_access=full_client_access, resource_registry=resource_registry, ), 200, {'X-Frame-Options': 'SAMEORIGIN'}