Ejemplo n.º 1
0
def run(args):
    """This function will allow a user to request a new session
       that will be validated by the passed public key and public
       signing certificate. This will return a URL that the user
       must connect to to then log in and validate that request.

        Args:
            args (dict): containing login data such as username, password etc

        Returns:
            dict: containing status of login attempt
    """
    username = args["username"]
    public_key = PublicKey.from_data(args["public_key"])
    public_cert = PublicKey.from_data(args["public_certificate"])

    try:
        scope = args["scope"]
    except:
        scope = None

    try:
        permissions = args["permissions"]
    except:
        permissions = None

    try:
        hostname = args["hostname"]
    except:
        hostname = None

    try:
        ipaddr = args["ipaddr"]
    except:
        ipaddr = None

    try:
        login_message = args["login_message"]
    except:
        login_message = None

    # Generate a login session for this request
    login_session = LoginSession(username=username,
                                 public_key=public_key,
                                 public_cert=public_cert,
                                 ipaddr=ipaddr, hostname=hostname,
                                 login_message=login_message,
                                 scope=scope, permissions=permissions)

    return_value = {}

    return_value["login_url"] = login_session.login_url()
    return_value["short_uid"] = login_session.short_uid()
    return_value["session_uid"] = login_session.uid()

    return return_value
Ejemplo n.º 2
0
def run(args):
    """This function will allow anyone to query the current login
       status of the session with passed UID"""

    status = 0
    message = None
    session_status = None

    session_uid = args["session_uid"]
    username = args["username"]

    # generate a sanitised version of the username
    user_account = UserAccount(username)

    # now log into the central identity account to query
    # the current status of this login session
    bucket = login_to_service_account()

    user_session_key = "sessions/%s/%s" % \
        (user_account.sanitised_name(), session_uid)

    try:
        login_session = LoginSession.from_data(
            ObjectStore.get_object_from_json(bucket, user_session_key))
    except:
        login_session = None

    if login_session is None:
        user_session_key = "expired_sessions/%s/%s" % \
                                (user_account.sanitised_name(),
                                    session_uid)

        login_session = LoginSession.from_data(
            ObjectStore.get_object_from_json(bucket, user_session_key))

    if login_session is None:
        raise InvalidSessionError("Cannot find the session '%s'" % session_uid)

    status = 0
    message = "Success: Status = %s" % login_session.status()
    session_status = login_session.status()

    return_value = create_return_value(status, message)

    if session_status:
        return_value["session_status"] = session_status

    return return_value
Ejemplo n.º 3
0
def run(args):
    """This function will allow the current user to authorise
       a logout from the current session - this will be authorised
       by signing the request to logout
       
       Args:
        args (dict): contains identifying information about the session
    
        Returns:
            dict: contains data on the success of the logout request
       
       """

    session_uid = args["session_uid"]

    try:
        authorisation = Authorisation.from_data(args["authorisation"])
    except:
        authorisation = None

    try:
        signature = string_to_bytes(args["signature"])
    except:
        signature = None

    login_session = LoginSession.load(uid=session_uid)

    login_session.set_logged_out(authorisation=authorisation,
                                 signature=signature)
Ejemplo n.º 4
0
def test_credentials(username, password):
    identity_uid = create_uuid()
    session_uid = create_uuid()

    if random.randint(0, 1):
        device_uid = create_uuid()
    else:
        device_uid = None

    short_uid = LoginSession.to_short_uid(session_uid)

    otpcode = "%06d" % random.randint(1, 999999)

    data = Credentials.package(identity_uid=identity_uid,
                               short_uid=short_uid,
                               device_uid=device_uid,
                               username=username,
                               password=password,
                               otpcode=otpcode)

    creds = Credentials.unpackage(data=data,
                                  username=username,
                                  short_uid=short_uid)

    assert (creds["username"] == username)
    assert (creds["short_uid"] == short_uid)

    if device_uid is None:
        assert (creds["device_uid"] != device_uid)
    else:
        assert (creds["device_uid"] == device_uid)

    encoded_password = Credentials.encode_password(identity_uid=identity_uid,
                                                   device_uid=device_uid,
                                                   password=password)

    assert (creds["password"] == encoded_password)
    assert (creds["otpcode"] == otpcode)
Ejemplo n.º 5
0
def run(args):
    """This function will allow the current user to authorise
       a logout from the current session - this will be authorised
       by signing the request to logout"""

    status = 0
    message = None

    session_uid = args["session_uid"]
    username = args["username"]
    permission = args["permission"]
    signature = string_to_bytes(args["signature"])

    # generate a sanitised version of the username
    user_account = UserAccount(username)

    # now log into the central identity account to query
    # the current status of this login session
    bucket = login_to_service_account()

    user_session_key = "sessions/%s/%s" % \
        (user_account.sanitised_name(), session_uid)

    request_session_key = "requests/%s/%s" % (session_uid[:8], session_uid)

    login_session = LoginSession.from_data(
        ObjectStore.get_object_from_json(bucket, user_session_key))

    if login_session:
        # get the signing certificate from the login session and
        # validate that the permission object has been signed by
        # the user requesting the logout
        cert = login_session.public_certificate()

        cert.verify(signature, permission)

        # the signature was correct, so log the user out. For record
        # keeping purposes we change the loginsession to a logout state
        # and move it to another part of the object store
        if login_session.is_approved():
            login_session.logout()

    # only save sessions that were successfully approved
    if login_session:
        if login_session.is_logged_out():
            expired_session_key = "expired_sessions/%s/%s" % \
                                    (user_account.sanitised_name(),
                                     session_uid)

            ObjectStore.set_object_from_json(bucket, expired_session_key,
                                             login_session.to_data())

    try:
        ObjectStore.delete_object(bucket, user_session_key)
    except:
        pass

    try:
        ObjectStore.delete_object(bucket, request_session_key)
    except:
        pass

    status = 0
    message = "Successfully logged out"

    return_value = create_return_value(status, message)

    return return_value
Ejemplo n.º 6
0
    def request_login(self, login_message=None):
        """Request to authenticate as this user. This returns a login URL that
           you must connect to to supply your login credentials

           If 'login_message' is supplied, then this is passed to
           the identity service so that it can be displayed
           when the user accesses the login page. This helps
           the user validate that they have accessed the correct
           login page. Note that if the message is None,
           then a random message will be generated.
        """
        self._check_for_error()

        from Acquire.Client import LoginError

        if not self.is_empty():
            raise LoginError("You cannot try to log in twice using the same "
                             "User object. Create another object if you want "
                             "to try to log in again.")

        if self._username is None or len(self._username) == 0:
            raise LoginError("Please supply a valid username!")

        # first, create a private key that will be used
        # to sign all requests and identify this login
        from Acquire.Client import PrivateKey as _PrivateKey
        session_key = _PrivateKey(name="user_session_key %s" % self._username)
        signing_key = _PrivateKey(name="user_session_cert %s" % self._username)

        args = {"username": self._username,
                "public_key": session_key.public_key().to_data(),
                "public_certificate": signing_key.public_key().to_data(),
                "scope": self._scope,
                "permissions": self._permissions
                }

        # get information from the local machine to help
        # the user validate that the login details are correct
        try:
            hostname = _socket.gethostname()
            ipaddr = _socket.gethostbyname(hostname)
            args["hostname"] = hostname
            args["ipaddr"] = ipaddr
        except:
            pass

        if login_message is None:
            try:
                login_message = _get_random_sentence()
            except:
                pass

        if login_message is not None:
            args["login_message"] = login_message

        identity_service = self.identity_service()

        result = identity_service.call_function(
                        function="request_login", args=args)

        try:
            login_url = result["login_url"]
        except:
            login_url = None

        if login_url is None:
            error = "Failed to login. Could not extract the login URL! " \
                    "Result is %s" % (str(result))
            self._set_error_state(error)
            raise LoginError(error)

        try:
            session_uid = result["session_uid"]
        except:
            session_uid = None

        if session_uid is None:
            error = "Failed to login. Could not extract the login " \
                    "session UID! Result is %s" % (str(result))

            self._set_error_state(error)
            raise LoginError(error)

        # now save all of the needed data
        self._login_url = result["login_url"]
        self._session_key = session_key
        self._signing_key = signing_key
        self._session_uid = session_uid
        self._status = _LoginStatus.LOGGING_IN
        self._user_uid = None

        _output("Login by visiting: %s" % self._login_url)

        if login_message is not None:
            _output("(please check that this page displays the message '%s')"
                    % login_message)

        from Acquire.Identity import LoginSession as _LoginSession

        return {"login_url": self._login_url,
                "session_uid": session_uid,
                "short_uid": _LoginSession.to_short_uid(session_uid)}
Ejemplo n.º 7
0
def run(args):
    """This function is called by the user to log in and validate
       that a session is authorised to connect"""

    status = 0
    message = None
    provisioning_uri = None
    assigned_device_uid = None

    short_uid = args["short_uid"]
    username = args["username"]
    password = args["password"]
    otpcode = args["otpcode"]

    try:
        remember_device = args["remember_device"]
    except:
        remember_device = False

    try:
        device_uid = args["device_uid"]
    except:
        device_uid = None

    # create the user account for the user
    user_account = UserAccount(username)

    # log into the central identity account to query
    # the current status of this login session
    bucket = login_to_service_account()

    # locate the session referred to by this uid
    base_key = "requests/%s" % short_uid
    session_keys = ObjectStore.get_all_object_names(bucket, base_key)

    # try all of the sessions to find the one that the user
    # may be referring to...
    login_session_key = None
    request_session_key = None

    for session_key in session_keys:
        request_session_key = "%s/%s" % (base_key, session_key)
        session_user = ObjectStore.get_string_object(
            bucket, request_session_key)

        # did the right user request this session?
        if user_account.name() == session_user:
            if login_session_key:
                # this is an extremely unlikely edge case, whereby
                # two login requests within a 30 minute interval for the
                # same user result in the same short UID. This should be
                # signified as an error and the user asked to create a
                # new request
                raise LoginError(
                    "You have found an extremely rare edge-case "
                    "whereby two different login requests have randomly "
                    "obtained the same short UID. As we can't work out "
                    "which request is valid, the login is denied. Please "
                    "create a new login request, which will then have a "
                    "new login request UID")
            else:
                login_session_key = session_key

    if not login_session_key:
        raise LoginError(
            "There is no active login request with the "
            "short UID '%s' for user '%s'" % (short_uid, username))

    login_session_key = "sessions/%s/%s" % (user_account.sanitised_name(),
                                            login_session_key)

    # fully load the user account from the object store so that we
    # can validate the username and password
    try:
        account_key = "accounts/%s" % user_account.sanitised_name()
        user_account = UserAccount.from_data(
            ObjectStore.get_object_from_json(bucket, account_key))
    except:
        raise LoginError("No account available with username '%s'" %
                         username)

    if (not remember_device) and device_uid:
        # see if this device has been seen before
        device_key = "devices/%s/%s" % (user_account.sanitised_name(),
                                        device_uid)

        try:
            device_secret = ObjectStore.get_string_object(bucket,
                                                          device_key)
        except:
            device_secret = None

        if device_secret is None:
            raise LoginError(
                "The login device is not recognised. Please try to "
                "log in again using your master one-time-password.")
    else:
        device_secret = None

    # now try to log into this account using the supplied
    # password and one-time-code
    try:
        if device_secret:
            user_account.validate_password(password, otpcode,
                                           device_secret=device_secret)
        elif remember_device:
            (device_secret, provisioning_uri) = \
                        user_account.validate_password(
                                    password, otpcode,
                                    remember_device=True)

            device_uid = str(uuid.uuid4())
            device_key = "devices/%s/%s" % (user_account.sanitised_name(),
                                            device_uid)

            assigned_device_uid = device_uid
        else:
            user_account.validate_password(password, otpcode)
    except:
        # don't leak info about why validation failed
        raise LoginError("The password or OTP code is incorrect")

    # the user is valid - load up the actual login session
    login_session = LoginSession.from_data(
                        ObjectStore.get_object_from_json(bucket,
                                                         login_session_key))

    # we must record the session against which this otpcode has
    # been validated. This is to stop us validating an otpcode more than
    # once (e.g. if the password and code have been intercepted).
    # Any sessions validated using the same code should be treated
    # as immediately suspcious
    otproot = "otps/%s" % user_account.sanitised_name()
    sessions = ObjectStore.get_all_strings(bucket, otproot)

    utcnow = datetime.datetime.utcnow()

    for session in sessions:
        otpkey = "%s/%s" % (otproot, session)
        otpstring = ObjectStore.get_string_object(bucket, otpkey)

        (timestamp, code) = otpstring.split("|||")

        # remove all codes that are more than 10 minutes old. The
        # otp codes are only valid for 3 minutes, so no need to record
        # codes that have been used that are older than that...
        timedelta = utcnow - datetime.datetime.fromtimestamp(
                                                    float(timestamp))

        if timedelta.seconds > 600:
            try:
                ObjectStore.delete_object(bucket, otpkey)
            except:
                pass

        elif code == str(otpcode):
            # Low probability there is some recycling,
            # but very suspicious if the code was validated within the last
            # 10 minutes... (as 3 minute timeout of a code)
            suspect_key = "sessions/%s/%s" % (
                user_account.sanitised_name(), session)

            suspect_session = None

            try:
                suspect_session = LoginSession.from_data(
                        ObjectStore.get_object_from_json(bucket,
                                                         suspect_key))
            except:
                pass

            if suspect_session:
                suspect_session.set_suspicious()
                ObjectStore.set_object_from_json(bucket, suspect_key,
                                                 suspect_session.to_data())

            raise LoginError(
                "Cannot authorise the login as the one-time-code "
                "you supplied has already been used within the last 10 "
                "minutes. The chance of this happening is really low, so "
                "we are treating this as a suspicious event. You need to "
                "try another code. Meanwhile, the other login that used "
                "this code has been put into a 'suspicious' state.")

    # record the value and timestamp of when this otpcode was used
    otpkey = "%s/%s" % (otproot, login_session.uuid())
    otpstring = "%s|||%s" % (datetime.datetime.utcnow().timestamp(),
                             otpcode)

    ObjectStore.set_string_object(bucket, otpkey, otpstring)

    login_session.set_approved()

    # write this session back to the object store
    ObjectStore.set_object_from_json(bucket, login_session_key,
                                     login_session.to_data())

    # save the device secret as everything has now worked
    if assigned_device_uid:
        ObjectStore.set_string_object(bucket, device_key,
                                      device_secret)

    # finally, remove this from the list of requested logins
    try:
        ObjectStore.delete_object(bucket, request_session_key)
    except:
        pass

    status = 0
    message = "Success: Status = %s" % login_session.status()

    return_value = create_return_value(status, message)

    if provisioning_uri:
        return_value["provisioning_uri"] = provisioning_uri
        return_value["device_uid"] = assigned_device_uid

    return return_value
Ejemplo n.º 8
0
def run(args):
    """This function will allow anyone to obtain the public
       keys for the passed login session
    """
    try:
        session_uid = args["session_uid"]
    except:
        session_uid = None

    try:
        short_uid = args["short_uid"]
    except:
        short_uid = None

    try:
        scope = args["scope"]
    except:
        scope = None

    try:
        permissions = args["permissions"]
    except:
        permissions = None

    if session_uid:
        login_session = LoginSession.load(uid=session_uid,
                                          scope=scope,
                                          permissions=permissions)
    else:
        if short_uid is None:
            raise PermissionError(
                "You must specify either the session_uid or the short_uid "
                "of the login session")

        try:
            status = args["status"]
        except:
            raise PermissionError(
                "You must specify the status of the short_uid session you "
                "wish to query...")

        login_session = LoginSession.load(short_uid=short_uid,
                                          status=status,
                                          scope=scope,
                                          permissions=permissions)

    return_value = {}

    # only send information if the user had logged in!
    should_return_data = False

    if login_session.is_approved():
        should_return_data = True
        return_value["public_key"] = login_session.public_key().to_data()

    elif login_session.is_logged_out():
        should_return_data = True
        return_value["logout_datetime"] = \
            datetime_to_string(login_session.logout_time())

    if should_return_data:
        return_value["public_cert"] = \
            login_session.public_certificate().to_data()
        return_value["scope"] = login_session.scope()
        return_value["permissions"] = login_session.permissions()
        return_value["user_uid"] = login_session.user_uid()

    return_value["session_status"] = login_session.status()
    return_value["login_message"] = login_session.login_message()

    return return_value
Ejemplo n.º 9
0
def run(args):
    """This function is called by the user to log in and validate
       that a session is authorised to connect

       Args:
        args (dict): contains identifying information about the user,
                     short_UID, username, password and OTP code
        Returns:
            dict: contains a URI and a UID for this login
    """
    short_uid = args["short_uid"]
    packed_credentials = args["credentials"]

    try:
        user_uid = args["user_uid"]
    except:
        user_uid = None

    try:
        remember_device = args["remember_device"]

        if remember_device:
            remember_device = True
        else:
            remember_device = False
    except:
        remember_device = False

    # get the session referred to by the short_uid
    sessions = LoginSession.load(short_uid=short_uid, status="pending")

    if isinstance(sessions, LoginSession):
        # we have many sessions to test...
        sessions = [sessions]

    result = None
    login_session = None
    last_error = None
    credentials = None

    for session in sessions:
        try:
            if credentials is None:
                credentials = Credentials.from_data(
                    data=packed_credentials,
                    username=session.username(),
                    short_uid=short_uid)
            else:
                credentials.assert_matching_username(session.username())

            result = UserAccount.login(credentials=credentials,
                                       user_uid=user_uid,
                                       remember_device=remember_device)
            login_session = session

            # success!
            break
        except Exception as e:
            last_error = e

    if result is None or login_session is None:
        # no valid logins
        raise last_error

    # we've successfully logged in
    login_session.set_approved(user_uid=result["user"].uid(),
                               device_uid=result["device_uid"])

    return_value = {}

    return_value["user_uid"] = login_session.user_uid()

    if remember_device:
        try:
            service = get_this_service(need_private_access=False)
            hostname = service.hostname()
            if hostname is None:
                hostname = "acquire"
            issuer = "%s@%s" % (service.service_type(), hostname)
            username = result["user"].name()
            device_uid = result["device_uid"]

            otp = result["otp"]
            provisioning_uri = otp.provisioning_uri(username=username,
                                                    issuer=issuer)

            return_value["provisioning_uri"] = provisioning_uri
            return_value["otpsecret"] = otp.secret()
            return_value["device_uid"] = device_uid
        except:
            pass

    return return_value
Ejemplo n.º 10
0
def run(args):
    """This function will allow anyone to obtain the public
       keys for the passed login session of a user with
       a specified login UID"""

    public_key = None
    public_cert = None
    login_status = None
    logout_timestamp = None

    session_uid = args["session_uid"]
    username = args["username"]

    # generate a sanitised version of the username
    user_account = UserAccount(username)

    # now log into the central identity account to query
    # the current status of this login session
    bucket = login_to_service_account()

    user_session_key = "sessions/%s/%s" % \
            (user_account.sanitised_name(), session_uid)

    try:
        login_session = LoginSession.from_data(
            ObjectStore.get_object_from_json(bucket, user_session_key))
    except:
        login_session = None

    if login_session is None:
        user_session_key = "expired_sessions/%s/%s" % \
                                (user_account.sanitised_name(),
                                 session_uid)

        login_session = LoginSession.from_data(
            ObjectStore.get_object_from_json(bucket, user_session_key))

    if login_session is None:
        raise InvalidSessionError("Cannot find the session '%s'" % session_uid)

    # only send valid keys if the user had logged in!
    if login_session.is_approved():
        public_key = login_session.public_key()
        public_cert = login_session.public_certificate()

    elif login_session.is_logged_out():
        public_cert = login_session.public_certificate()
        logout_timestamp = login_session.logout_time().timestamp()

    else:
        raise InvalidSessionError("You cannot get the keys for a session "
                                  "for which the user has not logged in!")

    login_status = login_session.status()

    status = 0
    message = "Success: Status = %s" % login_session.status()

    return_value = create_return_value(status, message)

    if public_key:
        return_value["public_key"] = public_key.to_data()

    if public_cert:
        return_value["public_cert"] = public_cert.to_data()

    if login_status:
        return_value["login_status"] = str(login_status)

    if logout_timestamp:
        return_value["logout_timestamp"] = logout_timestamp

    return return_value
Ejemplo n.º 11
0
def run(args):
    """This function will allow anyone to query who matches
       the passed UID or username (map from one to the other)"""

    status = 0
    message = None
    user_uid = None
    username = None
    public_key = None
    public_cert = None
    logout_timestamp = None
    login_status = None

    try:
        user_uid = args["user_uid"]
    except:
        pass

    try:
        username = args["username"]
    except:
        pass

    try:
        session_uid = args["session_uid"]
    except:
        session_uid = None

    bucket = None
    user_account = None

    if user_uid is None and username is None:
        raise WhoisLookupError(
            "You must supply either a username or user_uid to look up...")

    elif user_uid is None:
        # look up the user_uid from the username
        user_account = UserAccount(username)
        bucket = login_to_service_account()
        user_key = "accounts/%s" % user_account.sanitised_name()

        try:
            user_account = UserAccount.from_data(
                ObjectStore.get_object_from_json(bucket, user_key))
        except:
            raise WhoisLookupError("Cannot find an account for name '%s'" %
                                   username)

        user_uid = user_account.uid()

    elif username is None:
        # look up the username from the uuid
        bucket = login_to_service_account()

        uid_key = "whois/%s" % user_uid

        try:
            username = ObjectStore.get_string_object(bucket, uid_key)
        except:
            raise WhoisLookupError("Cannot find an account for user_uid '%s'" %
                                   user_uid)

    else:
        raise WhoisLookupError("You must only supply one of the username "
                               "or user_uid to look up - not both!")

    if session_uid:
        # now look up the public signing key for this session, if it is
        # a valid login session
        if user_account is None:
            user_account = UserAccount(username)

        user_session_key = "sessions/%s/%s" % \
            (user_account.sanitised_name(), session_uid)

        try:
            login_session = LoginSession.from_data(
                ObjectStore.get_object_from_json(bucket, user_session_key))
        except:
            login_session = None

        if login_session is None:
            user_session_key = "expired_sessions/%s/%s" % \
                                    (user_account.sanitised_name(),
                                     session_uid)

            login_session = LoginSession.from_data(
                ObjectStore.get_object_from_json(bucket, user_session_key))

        if login_session is None:
            raise InvalidSessionError("Cannot find the session '%s'" %
                                      session_uid)

        if login_session.is_approved():
            public_key = login_session.public_key()
            public_cert = login_session.public_certificate()

        elif login_session.is_logged_out():
            public_cert = login_session.public_certificate()
            logout_timestamp = login_session.logout_time().timestamp()

        else:
            raise InvalidSessionError("You cannot get the keys for a session "
                                      "for which the user has not logged in!")

        login_status = login_session.status()

    status = 0
    message = "Success"

    return_value = create_return_value(status, message)

    if user_uid:
        return_value["user_uid"] = str(user_uid)

    if username:
        return_value["username"] = str(username)

    if public_key:
        return_value["public_key"] = public_key.to_data()

    if public_cert:
        return_value["public_cert"] = public_cert.to_data()

    if logout_timestamp:
        return_value["logout_timestamp"] = logout_timestamp

    if login_status:
        return_value["login_status"] = str(login_status)

    return return_value
Ejemplo n.º 12
0
def run(args):
    """This function will allow a user to request a new session
       that will be validated by the passed public key and public
       signing certificate. This will return a URL that the user
       must connect to to then log in and validate that request.
    """

    status = 0
    message = None
    login_url = None
    login_uid = None
    user_uid = None

    username = args["username"]
    public_key = PublicKey.from_data(args["public_key"])
    public_cert = PublicKey.from_data(args["public_certificate"])

    ip_addr = None
    hostname = None
    login_message = None

    try:
        ip_addr = args["ipaddr"]
    except:
        pass

    try:
        hostname = args["hostname"]
    except:
        pass

    try:
        login_message = args["message"]
    except:
        pass

    # generate a sanitised version of the username
    user_account = UserAccount(username)

    # Now generate a login session for this request
    login_session = LoginSession(public_key, public_cert, ip_addr, hostname,
                                 login_message)

    # now log into the central identity account to record
    # that a request to open a login session has been opened
    bucket = login_to_service_account()

    # first, make sure that the user exists...
    account_key = "accounts/%s" % user_account.sanitised_name()

    try:
        existing_data = ObjectStore.get_object_from_json(bucket, account_key)
    except:
        existing_data = None

    if existing_data is None:
        raise InvalidLoginError("There is no user with name '%s'" % username)

    user_account = UserAccount.from_data(existing_data)
    user_uid = user_account.uid()

    # first, make sure that the user doens't have too many open
    # login sessions at once - this prevents denial of service
    user_session_root = "sessions/%s" % user_account.sanitised_name()

    open_sessions = ObjectStore.get_all_object_names(bucket, user_session_root)

    # take the opportunity to prune old user login sessions
    prune_expired_sessions(bucket, user_account, user_session_root,
                           open_sessions)

    # this is the key for the session in the object store
    user_session_key = "%s/%s" % (user_session_root, login_session.uuid())

    ObjectStore.set_object_from_json(bucket, user_session_key,
                                     login_session.to_data())

    # we will record a pointer to the request using the short
    # UUID. This way we can give a simple URL. If there is a clash,
    # then we will use the username provided at login to find the
    # correct request from a much smaller pool (likely < 3)
    request_key = "requests/%s/%s" % (login_session.short_uuid(),
                                      login_session.uuid())

    ObjectStore.set_string_object(bucket, request_key, user_account.name())

    status = 0
    # the login URL is the URL of this identity service plus the
    # short UID of the session
    login_url = "%s/s?id=%s" % (get_service_info().service_url(),
                                login_session.short_uuid())

    login_uid = login_session.uuid()

    message = "Success: Login via %s" % login_url

    return_value = create_return_value(status, message)

    if login_uid:
        return_value["session_uid"] = login_uid

    if login_url:
        return_value["login_url"] = login_url
    else:
        return_value["login_url"] = None

    if user_uid:
        return_value["user_uid"] = user_uid

    return return_value
Ejemplo n.º 13
0
def prune_expired_sessions(bucket, user_account, root, sessions, log=[]):
    """This function will scan through all open requests and
       login sessions and will prune away old, expired or otherwise
       weird sessions. It will also use the ipaddress of the source
       to rate limit or blacklist sources"""

    for name in sessions:
        key = "%s/%s" % (root, name)
        request_key = "requests/%s/%s" % (name[:8], name)

        try:
            session = ObjectStore.get_object_from_json(bucket, key)
        except:
            log.append("Session %s does not exist!" % name)
            session = None

        if session:
            should_delete = False
            should_logout = False

            try:
                session = LoginSession.from_data(session)
                if session.is_approved() or session.is_suspicious():
                    if session.hours_since_creation() > user_account \
                                                            .login_timeout():
                        should_logout = True
                        should_delete = True
                else:
                    if session.hours_since_creation() > user_account \
                                                    .login_request_timeout():
                        log.append("Expired login request: %s > %s" %
                                   (session.hours_since_creation(),
                                    user_account.login_request_timeout()))
                        should_delete = True
            except Exception as e:
                # this is corrupt - delete it
                log.append("Deleting session as corrupt? %s" % str(e))
                should_delete = True

            if should_logout:
                # auto-logout expired sessions
                log.append("Auto-logging out expired session '%s'" % key)
                session.logout()
                expire_session_key = "expired_sessions/%s/%s" % \
                                     (user_account.sanitised_name(),
                                      session.uuid())

                ObjectStore.set_object_from_json(bucket, expire_session_key,
                                                 session.to_data())

            # now delete any expired sessions
            if should_delete:
                log.append("Deleting expired session '%s'" % key)

                try:
                    ObjectStore.delete_object(bucket, key)
                except:
                    pass

                try:
                    ObjectStore.delete_object(bucket, request_key)
                except:
                    pass