Example #1
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:
        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,
        )
Example #2
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(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,
        )
Example #3
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(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,
        )