Exemplo n.º 1
0
def logout_client():
    """
    Client-initiated logout
    """
    cred = AuthClientCredential.get(request.args['client_id'])
    auth_client = cred.auth_client if cred else None

    if (auth_client is None or not request.referrer
            or not auth_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 auth_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))
Exemplo n.º 2
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 = AuthClientCredential.get(request.values['client_id'])
            if client_cred is not None and get_scheme_netloc(
                    client_cred.auth_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
Exemplo n.º 3
0
def login_beacon_json(client_id):
    cred = AuthClientCredential.get(client_id)
    auth_client = cred.auth_client if cred else None
    if auth_client is None:
        abort(404)
    if current_auth.is_authenticated:
        token = auth_client.authtoken_for(current_auth.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
Exemplo n.º 4
0
def login_beacon_iframe(client_id, login_url):
    cred = AuthClientCredential.get(client_id)
    auth_client = cred.auth_client if cred else None
    if auth_client is None:
        abort(404)
    if not auth_client.host_matches(login_url):
        abort(400)
    return (
        render_template('login_beacon.html.jinja2',
                        auth_client=auth_client,
                        login_url=login_url),
        200,
        {
            'Expires': 'Fri, 01 Jan 1990 00:00:00 GMT',
            'Cache-Control': 'private, max-age=86400',
        },
    )
Exemplo n.º 5
0
def client_cred_new(auth_client):
    form = ClientCredentialForm()
    if request.method == 'GET' and not auth_client.credentials:
        form.title.data = _("Default")
    if form.validate_on_submit():
        cred, secret = AuthClientCredential.new(auth_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,
    )
Exemplo n.º 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 = AuthClientCredential.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('auth_client', credential.auth_client, actor=True)
Exemplo n.º 7
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', '').split(' ')
    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: AuthClient exists

    credential = AuthClientCredential.get(client_id)
    if credential:
        auth_client = credential.auth_client
    else:
        return oauth_auth_403(_("Unknown client_id"))

    # Validation 1.2.1: Is the client active?
    if not auth_client.active:
        return oauth_auth_error(auth_client.redirect_uri, state,
                                'unauthorized_client')

    # Validation 1.3: Cross-check redirect_uri
    if not redirect_uri:
        redirect_uri = auth_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 not in auth_client.redirect_uris:
        if not auth_client.host_matches(redirect_uri):
            return oauth_auth_error(
                auth_client.redirect_uri,
                state,
                'invalid_request',
                _("Redirect URI hostname doesn't match"),
            )

    # Validation 1.4: AuthClient allows login for this user
    if not auth_client.allow_login_for(current_auth.user):
        return oauth_auth_error(
            auth_client.redirect_uri,
            state,
            'invalid_scope',
            _("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 ['code', '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, full_client_access = verifyscope(
            scope, auth_client)
    except ScopeException as scopeex:
        return oauth_auth_error(redirect_uri, state, 'invalid_scope',
                                str(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 auth_client.trusted:
        # Return auth token. No need for user confirmation
        if response_type == 'code':
            return oauth_auth_success(
                auth_client,
                redirect_uri,
                state,
                oauth_make_auth_code(auth_client, scope, redirect_uri),
            )
        else:
            return oauth_auth_success(
                auth_client,
                redirect_uri,
                state,
                code=None,
                token=oauth_make_token(current_auth.user, auth_client, scope,
                                       current_auth.session),
            )

    # If there is an existing auth token with the same or greater scope, don't ask user again; authorise silently
    existing_token = auth_client.authtoken_for(current_auth.user,
                                               current_auth.session)
    if existing_token and ('*' in existing_token.effective_scope
                           or set(scope).issubset(
                               set(existing_token.effective_scope))):
        if response_type == 'code':
            return oauth_auth_success(
                auth_client,
                redirect_uri,
                state,
                oauth_make_auth_code(auth_client, scope, redirect_uri),
            )
        else:
            return oauth_auth_success(
                auth_client,
                redirect_uri,
                state,
                code=None,
                token=oauth_make_token(current_auth.user, auth_client, scope,
                                       current_auth.session),
            )

    # If the user was prompted, take their input.
    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(
                    auth_client,
                    redirect_uri,
                    state,
                    oauth_make_auth_code(auth_client, scope, redirect_uri),
                )
            else:
                return oauth_auth_success(
                    auth_client,
                    redirect_uri,
                    state,
                    code=None,
                    token=oauth_make_token(current_auth.user, auth_client,
                                           scope, current_auth.session),
                )
        elif 'deny' in request.form:
            # User said no. Return "access_denied" error (OAuth2 spec)
            return oauth_auth_error(redirect_uri, state, 'access_denied')
        else:
            raise ValueError(
                "Received an authorize form without a valid action.")

    # GET request or POST with invalid CSRF
    return (
        render_template(
            'authorize.html.jinja2',
            form=form,
            auth_client=auth_client,
            redirect_uri=redirect_uri,
            internal_resources=internal_resources,
            full_client_access=full_client_access,
            resource_registry=resource_registry,
        ),
        200,
        {
            'X-Frame-Options': 'SAMEORIGIN'
        },
    )