def status_query(): now = single(session.utcnow()) return session.session.query( User, User.member_of(config.member_group, now).label('member'), (Account.balance <= 0).label('account_balanced'), # a User.properties hybrid attribute would be preferrable (User.has_property('network_access', now)).label('network_access'), (User.has_property('violation', now)).label('violation'), (User.has_property('ldap', now)).label('ldap'), or_(*(User.has_property(prop, now) for prop in admin_properties)).label('admin') ).join(Account)
def create_user(name, login, email, birthdate, groups, processor, address): """Create a new member Create a new user with a generated password, finance- and unix account, and make him member of the `config.member_group` and `config.network_access_group`. :param str name: The full name of the user (e.g. Max Mustermann) :param str login: The unix login for the user :param str email: E-Mail address of the user :param Date birthdate: Date of birth :param PropertyGroup groups: The initial groups of the new user :param User processor: The processor :param Address address: Where the user lives. May or may not come from a room. :return: """ now = session.utcnow() plain_password = user_helper.generate_password(12) # create a new user new_user = User( login=login, name=name, email=email, registered_at=now, account=Account(name="", type="USER_ASSET"), password=plain_password, birthdate=birthdate, address=address ) account = UnixAccount(home_directory="/home/{}".format(login)) new_user.unix_account = account with session.session.begin(subtransactions=True): session.session.add(new_user) session.session.add(account) new_user.account.name = deferred_gettext(u"User {id}").format( id=new_user.id).to_json() for group in groups: make_member_of(new_user, group, processor, closed(now, None)) log_user_event(author=processor, message=deferred_gettext(u"User created.").to_json(), user=new_user) return new_user, plain_password
def send_password_reset_mail(user: User): user.password_reset_token = generate_random_str(64) if not password_reset_url: raise ValueError("No url specified in PASSWORD_RESET_URL") try: user_send_mail(user, UserResetPasswordTemplate( password_reset_url=password_reset_url.format( user.password_reset_token)), use_internal=False) except ValueError: user.password_reset_token = None return False return True
def reset_wifi_password(user: User, processor: User) -> str: plain_password = generate_wifi_password() user.wifi_password = plain_password message = deferred_gettext(u"WIFI-Password was reset") log_user_event(author=processor, user=user, message=message.to_json()) return plain_password
def create_switch(name, management_ip, room, processor): switch = Switch(management_ip=management_ip, host=Host(room=room, owner=User.get(0), name=name)) session.add(switch) message = deferred_gettext("Created switch '{}' with management IP {}.")\ .format(switch.host.name, switch.management_ip) log_room_event(message.to_json(), processor, switch.host.room) return switch
def test_set_and_verify_password(self, user, session): password = generate_password(4) user.password = password session.flush() assert user.check_password(password) assert User.verify_and_get(user.login, password) == user assert User.verify_and_get(user.login, password + "_wrong") is None # TODO reduce set of examples, this is excessive. # Also, why do we depend on `generate_password` instead of testing it separately? # All of this is very unperformant with little benefit. for length in range(4, 10): for cnt in range(1, 3): pw = generate_password(length) if pw == password: continue assert not user.check_password(pw) assert User.verify_and_get(user.login, pw) is None
def post(self): auth_parser = reqparse.RequestParser() auth_parser.add_argument('login', dest='login', required=True) auth_parser.add_argument('password', dest='password', required=True) args = auth_parser.parse_args() user = User.verify_and_get(login=args.login, plaintext_password=args.password) if user is None: abort(401, msg="Authentication failed") return {'id': user.id}
def login(): if current_user is not None and current_user.is_authenticated(): flash(u'Sie sind bereits als "%s" angemeldet!' % current_user.name, "warning") return redirect(url_for('user.overview')) form = LoginForm() if form.validate_on_submit(): user = User.verify_and_get(form.login.data, form.password.data) if user is not None: login_user(user) flash(u"Erfolgreich angemeldet.", "success") return redirect(request.args.get("next") or url_for("user.overview")) flash(u"Benutzername und/oder Passwort falsch", "error") return render_template("login/login.html", form=form, next=request.args.get("next"))
def edit_email(user: User, email: str | None, email_forwarded: bool, processor: User, is_confirmed: bool = False): """ Changes the email address of a user and creates a log entry. :param user: User object to change :param email: New email address (empty interpreted as ``None``) :param email_forwarded: Boolean if emails should be forwarded :param processor: User object of the processor, which issues the change :param is_confirmed: If the email address is already confirmed :return:Changed user object """ if not can_target(user, processor): raise PermissionError("cannot change email of a user with a" " greater or equal permission level.") if not email: email = None else: email = email.lower() if email_forwarded != user.email_forwarded: user.email_forwarded = email_forwarded log_user_event( author=processor, user=user, message=deferred_gettext("Set e-mail forwarding to {}.").format( email_forwarded).to_json()) if is_confirmed: user.email_confirmed = True user.email_confirmation_key = None if email == user.email: # email wasn't changed, do nothing return user old_email = user.email user.email = email if email is not None: if not is_confirmed: send_confirmation_email(user) else: user.email_confirmed = False user.email_confirmation_key = None message = deferred_gettext("Changed e-mail from {} to {}.") log_user_event(author=processor, user=user, message=message.format(old_email, email).to_json()) return user
def get(self): parser = reqparse.RequestParser() parser.add_argument('user_id', required=True, type=int) args = parser.parse_args() user = User.get(args.user_id) if user is None: abort(404, message='User not found') send_confirmation_email(user) session.session.commit() return jsonify({'success': True})
def json_trafficdata(user_id, days=7): """Generate a JSON file to use with traffic and credit graphs. :param user_id: :param days: optional amount of days to be included :return: JSON with traffic and credit data formatted according to the following schema { "type": "object", "properties": { "items": { "type": "object", "properties": { "credit_limit": { "type": "integer" }, "traffic": { "type": "array", "items": { "type": "object", "properties": { "balance": { "type": "integer" }, "credit": { "type": "integer" }, "egress": { "type": "integer" }, "ingress": { "type": "integer" }, "timestamp": { "type": "string" } } } } } } } } } """ interval = timedelta(days=days) step = timedelta(days=1) result = traffic_history(user_id, session.utcnow() - interval + step, interval, step) credit_limit = session.session.execute(User.active_traffic_groups().where( User.id == user_id).with_only_columns( [func.max(TrafficGroup.credit_limit)])).scalar() return jsonify( items={ 'traffic': [e.__dict__ for e in result], 'credit_limit': credit_limit } )
def edit_address( user: User, processor: User, street: str, number: str, addition: Optional[str], zip_code: str, city: Optional[str], state: Optional[str], country: Optional[str], ): """Changes the address of a user and appends a log entry. Should do nothing if the user already has an address. """ address = get_or_create_address(street, number, addition, zip_code, city, state, country) user.address = address log_user_event( deferred_gettext("Changed address to {address}").format( address=str(address)).to_json(), processor, user)
def edit_person_id(user: User, person_id: int, processor: User): """ Changes the swdd_person_id of the user and creates a log entry. :param user: The user object. :param person_id: The new person_id. :return: The changed user object. """ if person_id == user.swdd_person_id: # name wasn't changed, do nothing return user old_person_id = user.swdd_person_id user.swdd_person_id = person_id message = deferred_gettext(u"Changed tenant number from {} to {}.") log_user_event(author=processor, user=user, message=message.format(str(old_person_id), str(person_id)).to_json()) return user
def host_create(): user = get_user_or_404(request.args.get('user_id', None)) form = HostForm(owner_id=user.id) def default_response(): form_args = { 'form': form, 'cancel_to': url_for('user.user_show', user_id=user.id) } return render_template('generic_form.html', page_title="Host erstellen", form_args=form_args, form=form) if not form.is_submitted(): refill_room_data(form, user.room) if not form.validate_on_submit(): return default_response() room = Room.q.filter_by(number=form.room_number.data, level=form.level.data, building=form.building.data).one() owner = User.get(form.owner_id.data) try: with handle_errors(session.session): host = lib_host.host_create(owner, room, form.name.data, processor=current_user) session.session.commit() except PycroftException: return default_response() return redirect( url_for('.interface_create', user_id=host.owner_id, host_id=host.id, _anchor='hosts'))
def _create_active_property_groups_query(when=None): return session.scalars( User.active_property_groups(when).where(User.id == user.id))
def get_user_or_404(user_id: int) -> User | NoReturn: user = User.get(user_id) if user is None: flash(f"Nutzer mit ID {user_id} existiert nicht!", 'error') abort(404) return user
def create_user(name, login, email, birthdate, groups, processor, address, passwd_hash=None, send_confirm_mail: bool = False): """Create a new member Create a new user with a generated password, finance- and unix account, and make him member of the `config.member_group` and `config.network_access_group`. :param str name: The full name of the user (e.g. Max Mustermann) :param str login: The unix login for the user :param str email: E-Mail address of the user :param Date birthdate: Date of birth :param PropertyGroup groups: The initial groups of the new user :param Optional[User] processor: The processor :param Address address: Where the user lives. May or may not come from a room. :param passwd_hash: Use password hash instead of generating a new password :param send_confirm_mail: If a confirmation mail should be send to the user :return: """ now = session.utcnow() plain_password = user_helper.generate_password(12) # create a new user new_user = User(login=login, name=name, email=email, registered_at=now, account=Account(name="", type="USER_ASSET"), password=plain_password, wifi_password=generate_wifi_password(), birthdate=birthdate, address=address) processor = processor if processor is not None else new_user if passwd_hash: new_user.passwd_hash = passwd_hash plain_password = None account = UnixAccount(home_directory="/home/{}".format(login)) new_user.unix_account = account with session.session.begin(subtransactions=True): session.session.add(new_user) session.session.add(account) new_user.account.name = deferred_gettext(u"User {id}").format( id=new_user.id).to_json() for group in groups: make_member_of(new_user, group, processor, closed(now, None)) log_user_event(author=processor, message=deferred_gettext(u"User created.").to_json(), user=new_user) user_send_mail(new_user, UserCreatedTemplate(), True) if email is not None and send_confirm_mail: send_confirmation_email(new_user) return new_user, plain_password
def move_in(name, login, email, dormitory, level, room_number, mac, processor, host_name=None): """ This function creates a new user, assign him to a room and creates some initial groups and transactions. :param name: The full name of the user. (Max Mustermann) :param login: The unix login for the user. :param email: E-Mail address of the user. :param dormitory: The dormitory the user moves in. :param level: The level the user moves in. :param room_number: The room number the user moves in. :param mac: The mac address of the users pc. :param host_name: An optional Hostname for the users pc. :return: The new user object. """ room = Room.q.filter_by(number=room_number, level=level, dormitory=dormitory).one() # create a new user new_user = User(login=login, name=name, email=email, room=room, registration_date=datetime.now()) plain_password = user.generate_password(12) #TODO: print plain password on paper instead print u"new password: "******"move_in"] for membership in conf["group_memberships"]: group = Group.q.filter(Group.name == membership["name"]).one() start_date = datetime.now() if membership.get("offset"): start_date += timedelta(membership["offset"]) new_membership = create_membership(start_date=start_date, end_date=None, group=group, user=new_user) if membership.get("duration"): assert membership["duration"] > 0 new_membership.end_date = datetime.now() + timedelta( membership["duration"]) setup_user_finance_account(new_user, processor) move_in_user_log_entry = create_user_log_entry(author=processor, message=conf["log_message"], timestamp=datetime.now(), user=new_user) return new_user
return render_template('generic_form.html', page_title="Host editieren", form_args=form_args, form=form) if not form.is_submitted(): refill_room_data(form, host.room) return default_response() if not form.validate(): return default_response() room = Room.q.filter_by(number=form.room_number.data, level=form.level.data, building=form.building.data).one() owner = User.get(form.owner_id.data) try: with handle_errors(session.session): lib_host.host_edit(host, owner, room, form.name.data, processor=current_user) session.session.commit() except PycroftException: return default_response() flash("Host erfolgreich bearbeitet.", 'success') return redirect( url_for('user.user_show', user_id=owner.id, _anchor='hosts'))
def merge_member_request(user: User, prm: PreMember, merge_name: bool, merge_email: bool, merge_person_id: bool, merge_room: bool, merge_password: bool, merge_birthdate: bool, processor: User): if prm.move_in_date is not None and prm.move_in_date < session.utcnow( ).date(): prm.move_in_date = session.utcnow().date() if merge_name: user = edit_name(user, prm.name, processor) if merge_email: user = edit_email(user, prm.email, user.email_forwarded, processor, is_confirmed=prm.email_confirmed) if merge_person_id: user = edit_person_id(user, prm.swdd_person_id, processor) move_in_datetime = datetime.combine(prm.move_in_date, utc.time_min()) if merge_room: if prm.room: if user.room: move(user, prm.room.building_id, prm.room.level, prm.room.number, processor=processor, when=move_in_datetime) else: move_in(user, prm.room.building_id, prm.room.level, prm.room.number, mac=None, processor=processor, when=move_in_datetime) if not user.member_of(config.member_group): make_member_of(user, config.member_group, processor, closed(move_in_datetime, None)) if merge_birthdate: user = edit_birthdate(user, prm.birthdate, processor) log_msg = "Merged information from registration {}." if merge_password: user.passwd_hash = prm.passwd_hash log_msg += " Password overridden." else: log_msg += " Kept old password." log_user_event( deferred_gettext(log_msg).format(encode_type2_user_id( prm.id)).to_json(), processor, user) session.session.delete(prm)
def get_user_or_404(user_id): user = User.get(user_id) if user is None: abort(404, message=f"User {user_id} does not exist") return user
def _create_active_memberships_query(when=None): return session.scalars( User.active_memberships(when).where(User.id == user.id))
def move_in(user: User, building_id: int, level: int, room_number: str, mac: str | None, processor: User | None = None, birthdate: date = None, host_annex: bool = False, begin_membership: bool = True, when: datetime | None = None): """Move in a user in a given room and do some initialization. The user is given a new Host with an interface of the given mac, a UnixAccount, a finance Account, and is made member of important groups. Networking is set up. :param User user: The user to move in :param building_id: :param level: :param room_number: :param mac: The mac address of the users pc. :param processor: :param birthdate: Date of birth` :param host_annex: when true: if MAC already in use, annex host to new user :param begin_membership: Starts a membership if true :param when: The date at which the user should be moved in :return: The user object. """ if when and when > session.utcnow(): task_params = UserMoveInParams(building_id=building_id, level=level, room_number=room_number, mac=mac, birthdate=birthdate, host_annex=host_annex, begin_membership=begin_membership) return schedule_user_task(task_type=TaskType.USER_MOVE_IN, due=when, user=user, parameters=task_params, processor=processor) if user.room is not None: raise ValueError("user is already living in a room.") room = get_room(building_id, level, room_number) if birthdate: user.birthdate = birthdate if begin_membership: for group in {config.external_group, config.pre_member_group}: if user.member_of(group): remove_member_of(user, group, processor, closedopen(session.utcnow(), None)) for group in {config.member_group, config.network_access_group}: if not user.member_of(group): make_member_of(user, group, processor, closed(session.utcnow(), None)) if room: user.room = room user.address = room.address if mac and user.birthdate: interface_existing = Interface.q.filter_by(mac=mac).first() if interface_existing is not None: if host_annex: host_existing = interface_existing.host host_existing.owner_id = user.id session.session.add(host_existing) migrate_user_host(host_existing, user.room, processor) else: raise MacExistsException else: new_host = Host(owner=user, room=room) session.session.add(new_host) session.session.add(Interface(mac=mac, host=new_host)) setup_ipv4_networking(new_host) user_send_mail(user, UserMovedInTemplate(), True) msg = deferred_gettext("Moved in: {room}") log_user_event(author=processor if processor is not None else user, message=msg.format(room=room.short_name).to_json(), user=user) return user
def _fetch_normal(uid: int) -> User | None: return User.get(uid)
def load_user(userid): return User.get(userid)
def move_in(name, login, email, dormitory, level, room_number, mac, processor, host_name=None): """ This function creates a new user, assign him to a room and creates some initial groups and transactions. :param name: The full name of the user. (Max Mustermann) :param login: The unix login for the user. :param email: E-Mail address of the user. :param dormitory: The dormitory the user moves in. :param level: The level the user moves in. :param room_number: The room number the user moves in. :param mac: The mac address of the users pc. :param host_name: An optional Hostname for the users pc. :return: The new user object. """ room = Room.q.filter_by(number=room_number, level=level, dormitory=dormitory).one() # create a new user new_user = User( login=login, name=name, email=email, room=room, registration_date=datetime.now() ) plain_password = user.generate_password(12) #TODO: print plain password on paper instead print u"new password: "******"move_in"] for membership in conf["group_memberships"]: group = Group.q.filter(Group.name == membership["name"]).one() start_date = datetime.now() if membership.get("offset"): start_date += timedelta(membership["offset"]) new_membership = create_membership( start_date=start_date, end_date=None, group=group, user=new_user ) if membership.get("duration"): assert membership["duration"] > 0 new_membership.end_date = datetime.now() + timedelta(membership["duration"]) setup_user_finance_account(new_user, processor) move_in_user_log_entry = create_user_log_entry( author=processor, message=conf["log_message"], timestamp=datetime.now(), user=new_user ) return new_user
def test_user_login_case_insensitive(self, session, user): password = '******' assert User.verify_and_get(user.login, password) == user # Verification of login name should be case insensitive assert User.verify_and_get(user.login.upper(), password) == user