def get_jwt_keys(self) -> Union[RSAPrivateKey, str]: """ Takes a provider and returns the set of keys associated with it. Returns a list of keys. """ if self.jwt_alg == JWTAlgorithms.RS256: # if the user selected RS256 but didn't select a # CertificateKeyPair, we fall back to HS256 if not self.rsa_key: Event.new( EventAction.CONFIGURATION_ERROR, provider=self, message= "Provider was configured for RS256, but no key was selected.", ).save() self.jwt_alg = JWTAlgorithms.HS256 self.save() else: return self.rsa_key.private_key if self.jwt_alg == JWTAlgorithms.HS256: return self.client_secret raise Exception("Unsupported key algorithm.")
def check_saml_request(self) -> Optional[HttpRequest]: """Handle REDIRECT bindings""" if REQUEST_KEY_SAML_REQUEST not in self.request.GET: LOGGER.info("handle_saml_request: SAML payload missing") return bad_request_message(self.request, "The SAML request payload is missing.") try: auth_n_request = AuthNRequestParser(self.provider).parse_detached( self.request.GET[REQUEST_KEY_SAML_REQUEST], self.request.GET.get(REQUEST_KEY_RELAY_STATE), self.request.GET.get(REQUEST_KEY_SAML_SIGNATURE), self.request.GET.get(REQUEST_KEY_SAML_SIG_ALG), ) self.request.session[SESSION_KEY_AUTH_N_REQUEST] = auth_n_request except CannotHandleAssertion as exc: Event.new( EventAction.CONFIGURATION_ERROR, provider=self.provider, message=str(exc), ).save() LOGGER.info(str(exc)) return bad_request_message(self.request, str(exc)) return None
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))
def create_event(self, action: str, message: str, **kwargs): """Create event with common values from `self.request` and `self.binding`.""" # Keep a reference to http_request even if its None, because cleanse_dict will remove it http_request = self.request.http_request event = Event.new( action=action, message=message, policy_uuid=self.binding.policy.policy_uuid.hex, binding=self.binding, request=self.request, **kwargs, ) event.set_user(self.request.user) if http_request: event.from_http(http_request) else: event.save()
def test_event_retention(self): """Test tenant's event retention""" tenant = Tenant.objects.create( domain="foo", default=True, branding_title="custom", event_retention="weeks=3", ) factory = RequestFactory() request = factory.get("/") request.tenant = tenant event = Event.new(action=EventAction.SYSTEM_EXCEPTION, message="test").from_http(request) self.assertEqual(event.expires.day, (event.created + timedelta_from_string("weeks=3")).day) self.assertEqual( event.expires.month, (event.created + timedelta_from_string("weeks=3")).month, ) self.assertEqual( event.expires.year, (event.created + timedelta_from_string("weeks=3")).year )
def test(self, request: Request, pk=None) -> Response: """Send example notification using selected transport. Requires Modify permissions.""" transport: NotificationTransport = self.get_object() notification = Notification( severity=NotificationSeverity.NOTICE, body=f"Test Notification from transport {transport.name}", user=request.user, event=Event( action="Test", user=get_user(request.user), app=self.__class__.__module__, context={"foo": "bar"}, ), ) try: response = NotificationTransportTestSerializer( data={"messages": transport.send(notification)}) response.is_valid() return Response(response.data) except NotificationTransportError as exc: return Response(str(exc.__cause__ or None), status=500)
def sync(self) -> int: """Iterate over all LDAP Users and create authentik_core.User instances""" if not self._source.sync_users: self._logger.warning("User syncing is disabled for this Source") return -1 users = self._source.connection.extend.standard.paged_search( search_base=self.base_dn_users, search_filter=self._source.user_object_filter, search_scope=ldap3.SUBTREE, attributes=[ ldap3.ALL_ATTRIBUTES, ldap3.ALL_OPERATIONAL_ATTRIBUTES ], ) user_count = 0 for user in users: attributes = user.get("attributes", {}) user_dn = self._flatten(user.get("entryDN", user.get("dn"))) if self._source.object_uniqueness_field not in attributes: self._logger.warning( "Cannot find uniqueness Field in attributes", attributes=attributes.keys(), dn=user_dn, ) continue uniq = self._flatten( attributes[self._source.object_uniqueness_field]) try: defaults = self.build_user_properties(user_dn, **attributes) self._logger.debug("Creating user with attributes", **defaults) if "username" not in defaults: raise IntegrityError( "Username was not set by propertymappings") ak_user, created = User.objects.update_or_create( **{ f"attributes__{LDAP_UNIQUENESS}": uniq, "defaults": defaults, }) except (IntegrityError, FieldError) as exc: Event.new( EventAction.CONFIGURATION_ERROR, message=( f"Failed to create user: {str(exc)} " "To merge new user with existing user, set the user's " f"Attribute '{LDAP_UNIQUENESS}' to '{uniq}'"), source=self._source, dn=user_dn, ).save() else: self._logger.debug("Synced User", user=ak_user.username, created=created) user_count += 1 pwd_last_set: datetime = attributes.get( "pwdLastSet", datetime.now()) pwd_last_set = pwd_last_set.replace(tzinfo=UTC) if created or pwd_last_set >= ak_user.password_change_date: self._logger.debug( "Reset user's password", user=ak_user.username, created=created, pwd_last_set=pwd_last_set, ) ak_user.set_unusable_password() ak_user.save() return user_count
def pre_delete_event(sender, instance: TOTPDevice, **_): """Create event before deleting TOTP Devices""" # Create event with email notification event = Event.new("totp_disable", message="User disabled Time-based OTP.") event.set_user(instance.user) event.save()
def run(self): Event.new(self.action, **self.kwargs).from_http(self.request, user=self.user)
def sync(self) -> int: """Iterate over all LDAP Groups and create authentik_core.Group instances""" if not self._source.sync_groups: self.message("Group syncing is disabled for this Source") return -1 groups = self._source.connection.extend.standard.paged_search( search_base=self.base_dn_groups, search_filter=self._source.group_object_filter, search_scope=ldap3.SUBTREE, attributes=[ ldap3.ALL_ATTRIBUTES, ldap3.ALL_OPERATIONAL_ATTRIBUTES ], ) group_count = 0 for group in groups: attributes = group.get("attributes", {}) group_dn = self._flatten( self._flatten(group.get("entryDN", group.get("dn")))) if self._source.object_uniqueness_field not in attributes: self.message( f"Cannot find uniqueness field in attributes: '{group_dn}'", attributes=attributes.keys(), dn=group_dn, ) continue uniq = self._flatten( attributes[self._source.object_uniqueness_field]) try: defaults = self.build_group_properties(group_dn, **attributes) self._logger.debug("Creating group with attributes", **defaults) if "name" not in defaults: raise IntegrityError( "Name was not set by propertymappings") # Special check for `users` field, as this is an M2M relation, and cannot be sync'd if "users" in defaults: del defaults["users"] ak_group, created = self.update_or_create_attributes( Group, { f"attributes__{LDAP_UNIQUENESS}": uniq, "parent": self._source.sync_parent_group, }, defaults, ) except (IntegrityError, FieldError, TypeError) as exc: Event.new( EventAction.CONFIGURATION_ERROR, message= (f"Failed to create group: {str(exc)} " "To merge new group with existing group, set the groups's " f"Attribute '{LDAP_UNIQUENESS}' to '{uniq}'"), source=self._source, dn=group_dn, ).save() else: self._logger.debug("Synced group", group=ak_group.name, created=created) group_count += 1 return group_count
def view_key(self, request: Request, identifier: str) -> Response: """Return token key and log access""" token: Token = self.get_object() Event.new(EventAction.SECRET_VIEW, secret=token).from_http(request) # noqa # nosec return Response(TokenViewSerializer({"key": token.key}).data)