Пример #1
0
def test_set_get():
    from pykern import pkunit
    from pykern.pkunit import pkeq
    from pykern.pkdebug import pkdp
    from pykern import pkcollections
    from sirepo import cookie

    class _Response(pkcollections.Dict):
        def set_cookie(self, *args, **kwargs):
            self.args = args
            self.kwargs = kwargs

    cookie.process_header('x')
    with pkunit.pkexcept('KeyError'):
        cookie.get_value('hi')
    with pkunit.pkexcept('AssertionError'):
        cookie.set_value('hi', 'hello')
    pkeq(None, cookie.unchecked_get_value('hi'))
    cookie.init_mock()
    cookie.set_value('hi', 'hello')
    r = _Response(status_code=200)
    cookie.save_to_cookie(r)
    pkeq('sirepo_dev', r.args[0])
    pkeq(False, r.kwargs['secure'])
    pkeq('hello', cookie.get_value('hi'))
    cookie.unchecked_remove('hi')
    pkeq(None, cookie.unchecked_get_value('hi'))
    cookie.process_header('sirepo_dev={}'.format(r.args[1]))
    pkeq('hello', cookie.get_value('hi'))
Пример #2
0
def logged_in_user(check_path=True):
    """Get the logged in user

    Args:
        check_path (bool): call `simulation_db.user_path` [True]
    Returns:
        str: uid of authenticated user
    """
    u = _get_user()
    if not _is_logged_in():
        raise util.SRException(
            'login',
            None,
            'user not logged in uid={}',
            u,
        )
    assert u, \
        'no user in cookie: state={} method={}'.format(
            cookie.unchecked_get_value(_COOKIE_STATE),
            cookie.unchecked_get_value(_COOKIE_METHOD),
        )
    if check_path:
        import sirepo.simulation_db
        sirepo.simulation_db.user_path(u, check=True)
    return u
Пример #3
0
def api_authState():
    s = cookie.unchecked_get_value(_COOKIE_STATE)
    v = pkcollections.Dict(
        avatarUrl=None,
        displayName=None,
        needCompleteRegistration=s == _STATE_COMPLETE_REGISTRATION,
        isLoggedIn=_is_logged_in(s),
        method=cookie.unchecked_get_value(_COOKIE_METHOD),
        userName=None,
        visibleMethods=visible_methods,
    )
    u = cookie.unchecked_get_value(_COOKIE_USER)
    if v.isLoggedIn:
        r = auth_db.UserRegistration.search_by(uid=u)
        if r:
            v.displayName = r.display_name
        _method_auth_state(v, u)
    if pkconfig.channel_in('dev'):
        # useful for testing/debugging
        v.uid = u
    return http_reply.render_static(
        'auth-state',
        'js',
        pkcollections.Dict(auth_state=v),
    )
Пример #4
0
def require_user():
    s = cookie.unchecked_get_value(_COOKIE_STATE)
    e = None
    r = 'login'
    m = cookie.unchecked_get_value(_COOKIE_METHOD)
    p = None
    if s is None:
        e = 'no user in cookie'
    elif s == _STATE_LOGGED_IN:
        if m in cfg.methods:
            # Success
            return None
        u = _get_user()
        if m in cfg.deprecated_methods:
            e = 'deprecated'
        else:
            e = 'invalid'
            reset_state()
        e = 'auth_method={} is {}, forcing login: uid='.format(m, e, u)
    elif s == _STATE_LOGGED_OUT:
        e = 'logged out uid={}'.format(_get_user())
        if m in cfg.deprecated_methods:
            # Force login to this specific method so we can migrate to valid method
            r = 'loginWith'
            p = {'method': m}
    elif s == _STATE_COMPLETE_REGISTRATION:
        r = 'completeRegistration'
        e = 'uid={} needs to complete registration'.format(_get_user())
    else:
        cookie.reset_state('state={} invalid, cannot continue'.format(s))
        e = 'invalid cookie'
    pkdlog('user not logged in: {}', e)
    return http_reply.gen_sr_exception(r, p)
Пример #5
0
def login(module, uid=None, model=None, sim_type=None, display_name=None, is_mock=False, want_redirect=False):
    """Login the user

    Raises an exception if successful, except in the case of methods

    Args:
        module (module): method module
        uid (str): user to login
        model (auth_db.UserDbBase): user to login (overrides uid)
        sim_type (str): app to redirect to
    """
    _validate_method(module, sim_type=sim_type)
    guest_uid = None
    if model:
        uid = model.uid
        # if previously cookied as a guest, move the non-example simulations into uid below
        m = cookie.unchecked_get_value(_COOKIE_METHOD)
        if m == METHOD_GUEST and module.AUTH_METHOD != METHOD_GUEST:
            guest_uid = _get_user() if _is_logged_in() else None
    if uid:
        _login_user(module, uid)
    if module.AUTH_METHOD in cfg.deprecated_methods:
        pkdlog('deprecated auth method={} uid={}'.format(module.AUTH_METHOD, uid))
        if not uid:
            # No user so clear cookie so this method is removed
            reset_state()
        # We are logged in with a deprecated method, and now the user
        # needs to login with an allowed method.
        login_fail_redirect(sim_type, module, 'deprecated', reload_js=not uid)
    if not uid:
        # No user in the cookie and method didn't provide one so
        # the user might be switching methods (e.g. github to email or guest to email).
        # Not allowed to go to guest from other methods, because there's
        # no authentication for guest.
        # Or, this is just a new user, and we'll create one.
        uid = _get_user() if _is_logged_in() else None
        m = cookie.unchecked_get_value(_COOKIE_METHOD)
        if uid and module.AUTH_METHOD not in (m, METHOD_GUEST):
            # switch this method to this uid (even for methods)
            # except if the same method, then assuming logging in as different user.
            # This handles the case where logging in as guest, creates a user every time
            _login_user(module, uid)
        else:
            uid = create_new_user(lambda u: _login_user(module, u), module)
        if model:
            model.uid = uid
            model.save()
    if display_name:
        complete_registration(_parse_display_name(display_name))
    if is_mock:
        return
    if sim_type:
        if guest_uid and guest_uid != uid:
            import sirepo.simulation_db
            sirepo.simulation_db.move_user_simulations(guest_uid, uid)
        login_success_response(sim_type, want_redirect)
    assert not module.AUTH_METHOD_VISIBLE
Пример #6
0
def logged_in_user():
    """Get the logged in user

    Returns:
        str: uid of authenticated user
    """
    res = _get_user()
    if not _is_logged_in():
        util.raise_unauthorized('user not logged in uid={}', res)
    assert res, 'no user in cookie: state={} method={}'.format(
        cookie.unchecked_get_value(_COOKIE_STATE),
        cookie.unchecked_get_value(_COOKIE_METHOD),
    )
    return res
Пример #7
0
def is_login_expired(res=None):
    """If expiry is configured, check timestamp

    Args:
        res (hash): If a hash and return is True, will contain (uid, expiry, and now).

    Returns:
        bool: true if login is expired
    """
    if not cfg.expiry_days:
        return False
    n = int(srtime.utc_now_as_float())
    t = int(cookie.unchecked_get_value(_COOKIE_EXPIRY_TIMESTAMP, 0))
    if n <= t:
        # cached timestamp less than expiry
        return False
    # db expiry at most one day from now so we can change expiry_days
    # and (in any event) ensure expiry is checked once a day. This
    # would also allow us to extend the expired period in the db.
    u = auth.logged_in_user()
    r = auth.user_registration(u)
    t = r.created + cfg.expiry_days
    n = srtime.utc_now()
    if n > t:
        if res is not None:
            res.update(uid=u, expiry=t, now=n)
        return True
    # set expiry in cookie
    t2 = n + _ONE_DAY
    if t2 < t:
        t = t2
    t -= datetime.datetime.utcfromtimestamp(0)
    cookie.set_value(_COOKIE_EXPIRY_TIMESTAMP, int(t.total_seconds()))
    return False
Пример #8
0
def user_name():
    u = getattr(
        _METHOD_MODULES[cookie.unchecked_get_value(_COOKIE_METHOD, )],
        'UserModel',
    )
    if u:
        with auth_db.thread_lock:
            return u.search_by(uid=logged_in_user()).user_name
Пример #9
0
def require_user():
    e = None
    m = cookie.unchecked_get_value(_COOKIE_METHOD)
    p = None
    r = 'login'
    s = cookie.unchecked_get_value(_COOKIE_STATE)
    u = _get_user()
    if s is None:
        e = 'no user in cookie'
    elif s == _STATE_LOGGED_IN:
        if m in cfg.methods:
            f = getattr(_METHOD_MODULES[m], 'validate_login', None)
            if f:
                pkdc('validate_login method={}', m)
                f()
            return
        if m in cfg.deprecated_methods:
            e = 'deprecated'
        else:
            e = 'invalid'
            reset_state()
            p = PKDict(reload_js=True)
        e = 'auth_method={} is {}, forcing login: uid='.format(m, e, u)
    elif s == _STATE_LOGGED_OUT:
        e = 'logged out uid={}'.format(u)
        if m in cfg.deprecated_methods:
            # Force login to this specific method so we can migrate to valid method
            r = 'loginWith'
            p = PKDict({':method': m})
            e = 'forced {}={} uid={}'.format(m, r, p)
    elif s == _STATE_COMPLETE_REGISTRATION:
        if m == METHOD_GUEST:
            pkdc('guest completeRegistration={}', u)
            complete_registration()
            return
        r = 'completeRegistration'
        e = 'uid={} needs to complete registration'.format(u)
    else:
        cookie.reset_state('uid={} state={} invalid, cannot continue'.format(
            s, u))
        p = PKDict(reload_js=True)
        e = 'invalid cookie state={} uid={}'.format(s, u)
    pkdc('SRException uid={} route={} params={} method={} error={}', u, r, p,
         m, e)
    raise util.SRException(r, p, 'user not logged in: {}', e)
Пример #10
0
def _is_logged_in(state=None):
    """Logged in is either needing to complete registration or done

    Args:
        state (str): logged in state [None: from cookie]
    Returns:
        bool: is in one of the logged in states
    """
    s = state or cookie.unchecked_get_value(_COOKIE_STATE)
    return s in (_STATE_COMPLETE_REGISTRATION, _STATE_LOGGED_IN)
Пример #11
0
def logged_in_user():
    """Get the logged in user

    Returns:
        str: uid of authenticated user
    """
    res = _get_user()
    if not _is_logged_in():
        raise util.SRException(
            'login',
            None,
            'user not logged in uid={}',
            res,
        )
    assert res, 'no user in cookie: state={} method={}'.format(
        cookie.unchecked_get_value(_COOKIE_STATE),
        cookie.unchecked_get_value(_COOKIE_METHOD),
    )
    return res
Пример #12
0
    def _op():
        from sirepo import cookie
        from sirepo import auth

        pkeq(uid, auth._get_user())
        for expect, key in cases:
            if expect is None:
                pkeq(False, cookie.has_key(key))
            else:
                pkeq(expect, cookie.unchecked_get_value(key))
Пример #13
0
def user_if_logged_in(method):
    """Verify user is logged in and method matches

    Args:
        method (str): method must be logged in as
    """
    if not _is_logged_in():
        return None
    m = cookie.unchecked_get_value(_COOKIE_METHOD)
    if m != method:
        return None
    return _get_user()
Пример #14
0
def test_set_get():
    from pykern import pkunit, pkcompat
    from pykern.pkunit import pkeq
    from pykern.pkdebug import pkdp
    from sirepo import cookie

    with cookie.process_header('x'):
        with pkunit.pkexcept('KeyError'):
            cookie.get_value('hi1')
        with pkunit.pkexcept('AssertionError'):
            cookie.set_value('hi2', 'hello')
        pkeq(None, cookie.unchecked_get_value('hi3'))
Пример #15
0
def user_name():
    m = cookie.unchecked_get_value(_COOKIE_METHOD)
    u = getattr(
        _METHOD_MODULES[m],
        'UserModel',
    )
    if u:
        with util.THREAD_LOCK:
            return  u.search_by(uid=logged_in_user()).user_name
    raise AssertionError(
        f'user_name not found for uid={logged_in_user()} with method={m}',
    )
Пример #16
0
def _auth_state():
    import sirepo.simulation_db
    s = cookie.unchecked_get_value(_COOKIE_STATE)
    v = pkcollections.Dict(
        avatarUrl=None,
        displayName=None,
        guestIsOnlyMethod=not non_guest_methods,
        isGuestUser=False,
        isLoggedIn=_is_logged_in(s),
        isLoginExpired=False,
        jobRunModeMap=sirepo.simulation_db.JOB_RUN_MODE_MAP,
        method=cookie.unchecked_get_value(_COOKIE_METHOD),
        needCompleteRegistration=s == _STATE_COMPLETE_REGISTRATION,
        roles=[],
        userName=None,
        visibleMethods=visible_methods,
    )
    if 'sbatch' in v.jobRunModeMap:
        v.sbatchQueueMaxes=job.NERSC_QUEUE_MAX
    u = cookie.unchecked_get_value(_COOKIE_USER)
    if v.isLoggedIn:
        if v.method == METHOD_GUEST:
            # currently only method to expire login
            v.displayName = _GUEST_USER_DISPLAY_NAME
            v.isGuestUser = True
            v.isLoginExpired = _METHOD_MODULES[METHOD_GUEST].is_login_expired()
            v.needCompleteRegistration = False
            v.visibleMethods = non_guest_methods
        else:
            r = auth_db.UserRegistration.search_by(uid=u)
            if r:
                v.displayName = r.display_name
        v.roles = auth_db.UserRole.get_roles(u)
        _plan(v)
        _method_auth_state(v, u)
    if pkconfig.channel_in_internal_test():
        # useful for testing/debugging
        v.uid = u
    pkdc('state={}', v)
    return v
Пример #17
0
def complete_registration(name=None):
    """Update the database with the user's display_name and sets state to logged-in.
    Guests will have no name.
    """
    u = _get_user()
    with auth_db.thread_lock:
        r = user_registration(u)
        if cookie.unchecked_get_value(_COOKIE_METHOD) is METHOD_GUEST:
            assert name is None, \
                'Cookie method is {} and name is {}. Expected name to be None'.format(METHOD_GUEST, name)
        r.display_name = name
        r.save()
    cookie.set_value(_COOKIE_STATE, _STATE_LOGGED_IN)
Пример #18
0
def _set_log_user():
    if not _uwsgi:
        # Only works for uWSGI (service.uwsgi). sirepo.service.http uses
        # the limited http server for development only. This uses
        # werkzeug.serving.WSGIRequestHandler.log which hardwires the
        # common log format to: '%s - - [%s] %s\n'. Could monkeypatch
        # but we only use the limited http server for development.
        return
    u = _get_user()
    if u:
        u = cookie.unchecked_get_value(_COOKIE_STATE) + '-' + u
    else:
        u = '-'
    _app.uwsgi.set_logvar(_UWSGI_LOG_KEY_USER, u)
Пример #19
0
def api_authState():
    s = cookie.unchecked_get_value(_COOKIE_STATE)
    v = pkcollections.Dict(
        avatarUrl=None,
        displayName=None,
        guestIsOnlyMethod=not non_guest_methods,
        isGuestUser=False,
        isLoggedIn=_is_logged_in(s),
        isLoginExpired=False,
        method=cookie.unchecked_get_value(_COOKIE_METHOD),
        needCompleteRegistration=s == _STATE_COMPLETE_REGISTRATION,
        userName=None,
        visibleMethods=visible_methods,
    )
    u = cookie.unchecked_get_value(_COOKIE_USER)
    if v.isLoggedIn:
        if v.method == METHOD_GUEST:
            # currently only method to expire login
            v.displayName = _GUEST_USER_DISPLAY_NAME
            v.isGuestUser = True
            v.isLoginExpired = _METHOD_MODULES[METHOD_GUEST].is_login_expired()
            v.needCompleteRegistration = False
            v.visibleMethods = non_guest_methods
        else:
            r = auth_db.UserRegistration.search_by(uid=u)
            if r:
                v.displayName = r.display_name
        _method_auth_state(v, u)
    if pkconfig.channel_in('dev'):
        # useful for testing/debugging
        v.uid = u
    pkdc('state={}', v)
    return http_reply.render_static(
        'auth-state',
        'js',
        pkcollections.Dict(auth_state=v),
    )
Пример #20
0
def login(module, uid=None, model=None, sim_type=None, **kwargs):
    """Login the user

    Args:
        module (module): method module
        uid (str): user to login
        model (auth_db.UserDbBase): user to login (overrides uid)
        sim_type (str): app to redirect to
    Returns:
        flask.Response: reply object or None (if no sim_type)
    """
    r = _validate_method(module, sim_type=sim_type)
    if r:
        return r
    if model:
        uid = model.uid
    if uid:
        _login_user(module, uid)
    if module.AUTH_METHOD in cfg.deprecated_methods:
        pkdlog('deprecated auth method={} uid={}'.format(
            module.AUTH_METHOD, uid))
        if not uid:
            # No user so clear cookie so this method is removed
            reset_state()
        # We are logged in with a deprecated method, and now the user
        # needs to login with an allowed method.
        return login_fail_redirect(sim_type, module, 'deprecated')
    if not uid:
        # No user in the cookie and method didn't provide one so
        # the user might be switching methods (e.g. github to email or guest to email).
        # Not allowed to go to guest from other methods, because there's
        # no authentication for guest.
        # Or, this is just a new user, and we'll create one.
        uid = _get_user() if _is_logged_in() else None
        m = cookie.unchecked_get_value(_COOKIE_METHOD)
        if uid and module.AUTH_METHOD not in (m, _METHOD_GUEST):
            # switch this method to this uid (even for methods)
            # except if the same method, then assuming logging in as different user.
            # This handles the case where logging in as guest, creates a user every time
            _login_user(module, uid)
        else:
            uid = simulation_db.user_create(lambda u: _login_user(module, u))
        if model:
            model.uid = uid
            model.save()
    if sim_type:
        return login_success_redirect(sim_type)
    # bluesky or basic
    return None
Пример #21
0
def test_cookie_outside_of_flask_request():
    from pykern import pkcompat
    from pykern.pkunit import pkeq
    from sirepo import cookie
    from sirepo import srunit

    with srunit.auth_db_session(), \
         cookie.set_cookie_outside_of_flask_request():
        cookie.set_value('hi4', 'hello')
        r = _Response(status_code=200)
        cookie.save_to_cookie(r)
        pkeq('sirepo_dev', r.args[0])
        pkeq(False, r.kwargs['secure'])
        pkeq('hello', cookie.get_value('hi4'))
        cookie.unchecked_remove('hi4')
        pkeq(None, cookie.unchecked_get_value('hi4'))
        # Nest cookie contexts
        with cookie.process_header(
                'sirepo_dev={}'.format(pkcompat.from_bytes(r.args[1])), ):
            pkeq('hello', cookie.get_value('hi4'))
Пример #22
0
def _get_user():
    return cookie.unchecked_get_value(_COOKIE_USER)