def send_webhook(self, notification: "Notification") -> list[str]: """Send notification to generic webhook""" default_body = { "body": notification.body, "severity": notification.severity, "user_email": notification.user.email, "user_username": notification.user.username, } if self.webhook_mapping: default_body = self.webhook_mapping.evaluate( user=notification.user, request=None, notification=notification, ) try: response = get_http_session().post( self.webhook_url, json=default_body, ) response.raise_for_status() except RequestException as exc: raise NotificationTransportError(exc.response.text) from exc return [ response.status_code, response.text, ]
def passes(self, request: PolicyRequest) -> PolicyResult: """Check if password is in HIBP DB. Hashes given Password with SHA1, uses the first 5 characters of Password in request and checks if full hash is in response. Returns 0 if Password is not in result otherwise the count of how many times it was used.""" if self.password_field not in request.context: LOGGER.warning( "Password field not set in Policy Request", field=self.password_field, fields=request.context.keys(), ) return PolicyResult(False, _("Password not set in context")) password = request.context[self.password_field] pw_hash = sha1(password.encode("utf-8")).hexdigest() # nosec url = f"https://api.pwnedpasswords.com/range/{pw_hash[:5]}" result = get_http_session().get(url).text final_count = 0 for line in result.split("\r\n"): full_hash, count = line.split(":") if pw_hash[5:] == full_hash.lower(): final_count = int(count) LOGGER.debug("got hibp result", count=final_count, hash=pw_hash[:5]) if final_count > self.allowed_count: message = _("Password exists on %(count)d online lists." % {"count": final_count}) return PolicyResult(False, message) return PolicyResult(True)
def send_twilio(self, token: str, device: "SMSDevice"): """send sms via twilio provider""" response = get_http_session().post( f"https://api.twilio.com/2010-04-01/Accounts/{self.account_sid}/Messages.json", data={ "From": self.from_number, "To": device.phone_number, "Body": token, }, auth=(self.account_sid, self.auth), ) LOGGER.debug("Sent SMS", to=device.phone_number) try: response.raise_for_status() except RequestException as exc: LOGGER.warning("Error sending token by Twilio SMS", exc=exc, body=response.text) if response.status_code == 400: raise ValidationError(response.json().get("message")) raise if "sid" not in response.json(): message = response.json().get("message") LOGGER.warning("Error sending token by Twilio SMS", message=message) raise Exception(message)
def __init__(self, source: OAuthSource, request: HttpRequest, callback: Optional[str] = None): self.source = source self.session = get_http_session() self.request = request self.callback = callback
def send_generic(self, token: str, device: "SMSDevice"): """Send SMS via outside API""" data = { "From": self.from_number, "To": device.phone_number, "Body": token, } if self.auth_type == SMSAuthTypes.BEARER: response = get_http_session().post( f"{self.account_sid}", json=data, headers={"Authorization": f"Bearer {self.auth}"}, ) elif self.auth_type == SMSAuthTypes.BASIC: response = get_http_session().post( f"{self.account_sid}", json=data, auth=(self.auth, self.auth_password), ) else: raise ValueError(f"Invalid Auth type '{self.auth_type}'") LOGGER.debug("Sent SMS", to=device.phone_number) try: response.raise_for_status() except RequestException as exc: LOGGER.warning( "Error sending token by generic SMS", exc=exc, status=response.status_code, body=response.text[:100], ) Event.new( EventAction.CONFIGURATION_ERROR, message="Error sending SMS", exc=exception_to_string(exc), status_code=response.status_code, body=response.text, ).set_user(device.user).save() if response.status_code >= 400: raise ValidationError(response.text) raise
def __init__(self, source: PlexSource, token: str): self._source = source self._token = token self._session = get_http_session() self._session.headers.update({ "Accept": "application/json", "Content-Type": "application/json" }) self._session.headers.update(self.headers)
def __init__(self): # update website/docs/expressions/_objects.md # update website/docs/expressions/_functions.md self._globals = { "regex_match": BaseEvaluator.expr_regex_match, "regex_replace": BaseEvaluator.expr_regex_replace, "ak_is_group_member": BaseEvaluator.expr_is_group_member, "ak_user_by": BaseEvaluator.expr_user_by, "ak_logger": get_logger(), "requests": get_http_session(), } self._context = {} self._filename = "BaseEvalautor"
def send_webhook_slack(self, notification: "Notification") -> list[str]: """Send notification to slack or slack-compatible endpoints""" fields = [ { "title": _("Severity"), "value": notification.severity, "short": True, }, { "title": _("Dispatched for user"), "value": str(notification.user), "short": True, }, ] if notification.event: for key, value in notification.event.context.items(): if not isinstance(value, str): continue # https://birdie0.github.io/discord-webhooks-guide/other/field_limits.html if len(fields) >= 25: continue fields.append({"title": key[:256], "value": value[:1024]}) body = { "username": "******", "icon_url": "https://goauthentik.io/img/icon.png", "attachments": [{ "author_name": "authentik", "author_link": "https://goauthentik.io", "author_icon": "https://goauthentik.io/img/icon.png", "title": notification.body, "color": "#fd4b2d", "fields": fields, "footer": f"authentik v{__version__}", }], } if notification.event: body["attachments"][0]["title"] = notification.event.action try: response = get_http_session().post(self.webhook_url, json=body) response.raise_for_status() except RequestException as exc: text = exc.response.text if exc.response else str(exc) raise NotificationTransportError(text) from exc return [ response.status_code, response.text, ]
def validate_token(self, token: str) -> str: """Validate captcha token""" stage: CaptchaStage = self.stage.executor.current_stage try: response = get_http_session().post( "https://www.google.com/recaptcha/api/siteverify", headers={ "Content-type": "application/x-www-form-urlencoded", }, data={ "secret": stage.private_key, "response": token, "remoteip": get_client_ip(self.stage.request), }, ) response.raise_for_status() data = response.json() if not data.get("success", False): raise ValidationError( f"Failed to validate token: {data.get('error-codes', '')}") except RequestException as exc: raise ValidationError("Failed to validate token") from exc return token
def update_latest_version(self: MonitoredTask): """Update latest version info""" if CONFIG.y_bool("disable_update_check"): cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT) self.set_status( TaskResult(TaskResultStatus.WARNING, messages=["Version check disabled."])) return try: response = get_http_session().get( "https://version.goauthentik.io/version.json", ) response.raise_for_status() data = response.json() upstream_version = data.get("stable", {}).get("version") cache.set(VERSION_CACHE_KEY, upstream_version, VERSION_CACHE_TIMEOUT) self.set_status( TaskResult(TaskResultStatus.SUCCESSFUL, ["Successfully updated latest Version"])) _set_prom_info() # Check if upstream version is newer than what we're running, # and if no event exists yet, create one. if LOCAL_VERSION < parse(upstream_version): # Event has already been created, don't create duplicate if Event.objects.filter( action=EventAction.UPDATE_AVAILABLE, context__new_version=upstream_version, ).exists(): return event_dict = {"new_version": upstream_version} if match := re.search(URL_FINDER, data.get("stable", {}).get("changelog", "")): event_dict["message"] = f"Changelog: {match.group()}" Event.new(EventAction.UPDATE_AVAILABLE, **event_dict).save() except (RequestException, IndexError) as exc: cache.set(VERSION_CACHE_KEY, "0.0.0", VERSION_CACHE_TIMEOUT) self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc))
) if not CONFIG.y_bool("disable_startup_analytics", False): should_send = env not in ["dev", "ci"] if should_send: try: get_http_session().post( "https://goauthentik.io/api/event", json={ "domain": "authentik", "name": "pageview", "referrer": get_full_version(), "url": (f"http://localhost/{env}?utm_source={get_full_version()}&utm_medium={env}" ), }, headers={ "User-Agent": sha512(str(SECRET_KEY).encode("ascii")).hexdigest()[:16], "Content-Type": "application/json", }, timeout=5, ) # pylint: disable=bare-except except: # nosec pass # Static files (CSS, JavaScript, Images)