Exemple #1
0
    def create_ssh_tunnel(self, tunnel_password):
        """
        This method is used to create ssh tunnel and update the IP Address and
        IP Address and port to localhost and the local bind port return by the
        SSHTunnelForwarder class.
        :return: True if tunnel is successfully created else error message.
        """
        # Fetch Logged in User Details.
        user = User.query.filter_by(id=current_user.id).first()
        if user is None:
            return False, gettext("Unauthorized request.")

        if tunnel_password is not None and tunnel_password != '':
            crypt_key_present, crypt_key = get_crypt_key()
            if not crypt_key_present:
                raise CryptKeyMissing()

            try:
                tunnel_password = decrypt(tunnel_password, crypt_key)
                # Handling of non ascii password (Python2)
                if hasattr(str, 'decode'):
                    tunnel_password = \
                        tunnel_password.decode('utf-8').encode('utf-8')
                # password is in bytes, for python3 we need it in string
                elif isinstance(tunnel_password, bytes):
                    tunnel_password = tunnel_password.decode()

            except Exception as e:
                current_app.logger.exception(e)
                return False, "Failed to decrypt the SSH tunnel " \
                              "password.\nError: {0}".format(str(e))

        try:
            # If authentication method is 1 then it uses identity file
            # and password
            if self.tunnel_authentication == 1:
                self.tunnel_object = SSHTunnelForwarder(
                    (self.tunnel_host, int(self.tunnel_port)),
                    ssh_username=self.tunnel_username,
                    ssh_pkey=get_complete_file_path(self.tunnel_identity_file),
                    ssh_private_key_password=tunnel_password,
                    remote_bind_address=(self.host, self.port))
            else:
                self.tunnel_object = SSHTunnelForwarder(
                    (self.tunnel_host, int(self.tunnel_port)),
                    ssh_username=self.tunnel_username,
                    ssh_password=tunnel_password,
                    remote_bind_address=(self.host, self.port))

            self.tunnel_object.start()
            self.tunnel_created = True
        except BaseSSHTunnelForwarderError as e:
            current_app.logger.exception(e)
            return False, "Failed to create the SSH tunnel." \
                          "\nError: {0}".format(str(e))

        # Update the port to communicate locally
        self.local_bind_port = self.tunnel_object.local_bind_port

        return True, None
Exemple #2
0
def reset_master_password():
    """
    Removes the master password and remove all saved passwords
    This password will be used to encrypt/decrypt saved server passwords
    """
    cleanup_master_password()
    return make_json_response(data=get_crypt_key()[0])
Exemple #3
0
    def export_password_env(self, env):
        if self.password:
            crypt_key_present, crypt_key = get_crypt_key()
            if not crypt_key_present:
                return False, crypt_key

            password = decrypt(self.password, crypt_key).decode()
            os.environ[str(env)] = password
Exemple #4
0
    def change_password():
        """View function which handles a change password request."""

        has_error = False
        form_class = _security.change_password_form

        if request.json:
            form = form_class(MultiDict(request.json))
        else:
            form = form_class()

        if form.validate_on_submit():
            try:
                change_user_password(current_user._get_current_object(),
                                     form.new_password.data)
            except SOCKETErrorException as e:
                # Handle socket errors which are not covered by SMTPExceptions.
                logging.exception(str(e), exc_info=True)
                flash(gettext(SMTP_SOCKET_ERROR).format(e), 'danger')
                has_error = True
            except (SMTPConnectError, SMTPResponseException,
                    SMTPServerDisconnected, SMTPDataError, SMTPHeloError,
                    SMTPException, SMTPAuthenticationError, SMTPSenderRefused,
                    SMTPRecipientsRefused) as e:
                # Handle smtp specific exceptions.
                logging.exception(str(e), exc_info=True)
                flash(gettext(SMTP_ERROR).format(e), 'danger')
                has_error = True
            except Exception as e:
                # Handle other exceptions.
                logging.exception(str(e), exc_info=True)
                flash(gettext(PASS_ERROR).format(e), 'danger')
                has_error = True

            if request.json is None and not has_error:
                after_this_request(view_commit)
                do_flash(*get_message('PASSWORD_CHANGE'))

                old_key = get_crypt_key()[1]
                set_crypt_key(form.new_password.data, False)

                from pgadmin.browser.server_groups.servers.utils \
                    import reencrpyt_server_passwords
                reencrpyt_server_passwords(current_user.id, old_key,
                                           form.new_password.data)

                return redirect(
                    get_url(_security.post_change_view)
                    or get_url(_security.post_login_view))

        if request.json and not has_error:
            form.user = current_user
            return default_render_json(form)

        return _security.render_template(
            config_value('CHANGE_PASSWORD_TEMPLATE'),
            change_password_form=form,
            **_ctx('change_password'))
Exemple #5
0
def set_master_password():
    """
    Set the master password and store in the memory
    This password will be used to encrypt/decrypt saved server passwords
    """

    data = None

    if hasattr(request.data, 'decode'):
        data = request.data.decode('utf-8')

    if data != '':
        data = json.loads(data)

    # Master password is not applicable for server mode
    if not config.SERVER_MODE and config.MASTER_PASSWORD_REQUIRED:

        # if master pass is set previously
        if current_user.masterpass_check is not None and \
            data.get('button_click') and \
                not validate_master_password(data.get('password')):
            return form_master_password_response(
                existing=True,
                present=False,
                errmsg=gettext("Incorrect master password"))

        if data != '' and data.get('password', '') != '':

            # store the master pass in the memory
            set_crypt_key(data.get('password'))

            if current_user.masterpass_check is None:
                # master check is not set, which means the server password
                # data is old and is encrypted with old key
                # Re-encrypt with new key

                from pgadmin.browser.server_groups.servers.utils \
                    import reencrpyt_server_passwords
                reencrpyt_server_passwords(current_user.id,
                                           current_user.password,
                                           data.get('password'))

            # set the encrypted sample text with the new
            # master pass
            set_masterpass_check_text(data.get('password'))

        elif not get_crypt_key()[0] and \
                current_user.masterpass_check is not None:
            return form_master_password_response(
                existing=True,
                present=False,
            )
        elif not get_crypt_key()[0]:
            error_message = None
            if data.get('button_click') and data.get('password') == '':
                # If user attempted to enter a blank password, then throw error
                error_message = gettext("Master password cannot be empty")
            return form_master_password_response(existing=False,
                                                 present=False,
                                                 errmsg=error_message)

    # if master password is disabled now, but was used once then
    # remove all the saved passwords
    process_masterpass_disabled()

    if config.SERVER_MODE and current_user.masterpass_check is None:

        crypt_key = get_crypt_key()[1]
        from pgadmin.browser.server_groups.servers.utils \
            import reencrpyt_server_passwords
        reencrpyt_server_passwords(current_user.id, current_user.password,
                                   crypt_key)

        set_masterpass_check_text(crypt_key)

    return form_master_password_response(present=True, )
Exemple #6
0
def check_master_password():
    """
    Checks if the master password is available in the memory
    This password will be used to encrypt/decrypt saved server passwords
    """
    return make_json_response(data=get_crypt_key()[0])
Exemple #7
0
    def connection(self,
                   database=None,
                   conn_id=None,
                   auto_reconnect=True,
                   did=None,
                   async_=None,
                   use_binary_placeholder=False,
                   array_to_string=False):
        if database is not None:
            if hasattr(str, 'decode') and \
                    not isinstance(database, unicode):
                database = database.decode('utf-8')
            if did is not None:
                if did in self.db_info:
                    self.db_info[did]['datname'] = database
        else:
            if did is None:
                database = self.db
            elif did in self.db_info:
                database = self.db_info[did]['datname']
            else:
                maintenance_db_id = u'DB:{0}'.format(self.db)
                if maintenance_db_id in self.connections:
                    conn = self.connections[maintenance_db_id]
                    # try to connect maintenance db if not connected
                    if not conn.connected():
                        conn.connect()

                    if conn.connected():
                        status, res = conn.execute_dict(u"""
SELECT
    db.oid as did, db.datname, db.datallowconn,
    pg_encoding_to_char(db.encoding) AS serverencoding,
    has_database_privilege(db.oid, 'CREATE') as cancreate, datlastsysoid
FROM
    pg_database db
WHERE db.oid = {0}""".format(did))

                        if status and len(res['rows']) > 0:
                            for row in res['rows']:
                                self.db_info[did] = row
                                database = self.db_info[did]['datname']

                        if did not in self.db_info:
                            raise Exception(
                                gettext(
                                    "Could not find the specified database."))

        if not get_crypt_key()[0]:
            # the reason its not connected might be missing key
            raise CryptKeyMissing()

        if database is None:
            # Check SSH Tunnel is alive or not.
            if self.use_ssh_tunnel == 1:
                self.check_ssh_tunnel_alive()
            else:
                raise ConnectionLost(self.sid, None, None)

        my_id = (u'CONN:{0}'.format(conn_id)) if conn_id is not None else \
            (u'DB:{0}'.format(database))

        self.pinged = datetime.datetime.now()

        if my_id in self.connections:
            return self.connections[my_id]
        else:
            if async_ is None:
                async_ = 1 if conn_id is not None else 0
            else:
                async_ = 1 if async_ is True else 0
            self.connections[my_id] = Connection(
                self,
                my_id,
                database,
                auto_reconnect,
                async_,
                use_binary_placeholder=use_binary_placeholder,
                array_to_string=array_to_string)

            return self.connections[my_id]
Exemple #8
0
    def connection(self, **kwargs):
        database = kwargs.get('database', None)
        conn_id = kwargs.get('conn_id', None)
        auto_reconnect = kwargs.get('auto_reconnect', True)
        did = kwargs.get('did', None)
        async_ = kwargs.get('async_', None)
        use_binary_placeholder = kwargs.get('use_binary_placeholder', False)
        array_to_string = kwargs.get('array_to_string', False)

        if database is not None:
            if did is not None and did in self.db_info:
                self.db_info[did]['datname'] = database
        else:
            if did is None:
                database = self.db
            elif did in self.db_info:
                database = self.db_info[did]['datname']
            else:
                maintenance_db_id = 'DB:{0}'.format(self.db)
                if maintenance_db_id in self.connections:
                    conn = self.connections[maintenance_db_id]
                    # try to connect maintenance db if not connected
                    if not conn.connected():
                        conn.connect()

                    if conn.connected():
                        status, res = conn.execute_dict("""
SELECT
    db.oid as did, db.datname, db.datallowconn,
    pg_catalog.pg_encoding_to_char(db.encoding) AS serverencoding,
    pg_catalog.has_database_privilege(db.oid, 'CREATE') as cancreate,
    datlastsysoid, datistemplate
FROM
    pg_catalog.pg_database db
WHERE db.oid = {0}""".format(did))

                        if status and len(res['rows']) > 0:
                            for row in res['rows']:
                                self.db_info[did] = row
                                database = self.db_info[did]['datname']

                        if did not in self.db_info:
                            raise ObjectGone(
                                gettext(
                                    "Could not find the specified database."))

        if not get_crypt_key()[0]:
            # the reason its not connected might be missing key
            raise CryptKeyMissing()

        if database is None:
            # Check SSH Tunnel is alive or not.
            if self.use_ssh_tunnel == 1:
                self.check_ssh_tunnel_alive()
            else:
                raise ConnectionLost(self.sid, None, None)

        my_id = ('CONN:{0}'.format(conn_id)) if conn_id is not None else \
            ('DB:{0}'.format(database))

        self.pinged = datetime.datetime.now()

        if my_id in self.connections:
            return self.connections[my_id]
        else:
            if async_ is None:
                async_ = 1 if conn_id is not None else 0
            else:
                async_ = 1 if async_ is True else 0
            self.connections[my_id] = Connection(
                self,
                my_id,
                database,
                auto_reconnect=auto_reconnect,
                async_=async_,
                use_binary_placeholder=use_binary_placeholder,
                array_to_string=array_to_string)

            return self.connections[my_id]