The key issue here was SecurityContextHolder using ThreadLocal and my subsystem using custom class loader. SecurityContextHolder called within a class, created by custom class loader will cause that class loader to load SecurityContextHolder class and initialize it with empty context, hence the effect described above.
So in short, ThreadLocal and custom class loaders do not mix well, as described here: