Exemplo n.º 1
0
def test_login_user_with_idp_already_in_db(db_session):
    """
    Test that if a user is already in the database, has identity_provider
    configured, and logs in, the session will contain the user's information.
    """
    email = "*****@*****.**"
    provider = "Test Provider"
    id_from_idp = "Provider_ID_0001"

    test_user = User(username=email,
                     email=email,
                     id_from_idp=id_from_idp,
                     is_admin=False)
    test_idp = IdentityProvider(name=provider)
    test_user.identity_provider = test_idp

    db_session.add(test_user)
    db_session.commit()
    user_id = str(test_user.id)

    login_user(email, provider, email=email, id_from_idp=id_from_idp)

    assert test_user.identity_provider.name == provider
    assert test_user.id_from_idp == id_from_idp
    assert test_user.email == email
    assert flask.session["username"] == email
    assert flask.session["provider"] == provider
    assert flask.session["user_id"] == user_id
    assert flask.g.user == test_user
Exemplo n.º 2
0
def login_user(username, provider, fence_idp=None, shib_idp=None, email=None):
    """
    Login a user with the given username and provider. Set values in Flask
    session to indicate the user being logged in. In addition, commit the user
    and associated idp information to the db.

    Args:
        username (str): specific username of user to be logged in
        provider (str): specfic idp of user to be logged in
        fence_idp (str, optional): Downstreawm fence IdP
        shib_idp (str, optional): Downstreawm shibboleth IdP
        email (str, optional): email of user (may or may not match username depending
            on the IdP)
    """
    def set_flask_session_values(user):
        """
        Helper fuction to set user values in the session.

        Args:
            user (User): User object
        """
        flask.session["username"] = user.username
        flask.session["user_id"] = str(user.id)
        flask.session["provider"] = user.identity_provider.name
        if fence_idp:
            flask.session["fence_idp"] = fence_idp
        if shib_idp:
            flask.session["shib_idp"] = shib_idp
        flask.g.user = user
        flask.g.scopes = ["_all"]
        flask.g.token = None

    user = query_for_user(session=current_session, username=username)
    if user:
        _update_users_email(user, email)

        #  This expression is relevant to those users who already have user and
        #  idp info persisted to the database. We return early to avoid
        #  unnecessarily re-saving that user and idp info.
        if user.identity_provider and user.identity_provider.name == provider:
            set_flask_session_values(user)
            return
    else:
        if email:
            user = User(username=username, email=email)
        else:
            user = User(username=username)

    idp = (current_session.query(IdentityProvider).filter(
        IdentityProvider.name == provider).first())
    if not idp:
        idp = IdentityProvider(name=provider)

    user.identity_provider = idp
    current_session.add(user)
    current_session.commit()

    set_flask_session_values(user)
Exemplo n.º 3
0
def create_providers(data, db_session):
    s = db_session
    providers = data["providers"]
    for provider in providers:
        prov = CloudProvider()
        prov.name = provider["name"]
        prov.backend = provider["backend"]
        prov.service = provider["service"]
        s.add(prov)
        s.flush

    for name, user in list(data["users"].items()):
        new_user = User()
        new_user.username = name
        new_user.email = user["email"]
        new_user.is_admin = user["is_admin"]
        s.add(new_user)
        user["id"] = new_user.id

    for project in data["projects"]:
        new_project = Project()
        new_project.name = project["name"]
        s.add(new_project)
        for storage in project["storage_access"]:
            provider = s.query(CloudProvider).filter_by(name=storage).first()
            if provider:
                new_storage_access = StorageAccess(provider_id=provider.id,
                                                   project_id=new_project.id)
                s.add(new_storage_access)

        for bucket in project["buckets"]:
            new_bucket = Bucket()
            new_bucket.name = bucket["name"]
            provider = s.query(CloudProvider).filter_by(
                name=bucket["provider"]).first()
            new_bucket.provider_id = provider.id
            s.add(new_bucket)
            s.flush()
            project_to_bucket = ProjectToBucket()
            project_to_bucket.bucket_id = new_bucket.id
            project_to_bucket.project_id = new_project.id
            s.add(project_to_bucket)
            s.flush()
        for user in project["users"]:
            access = AccessPrivilege()
            access.user_id = data["users"][user["name"]]["id"]
            access.project_id = new_project.id
            s.add(access)
Exemplo n.º 4
0
def test_login_user_already_in_db(db_session):
    """
    Test that if a user is already in the database and logs in, the session will contain
    the user's information (including additional information that may have been provided
    during the login like email and id_from_idp)
    """
    email = "*****@*****.**"
    provider = "Test Provider"
    id_from_idp = "Provider_ID_0001"

    test_user = User(username=email, is_admin=False)
    db_session.add(test_user)
    db_session.commit()
    user_id = str(test_user.id)
    assert not test_user.email
    assert not test_user.id_from_idp

    login_user(email, provider, email=email, id_from_idp=id_from_idp)

    assert test_user.identity_provider.name == provider
    assert test_user.id_from_idp == id_from_idp
    assert test_user.email == email
    assert flask.session["username"] == email
    assert flask.session["provider"] == provider
    assert flask.session["user_id"] == user_id
    assert flask.g.user == test_user
Exemplo n.º 5
0
def create_awg_user(users, db_session):
    s = db_session
    for username in list(users.keys()):
        user = query_for_user(session=s, username=username)
        if not user:
            user = User(username=username)
            s.add(user)

        projects = {}
        for project_data in users[username]["projects"]:
            auth_id = project_data["auth_id"]
            p_name = project_data.get("name", auth_id)

            project = s.query(Project).filter(Project.auth_id == auth_id).first()
            if not project:
                project = Project(name=p_name, auth_id=auth_id)
                s.add(project)
            projects[p_name] = project

        groups = users[username].get("groups", [])
        for group in groups:
            group_name = group["name"]
            group_desc = group["description"]
            grp = s.query(Group).filter(Group.name == group_name).first()
            if not grp:
                grp = Group()
                grp.name = group_name
                grp.description = group_desc
                s.add(grp)
                s.flush()
            UserToGroup(group=grp, user=user)
            for projectname in group["projects"]:
                gap = (
                    s.query(AccessPrivilege)
                    .join(AccessPrivilege.project)
                    .join(AccessPrivilege.group)
                    .filter(Project.name == projectname, Group.name == group_name)
                    .first()
                )
                if not gap:
                    project = projects[projectname]
                    gap = AccessPrivilege(project_id=project.id, group_id=grp.id)
                    s.add(gap)
                    s.flush()
                ap = (
                    s.query(AccessPrivilege)
                    .join(AccessPrivilege.project)
                    .join(AccessPrivilege.user)
                    .filter(Project.name == projectname, User.username == user.username)
                    .first()
                )
                privilege = {"read"}
                if not ap:
                    project = projects[projectname]
                    ap = AccessPrivilege(
                        project=project, user=user, privilege=privilege
                    )
                    s.add(ap)
                    s.flush()
    return user.id, user.username
Exemplo n.º 6
0
def test_valid_id_token_without_nonce(app):
    """
    Create a token and then validate it and make sure there are no exceptions
    when a nonce is not provided.
    """
    issuer = app.config.get('BASE_URL')
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username='******', is_admin=False)
    expires_in = 2592000
    nonce = None
    max_age = None

    signed_token = create_id_token(
        user=user, keypair=keypair, expires_in=expires_in,
        client_id=client_id, audiences=[client_id],
        auth_time=None, max_age=max_age, nonce=nonce
    )

    unsigned_token = UnsignedIDToken.from_signed_and_encoded_token(
        signed_token, client_id=client_id, issuer=issuer,
        max_age=max_age, nonce=nonce)

    unsigned_token.validate(
        issuer=issuer, client_id=client_id, max_age=max_age, nonce=nonce
    )

    assert not unsigned_token.token.get("nonce")
Exemplo n.º 7
0
def test_user(db_session):

    user = User(id=1, email="*****@*****.**")
    db_session.add(user)
    db_session.commit()

    yield user
Exemplo n.º 8
0
def test_map_iss_sub_pair_to_user_with_prior_login_and_prior_DRS_access(
    db_session, ):
    """
    Test RASOauth2Client.map_iss_sub_pair_to_user when the username passed in
    (e.g. eRA username) already exists in the Fence database and that
    user's <iss, sub> combination has already been mapped to a separate user
    created during a prior DRS access request. In this case,
    map_iss_sub_pair_to_user returns the user created from prior DRS/data
    access, rendering the other user (e.g. the eRA one) inaccessible.
    """
    iss = "https://domain.tld"
    sub = "123_abc"
    username = "******"
    email = "*****@*****.**"
    oidc = config.get("OPENID_CONNECT", {})
    ras_client = RASClient(
        oidc["ras"],
        HTTP_PROXY=config.get("HTTP_PROXY"),
        logger=logger,
    )

    # reset users table
    db_session.query(User).delete()
    db_session.commit()

    user = User(username=username, email=email)
    db_session.add(user)
    db_session.commit()

    get_or_create_gen3_user_from_iss_sub(iss, sub, db_session=db_session)
    username_to_log_in = ras_client.map_iss_sub_pair_to_user(
        iss, sub, username, email, db_session=db_session)
    assert username_to_log_in == "123_abcdomain.tld"
    iss_sub_pair_to_user = db_session.query(IssSubPairToUser).get((iss, sub))
    assert iss_sub_pair_to_user.user.username == "123_abcdomain.tld"
Exemplo n.º 9
0
def create_user(current_session, username, role, email):
    """
    Create a user for all the projects or groups in the list.
    If the user already exists, to avoid unadvertedly changing it, we suggest update
    Returns a dictionary.
    """
    if not username:
        raise UserError(("Error: Please provide a username"))
    try:
        usr = us.get_user(current_session, username)
        raise UserError(("Error: user already exist. If this is not a"
                         " mistake, please, retry using update"))
    except NotFound:
        user_list = [
            user["name"].upper()
            for user in get_all_users(current_session)["users"]
        ]
        if username.upper() in user_list:
            raise UserError(
                ("Error: user with a name with the same combination/order "
                 "of characters already exists. Please remove this other user"
                 " or modify the new one. Contact us in case of doubt"))
        is_admin = role == "admin"
        email_add = email
        usr = User(username=username,
                   active=True,
                   is_admin=is_admin,
                   email=email_add)
        current_session.add(usr)
        return us.get_user_info(current_session, username)
Exemplo n.º 10
0
def create_client(
    username,
    urls,
    DB,
    name="",
    description="",
    auto_approve=False,
    is_admin=False,
    grant_types=None,
    confidential=True,
    arborist=None,
    policies=None,
    allowed_scopes=None,
):
    client_id = random_str(40)
    if arborist is not None:
        arborist.create_client(client_id, policies)
    grant_types = grant_types
    driver = SQLAlchemyDriver(DB)
    client_secret = None
    hashed_secret = None
    if confidential:
        client_secret = random_str(55)
        hashed_secret = bcrypt.hashpw(client_secret.encode("utf-8"),
                                      bcrypt.gensalt()).decode("utf-8")
    auth_method = "client_secret_basic" if confidential else "none"
    allowed_scopes = allowed_scopes or config["CLIENT_ALLOWED_SCOPES"]
    if not set(allowed_scopes).issubset(set(config["CLIENT_ALLOWED_SCOPES"])):
        raise ValueError("Each allowed scope must be one of: {}".format(
            config["CLIENT_ALLOWED_SCOPES"]))
    if "openid" not in allowed_scopes:
        allowed_scopes.append("openid")
        logger.warning(
            'Adding required "openid" scope to list of allowed scopes.')
    with driver.session as s:
        user = query_for_user(session=s, username=username)

        if not user:
            user = User(username=username, is_admin=is_admin)
            s.add(user)
        if s.query(Client).filter(Client.name == name).first():
            if arborist is not None:
                arborist.delete_client(client_id)
            raise Exception("client {} already exists".format(name))
        client = Client(
            client_id=client_id,
            client_secret=hashed_secret,
            user=user,
            redirect_uris=urls,
            _allowed_scopes=" ".join(allowed_scopes),
            description=description,
            name=name,
            auto_approve=auto_approve,
            grant_types=grant_types,
            is_confidential=confidential,
            token_endpoint_auth_method=auth_method,
        )
        s.add(client)
        s.commit()
    return client_id, client_secret
Exemplo n.º 11
0
def create_user(users, db_session, is_admin=False):
    s = db_session
    for username in list(users.keys()):
        user = query_for_user(session=s, username=username)
        if not user:
            user = User(username=username, is_admin=is_admin)
            s.add(user)
        for project_data in users[username]["projects"]:
            privilege = project_data["privilege"]
            auth_id = project_data["auth_id"]
            p_name = project_data.get("name", auth_id)

            project = s.query(Project).filter(
                Project.auth_id == auth_id).first()
            if not project:
                project = Project(name=p_name, auth_id=auth_id)
                s.add(project)
            ap = (s.query(AccessPrivilege).join(
                AccessPrivilege.project).join(AccessPrivilege.user).filter(
                    Project.name == p_name,
                    User.username == user.username).first())
            if not ap:
                ap = AccessPrivilege(project=project,
                                     user=user,
                                     privilege=privilege)
                s.add(ap)
            else:
                ap.privilege = privilege

    return user.id, user.username
Exemplo n.º 12
0
def test_valid_id_token_without_nonce(app):
    """
    Create a token and then validate it and make sure there are no exceptions
    when a nonce is not provided.
    """
    issuer = config.get("BASE_URL")
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username="******", is_admin=False)
    expires_in = 2592000
    nonce = None
    max_age = None
    token_result = generate_signed_id_token(
        keypair.kid,
        keypair.private_key,
        user,
        expires_in,
        client_id,
        audiences=[client_id],
        auth_time=None,
        max_age=None,
        nonce=None,
    )
    unsigned_token = UnsignedIDToken.from_signed_and_encoded_token(
        token_result.token,
        client_id=client_id,
        issuer=issuer,
        max_age=max_age,
        nonce=nonce,
    )
    unsigned_token.validate()
    assert not unsigned_token.get("nonce")
Exemplo n.º 13
0
def test_valid_id_token(app):
    """
    Create a token and then validate it and make sure there are no exceptions
    """
    issuer = config.get("BASE_URL")
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username="******", is_admin=False)
    expires_in = 2592000
    nonce = "a1b2c3d4e5f6g7h8i9j0k!l@#n$%^q&*stuvwxyz"
    max_age = None
    token_result = generate_signed_id_token(
        keypair.kid,
        keypair.private_key,
        user,
        expires_in,
        client_id,
        audiences=[client_id],
        auth_time=None,
        max_age=None,
        nonce=None,
    )
    unsigned_token = UnsignedIDToken.from_signed_and_encoded_token(
        token_result.token,
        client_id=client_id,
        issuer=issuer,
        max_age=max_age,
        nonce=nonce,
    )
    unsigned_token.validate()
Exemplo n.º 14
0
def test_valid_id_token(app):
    """
    Create a token and then validate it and make sure there are no exceptions
    """
    issuer = app.config.get('BASE_URL')
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username='******', is_admin=False)
    expires_in = 2592000
    nonce = "a1b2c3d4e5f6g7h8i9j0k!l@#n$%^q&*stuvwxyz"
    max_age = None

    signed_token = create_id_token(
        user=user, keypair=keypair, expires_in=expires_in,
        client_id=client_id, audiences=[client_id],
        auth_time=None, max_age=max_age, nonce=nonce
    )

    unsigned_token = UnsignedIDToken.from_signed_and_encoded_token(
        signed_token, client_id=client_id, issuer=issuer,
        max_age=max_age, nonce=nonce)

    unsigned_token.validate(
        issuer=issuer, client_id=client_id, max_age=max_age, nonce=nonce
    )

    assert True
Exemplo n.º 15
0
def login_user(request, username, provider):
    user = current_session.query(
        User).filter(User.username == username).first()
    if not user:
        user = User(username=username)
        idp = (
            current_session.query(IdentityProvider)
            .filter(IdentityProvider.name == provider).first()
        )
        if not idp:
            idp = IdentityProvider(name=provider)
        user.identity_provider = idp
        current_session.add(user)
        current_session.commit()
    flask.g.user = user
    flask.g.scopes = ["_all"]
    flask.g.token = None
Exemplo n.º 16
0
def add_test_user(db_session, username="******", id="5678", is_admin=True):
    test_user = User(username=username, id=id, is_admin=is_admin)
    # id is part of primary key
    check_user_exists = db_session.query(User).filter_by(id=id).first()
    if not check_user_exists:
        db_session.add(test_user)
        db_session.commit()
    return test_user
Exemplo n.º 17
0
def test_user(db_session):

    user = User(id=1, email="*****@*****.**")
    test_user = db_session.query(User).filter_by(id=1).first()
    if not test_user:
        db_session.add(user)
        db_session.commit()

    yield user
Exemplo n.º 18
0
def login_user(request, username, provider):
    user = query_for_user(session=current_session, username=username)

    if not user:
        user = User(username=username)
        idp = (current_session.query(IdentityProvider).filter(
            IdentityProvider.name == provider).first())
        if not idp:
            idp = IdentityProvider(name=provider)
        user.identity_provider = idp
        current_session.add(user)
        current_session.commit()
    flask.session["username"] = username
    flask.session["provider"] = provider
    flask.session["user_id"] = str(user.id)
    flask.g.user = user
    flask.g.scopes = ["_all"]
    flask.g.token = None
Exemplo n.º 19
0
def test_delete_user_with_access_privilege(app, db_session):
    user = User(username="******")
    project = Project(id=1, name="test-project")
    access_privilege = AccessPrivilege(user=user, privilege=["read"], project=project)
    db_session.add(user)
    db_session.add(project)
    db_session.add(access_privilege)
    db_session.commit()
    delete_users(config["DB"], [user.username])
    remaining_usernames = db_session.query(User.username).all()
    assert db_session.query(User).count() == 0, remaining_usernames
Exemplo n.º 20
0
def test_create_user_refresh_token_with_no_found_user(app, db_session, kid,
                                                      rsa_private_key):
    user = User(username="******")
    db_session.add(user)
    jwt_creator = JWTCreator(
        app.config["DB"],
        app.config["BASE_URL"],
        kid=kid,
        username="******",
        scopes="fence",
        expires_in=3600,
        private_key=rsa_private_key,
    )
    with pytest.raises(EnvironmentError):
        jwt_creator.create_refresh_token()
Exemplo n.º 21
0
 def _grant_from_db(self, s, userinfo, to_add, auth_provider):
     '''
     Grant user access to projects in the auth database
     Args:
         s: sqlalchemy session
         to_add: a set of (username, project.auth_id) to be granted
     Return:
         None
     '''
     for (username, project_auth_id) in to_add:
         u = s.query(User).filter(User.username == username).first()
         if not u:
             self.logger.info('create user {}'.format(username))
             u = User(username=username)
         u.email = userinfo[username]['email']
         s.add(u)
         self.logger.info('grant {} access to {} in db'.format(
             username, project_auth_id))
         user_access = AccessPrivilege(
             user=u,
             project=self._projects[project_auth_id],
             privilege=['read-storage'],
             auth_provider=auth_provider)
         s.add(user_access)
Exemplo n.º 22
0
def test_user_d(db_session):
    """
    Test user for delete /user/<username>
    For delete-user tests you probably want to just use
    one of the load_*_user_data fixtures
    """
    user = (db_session.query(User).filter_by(
        username=userd_dict["user_username"]).first())
    if not user:
        user = User(
            id=userd_dict["user_id"],
            username=userd_dict["user_username"],
            email=userd_dict["user_email"],
        )
        db_session.add(user)
        db_session.commit()
Exemplo n.º 23
0
def test_recode_id_token(app, kid, rsa_private_key):
    """
    Test that after signing, unsigning, re-signing, and unsigning again,
    the contents of the ID Token that should be the same, are.
    """
    issuer = config.get("BASE_URL")
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username="******", is_admin=False)
    expires_in = 2592000
    nonce = "a1b2c3d4e5f6g7h8i9j0k!l@#n$%^q&*stuvwxyz"
    max_age = None

    original_signed_token = generate_signed_id_token(
        keypair.kid,
        keypair.private_key,
        user,
        expires_in,
        client_id,
        audiences=[client_id],
        auth_time=None,
        max_age=max_age,
        nonce=nonce,
    )
    original_unsigned_token = UnsignedCodeIDToken.from_signed_and_encoded_token(
        original_signed_token.token,
        client_id=client_id,
        issuer=issuer,
        max_age=max_age,
        nonce=nonce,
    )

    new_signed_token = original_unsigned_token.get_signed_and_encoded_token(
        kid, rsa_private_key)
    new_unsigned_token = UnsignedCodeIDToken.from_signed_and_encoded_token(
        new_signed_token,
        client_id=client_id,
        issuer=issuer,
        max_age=max_age,
        nonce=nonce,
    )

    assert original_unsigned_token.iss == new_unsigned_token.iss
    assert original_unsigned_token.sub == new_unsigned_token.sub
    assert original_unsigned_token.aud == new_unsigned_token.aud
    assert original_unsigned_token.azp == new_unsigned_token.azp
    assert original_unsigned_token.nonce == new_unsigned_token.nonce
Exemplo n.º 24
0
def test_delete_users(app, db_session, example_usernames):
    """
    Test the basic functionality of ``delete_users``.
    """
    for username in example_usernames:
        db_session.add(User(username=username))
        db_session.commit()
    # Delete all but the first user; check that the first one is still there
    # and the rest are gone.
    delete_users(app.config["DB"], example_usernames[1:])
    # Get the list of usernames for users that still exist.
    # (The `list(zip(...))` trick is to turn a list of 1-tuples into a
    # flattened list.)
    remaining_usernames = list(zip(*db_session.query(User.username).all())[0])
    assert example_usernames[0] in remaining_usernames
    for username in example_usernames[1:]:
        assert username not in remaining_usernames
Exemplo n.º 25
0
def test_create_user_access_token(app, db_session, client, kid,
                                  rsa_private_key, oauth_client):
    user = User(username="******")
    db_session.add(user)

    jwt_result = JWTCreator(
        config["DB"],
        config["BASE_URL"],
        kid=kid,
        username="******",
        scopes=["openid", "user"],
        expires_in=3600,
        private_key=rsa_private_key,
    ).create_access_token()
    r = client.get("/user",
                   headers={"Authorization": "Bearer " + jwt_result.token})
    assert r.status_code == 200
Exemplo n.º 26
0
def test_create_id_token(app):
    """
    Naive ID Token generation test. Just makes sure there are no exceptions and
    something is created.
    """
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username='******', is_admin=False)
    expires_in = 2592000

    token = create_id_token(
        user=user, keypair=keypair, expires_in=expires_in,
        client_id=client_id, audiences=[client_id],
        auth_time=None, max_age=None, nonce=None
    )

    assert token is not None
Exemplo n.º 27
0
def test_expired_id_token(app):
    """
    Create a token that is already expired make sure an exception is thrown.
    """
    keypair = app.keypairs[0]
    client_id = "client_12345"
    user = User(username='******', is_admin=False)
    expires_in = 0
    nonce = None
    max_age = None

    with pytest.raises(IDTokenError):
        token = generate_signed_id_token(
            keypair.kid, keypair.private_key, user, expires_in, client_id,
            audiences=[client_id], auth_time=None, max_age=max_age, nonce=nonce
        )
        assert not token
Exemplo n.º 28
0
def test_login_user_already_in_db(db_session):
    """
    Test that if a user is already in the database and
    logs in, the session will contain the user's information.
    """
    email = "*****@*****.**"
    provider = "Test Provider"

    test_user = User(username=email, is_admin=False)
    db_session.add(test_user)
    db_session.commit()
    user_id = str(test_user.id)

    login_user(flask.request, email, provider)
    assert flask.session["username"] == email
    assert flask.session["provider"] == provider
    assert flask.session["user_id"] == user_id
    assert flask.g.user == test_user
Exemplo n.º 29
0
def test_user_delete_cascade(db_session):
    """
    test deleting a user will cascade to its children
    """
    user = User(username="******")
    client = Client(
        name="test_client",
        user=user,
        client_id=random_str(40),
        client_secret=random_str(60),
    )
    db_session.add(user)
    db_session.add(client)
    db_session.flush()
    assert len(user.clients) == 1
    db_session.delete(user)
    assert db_session.query(Client).filter_by(
        client_id=client.client_id).count() == 0
Exemplo n.º 30
0
def create_client(
    username,
    urls,
    DB,
    name="",
    description="",
    auto_approve=False,
    is_admin=False,
    grant_types=None,
    confidential=True,
):
    grant_types = grant_types
    driver = SQLAlchemyDriver(DB)
    client_id = random_str(40)
    client_secret = None
    hashed_secret = None
    if confidential:
        client_secret = random_str(55)
        hashed_secret = bcrypt.hashpw(client_secret, bcrypt.gensalt())
    auth_method = "client_secret_basic" if confidential else "none"
    with driver.session as s:
        user = query_for_user(session=s, username=username)

        if not user:
            user = User(username=username, is_admin=is_admin)
            s.add(user)
        if s.query(Client).filter(Client.name == name).first():
            raise Exception("client {} already exists".format(name))
        client = Client(
            client_id=client_id,
            client_secret=hashed_secret,
            user=user,
            redirect_uris=urls,
            _allowed_scopes=" ".join(config["CLIENT_ALLOWED_SCOPES"]),
            description=description,
            name=name,
            auto_approve=auto_approve,
            grant_types=grant_types,
            is_confidential=confidential,
            token_endpoint_auth_method=auth_method,
        )
        s.add(client)
        s.commit()
    return client_id, client_secret