Example #1
0
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)
Example #2
0
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
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
    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
Example #7
0
    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}
Example #8
0
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"))
Example #9
0
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
Example #10
0
    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})
Example #11
0
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
        }
    )
Example #12
0
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)
Example #13
0
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
Example #14
0
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'))
Example #15
0
 def _create_active_property_groups_query(when=None):
     return session.scalars(
         User.active_property_groups(when).where(User.id == user.id))
Example #16
0
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
Example #17
0
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
Example #18
0
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
Example #19
0
        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'))
Example #20
0
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)
Example #21
0
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
Example #22
0
 def _create_active_memberships_query(when=None):
     return session.scalars(
         User.active_memberships(when).where(User.id == user.id))
Example #23
0
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
Example #24
0
 def _fetch_normal(uid: int) -> User | None:
     return User.get(uid)
Example #25
0
def load_user(userid):
    return User.get(userid)
Example #26
0
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
Example #27
0
 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