예제 #1
0
 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,
     ]
예제 #2
0
    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)
예제 #3
0
    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)
예제 #4
0
 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
예제 #5
0
    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
예제 #6
0
 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)
예제 #7
0
 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"
예제 #8
0
 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,
     ]
예제 #9
0
 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
예제 #10
0
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))
예제 #11
0
    )
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)