Beispiel #1
0
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))
Beispiel #2
0
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
Beispiel #3
0
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'
        }
Beispiel #4
0
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)
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
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
Beispiel #8
0
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'
                           }
Beispiel #9
0
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
Beispiel #10
0
    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
Beispiel #11
0
    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
Beispiel #12
0
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))
Beispiel #13
0
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'}
Beispiel #14
0
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'}