def authenticate(db_session, auth_data): if 'username' not in auth_data.keys(): raise HTTPRequestError(400, 'missing username') if 'passwd' not in auth_data.keys(): raise HTTPRequestError(400, 'missing password') username = auth_data['username'] passwd = auth_data['passwd'] try: user = db_session.query(User).filter_by( username=username.lower()).one() except orm_exceptions.NoResultFound: raise HTTPRequestError(401, 'not authorized') except sqlalchemy_exceptions.DBAPIError: raise HTTPRequestError(500, 'Problem connecting to database') if not user.hash: raise HTTPRequestError(401, 'This user is inactive') if user.hash == crypt(passwd, user.salt, 1000).split('$').pop(): groups_id = [g.id for g in user.groups] claims = { 'iss': user.key, 'iat': int(time.time()), 'exp': int(time.time() + conf.tokenExpiration), 'name': user.name, 'email': user.email, 'profile': user.profile, # Obsolete. Kept for compatibility 'groups': groups_id, 'userid': user.id, # Generate a random string as nonce 'jti': str(binascii.hexlify(os.urandom(16)), 'ascii'), 'service': user.service, 'username': user.username } encoded = jwt.encode(claims, user.secret, algorithm='HS256') log().info('user ' + user.username + ' loged in') return str(encoded, 'ascii') raise HTTPRequestError(401, 'not authorized')
def addUserGroup(dbSession, user, group, requester): try: user = User.getByNameOrID(user) except sqlalchemy.orm.exc.NoResultFound: raise HTTPRequestError(404, "No user found with this ID or name") try: group = Group.getByNameOrID(group) except sqlalchemy.orm.exc.NoResultFound: raise HTTPRequestError(404, "No group found with this ID or name") if dbSession.query(UserGroup).filter_by(user_id=user.id, group_id=group.id).one_or_none(): raise HTTPRequestError(409, "User is already a member of the group") r = UserGroup(user_id=user.id, group_id=group.id) dbSession.add(r) cache.deleteKey(userid=user.id) log().info('user ' + user.username + ' added to group ' + group.name + ' by ' + requester['username'])
def remove_group_permission(db_session, group, permission, requester): try: group = Group.getByNameOrID(group) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No group found with this ID or name") try: perm = Permission.getByNameOrID(permission) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID") try: relation = db_session.query(GroupPermission) \ .filter_by(group_id=group.id, permission_id=perm.id).one() db_session.delete(relation) cache.delete_key(action=perm.method, resource=perm.path) log().info('permission ' + perm.name + ' removed from ' ' group ' + group.name + ' by ' + requester['username']) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "Group does not have this permission")
def addUserPermission(dbSession, user, permission, requester): try: user = User.getByNameOrID(user) except sqlalchemy.orm.exc.NoResultFound: raise HTTPRequestError(404, "No user found with this ID or name") try: perm = Permission.getByNameOrID(permission) except sqlalchemy.orm.exc.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID") if dbSession.query(UserPermission) \ .filter_by(user_id=user.id, permission_id=perm.id).one_or_none(): raise HTTPRequestError(409, "User already have this permission") r = UserPermission(user_id=user.id, permission_id=perm.id) dbSession.add(r) cache.deleteKey(userid=user.id, action=perm.method, resource=perm.path) log().info('user ' + user.username + ' received permission ' + perm.name + ' by ' + requester['username'])
def addGroupPermission(dbSession, group, permission, requester): try: group = Group.getByNameOrID(group) except sqlalchemy.orm.exc.NoResultFound: raise HTTPRequestError(404, "No group found with this ID or name") try: perm = Permission.getByNameOrID(permission) except sqlalchemy.orm.exc.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID or name") if dbSession.query(GroupPermission) \ .filter_by(group_id=group.id, permission_id=perm.id).one_or_none(): raise HTTPRequestError(409, "Group already have this permission") r = GroupPermission(group_id=group.id, permission_id=perm.id) dbSession.add(r) cache.deleteKey(action=perm.method, resource=perm.path) log().info('permission ' + perm.name + ' added to group ' + group.name + ' by ' + requester['username'])
def remove_group_permission(db_session, group, permission, requester): try: group = Group.get_by_name_or_id(group) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No group found with this ID or name") try: perm = Permission.get_by_name_or_id(permission) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID") try: relation = db_session.query(GroupPermission) \ .filter_by(group_id=group.id, permission_id=perm.id).one() db_session.delete(relation) cache.delete_key(action=perm.method, resource=perm.path) log().info(f"permission {perm.name} removed from group {group.name} by {requester['username']}") MVGroupPermission.refresh() db_session.commit() except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "Group does not have this permission")
def remove_user_permission(db_session, user, permission, requester): try: user = User.getByNameOrID(user) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No user found with this ID or name") try: perm = Permission.getByNameOrID(permission) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID") try: relation = db_session.query(UserPermission) \ .filter_by(user_id=user.id, permission_id=perm.id).one() db_session.delete(relation) cache.delete_key(userid=user.id, action=perm.method, resource=perm.path) log().info('user ' + user.username + ' removed permission ' + perm.name + ' by ' + requester['username']) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "User does not have this permission")
def delete_group(db_session, group, requester): try: group = Group.get_by_name_or_id(group) if group.name == 'admin': raise HTTPRequestError(405, "Can't delete admin group") db_session.execute( GroupPermission.__table__.delete( GroupPermission.group_id == group.id)) db_session.execute( UserGroup.__table__.delete(UserGroup.group_id == group.id)) cache.delete_key() log().info( 'group ' + group.name + ' deleted by ' + requester['username'], group.safe_dict()) db_session.delete(group) MVGroupPermission.refresh() db_session.commit() except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No group found with this ID")
def remove_user_permission(db_session, user, permission, requester): try: user = User.get_by_name_or_id(user) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No user found with this ID or name") try: perm = Permission.get_by_name_or_id(permission) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID") try: relation = db_session.query(UserPermission) \ .filter_by(user_id=user.id, permission_id=perm.id).one() db_session.delete(relation) cache.delete_key(userid=user.id, action=perm.method, resource=perm.path) log().info(f"permission {perm.name} for user {user.username} was revoked by {requester['username']}") MVUserPermission.refresh() db_session.commit() except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "User does not have this permission")
def add_group_permission(db_session, group, permission, requester): try: group = Group.get_by_name_or_id(group) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No group found with this ID or name") try: perm = Permission.get_by_name_or_id(permission) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID or name") if db_session.query(GroupPermission) \ .filter_by(group_id=group.id, permission_id=perm.id).one_or_none(): raise HTTPRequestError(409, "Group already have this permission") r = GroupPermission(group_id=group.id, permission_id=perm.id) db_session.add(r) cache.delete_key(action=perm.method, resource=perm.path) log().info(f"permission {perm.name} added to group {group.name} by {requester['username']}") MVGroupPermission.refresh() db_session.commit()
def add_user_group(db_session, user, group, requester): try: user = User.get_by_name_or_id(user) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, f"No user found with this ID or name: {user}") try: group = Group.get_by_name_or_id(group) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, f"No group found with this ID or name: {group}") if db_session.query(UserGroup).filter_by( user_id=user.id, group_id=group.id ).one_or_none(): raise HTTPRequestError(409, "User is already a member of the group") r = UserGroup(user_id=user.id, group_id=group.id) db_session.add(r) cache.delete_key(userid=user.id) log().info(f"user {user.username} added to group {group.name} by {requester['username']}") db_session.commit()
def add_user_permission(db_session, user, permission, requester): try: user = User.get_by_name_or_id(user) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No user found with this ID or name") try: perm = Permission.get_by_name_or_id(permission) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No permission found with this ID") if db_session.query(UserPermission) \ .filter_by(user_id=user.id, permission_id=perm.id).one_or_none(): raise HTTPRequestError(409, "User already have this permission") r = UserPermission(user_id=user.id, permission_id=perm.id) db_session.add(r) cache.delete_key(userid=user.id, action=perm.method, resource=perm.path) MVUserPermission.refresh() db_session.commit() log().info( f"user {user.username} received permission {perm.name} by {requester['username']}" )
def create_perm(db_session, permission, requester): """ Creates a new permission :param db_session: The postgres session to be used :param permission: The new permission :param requester: Who is creating this user. This is a dictionary with two keys: "userid" and "username" :return: The new permission """ # Drop invalid fields permission = { k: permission[k] for k in permission if k in Permission.fillable } check_perm(permission) permission['created_by'] = requester['userid'] perm = Permission(**permission) log().info(f"permission {perm.name} create by {requester['username']}") log().info(perm.safe_dict()) db_session.add(perm) db_session.commit() return perm
def pdpMain(dbSession, pdpRequest): checkRequest(pdpRequest) jwtPayload = getJwtPayload(pdpRequest['jwt']) user_id = jwtPayload['userid'] # try to retrieve the veredict from cache cachedVeredict = cache.getKey(user_id, pdpRequest['action'], pdpRequest['resource']) # Return the cached answer if it exist if cachedVeredict: log().info('user ' + user_id + ' ' + cachedVeredict + ' to ' + pdpRequest['action'] + ' on ' + pdpRequest['resource']) return cachedVeredict veredict = iteratePermissions(user_id, jwtPayload['groups'], pdpRequest['action'], pdpRequest['resource']) # Registry this veredict on cache cache.setKey(user_id, pdpRequest['action'], pdpRequest['resource'], veredict) log.info('user ' + user_id + ' ' + veredict + ' to ' + pdpRequest['action'] + ' on ' + pdpRequest['resource']) return veredict
def update_user(db_session, user, updated_info, requester): # Drop invalid fields updated_info = { k: updated_info[k] for k in updated_info if k in User.fillable } old_user = User.getByNameOrID(user) old_service = old_user.service if 'username' in updated_info.keys() \ and updated_info['username'] != old_user.username: raise HTTPRequestError(400, "usernames can't be updated") check_user(updated_info) # Verify if the email is in use by another user if 'email' in updated_info.keys( ) and updated_info['email'] != old_user.email: another_user = db_session.query(User) \ .filter_by(email=updated_info['email']) \ .one_or_none() if another_user: raise HTTPRequestError(400, "email already in use") log().info( 'user ' + old_user.username + ' updated by ' + requester['username'], { 'oldUser': old_user.safeDict(), 'newUser': updated_info }) if 'name' in updated_info.keys(): old_user.name = updated_info['name'] if 'service' in updated_info.keys(): old_user.service = updated_info['service'] if 'email' in updated_info.keys(): old_user.email = updated_info['email'] return (old_user, old_service)
def update_user(user): try: requester = auth.get_jwt_payload(request.headers.get('Authorization')) auth_data = load_json_from_request(request) updated_user, old_service = crud.update_user(db.session, user, auth_data, requester) # Create a new kong secret and delete the old one kong_data = kong.configure_kong(updated_user.username) if kong_data is None: return format_response( 500, 'failed to configure verification subsystem') kong.revoke_kong_secret(updated_user.username, updated_user.kongId) updated_user.secret = kong_data['secret'] updated_user.key = kong_data['key'] updated_user.kongid = kong_data['kongid'] db.session.add(updated_user) db.session.commit() if crud.count_tenant_users(db.session, old_service) == 0: log().info("will emit tenant lifecycle event {} - DELETE".format( old_service)) send_notification({"type": 'DELETE', 'tenant': old_service}) if crud.count_tenant_users(db.session, updated_user.service) == 1: log().info("will emit tenant lifecycle event {} - CREATE".format( updated_user.service)) send_notification({ "type": 'CREATE', 'tenant': updated_user.service }) return format_response(200) except HTTPRequestError as err: return format_response(err.errorCode, err.message)
def pdp_main(db_session, pdp_request): check_request(pdp_request) jwt_payload = get_jwt_payload(pdp_request['jwt']) user_id = jwt_payload['userid'] # try to retrieve the veredict from cache cached_veredict = cache.get_key(user_id, pdp_request['action'], pdp_request['resource']) # Return the cached answer if it exist if cached_veredict: log().info('user ' + str(user_id) + ' ' + cached_veredict + ' to ' + pdp_request['action'] + ' on ' + pdp_request['resource']) return cached_veredict veredict = iterate_permissions(user_id, jwt_payload['groups'], pdp_request['action'], pdp_request['resource']) # Registry this veredict on cache cache.set_key(user_id, pdp_request['action'], pdp_request['resource'], veredict) log().info('user ' + str(user_id) + ' ' + veredict + ' to ' + pdp_request['action'] + ' on ' + pdp_request['resource']) return veredict
def remove_user_group(db_session, user, group, requester): try: user = User.get_by_name_or_id(user) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No user found with this ID or name") try: group = Group.get_by_name_or_id(group) except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No group found with this ID or name") try: relation = db_session.query(UserGroup) \ .filter_by(user_id=user.id, group_id=group.id).one() db_session.delete(relation) cache.delete_key(userid=user.id) user.reset_token() db_session.add(user) log().info( f"user {user.username} removed from {group.name} by {requester['username']}" ) db_session.commit() except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "User is not a member of the group")
def delete_user(db_session, username: str, requester): """ Deletes an user from the system :param db_session: The postgres session to be used :param username: String The user to be removed :param requester: Who is creating this user. This is a dictionary with two keys: "userid" and "username" :return: The removed user :raises HTTPRequestError: If the user tries to remove itself. :raises HTTPRequestError: Can't delete the admin user. :raises HTTPRequestError: If the user is not in the database. """ try: user = User.get_by_name_or_id(username) if user.id == requester['userid']: raise HTTPRequestError(400, "a user can't remove himself") elif user.username == 'admin': raise HTTPRequestError(405, "Can't delete the admin user") db_session.execute( UserPermission.__table__.delete(UserPermission.user_id == user.id)) db_session.execute( UserGroup.__table__.delete(UserGroup.user_id == user.id)) cache.delete_key(userid=user.id) # The user is not hardDeleted. # it should be copied to inactiveUser table inactiveTables.PasswdInactive.createInactiveFromUser( db_session, user, ) inactiveTables.UserInactive.createInactiveFromUser( db_session, user, requester['userid']) password.expire_password_reset_requests(db_session, user.id) db_session.delete(user) log().info(f"user {user.username} deleted by {requester['username']}") log().info(user.safe_dict()) kongUtils.remove_from_kong(user.username) MVUserPermission.refresh() MVGroupPermission.refresh() db_session.commit() if count_tenant_users(db_session, user.service) == 0: log().info( f"will emit tenant lifecycle event {user.service} - DELETE") Publisher.send_notification({ "type": 'DELETE', 'tenant': user.service }) return user except orm_exceptions.NoResultFound: raise HTTPRequestError(404, "No user found with this ID")
def create_user(db_session, user: User, requester): """ Create a new user. :param db_session: The postgres db session to be used :param user: User The user to be created. This is a simple dictionary with all 'fillable' field listed in Models.User class. :param requester: Who is creating this user. This is a dictionary with two keys: "userid" and "username" :return: The result of creating this user. :raises HTTPRequestError: If username is already in use :raises HTTPRequestError: If e-mail is already in use :raises HTTPRequestError: If any problem occurs while configuring Kong """ # Drop invalid fields user = {k: user[k] for k in user if k in User.fillable} LOGGER.debug("Checking user data...") check_user(user) LOGGER.debug("... user data is OK.") # Sanity checks # Check whether username and e-mail are unique. LOGGER.debug("Checking whether user already exist...") if db_session.query( User.id).filter_by(username=user['username']).one_or_none(): LOGGER.warning("User already exists.") raise HTTPRequestError(400, f"Username {user['username']} is in use.") LOGGER.debug("... user doesn't exist.") LOGGER.debug("Checking whether user e-mail is already being used...") if db_session.query(User.id).filter_by(email=user['email']).one_or_none(): LOGGER.warning("User e-mail is already being used.") raise HTTPRequestError(400, f"E-mail {user['email']} is in use.") LOGGER.debug("... user e-mail is not being used.") if conf.emailHost == 'NOEMAIL': user['salt'], user['hash'] = password.create_pwd( conf.temporaryPassword) # Last field to be filled automatically, before parsing user['created_by'] = requester['userid'] # User structure is finished. LOGGER.debug("Creating user instance...") new_user = User(**user) LOGGER.debug("... user instance was created.") LOGGER.debug( f"User data is: {user['username']} created by {requester['username']}") # If no problems occur to create user (no exceptions), configure kong LOGGER.debug("Configuring Kong...") kong_data = kongUtils.configure_kong(new_user.username) if kong_data is None: LOGGER.warning("Could not configure Kong.") raise HTTPRequestError(500, 'failed to configure verification subsystem') LOGGER.debug("... Kong was successfully configured.") new_user.secret = kong_data['secret'] new_user.key = kong_data['key'] new_user.kongId = kong_data['kongid'] # Add the new user to the database LOGGER.debug("Adding new user to database session...") db_session.add(new_user) LOGGER.debug("... new user was added to database session.") LOGGER.debug("Committing database changes...") db_session.commit() LOGGER.debug("... database changes were committed.") # Configuring groups and user profiles group_success = [] group_failed = [] LOGGER.debug("Configuring user profile...") if 'profile' in user.keys(): group_success, group_failed = rship. \ add_user_many_groups(db_session, new_user.id, user['profile'], requester) db_session.commit() LOGGER.debug("... user profile was configured.") LOGGER.debug("Configuring user password...") if conf.emailHost != 'NOEMAIL': try: pwdc.create_password_set_request(db_session, new_user) db_session.commit() except Exception as e: log().warning(e) LOGGER.debug("... user password was configured.") LOGGER.debug("Sending tenant creation message to other components...") if count_tenant_users(db_session, new_user.service) == 1: LOGGER.info( f"Will emit tenant lifecycle event {new_user.service} - CREATE") Publisher.send_notification({ "type": 'CREATE', 'tenant': new_user.service }) LOGGER.debug("... tenant creation message was sent.") ret = { "user": new_user.safe_dict(), "groups": group_success, "could not add": group_failed, "message": "user created" } return ret
def update_user(db_session, user: str, updated_info, requester) -> (dict, str): """ Updates all the information about a particular user. :param db_session: The postgres session to be used. :param user: The user ID to be updated. :param updated_info: The new data. :param requester: Who is requiring this update. :return: The old information (a dictionary containing the old information about the user and the old service. :raises HTTPRequestError: If the username is different from the original (this field cannot be updated). """ # Drop invalid fields updated_info = { k: updated_info[k] for k in updated_info if k in User.fillable } user = User.get_by_name_or_id(user) old_user = user.safe_dict() old_service = user.service if 'username' in updated_info.keys() \ and updated_info['username'] != user.username: raise HTTPRequestError(400, "usernames can't be updated") # check_user function needs username. updated_info['username'] = user.username check_user(updated_info) # Verify if the email is in use by another user if 'email' in updated_info.keys() and updated_info['email'] != user.email: if db_session.query(User).filter_by( email=updated_info['email']).one_or_none(): raise HTTPRequestError(400, "email already in use") log().info(f"user {user.username} updated by {requester['username']}") log().info({'oldUser': user.safe_dict(), 'newUser': updated_info}) # Update all new data. if 'name' in updated_info.keys(): user.name = updated_info['name'] if 'service' in updated_info.keys(): user.service = updated_info['service'] if 'email' in updated_info.keys(): user.email = updated_info['email'] # Create a new kong secret and delete the old one kong_data = kongUtils.configure_kong(user.username) if kong_data is None: raise HTTPRequestError(500, 'failed to configure verification subsystem') kongUtils.revoke_kong_secret(user.username, user.kongId) user.secret = kong_data['secret'] user.key = kong_data['key'] user.kongId = kong_data['kongid'] db_session.add(user) db_session.commit() # Publish messages related to service creation/deletion if count_tenant_users(db_session, old_service) == 0: log().info(f"will emit tenant lifecycle event {old_service} - DELETE") send_notification({"type": 'DELETE', 'tenant': old_service}) if count_tenant_users(db_session, user.service) == 1: log().info(f"will emit tenant lifecycle event {user.service} - CREATE") send_notification({"type": 'CREATE', 'tenant': user.service}) return old_user, old_service