def resolveStandardUserToken(self, username, password, clientId): params = self.resolveStandardUserTokenRequestParameters(clientId) redirectUri = urllib.parse.unquote(params['redirectUri']) params = self.resolveKeycloakSessionAuthenticationCode(username, password, params) code = params.get("code", None) if isEmpty(code): die("No Keycloak access token session code") requestHeaders = { "Accepts": "application/json", "Content-Type": "application/x-www-form-urlencoded" } formData = "&".join( ( "grant_type=authorization_code", "code=%s" % code, "client_id=%s" % clientId, "redirect_uri=%s"% redirectUri ) ) url = self.resolveKeycloakDirectTokenAccessUrl() rsp = self.executeHttpRequest(url, "POST", requestHeaders, formData, asJson=True) return rsp["body"]
def resolveKeycloakRealmAccessUrl(self): if self.args is None: die("No Keycloak access arguments provided") protocol = self.args.get("protocol", "https") host = self.args.get("host", None) if isEmpty(host): die("No Keycloak host specified") port = self.args.get("port", -1) realm = self.args.get("realm", "unifiedpush-installations") if port > 0: return "%s://%s:%d/auth/realms/%s" % (protocol, host, port, realm) else: return "%s://%s/auth/realms/%s" % (protocol, host, realm)
def parse_site_url(args): url = args["site_basic_url"] protocol = url.split("://")[0] args["protocol"] = protocol base_url = url.split("://")[1] args["host"] = base_url.split(":")[0] if len(base_url.split(":")) > 1: args["port"] = base_url.split(":")[1] domain = args.get("domain") if domain not in base_url: die("domain %s is missing from site_basic_url %s" % (domain, url)) client_id = base_url.split("-%s" % domain)[0] args["clientId"] = client_id
def resolveKeycloakSessionAuthenticationCode(self, username, password, params): url = params['loginUrl'] if isEmpty(url): die("Failed to extract Keycloak login URL value") cookies = {} sessionId = params.get('AUTH_SESSION_ID', None) if isEmpty(sessionId): die("No Keycloak session ID cookie present") cookies["AUTH_SESSION_ID"] = sessionId kcToken = params.get('KC_RESTART', None) if isEmpty(kcToken): die("No Keycloak restart cookie present") cookies["KC_RESTART"] = kcToken requestHeaders = { "Content-Type": "application/x-www-form-urlencoded", "Referer": params["referer"] } formData = "&".join(("username=%s" % username, "password=%s" % password)) rsp = self.executeHttpRequest(url, "POST", requestHeaders, formData, cookieJar=cookies, asJson=False) redirectHistory = rsp.get("history", None) if isEmpty(redirectHistory): if "INVALID_USER_PASS" in rsp.get("body", None): die("Invalid Username or Password") else: die("No Keycloak redirection available") rdData = redirectHistory[0] rdHeaders = rdData.headers locHeader = rdHeaders.get("Location", None) locItems = urllib.parse.urlparse(locHeader) # Response is https://..../#state=... queryParams = urllib.parse.parse_qs(locItems.fragment) code = queryParams.get("code", None) if isinstance(code, list): code = code[0] return { "url": rdData.url, "cookies": rsp.get("cookies", None), "code": code }
def run(self, opt_args=None): pyVersion = sys.version_info if pyVersion.major != 3: die("Major Python version must be 3.x: %s" % str(pyVersion)) if pyVersion.minor < 0: die("Minor Python version %s should be at least 3.0+" % str(pyVersion)) signal.signal(signal.SIGINT, self.signal_handler) if os.name == 'nt': sys.stderr.write("Use Ctrl+Break to stop the script\n") else: sys.stderr.write("Use Ctrl+C to stop the script\n") if opt_args is None: args = arguments_parser.ArgumentParser( self.report_type).parse_arguments() else: args = opt_args arguments_parser.process_args(args, self.report_type) logFactory = LogFactory(args) logger = logFactory.getLogger("main") token_fetcher = access_token_fetcher.AccessTokenFetcher(logger, args) token = token_fetcher.get_access_token() if isEmpty(token): die("Could not get access token for the username") try: if self.report_type == ReportType.RESPONSE: self.response_report(args, logger, token) else: self.earnings_report(args, logger, token) finally: token_fetcher.logout(token)
def resolve_user_token(self, username, password): self.logger.debug("Retrieving Keycloak access token") if isinstance(username, (int, float)): username = str(username) elif isEmpty(username): die("No Keycloak access username provided") if isinstance(password, (int, float)): password = str(password) elif isEmpty(password): die("No Keycloak access password provided") clientId = self.args.get("clientId", None) if isEmpty(clientId): die("No Keycloak client identifier provided") clientIdFormat = self.args.get("clientIdFormat", "ups-installation-%s") effectiveClientId = clientIdFormat % clientId mode = self.args.get("mode", "STANDARD") mode = mode.upper() if mode == "STANDARD": rsp = self.resolveStandardUserToken( username, password, effectiveClientId) elif mode == "DIRECT": rsp = self.resolveDirectGrantUserToken( username, password, effectiveClientId) else: die("Unknown Keycloak access token retrieval mode: %s" % mode) accessToken = rsp.get("access_token", None) self.refresh_token = rsp.get("refresh_token", None) if isEmpty(accessToken): self.logger.error("No access token in Keycloak response: %s" % str(rsp)) die("No access token returned from Keycloak") self.logger.debug("Retrieved Keycloak access token") return accessToken
def appendLog(self, level, msg, err=None): nowValue = datetime.datetime.now() timestamp = nowValue.strftime(self.dateTimeFormat) threadName = "unknown" thread = threading.current_thread() if not thread is None: threadName = thread.name if msg: if '\n' in msg: for line in msg.splitlines(False): self.writeLogMessage( level, "%s %s [%s] [%s] %s" % (timestamp, threadName, level.name, self.name, line)) else: self.writeLogMessage( level, "%s %s [%s] [%s] %s" % (timestamp, threadName, level.name, self.name, msg)) if err: self.writeLogMessage( level, "%s %s [%s] [%s] %s: %s" % (timestamp, threadName, level.name, self.name, err.__class__.__name__, str(err))) if self.maxStackTraceDepth > 0: # TODO this doesn't quite do the job - by the time it is here, most stack trace data is gone... traceValue = traceback.format_exc(self.maxStackTraceDepth) lines = traceValue.splitlines() for traceLine in lines: self.writeLogMessage( level, "%s %s [%s] %s %s" % (timestamp, threadName, level.name, self.name, traceLine)) if err.__class__.__name__ == "KeyboardInterrupt": die("Killed by Control+C")
def signal_handler(self): die('Exit due to Control+C')